Lines Matching +full:ipa +full:- +full:reg
1 // SPDX-License-Identifier: GPL-2.0
3 /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
4 * Copyright (C) 2018-2023 Linaro Ltd.
22 #include "ipa.h"
41 * This driver supports the Qualcomm IP Accelerator (IPA), which is a
42 * networking component found in many Qualcomm SoCs. The IPA is connected
46 * The IPA is the conduit between the AP and the modem that carries network
50 * The IPA provides protocol checksum calculation, offloading this work
51 * from the AP. The IPA offers additional functionality, including routing,
53 * currently supported. Despite that, some resources--including routing
54 * tables and filter tables--are defined in this driver because they must
57 * There are two distinct layers that implement the IPA hardware, and this
59 * interface (GSI) is an integral component of the IPA, providing a
60 * well-defined communication layer between the AP subsystem and the IPA
62 * between the AP and the IPA.
64 * The IPA layer uses GSI channels to implement its "endpoints". And while
65 * a GSI channel carries data between the AP and the IPA, a pair of IPA
77 /* IPA v5.5+ does not specify Qtime timestamp config for DPL */
103 * ipa_setup() - Set up IPA hardware
104 * @ipa: IPA pointer
113 int ipa_setup(struct ipa *ipa) in ipa_setup() argument
117 struct device *dev = &ipa->pdev->dev; in ipa_setup()
120 ret = gsi_setup(&ipa->gsi); in ipa_setup()
124 ret = ipa_power_setup(ipa); in ipa_setup()
128 ipa_endpoint_setup(ipa); in ipa_setup()
133 command_endpoint = ipa->name_map[IPA_ENDPOINT_AP_COMMAND_TX]; in ipa_setup()
138 ret = ipa_mem_setup(ipa); /* No matching teardown required */ in ipa_setup()
142 ret = ipa_table_setup(ipa); /* No matching teardown required */ in ipa_setup()
149 exception_endpoint = ipa->name_map[IPA_ENDPOINT_AP_LAN_RX]; in ipa_setup()
154 ipa_endpoint_default_route_set(ipa, exception_endpoint->endpoint_id); in ipa_setup()
157 ret = ipa_qmi_setup(ipa); in ipa_setup()
161 ipa->setup_complete = true; in ipa_setup()
163 dev_info(dev, "IPA driver setup completed successfully\n"); in ipa_setup()
168 ipa_endpoint_default_route_clear(ipa); in ipa_setup()
173 ipa_endpoint_teardown(ipa); in ipa_setup()
174 ipa_power_teardown(ipa); in ipa_setup()
176 gsi_teardown(&ipa->gsi); in ipa_setup()
182 * ipa_teardown() - Inverse of ipa_setup()
183 * @ipa: IPA pointer
185 static void ipa_teardown(struct ipa *ipa) in ipa_teardown() argument
191 ipa->setup_complete = false; in ipa_teardown()
193 ipa_qmi_teardown(ipa); in ipa_teardown()
194 ipa_endpoint_default_route_clear(ipa); in ipa_teardown()
195 exception_endpoint = ipa->name_map[IPA_ENDPOINT_AP_LAN_RX]; in ipa_teardown()
197 command_endpoint = ipa->name_map[IPA_ENDPOINT_AP_COMMAND_TX]; in ipa_teardown()
199 ipa_endpoint_teardown(ipa); in ipa_teardown()
200 ipa_power_teardown(ipa); in ipa_teardown()
201 gsi_teardown(&ipa->gsi); in ipa_teardown()
205 ipa_hardware_config_bcr(struct ipa *ipa, const struct ipa_data *data) in ipa_hardware_config_bcr() argument
207 const struct reg *reg; in ipa_hardware_config_bcr() local
210 /* IPA v4.5+ has no backward compatibility register */ in ipa_hardware_config_bcr()
211 if (ipa->version >= IPA_VERSION_4_5) in ipa_hardware_config_bcr()
214 reg = ipa_reg(ipa, IPA_BCR); in ipa_hardware_config_bcr()
215 val = data->backward_compat; in ipa_hardware_config_bcr()
216 iowrite32(val, ipa->reg_virt + reg_offset(reg)); in ipa_hardware_config_bcr()
219 static void ipa_hardware_config_tx(struct ipa *ipa) in ipa_hardware_config_tx() argument
221 enum ipa_version version = ipa->version; in ipa_hardware_config_tx()
222 const struct reg *reg; in ipa_hardware_config_tx() local
230 reg = ipa_reg(ipa, IPA_TX_CFG); in ipa_hardware_config_tx()
231 offset = reg_offset(reg); in ipa_hardware_config_tx()
233 val = ioread32(ipa->reg_virt + offset); in ipa_hardware_config_tx()
235 val &= ~reg_bit(reg, PA_MASK_EN); in ipa_hardware_config_tx()
237 iowrite32(val, ipa->reg_virt + offset); in ipa_hardware_config_tx()
240 static void ipa_hardware_config_clkon(struct ipa *ipa) in ipa_hardware_config_clkon() argument
242 enum ipa_version version = ipa->version; in ipa_hardware_config_clkon()
243 const struct reg *reg; in ipa_hardware_config_clkon() local
253 reg = ipa_reg(ipa, CLKON_CFG); in ipa_hardware_config_clkon()
256 val = reg_bit(reg, CLKON_MISC); in ipa_hardware_config_clkon()
257 } else { /* IPA v4.0+ */ in ipa_hardware_config_clkon()
259 val = reg_bit(reg, CLKON_GLOBAL); in ipa_hardware_config_clkon()
260 val |= reg_bit(reg, GLOBAL_2X_CLK); in ipa_hardware_config_clkon()
263 iowrite32(val, ipa->reg_virt + reg_offset(reg)); in ipa_hardware_config_clkon()
266 /* Configure bus access behavior for IPA components */
267 static void ipa_hardware_config_comp(struct ipa *ipa) in ipa_hardware_config_comp() argument
269 const struct reg *reg; in ipa_hardware_config_comp() local
273 /* Nothing to configure prior to IPA v4.0 */ in ipa_hardware_config_comp()
274 if (ipa->version < IPA_VERSION_4_0) in ipa_hardware_config_comp()
277 reg = ipa_reg(ipa, COMP_CFG); in ipa_hardware_config_comp()
278 offset = reg_offset(reg); in ipa_hardware_config_comp()
280 val = ioread32(ipa->reg_virt + offset); in ipa_hardware_config_comp()
282 if (ipa->version == IPA_VERSION_4_0) { in ipa_hardware_config_comp()
283 val &= ~reg_bit(reg, IPA_QMB_SELECT_CONS_EN); in ipa_hardware_config_comp()
284 val &= ~reg_bit(reg, IPA_QMB_SELECT_PROD_EN); in ipa_hardware_config_comp()
285 val &= ~reg_bit(reg, IPA_QMB_SELECT_GLOBAL_EN); in ipa_hardware_config_comp()
286 } else if (ipa->version < IPA_VERSION_4_5) { in ipa_hardware_config_comp()
287 val |= reg_bit(reg, GSI_MULTI_AXI_MASTERS_DIS); in ipa_hardware_config_comp()
289 /* For IPA v4.5+ FULL_FLUSH_WAIT_RS_CLOSURE_EN is 0 */ in ipa_hardware_config_comp()
292 val |= reg_bit(reg, GSI_MULTI_INORDER_RD_DIS); in ipa_hardware_config_comp()
293 val |= reg_bit(reg, GSI_MULTI_INORDER_WR_DIS); in ipa_hardware_config_comp()
295 iowrite32(val, ipa->reg_virt + offset); in ipa_hardware_config_comp()
300 ipa_hardware_config_qsb(struct ipa *ipa, const struct ipa_data *data) in ipa_hardware_config_qsb() argument
304 const struct reg *reg; in ipa_hardware_config_qsb() local
308 data0 = &data->qsb_data[IPA_QSB_MASTER_DDR]; in ipa_hardware_config_qsb()
309 if (data->qsb_count > 1) in ipa_hardware_config_qsb()
310 data1 = &data->qsb_data[IPA_QSB_MASTER_PCIE]; in ipa_hardware_config_qsb()
313 reg = ipa_reg(ipa, QSB_MAX_WRITES); in ipa_hardware_config_qsb()
315 val = reg_encode(reg, GEN_QMB_0_MAX_WRITES, data0->max_writes); in ipa_hardware_config_qsb()
316 if (data->qsb_count > 1) in ipa_hardware_config_qsb()
317 val |= reg_encode(reg, GEN_QMB_1_MAX_WRITES, data1->max_writes); in ipa_hardware_config_qsb()
319 iowrite32(val, ipa->reg_virt + reg_offset(reg)); in ipa_hardware_config_qsb()
322 reg = ipa_reg(ipa, QSB_MAX_READS); in ipa_hardware_config_qsb()
324 val = reg_encode(reg, GEN_QMB_0_MAX_READS, data0->max_reads); in ipa_hardware_config_qsb()
325 if (ipa->version >= IPA_VERSION_4_0) in ipa_hardware_config_qsb()
326 val |= reg_encode(reg, GEN_QMB_0_MAX_READS_BEATS, in ipa_hardware_config_qsb()
327 data0->max_reads_beats); in ipa_hardware_config_qsb()
328 if (data->qsb_count > 1) { in ipa_hardware_config_qsb()
329 val = reg_encode(reg, GEN_QMB_1_MAX_READS, data1->max_reads); in ipa_hardware_config_qsb()
330 if (ipa->version >= IPA_VERSION_4_0) in ipa_hardware_config_qsb()
331 val |= reg_encode(reg, GEN_QMB_1_MAX_READS_BEATS, in ipa_hardware_config_qsb()
332 data1->max_reads_beats); in ipa_hardware_config_qsb()
335 iowrite32(val, ipa->reg_virt + reg_offset(reg)); in ipa_hardware_config_qsb()
349 return DIV_ROUND_CLOSEST(usec * TIMER_FREQUENCY, USEC_PER_SEC) - 1; in ipa_aggr_granularity_val()
352 /* IPA uses unified Qtime starting at IPA v4.5, implementing various
353 * timestamps and timers independent of the IPA core clock rate. The
354 * Qtimer is based on a 56-bit timestamp incremented at each tick of
357 * For IPA timestamps (tag, NAT, data path logging) a lower resolution
359 * some number of bits to produce the low-order bits of the coarser
365 * timer ticks at a configurable frequency. IPA timers (such as
366 * those used for aggregation or head-of-line block handling) now
369 static void ipa_qtime_config(struct ipa *ipa) in ipa_qtime_config() argument
371 const struct reg *reg; in ipa_qtime_config() local
376 reg = ipa_reg(ipa, TIMERS_XO_CLK_DIV_CFG); in ipa_qtime_config()
377 iowrite32(0, ipa->reg_virt + reg_offset(reg)); in ipa_qtime_config()
379 reg = ipa_reg(ipa, QTIME_TIMESTAMP_CFG); in ipa_qtime_config()
380 if (ipa->version < IPA_VERSION_5_5) { in ipa_qtime_config()
382 val = reg_encode(reg, DPL_TIMESTAMP_LSB, DPL_TIMESTAMP_SHIFT); in ipa_qtime_config()
383 val |= reg_bit(reg, DPL_TIMESTAMP_SEL); in ipa_qtime_config()
386 val = reg_encode(reg, TAG_TIMESTAMP_LSB, TAG_TIMESTAMP_SHIFT); in ipa_qtime_config()
387 val = reg_encode(reg, NAT_TIMESTAMP_LSB, NAT_TIMESTAMP_SHIFT); in ipa_qtime_config()
389 iowrite32(val, ipa->reg_virt + reg_offset(reg)); in ipa_qtime_config()
392 reg = ipa_reg(ipa, TIMERS_PULSE_GRAN_CFG); in ipa_qtime_config()
393 val = reg_encode(reg, PULSE_GRAN_0, IPA_GRAN_100_US); in ipa_qtime_config()
394 val |= reg_encode(reg, PULSE_GRAN_1, IPA_GRAN_1_MS); in ipa_qtime_config()
395 if (ipa->version >= IPA_VERSION_5_0) { in ipa_qtime_config()
396 val |= reg_encode(reg, PULSE_GRAN_2, IPA_GRAN_10_MS); in ipa_qtime_config()
397 val |= reg_encode(reg, PULSE_GRAN_3, IPA_GRAN_10_MS); in ipa_qtime_config()
399 val |= reg_encode(reg, PULSE_GRAN_2, IPA_GRAN_1_MS); in ipa_qtime_config()
402 iowrite32(val, ipa->reg_virt + reg_offset(reg)); in ipa_qtime_config()
405 reg = ipa_reg(ipa, TIMERS_XO_CLK_DIV_CFG); in ipa_qtime_config()
406 offset = reg_offset(reg); in ipa_qtime_config()
408 val = reg_encode(reg, DIV_VALUE, IPA_XO_CLOCK_DIVIDER - 1); in ipa_qtime_config()
410 iowrite32(val, ipa->reg_virt + offset); in ipa_qtime_config()
412 /* Divider value is set; re-enable the common timer clock divider */ in ipa_qtime_config()
413 val |= reg_bit(reg, DIV_ENABLE); in ipa_qtime_config()
415 iowrite32(val, ipa->reg_virt + offset); in ipa_qtime_config()
418 /* Before IPA v4.5 timing is controlled by a counter register */
419 static void ipa_hardware_config_counter(struct ipa *ipa) in ipa_hardware_config_counter() argument
422 const struct reg *reg; in ipa_hardware_config_counter() local
425 reg = ipa_reg(ipa, COUNTER_CFG); in ipa_hardware_config_counter()
427 val = reg_encode(reg, AGGR_GRANULARITY, granularity); in ipa_hardware_config_counter()
428 iowrite32(val, ipa->reg_virt + reg_offset(reg)); in ipa_hardware_config_counter()
431 static void ipa_hardware_config_timing(struct ipa *ipa) in ipa_hardware_config_timing() argument
433 if (ipa->version < IPA_VERSION_4_5) in ipa_hardware_config_timing()
434 ipa_hardware_config_counter(ipa); in ipa_hardware_config_timing()
436 ipa_qtime_config(ipa); in ipa_hardware_config_timing()
439 static void ipa_hardware_config_hashing(struct ipa *ipa) in ipa_hardware_config_hashing() argument
441 const struct reg *reg; in ipa_hardware_config_hashing() local
443 /* Other than IPA v4.2, all versions enable "hashing". Starting in ipa_hardware_config_hashing()
444 * with IPA v5.0, the filter and router tables are implemented in ipa_hardware_config_hashing()
448 if (ipa->version != IPA_VERSION_4_2) in ipa_hardware_config_hashing()
451 /* IPA v4.2 does not support hashed tables, so disable them */ in ipa_hardware_config_hashing()
452 reg = ipa_reg(ipa, FILT_ROUT_HASH_EN); in ipa_hardware_config_hashing()
457 iowrite32(0, ipa->reg_virt + reg_offset(reg)); in ipa_hardware_config_hashing()
460 static void ipa_idle_indication_cfg(struct ipa *ipa, in ipa_idle_indication_cfg() argument
464 const struct reg *reg; in ipa_idle_indication_cfg() local
467 if (ipa->version < IPA_VERSION_3_5_1) in ipa_idle_indication_cfg()
470 reg = ipa_reg(ipa, IDLE_INDICATION_CFG); in ipa_idle_indication_cfg()
471 val = reg_encode(reg, ENTER_IDLE_DEBOUNCE_THRESH, in ipa_idle_indication_cfg()
474 val |= reg_bit(reg, CONST_NON_IDLE_ENABLE); in ipa_idle_indication_cfg()
476 iowrite32(val, ipa->reg_virt + reg_offset(reg)); in ipa_idle_indication_cfg()
480 * ipa_hardware_dcd_config() - Enable dynamic clock division on IPA
481 * @ipa: IPA pointer
483 * Configures when the IPA signals it is idle to the global clock
487 static void ipa_hardware_dcd_config(struct ipa *ipa) in ipa_hardware_dcd_config() argument
489 /* Recommended values for IPA 3.5 and later according to IPA HPG */ in ipa_hardware_dcd_config()
490 ipa_idle_indication_cfg(ipa, 256, false); in ipa_hardware_dcd_config()
493 static void ipa_hardware_dcd_deconfig(struct ipa *ipa) in ipa_hardware_dcd_deconfig() argument
495 /* Power-on reset values */ in ipa_hardware_dcd_deconfig()
496 ipa_idle_indication_cfg(ipa, 0, true); in ipa_hardware_dcd_deconfig()
500 * ipa_hardware_config() - Primitive hardware initialization
501 * @ipa: IPA pointer
502 * @data: IPA configuration data
504 static void ipa_hardware_config(struct ipa *ipa, const struct ipa_data *data) in ipa_hardware_config() argument
506 ipa_hardware_config_bcr(ipa, data); in ipa_hardware_config()
507 ipa_hardware_config_tx(ipa); in ipa_hardware_config()
508 ipa_hardware_config_clkon(ipa); in ipa_hardware_config()
509 ipa_hardware_config_comp(ipa); in ipa_hardware_config()
510 ipa_hardware_config_qsb(ipa, data); in ipa_hardware_config()
511 ipa_hardware_config_timing(ipa); in ipa_hardware_config()
512 ipa_hardware_config_hashing(ipa); in ipa_hardware_config()
513 ipa_hardware_dcd_config(ipa); in ipa_hardware_config()
517 * ipa_hardware_deconfig() - Inverse of ipa_hardware_config()
518 * @ipa: IPA pointer
520 * This restores the power-on reset values (even if they aren't different)
522 static void ipa_hardware_deconfig(struct ipa *ipa) in ipa_hardware_deconfig() argument
525 ipa_hardware_dcd_deconfig(ipa); in ipa_hardware_deconfig()
529 * ipa_config() - Configure IPA hardware
530 * @ipa: IPA pointer
531 * @data: IPA configuration data
533 * Perform initialization requiring IPA power to be enabled.
535 static int ipa_config(struct ipa *ipa, const struct ipa_data *data) in ipa_config() argument
539 ipa_hardware_config(ipa, data); in ipa_config()
541 ret = ipa_mem_config(ipa); in ipa_config()
545 ipa->interrupt = ipa_interrupt_config(ipa); in ipa_config()
546 if (IS_ERR(ipa->interrupt)) { in ipa_config()
547 ret = PTR_ERR(ipa->interrupt); in ipa_config()
548 ipa->interrupt = NULL; in ipa_config()
552 ipa_uc_config(ipa); in ipa_config()
554 ret = ipa_endpoint_config(ipa); in ipa_config()
558 ipa_table_config(ipa); /* No deconfig required */ in ipa_config()
561 ret = ipa_resource_config(ipa, data->resource_data); in ipa_config()
565 ret = ipa_modem_config(ipa); in ipa_config()
572 ipa_endpoint_deconfig(ipa); in ipa_config()
574 ipa_uc_deconfig(ipa); in ipa_config()
575 ipa_interrupt_deconfig(ipa->interrupt); in ipa_config()
576 ipa->interrupt = NULL; in ipa_config()
578 ipa_mem_deconfig(ipa); in ipa_config()
580 ipa_hardware_deconfig(ipa); in ipa_config()
586 * ipa_deconfig() - Inverse of ipa_config()
587 * @ipa: IPA pointer
589 static void ipa_deconfig(struct ipa *ipa) in ipa_deconfig() argument
591 ipa_modem_deconfig(ipa); in ipa_deconfig()
592 ipa_endpoint_deconfig(ipa); in ipa_deconfig()
593 ipa_uc_deconfig(ipa); in ipa_deconfig()
594 ipa_interrupt_deconfig(ipa->interrupt); in ipa_deconfig()
595 ipa->interrupt = NULL; in ipa_deconfig()
596 ipa_mem_deconfig(ipa); in ipa_deconfig()
597 ipa_hardware_deconfig(ipa); in ipa_deconfig()
611 node = of_parse_phandle(dev->of_node, "memory-region", 0); in ipa_firmware_load()
613 dev_err(dev, "DT error getting \"memory-region\" property\n"); in ipa_firmware_load()
614 return -EINVAL; in ipa_firmware_load()
620 dev_err(dev, "error %d getting \"memory-region\" resource\n", in ipa_firmware_load()
626 ret = of_property_read_string(dev->of_node, "firmware-name", &path); in ipa_firmware_load()
628 dev_dbg(dev, "error %d getting \"firmware-name\" resource\n", in ipa_firmware_load()
644 ret = -ENOMEM; in ipa_firmware_load()
663 .compatible = "qcom,msm8998-ipa",
667 .compatible = "qcom,sdm845-ipa",
671 .compatible = "qcom,sc7180-ipa",
675 .compatible = "qcom,sdx55-ipa",
679 .compatible = "qcom,sm6350-ipa",
683 .compatible = "qcom,sm8350-ipa",
687 .compatible = "qcom,sc7280-ipa",
691 .compatible = "qcom,sdx65-ipa",
695 .compatible = "qcom,sm8550-ipa",
708 /* At one time we assumed a 64-bit build, allowing some do_div() in ipa_validate_build()
712 * of being a 64-bit value. (It should be guaranteed 32 bits wide in ipa_validate_build()
713 * on a 32-bit build, but there is no harm in verifying that.) in ipa_validate_build()
729 * TLV FIFO size. A transaction structure uses 8-bit fields in ipa_validate_build()
748 modem_init = of_property_read_bool(dev->of_node, "modem-init"); in ipa_firmware_loader()
749 ret = of_property_read_string(dev->of_node, "qcom,gsi-loader", &str); in ipa_firmware_loader()
752 if (ret == -EINVAL) { in ipa_firmware_loader()
786 * ipa_probe() - IPA platform driver probe function
792 * This is the main entry point for the IPA driver. Initialization proceeds
794 * - The "init" stage involves activities that can be initialized without
795 * access to the IPA hardware.
796 * - The "config" stage requires IPA power to be active so IPA registers
797 * can be accessed, but does not require the use of IPA immediate commands.
798 * - The "setup" stage uses IPA immediate commands, and so requires the GSI
801 * A Boolean Device Tree "modem-init" property determines whether GSI
806 * to the AP; this triggers the start if IPA setup.
810 struct device *dev = &pdev->dev; in ipa_probe()
814 struct ipa *ipa; in ipa_probe() local
823 return -ENODEV; in ipa_probe()
826 if (!ipa_version_supported(data->version)) { in ipa_probe()
827 dev_err(dev, "unsupported IPA version %u\n", data->version); in ipa_probe()
828 return -EINVAL; in ipa_probe()
831 if (!data->modem_route_count) { in ipa_probe()
833 return -EINVAL; in ipa_probe()
838 return -EINVAL; in ipa_probe()
840 return -EPROBE_DEFER; in ipa_probe()
843 * probed, so might return -EPROBE_DEFER. in ipa_probe()
845 power = ipa_power_init(dev, data->power_data); in ipa_probe()
849 /* No more EPROBE_DEFER. Allocate and initialize the IPA structure */ in ipa_probe()
850 ipa = kzalloc(sizeof(*ipa), GFP_KERNEL); in ipa_probe()
851 if (!ipa) { in ipa_probe()
852 ret = -ENOMEM; in ipa_probe()
856 ipa->pdev = pdev; in ipa_probe()
857 dev_set_drvdata(dev, ipa); in ipa_probe()
858 ipa->power = power; in ipa_probe()
859 ipa->version = data->version; in ipa_probe()
860 ipa->modem_route_count = data->modem_route_count; in ipa_probe()
861 init_completion(&ipa->completion); in ipa_probe()
863 ret = ipa_reg_init(ipa); in ipa_probe()
867 ret = ipa_mem_init(ipa, data->mem_data); in ipa_probe()
871 ret = gsi_init(&ipa->gsi, pdev, ipa->version, data->endpoint_count, in ipa_probe()
872 data->endpoint_data); in ipa_probe()
876 /* Result is a non-zero mask of endpoints that support filtering */ in ipa_probe()
877 ret = ipa_endpoint_init(ipa, data->endpoint_count, data->endpoint_data); in ipa_probe()
881 ret = ipa_table_init(ipa); in ipa_probe()
885 ret = ipa_smp2p_init(ipa, loader == IPA_LOADER_MODEM); in ipa_probe()
894 ret = ipa_config(ipa, data); in ipa_probe()
898 dev_info(dev, "IPA driver initialized"); in ipa_probe()
914 ret = ipa_setup(ipa); in ipa_probe()
924 ipa_deconfig(ipa); in ipa_probe()
927 ipa_smp2p_exit(ipa); in ipa_probe()
929 ipa_table_exit(ipa); in ipa_probe()
931 ipa_endpoint_exit(ipa); in ipa_probe()
933 gsi_exit(&ipa->gsi); in ipa_probe()
935 ipa_mem_exit(ipa); in ipa_probe()
937 ipa_reg_exit(ipa); in ipa_probe()
939 kfree(ipa); in ipa_probe()
948 struct ipa *ipa = dev_get_drvdata(&pdev->dev); in ipa_remove() local
949 struct ipa_power *power = ipa->power; in ipa_remove()
950 struct device *dev = &pdev->dev; in ipa_remove()
954 * also ensures a modem-initiated setup that's underway completes. in ipa_remove()
956 ipa_smp2p_irq_disable_setup(ipa); in ipa_remove()
962 if (ipa->setup_complete) { in ipa_remove()
963 ret = ipa_modem_stop(ipa); in ipa_remove()
965 if (ret == -EBUSY) { in ipa_remove()
967 ret = ipa_modem_stop(ipa); in ipa_remove()
980 ipa_teardown(ipa); in ipa_remove()
983 ipa_deconfig(ipa); in ipa_remove()
986 ipa_smp2p_exit(ipa); in ipa_remove()
987 ipa_table_exit(ipa); in ipa_remove()
988 ipa_endpoint_exit(ipa); in ipa_remove()
989 gsi_exit(&ipa->gsi); in ipa_remove()
990 ipa_mem_exit(ipa); in ipa_remove()
991 ipa_reg_exit(ipa); in ipa_remove()
992 kfree(ipa); in ipa_remove()
995 dev_info(dev, "IPA driver removed"); in ipa_remove()
1011 .name = "ipa",