1 // SPDX-License-Identifier: BSD-3-Clause-Clear
3 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
6 #include <linux/module.h>
7 #include <linux/platform_device.h>
8 #include <linux/of_device.h>
10 #include <linux/dma-mapping.h>
14 #include <linux/remoteproc.h>
16 static const struct of_device_id ath11k_ahb_of_match
[] = {
17 /* TODO: Should we change the compatible string to something similar
18 * to one that ath10k uses?
20 { .compatible
= "qcom,ipq8074-wifi",
21 .data
= (void *)ATH11K_HW_IPQ8074
,
23 { .compatible
= "qcom,ipq6018-wifi",
24 .data
= (void *)ATH11K_HW_IPQ6018_HW10
,
29 MODULE_DEVICE_TABLE(of
, ath11k_ahb_of_match
);
31 static const struct ath11k_bus_params ath11k_ahb_bus_params
= {
33 .m3_fw_support
= false,
34 .fixed_bdf_addr
= true,
35 .fixed_mem_region
= true,
38 #define ATH11K_IRQ_CE0_OFFSET 4
40 static const char *irq_name
[ATH11K_IRQ_NUM_MAX
] = {
58 "host2reo-re-injection",
60 "host2rxdma-monitor-ring3",
61 "host2rxdma-monitor-ring2",
62 "host2rxdma-monitor-ring1",
64 "wbm2host-rx-release",
66 "reo2host-destination-ring4",
67 "reo2host-destination-ring3",
68 "reo2host-destination-ring2",
69 "reo2host-destination-ring1",
70 "rxdma2host-monitor-destination-mac3",
71 "rxdma2host-monitor-destination-mac2",
72 "rxdma2host-monitor-destination-mac1",
73 "ppdu-end-interrupts-mac3",
74 "ppdu-end-interrupts-mac2",
75 "ppdu-end-interrupts-mac1",
76 "rxdma2host-monitor-status-ring-mac3",
77 "rxdma2host-monitor-status-ring-mac2",
78 "rxdma2host-monitor-status-ring-mac1",
79 "host2rxdma-host-buf-ring-mac3",
80 "host2rxdma-host-buf-ring-mac2",
81 "host2rxdma-host-buf-ring-mac1",
82 "rxdma2host-destination-ring-mac3",
83 "rxdma2host-destination-ring-mac2",
84 "rxdma2host-destination-ring-mac1",
85 "host2tcl-input-ring4",
86 "host2tcl-input-ring3",
87 "host2tcl-input-ring2",
88 "host2tcl-input-ring1",
89 "wbm2host-tx-completions-ring3",
90 "wbm2host-tx-completions-ring2",
91 "wbm2host-tx-completions-ring1",
92 "tcl2host-status-ring",
95 /* enum ext_irq_num - irq numbers that can be used by external modules
99 host2wbm_desc_feed
= 16,
100 host2reo_re_injection
,
102 host2rxdma_monitor_ring3
,
103 host2rxdma_monitor_ring2
,
104 host2rxdma_monitor_ring1
,
108 reo2host_destination_ring4
,
109 reo2host_destination_ring3
,
110 reo2host_destination_ring2
,
111 reo2host_destination_ring1
,
112 rxdma2host_monitor_destination_mac3
,
113 rxdma2host_monitor_destination_mac2
,
114 rxdma2host_monitor_destination_mac1
,
115 ppdu_end_interrupts_mac3
,
116 ppdu_end_interrupts_mac2
,
117 ppdu_end_interrupts_mac1
,
118 rxdma2host_monitor_status_ring_mac3
,
119 rxdma2host_monitor_status_ring_mac2
,
120 rxdma2host_monitor_status_ring_mac1
,
121 host2rxdma_host_buf_ring_mac3
,
122 host2rxdma_host_buf_ring_mac2
,
123 host2rxdma_host_buf_ring_mac1
,
124 rxdma2host_destination_ring_mac3
,
125 rxdma2host_destination_ring_mac2
,
126 rxdma2host_destination_ring_mac1
,
127 host2tcl_input_ring4
,
128 host2tcl_input_ring3
,
129 host2tcl_input_ring2
,
130 host2tcl_input_ring1
,
131 wbm2host_tx_completions_ring3
,
132 wbm2host_tx_completions_ring2
,
133 wbm2host_tx_completions_ring1
,
134 tcl2host_status_ring
,
137 static inline u32
ath11k_ahb_read32(struct ath11k_base
*ab
, u32 offset
)
139 return ioread32(ab
->mem
+ offset
);
142 static inline void ath11k_ahb_write32(struct ath11k_base
*ab
, u32 offset
, u32 value
)
144 iowrite32(value
, ab
->mem
+ offset
);
147 static void ath11k_ahb_kill_tasklets(struct ath11k_base
*ab
)
151 for (i
= 0; i
< ab
->hw_params
.ce_count
; i
++) {
152 struct ath11k_ce_pipe
*ce_pipe
= &ab
->ce
.ce_pipe
[i
];
154 if (ath11k_ce_get_attr_flags(ab
, i
) & CE_ATTR_DIS_INTR
)
157 tasklet_kill(&ce_pipe
->intr_tq
);
161 static void ath11k_ahb_ext_grp_disable(struct ath11k_ext_irq_grp
*irq_grp
)
165 for (i
= 0; i
< irq_grp
->num_irq
; i
++)
166 disable_irq_nosync(irq_grp
->ab
->irq_num
[irq_grp
->irqs
[i
]]);
169 static void __ath11k_ahb_ext_irq_disable(struct ath11k_base
*ab
)
173 for (i
= 0; i
< ATH11K_EXT_IRQ_GRP_NUM_MAX
; i
++) {
174 struct ath11k_ext_irq_grp
*irq_grp
= &ab
->ext_irq_grp
[i
];
176 ath11k_ahb_ext_grp_disable(irq_grp
);
178 napi_synchronize(&irq_grp
->napi
);
179 napi_disable(&irq_grp
->napi
);
183 static void ath11k_ahb_ext_grp_enable(struct ath11k_ext_irq_grp
*irq_grp
)
187 for (i
= 0; i
< irq_grp
->num_irq
; i
++)
188 enable_irq(irq_grp
->ab
->irq_num
[irq_grp
->irqs
[i
]]);
191 static void ath11k_ahb_setbit32(struct ath11k_base
*ab
, u8 bit
, u32 offset
)
195 val
= ath11k_ahb_read32(ab
, offset
);
196 ath11k_ahb_write32(ab
, offset
, val
| BIT(bit
));
199 static void ath11k_ahb_clearbit32(struct ath11k_base
*ab
, u8 bit
, u32 offset
)
203 val
= ath11k_ahb_read32(ab
, offset
);
204 ath11k_ahb_write32(ab
, offset
, val
& ~BIT(bit
));
207 static void ath11k_ahb_ce_irq_enable(struct ath11k_base
*ab
, u16 ce_id
)
209 const struct ce_pipe_config
*ce_config
;
211 ce_config
= &ab
->hw_params
.target_ce_config
[ce_id
];
212 if (__le32_to_cpu(ce_config
->pipedir
) & PIPEDIR_OUT
)
213 ath11k_ahb_setbit32(ab
, ce_id
, CE_HOST_IE_ADDRESS
);
215 if (__le32_to_cpu(ce_config
->pipedir
) & PIPEDIR_IN
) {
216 ath11k_ahb_setbit32(ab
, ce_id
, CE_HOST_IE_2_ADDRESS
);
217 ath11k_ahb_setbit32(ab
, ce_id
+ CE_HOST_IE_3_SHIFT
,
218 CE_HOST_IE_3_ADDRESS
);
222 static void ath11k_ahb_ce_irq_disable(struct ath11k_base
*ab
, u16 ce_id
)
224 const struct ce_pipe_config
*ce_config
;
226 ce_config
= &ab
->hw_params
.target_ce_config
[ce_id
];
227 if (__le32_to_cpu(ce_config
->pipedir
) & PIPEDIR_OUT
)
228 ath11k_ahb_clearbit32(ab
, ce_id
, CE_HOST_IE_ADDRESS
);
230 if (__le32_to_cpu(ce_config
->pipedir
) & PIPEDIR_IN
) {
231 ath11k_ahb_clearbit32(ab
, ce_id
, CE_HOST_IE_2_ADDRESS
);
232 ath11k_ahb_clearbit32(ab
, ce_id
+ CE_HOST_IE_3_SHIFT
,
233 CE_HOST_IE_3_ADDRESS
);
237 static void ath11k_ahb_sync_ce_irqs(struct ath11k_base
*ab
)
242 for (i
= 0; i
< ab
->hw_params
.ce_count
; i
++) {
243 if (ath11k_ce_get_attr_flags(ab
, i
) & CE_ATTR_DIS_INTR
)
246 irq_idx
= ATH11K_IRQ_CE0_OFFSET
+ i
;
247 synchronize_irq(ab
->irq_num
[irq_idx
]);
251 static void ath11k_ahb_sync_ext_irqs(struct ath11k_base
*ab
)
256 for (i
= 0; i
< ATH11K_EXT_IRQ_GRP_NUM_MAX
; i
++) {
257 struct ath11k_ext_irq_grp
*irq_grp
= &ab
->ext_irq_grp
[i
];
259 for (j
= 0; j
< irq_grp
->num_irq
; j
++) {
260 irq_idx
= irq_grp
->irqs
[j
];
261 synchronize_irq(ab
->irq_num
[irq_idx
]);
266 static void ath11k_ahb_ce_irqs_enable(struct ath11k_base
*ab
)
270 for (i
= 0; i
< ab
->hw_params
.ce_count
; i
++) {
271 if (ath11k_ce_get_attr_flags(ab
, i
) & CE_ATTR_DIS_INTR
)
273 ath11k_ahb_ce_irq_enable(ab
, i
);
277 static void ath11k_ahb_ce_irqs_disable(struct ath11k_base
*ab
)
281 for (i
= 0; i
< ab
->hw_params
.ce_count
; i
++) {
282 if (ath11k_ce_get_attr_flags(ab
, i
) & CE_ATTR_DIS_INTR
)
284 ath11k_ahb_ce_irq_disable(ab
, i
);
288 static int ath11k_ahb_start(struct ath11k_base
*ab
)
290 ath11k_ahb_ce_irqs_enable(ab
);
291 ath11k_ce_rx_post_buf(ab
);
296 static void ath11k_ahb_ext_irq_enable(struct ath11k_base
*ab
)
300 for (i
= 0; i
< ATH11K_EXT_IRQ_GRP_NUM_MAX
; i
++) {
301 struct ath11k_ext_irq_grp
*irq_grp
= &ab
->ext_irq_grp
[i
];
303 napi_enable(&irq_grp
->napi
);
304 ath11k_ahb_ext_grp_enable(irq_grp
);
308 static void ath11k_ahb_ext_irq_disable(struct ath11k_base
*ab
)
310 __ath11k_ahb_ext_irq_disable(ab
);
311 ath11k_ahb_sync_ext_irqs(ab
);
314 static void ath11k_ahb_stop(struct ath11k_base
*ab
)
316 if (!test_bit(ATH11K_FLAG_CRASH_FLUSH
, &ab
->dev_flags
))
317 ath11k_ahb_ce_irqs_disable(ab
);
318 ath11k_ahb_sync_ce_irqs(ab
);
319 ath11k_ahb_kill_tasklets(ab
);
320 del_timer_sync(&ab
->rx_replenish_retry
);
321 ath11k_ce_cleanup_pipes(ab
);
324 static int ath11k_ahb_power_up(struct ath11k_base
*ab
)
326 struct ath11k_ahb
*ab_ahb
= ath11k_ahb_priv(ab
);
329 ret
= rproc_boot(ab_ahb
->tgt_rproc
);
331 ath11k_err(ab
, "failed to boot the remote processor Q6\n");
336 static void ath11k_ahb_power_down(struct ath11k_base
*ab
)
338 struct ath11k_ahb
*ab_ahb
= ath11k_ahb_priv(ab
);
340 rproc_shutdown(ab_ahb
->tgt_rproc
);
343 static int ath11k_ahb_fwreset_from_cold_boot(struct ath11k_base
*ab
)
347 if (ath11k_cold_boot_cal
== 0 || ab
->qmi
.cal_done
||
348 ab
->hw_params
.cold_boot_calib
== 0)
351 ath11k_dbg(ab
, ATH11K_DBG_AHB
, "wait for cold boot done\n");
352 timeout
= wait_event_timeout(ab
->qmi
.cold_boot_waitq
,
353 (ab
->qmi
.cal_done
== 1),
354 ATH11K_COLD_BOOT_FW_RESET_DELAY
);
356 ath11k_cold_boot_cal
= 0;
357 ath11k_warn(ab
, "Coldboot Calibration failed timed out\n");
360 /* reset the firmware */
361 ath11k_ahb_power_down(ab
);
362 ath11k_ahb_power_up(ab
);
364 ath11k_dbg(ab
, ATH11K_DBG_AHB
, "exited from cold boot mode\n");
368 static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base
*ab
)
370 struct ath11k_qmi_ce_cfg
*cfg
= &ab
->qmi
.ce_cfg
;
372 cfg
->tgt_ce_len
= ab
->hw_params
.target_ce_count
;
373 cfg
->tgt_ce
= ab
->hw_params
.target_ce_config
;
374 cfg
->svc_to_ce_map_len
= ab
->hw_params
.svc_to_ce_map_len
;
375 cfg
->svc_to_ce_map
= ab
->hw_params
.svc_to_ce_map
;
376 ab
->qmi
.service_ins_id
= ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074
;
379 static void ath11k_ahb_free_ext_irq(struct ath11k_base
*ab
)
383 for (i
= 0; i
< ATH11K_EXT_IRQ_GRP_NUM_MAX
; i
++) {
384 struct ath11k_ext_irq_grp
*irq_grp
= &ab
->ext_irq_grp
[i
];
386 for (j
= 0; j
< irq_grp
->num_irq
; j
++)
387 free_irq(ab
->irq_num
[irq_grp
->irqs
[j
]], irq_grp
);
391 static void ath11k_ahb_free_irq(struct ath11k_base
*ab
)
396 for (i
= 0; i
< ab
->hw_params
.ce_count
; i
++) {
397 if (ath11k_ce_get_attr_flags(ab
, i
) & CE_ATTR_DIS_INTR
)
399 irq_idx
= ATH11K_IRQ_CE0_OFFSET
+ i
;
400 free_irq(ab
->irq_num
[irq_idx
], &ab
->ce
.ce_pipe
[i
]);
403 ath11k_ahb_free_ext_irq(ab
);
406 static void ath11k_ahb_ce_tasklet(struct tasklet_struct
*t
)
408 struct ath11k_ce_pipe
*ce_pipe
= from_tasklet(ce_pipe
, t
, intr_tq
);
410 ath11k_ce_per_engine_service(ce_pipe
->ab
, ce_pipe
->pipe_num
);
412 ath11k_ahb_ce_irq_enable(ce_pipe
->ab
, ce_pipe
->pipe_num
);
415 static irqreturn_t
ath11k_ahb_ce_interrupt_handler(int irq
, void *arg
)
417 struct ath11k_ce_pipe
*ce_pipe
= arg
;
419 /* last interrupt received for this CE */
420 ce_pipe
->timestamp
= jiffies
;
422 ath11k_ahb_ce_irq_disable(ce_pipe
->ab
, ce_pipe
->pipe_num
);
424 tasklet_schedule(&ce_pipe
->intr_tq
);
429 static int ath11k_ahb_ext_grp_napi_poll(struct napi_struct
*napi
, int budget
)
431 struct ath11k_ext_irq_grp
*irq_grp
= container_of(napi
,
432 struct ath11k_ext_irq_grp
,
434 struct ath11k_base
*ab
= irq_grp
->ab
;
437 work_done
= ath11k_dp_service_srng(ab
, irq_grp
, budget
);
438 if (work_done
< budget
) {
439 napi_complete_done(napi
, work_done
);
440 ath11k_ahb_ext_grp_enable(irq_grp
);
443 if (work_done
> budget
)
449 static irqreturn_t
ath11k_ahb_ext_interrupt_handler(int irq
, void *arg
)
451 struct ath11k_ext_irq_grp
*irq_grp
= arg
;
453 /* last interrupt received for this group */
454 irq_grp
->timestamp
= jiffies
;
456 ath11k_ahb_ext_grp_disable(irq_grp
);
458 napi_schedule(&irq_grp
->napi
);
463 static int ath11k_ahb_ext_irq_config(struct ath11k_base
*ab
)
465 struct ath11k_hw_params
*hw
= &ab
->hw_params
;
470 for (i
= 0; i
< ATH11K_EXT_IRQ_GRP_NUM_MAX
; i
++) {
471 struct ath11k_ext_irq_grp
*irq_grp
= &ab
->ext_irq_grp
[i
];
476 init_dummy_netdev(&irq_grp
->napi_ndev
);
477 netif_napi_add(&irq_grp
->napi_ndev
, &irq_grp
->napi
,
478 ath11k_ahb_ext_grp_napi_poll
, NAPI_POLL_WEIGHT
);
480 for (j
= 0; j
< ATH11K_EXT_IRQ_NUM_MAX
; j
++) {
481 if (ab
->hw_params
.ring_mask
->tx
[i
] & BIT(j
)) {
482 irq_grp
->irqs
[num_irq
++] =
483 wbm2host_tx_completions_ring1
- j
;
486 if (ab
->hw_params
.ring_mask
->rx
[i
] & BIT(j
)) {
487 irq_grp
->irqs
[num_irq
++] =
488 reo2host_destination_ring1
- j
;
491 if (ab
->hw_params
.ring_mask
->rx_err
[i
] & BIT(j
))
492 irq_grp
->irqs
[num_irq
++] = reo2host_exception
;
494 if (ab
->hw_params
.ring_mask
->rx_wbm_rel
[i
] & BIT(j
))
495 irq_grp
->irqs
[num_irq
++] = wbm2host_rx_release
;
497 if (ab
->hw_params
.ring_mask
->reo_status
[i
] & BIT(j
))
498 irq_grp
->irqs
[num_irq
++] = reo2host_status
;
500 if (j
< ab
->hw_params
.max_radios
) {
501 if (ab
->hw_params
.ring_mask
->rxdma2host
[i
] & BIT(j
)) {
502 irq_grp
->irqs
[num_irq
++] =
503 rxdma2host_destination_ring_mac1
-
504 ath11k_hw_get_mac_from_pdev_id(hw
, j
);
507 if (ab
->hw_params
.ring_mask
->host2rxdma
[i
] & BIT(j
)) {
508 irq_grp
->irqs
[num_irq
++] =
509 host2rxdma_host_buf_ring_mac1
-
510 ath11k_hw_get_mac_from_pdev_id(hw
, j
);
513 if (ab
->hw_params
.ring_mask
->rx_mon_status
[i
] & BIT(j
)) {
514 irq_grp
->irqs
[num_irq
++] =
515 ppdu_end_interrupts_mac1
-
516 ath11k_hw_get_mac_from_pdev_id(hw
, j
);
517 irq_grp
->irqs
[num_irq
++] =
518 rxdma2host_monitor_status_ring_mac1
-
519 ath11k_hw_get_mac_from_pdev_id(hw
, j
);
523 irq_grp
->num_irq
= num_irq
;
525 for (j
= 0; j
< irq_grp
->num_irq
; j
++) {
526 int irq_idx
= irq_grp
->irqs
[j
];
528 irq
= platform_get_irq_byname(ab
->pdev
,
530 ab
->irq_num
[irq_idx
] = irq
;
531 irq_set_status_flags(irq
, IRQ_NOAUTOEN
| IRQ_DISABLE_UNLAZY
);
532 ret
= request_irq(irq
, ath11k_ahb_ext_interrupt_handler
,
534 irq_name
[irq_idx
], irq_grp
);
536 ath11k_err(ab
, "failed request_irq for %d\n",
545 static int ath11k_ahb_config_irq(struct ath11k_base
*ab
)
550 /* Configure CE irqs */
551 for (i
= 0; i
< ab
->hw_params
.ce_count
; i
++) {
552 struct ath11k_ce_pipe
*ce_pipe
= &ab
->ce
.ce_pipe
[i
];
554 if (ath11k_ce_get_attr_flags(ab
, i
) & CE_ATTR_DIS_INTR
)
557 irq_idx
= ATH11K_IRQ_CE0_OFFSET
+ i
;
559 tasklet_setup(&ce_pipe
->intr_tq
, ath11k_ahb_ce_tasklet
);
560 irq
= platform_get_irq_byname(ab
->pdev
, irq_name
[irq_idx
]);
561 ret
= request_irq(irq
, ath11k_ahb_ce_interrupt_handler
,
562 IRQF_TRIGGER_RISING
, irq_name
[irq_idx
],
567 ab
->irq_num
[irq_idx
] = irq
;
570 /* Configure external interrupts */
571 ret
= ath11k_ahb_ext_irq_config(ab
);
576 static int ath11k_ahb_map_service_to_pipe(struct ath11k_base
*ab
, u16 service_id
,
577 u8
*ul_pipe
, u8
*dl_pipe
)
579 const struct service_to_pipe
*entry
;
580 bool ul_set
= false, dl_set
= false;
583 for (i
= 0; i
< ab
->hw_params
.svc_to_ce_map_len
; i
++) {
584 entry
= &ab
->hw_params
.svc_to_ce_map
[i
];
586 if (__le32_to_cpu(entry
->service_id
) != service_id
)
589 switch (__le32_to_cpu(entry
->pipedir
)) {
594 *dl_pipe
= __le32_to_cpu(entry
->pipenum
);
599 *ul_pipe
= __le32_to_cpu(entry
->pipenum
);
605 *dl_pipe
= __le32_to_cpu(entry
->pipenum
);
606 *ul_pipe
= __le32_to_cpu(entry
->pipenum
);
613 if (WARN_ON(!ul_set
|| !dl_set
))
619 static const struct ath11k_hif_ops ath11k_ahb_hif_ops
= {
620 .start
= ath11k_ahb_start
,
621 .stop
= ath11k_ahb_stop
,
622 .read32
= ath11k_ahb_read32
,
623 .write32
= ath11k_ahb_write32
,
624 .irq_enable
= ath11k_ahb_ext_irq_enable
,
625 .irq_disable
= ath11k_ahb_ext_irq_disable
,
626 .map_service_to_pipe
= ath11k_ahb_map_service_to_pipe
,
627 .power_down
= ath11k_ahb_power_down
,
628 .power_up
= ath11k_ahb_power_up
,
631 static int ath11k_core_get_rproc(struct ath11k_base
*ab
)
633 struct ath11k_ahb
*ab_ahb
= ath11k_ahb_priv(ab
);
634 struct device
*dev
= ab
->dev
;
635 struct rproc
*prproc
;
636 phandle rproc_phandle
;
638 if (of_property_read_u32(dev
->of_node
, "qcom,rproc", &rproc_phandle
)) {
639 ath11k_err(ab
, "failed to get q6_rproc handle\n");
643 prproc
= rproc_get_by_phandle(rproc_phandle
);
645 ath11k_err(ab
, "failed to get rproc\n");
648 ab_ahb
->tgt_rproc
= prproc
;
653 static int ath11k_ahb_probe(struct platform_device
*pdev
)
655 struct ath11k_base
*ab
;
656 const struct of_device_id
*of_id
;
657 struct resource
*mem_res
;
661 of_id
= of_match_device(ath11k_ahb_of_match
, &pdev
->dev
);
663 dev_err(&pdev
->dev
, "failed to find matching device tree id\n");
667 mem
= devm_platform_get_and_ioremap_resource(pdev
, 0, &mem_res
);
669 dev_err(&pdev
->dev
, "ioremap error\n");
673 ret
= dma_set_mask_and_coherent(&pdev
->dev
, DMA_BIT_MASK(32));
675 dev_err(&pdev
->dev
, "failed to set 32-bit consistent dma\n");
679 ab
= ath11k_core_alloc(&pdev
->dev
, sizeof(struct ath11k_ahb
),
681 &ath11k_ahb_bus_params
);
683 dev_err(&pdev
->dev
, "failed to allocate ath11k base\n");
687 ab
->hif
.ops
= &ath11k_ahb_hif_ops
;
689 ab
->hw_rev
= (enum ath11k_hw_rev
)of_id
->data
;
691 ab
->mem_len
= resource_size(mem_res
);
692 platform_set_drvdata(pdev
, ab
);
694 ret
= ath11k_core_pre_init(ab
);
698 ret
= ath11k_hal_srng_init(ab
);
702 ret
= ath11k_ce_alloc_pipes(ab
);
704 ath11k_err(ab
, "failed to allocate ce pipes: %d\n", ret
);
705 goto err_hal_srng_deinit
;
708 ath11k_ahb_init_qmi_ce_config(ab
);
710 ret
= ath11k_core_get_rproc(ab
);
712 ath11k_err(ab
, "failed to get rproc: %d\n", ret
);
716 ret
= ath11k_core_init(ab
);
718 ath11k_err(ab
, "failed to init core: %d\n", ret
);
722 ret
= ath11k_ahb_config_irq(ab
);
724 ath11k_err(ab
, "failed to configure irq: %d\n", ret
);
728 ath11k_ahb_fwreset_from_cold_boot(ab
);
733 ath11k_ce_free_pipes(ab
);
736 ath11k_hal_srng_deinit(ab
);
739 ath11k_core_free(ab
);
740 platform_set_drvdata(pdev
, NULL
);
745 static int ath11k_ahb_remove(struct platform_device
*pdev
)
747 struct ath11k_base
*ab
= platform_get_drvdata(pdev
);
750 if (test_bit(ATH11K_FLAG_QMI_FAIL
, &ab
->dev_flags
)) {
751 ath11k_ahb_power_down(ab
);
752 ath11k_debugfs_soc_destroy(ab
);
753 ath11k_qmi_deinit_service(ab
);
757 reinit_completion(&ab
->driver_recovery
);
759 if (test_bit(ATH11K_FLAG_RECOVERY
, &ab
->dev_flags
)) {
760 left
= wait_for_completion_timeout(&ab
->driver_recovery
,
761 ATH11K_AHB_RECOVERY_TIMEOUT
);
763 ath11k_warn(ab
, "failed to receive recovery response completion\n");
766 set_bit(ATH11K_FLAG_UNREGISTERING
, &ab
->dev_flags
);
767 cancel_work_sync(&ab
->restart_work
);
769 ath11k_core_deinit(ab
);
771 ath11k_ahb_free_irq(ab
);
772 ath11k_hal_srng_deinit(ab
);
773 ath11k_ce_free_pipes(ab
);
774 ath11k_core_free(ab
);
775 platform_set_drvdata(pdev
, NULL
);
780 static struct platform_driver ath11k_ahb_driver
= {
783 .of_match_table
= ath11k_ahb_of_match
,
785 .probe
= ath11k_ahb_probe
,
786 .remove
= ath11k_ahb_remove
,
789 static int ath11k_ahb_init(void)
791 return platform_driver_register(&ath11k_ahb_driver
);
793 module_init(ath11k_ahb_init
);
795 static void ath11k_ahb_exit(void)
797 platform_driver_unregister(&ath11k_ahb_driver
);
799 module_exit(ath11k_ahb_exit
);
801 MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN AHB devices");
802 MODULE_LICENSE("Dual BSD/GPL");