diff options
Diffstat (limited to 'drivers/net/ipa/ipa_main.c')
-rw-r--r-- | drivers/net/ipa/ipa_main.c | 102 |
1 files changed, 61 insertions, 41 deletions
diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index da853353a5c7..57b241417e8c 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -7,7 +7,6 @@ #include <linux/types.h> #include <linux/atomic.h> #include <linux/bitfield.h> -#include <linux/device.h> #include <linux/bug.h> #include <linux/io.h> #include <linux/firmware.h> @@ -74,6 +73,7 @@ #define IPA_PAS_ID 15 /* Shift of 19.2 MHz timestamp to achieve lower resolution timestamps */ +/* IPA v5.5+ does not specify Qtime timestamp config for DPL */ #define DPL_TIMESTAMP_SHIFT 14 /* ~1.172 kHz, ~853 usec per tick */ #define TAG_TIMESTAMP_SHIFT 14 #define NAT_TIMESTAMP_SHIFT 24 /* ~1.144 Hz, ~874 msec per tick */ @@ -113,7 +113,7 @@ int ipa_setup(struct ipa *ipa) { struct ipa_endpoint *exception_endpoint; struct ipa_endpoint *command_endpoint; - struct device *dev = &ipa->pdev->dev; + struct device *dev = ipa->dev; int ret; ret = gsi_setup(&ipa->gsi); @@ -376,9 +376,11 @@ static void ipa_qtime_config(struct ipa *ipa) iowrite32(0, ipa->reg_virt + reg_offset(reg)); reg = ipa_reg(ipa, QTIME_TIMESTAMP_CFG); - /* Set DPL time stamp resolution to use Qtime (instead of 1 msec) */ - val = reg_encode(reg, DPL_TIMESTAMP_LSB, DPL_TIMESTAMP_SHIFT); - val |= reg_bit(reg, DPL_TIMESTAMP_SEL); + if (ipa->version < IPA_VERSION_5_5) { + /* Set DPL time stamp resolution to use Qtime (not 1 msec) */ + val = reg_encode(reg, DPL_TIMESTAMP_LSB, DPL_TIMESTAMP_SHIFT); + val |= reg_bit(reg, DPL_TIMESTAMP_SEL); + } /* Configure tag and NAT Qtime timestamp resolution as well */ val = reg_encode(reg, TAG_TIMESTAMP_LSB, TAG_TIMESTAMP_SHIFT); val = reg_encode(reg, NAT_TIMESTAMP_LSB, NAT_TIMESTAMP_SHIFT); @@ -539,12 +541,9 @@ static int ipa_config(struct ipa *ipa, const struct ipa_data *data) if (ret) goto err_hardware_deconfig; - ipa->interrupt = ipa_interrupt_config(ipa); - if (IS_ERR(ipa->interrupt)) { - ret = PTR_ERR(ipa->interrupt); - ipa->interrupt = NULL; + ret = ipa_interrupt_config(ipa); + if (ret) goto err_mem_deconfig; - } ipa_uc_config(ipa); @@ -569,8 +568,7 @@ err_endpoint_deconfig: ipa_endpoint_deconfig(ipa); err_uc_deconfig: ipa_uc_deconfig(ipa); - ipa_interrupt_deconfig(ipa->interrupt); - ipa->interrupt = NULL; + ipa_interrupt_deconfig(ipa); err_mem_deconfig: ipa_mem_deconfig(ipa); err_hardware_deconfig: @@ -588,8 +586,7 @@ static void ipa_deconfig(struct ipa *ipa) ipa_modem_deconfig(ipa); ipa_endpoint_deconfig(ipa); ipa_uc_deconfig(ipa); - ipa_interrupt_deconfig(ipa->interrupt); - ipa->interrupt = NULL; + ipa_interrupt_deconfig(ipa); ipa_mem_deconfig(ipa); ipa_hardware_deconfig(ipa); } @@ -688,6 +685,10 @@ static const struct of_device_id ipa_match[] = { .compatible = "qcom,sdx65-ipa", .data = &ipa_data_v5_0, }, + { + .compatible = "qcom,sm8550-ipa", + .data = &ipa_data_v5_5, + }, { }, }; MODULE_DEVICE_TABLE(of, ipa_match); @@ -801,6 +802,7 @@ out_self: static int ipa_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct ipa_interrupt *interrupt; enum ipa_firmware_loader loader; const struct ipa_data *data; struct ipa_power *power; @@ -832,12 +834,21 @@ static int ipa_probe(struct platform_device *pdev) if (loader == IPA_LOADER_DEFER) return -EPROBE_DEFER; - /* The clock and interconnects might not be ready when we're - * probed, so might return -EPROBE_DEFER. + /* The IPA interrupt might not be ready when we're probed, so this + * might return -EPROBE_DEFER. + */ + interrupt = ipa_interrupt_init(pdev); + if (IS_ERR(interrupt)) + return PTR_ERR(interrupt); + + /* The clock and interconnects might not be ready when we're probed, + * so this might return -EPROBE_DEFER. */ power = ipa_power_init(dev, data->power_data); - if (IS_ERR(power)) - return PTR_ERR(power); + if (IS_ERR(power)) { + ret = PTR_ERR(power); + goto err_interrupt_exit; + } /* No more EPROBE_DEFER. Allocate and initialize the IPA structure */ ipa = kzalloc(sizeof(*ipa), GFP_KERNEL); @@ -846,18 +857,19 @@ static int ipa_probe(struct platform_device *pdev) goto err_power_exit; } - ipa->pdev = pdev; + ipa->dev = dev; dev_set_drvdata(dev, ipa); + ipa->interrupt = interrupt; ipa->power = power; ipa->version = data->version; ipa->modem_route_count = data->modem_route_count; init_completion(&ipa->completion); - ret = ipa_reg_init(ipa); + ret = ipa_reg_init(ipa, pdev); if (ret) goto err_kfree_ipa; - ret = ipa_mem_init(ipa, data->mem_data); + ret = ipa_mem_init(ipa, pdev, data->mem_data); if (ret) goto err_reg_exit; @@ -875,7 +887,7 @@ static int ipa_probe(struct platform_device *pdev) if (ret) goto err_endpoint_exit; - ret = ipa_smp2p_init(ipa, loader == IPA_LOADER_MODEM); + ret = ipa_smp2p_init(ipa, pdev, loader == IPA_LOADER_MODEM); if (ret) goto err_table_exit; @@ -932,17 +944,27 @@ err_kfree_ipa: kfree(ipa); err_power_exit: ipa_power_exit(power); +err_interrupt_exit: + ipa_interrupt_exit(interrupt); return ret; } -static int ipa_remove(struct platform_device *pdev) +static void ipa_remove(struct platform_device *pdev) { - struct ipa *ipa = dev_get_drvdata(&pdev->dev); - struct ipa_power *power = ipa->power; - struct device *dev = &pdev->dev; + struct ipa_interrupt *interrupt; + struct ipa_power *power; + struct device *dev; + struct ipa *ipa; int ret; + ipa = dev_get_drvdata(&pdev->dev); + dev = ipa->dev; + WARN_ON(dev != &pdev->dev); + + power = ipa->power; + interrupt = ipa->interrupt; + /* Prevent the modem from triggering a call to ipa_setup(). This * also ensures a modem-initiated setup that's underway completes. */ @@ -959,8 +981,16 @@ static int ipa_remove(struct platform_device *pdev) usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC); ret = ipa_modem_stop(ipa); } - if (ret) - return ret; + if (ret) { + /* + * Not cleaning up here properly might also yield a + * crash later on. As the device is still unregistered + * in this case, this might even yield a crash later on. + */ + dev_err(dev, "Failed to stop modem (%pe), leaking resources\n", + ERR_PTR(ret)); + return; + } ipa_teardown(ipa); } @@ -976,19 +1006,9 @@ out_power_put: ipa_reg_exit(ipa); kfree(ipa); ipa_power_exit(power); + ipa_interrupt_exit(interrupt); dev_info(dev, "IPA driver removed"); - - return 0; -} - -static void ipa_shutdown(struct platform_device *pdev) -{ - int ret; - - ret = ipa_remove(pdev); - if (ret) - dev_err(&pdev->dev, "shutdown: remove returned %d\n", ret); } static const struct attribute_group *ipa_attribute_groups[] = { @@ -1001,8 +1021,8 @@ static const struct attribute_group *ipa_attribute_groups[] = { static struct platform_driver ipa_driver = { .probe = ipa_probe, - .remove = ipa_remove, - .shutdown = ipa_shutdown, + .remove_new = ipa_remove, + .shutdown = ipa_remove, .driver = { .name = "ipa", .pm = &ipa_pm_ops, |