xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/ahb.c (revision ba929d6f)
1d5c65159SKalle Valo // SPDX-License-Identifier: BSD-3-Clause-Clear
2d5c65159SKalle Valo /*
3d5c65159SKalle Valo  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4d5c65159SKalle Valo  */
5d5c65159SKalle Valo 
6d5c65159SKalle Valo #include <linux/module.h>
7d5c65159SKalle Valo #include <linux/platform_device.h>
8d5c65159SKalle Valo #include <linux/of_device.h>
9d5c65159SKalle Valo #include <linux/of.h>
10d5c65159SKalle Valo #include <linux/dma-mapping.h>
11d5c65159SKalle Valo #include "ahb.h"
12d5c65159SKalle Valo #include "debug.h"
1331858805SGovind Singh #include "hif.h"
14d5c65159SKalle Valo #include <linux/remoteproc.h>
15d5c65159SKalle Valo 
16d5c65159SKalle Valo static const struct of_device_id ath11k_ahb_of_match[] = {
17d5c65159SKalle Valo 	/* TODO: Should we change the compatible string to something similar
18d5c65159SKalle Valo 	 * to one that ath10k uses?
19d5c65159SKalle Valo 	 */
20d5c65159SKalle Valo 	{ .compatible = "qcom,ipq8074-wifi",
21d5c65159SKalle Valo 	  .data = (void *)ATH11K_HW_IPQ8074,
22d5c65159SKalle Valo 	},
23b129699aSAnilkumar Kolli 	{ .compatible = "qcom,ipq6018-wifi",
24b129699aSAnilkumar Kolli 	  .data = (void *)ATH11K_HW_IPQ6018_HW10,
25b129699aSAnilkumar Kolli 	},
26d5c65159SKalle Valo 	{ }
27d5c65159SKalle Valo };
28d5c65159SKalle Valo 
29d5c65159SKalle Valo MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match);
30d5c65159SKalle Valo 
311ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_ahb_bus_params = {
321ff8ed78SGovind Singh 	.mhi_support = false,
3356970454SGovind Singh 	.m3_fw_support = false,
346eb6ea51SGovind Singh 	.fixed_bdf_addr = true,
356eb6ea51SGovind Singh 	.fixed_mem_region = true,
361ff8ed78SGovind Singh };
371ff8ed78SGovind Singh 
38d5c65159SKalle Valo #define ATH11K_IRQ_CE0_OFFSET 4
39d5c65159SKalle Valo 
40d5c65159SKalle Valo static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
41d5c65159SKalle Valo 	"misc-pulse1",
42d5c65159SKalle Valo 	"misc-latch",
43d5c65159SKalle Valo 	"sw-exception",
44d5c65159SKalle Valo 	"watchdog",
45d5c65159SKalle Valo 	"ce0",
46d5c65159SKalle Valo 	"ce1",
47d5c65159SKalle Valo 	"ce2",
48d5c65159SKalle Valo 	"ce3",
49d5c65159SKalle Valo 	"ce4",
50d5c65159SKalle Valo 	"ce5",
51d5c65159SKalle Valo 	"ce6",
52d5c65159SKalle Valo 	"ce7",
53d5c65159SKalle Valo 	"ce8",
54d5c65159SKalle Valo 	"ce9",
55d5c65159SKalle Valo 	"ce10",
56d5c65159SKalle Valo 	"ce11",
57d5c65159SKalle Valo 	"host2wbm-desc-feed",
58d5c65159SKalle Valo 	"host2reo-re-injection",
59d5c65159SKalle Valo 	"host2reo-command",
60d5c65159SKalle Valo 	"host2rxdma-monitor-ring3",
61d5c65159SKalle Valo 	"host2rxdma-monitor-ring2",
62d5c65159SKalle Valo 	"host2rxdma-monitor-ring1",
63d5c65159SKalle Valo 	"reo2ost-exception",
64d5c65159SKalle Valo 	"wbm2host-rx-release",
65d5c65159SKalle Valo 	"reo2host-status",
66d5c65159SKalle Valo 	"reo2host-destination-ring4",
67d5c65159SKalle Valo 	"reo2host-destination-ring3",
68d5c65159SKalle Valo 	"reo2host-destination-ring2",
69d5c65159SKalle Valo 	"reo2host-destination-ring1",
70d5c65159SKalle Valo 	"rxdma2host-monitor-destination-mac3",
71d5c65159SKalle Valo 	"rxdma2host-monitor-destination-mac2",
72d5c65159SKalle Valo 	"rxdma2host-monitor-destination-mac1",
73d5c65159SKalle Valo 	"ppdu-end-interrupts-mac3",
74d5c65159SKalle Valo 	"ppdu-end-interrupts-mac2",
75d5c65159SKalle Valo 	"ppdu-end-interrupts-mac1",
76d5c65159SKalle Valo 	"rxdma2host-monitor-status-ring-mac3",
77d5c65159SKalle Valo 	"rxdma2host-monitor-status-ring-mac2",
78d5c65159SKalle Valo 	"rxdma2host-monitor-status-ring-mac1",
79d5c65159SKalle Valo 	"host2rxdma-host-buf-ring-mac3",
80d5c65159SKalle Valo 	"host2rxdma-host-buf-ring-mac2",
81d5c65159SKalle Valo 	"host2rxdma-host-buf-ring-mac1",
82d5c65159SKalle Valo 	"rxdma2host-destination-ring-mac3",
83d5c65159SKalle Valo 	"rxdma2host-destination-ring-mac2",
84d5c65159SKalle Valo 	"rxdma2host-destination-ring-mac1",
85d5c65159SKalle Valo 	"host2tcl-input-ring4",
86d5c65159SKalle Valo 	"host2tcl-input-ring3",
87d5c65159SKalle Valo 	"host2tcl-input-ring2",
88d5c65159SKalle Valo 	"host2tcl-input-ring1",
89d5c65159SKalle Valo 	"wbm2host-tx-completions-ring3",
90d5c65159SKalle Valo 	"wbm2host-tx-completions-ring2",
91d5c65159SKalle Valo 	"wbm2host-tx-completions-ring1",
92d5c65159SKalle Valo 	"tcl2host-status-ring",
93d5c65159SKalle Valo };
94d5c65159SKalle Valo 
95d5c65159SKalle Valo /* enum ext_irq_num - irq numbers that can be used by external modules
96d5c65159SKalle Valo  * like datapath
97d5c65159SKalle Valo  */
98d5c65159SKalle Valo enum ext_irq_num {
99d5c65159SKalle Valo 	host2wbm_desc_feed = 16,
100d5c65159SKalle Valo 	host2reo_re_injection,
101d5c65159SKalle Valo 	host2reo_command,
102d5c65159SKalle Valo 	host2rxdma_monitor_ring3,
103d5c65159SKalle Valo 	host2rxdma_monitor_ring2,
104d5c65159SKalle Valo 	host2rxdma_monitor_ring1,
105d5c65159SKalle Valo 	reo2host_exception,
106d5c65159SKalle Valo 	wbm2host_rx_release,
107d5c65159SKalle Valo 	reo2host_status,
108d5c65159SKalle Valo 	reo2host_destination_ring4,
109d5c65159SKalle Valo 	reo2host_destination_ring3,
110d5c65159SKalle Valo 	reo2host_destination_ring2,
111d5c65159SKalle Valo 	reo2host_destination_ring1,
112d5c65159SKalle Valo 	rxdma2host_monitor_destination_mac3,
113d5c65159SKalle Valo 	rxdma2host_monitor_destination_mac2,
114d5c65159SKalle Valo 	rxdma2host_monitor_destination_mac1,
115d5c65159SKalle Valo 	ppdu_end_interrupts_mac3,
116d5c65159SKalle Valo 	ppdu_end_interrupts_mac2,
117d5c65159SKalle Valo 	ppdu_end_interrupts_mac1,
118d5c65159SKalle Valo 	rxdma2host_monitor_status_ring_mac3,
119d5c65159SKalle Valo 	rxdma2host_monitor_status_ring_mac2,
120d5c65159SKalle Valo 	rxdma2host_monitor_status_ring_mac1,
121d5c65159SKalle Valo 	host2rxdma_host_buf_ring_mac3,
122d5c65159SKalle Valo 	host2rxdma_host_buf_ring_mac2,
123d5c65159SKalle Valo 	host2rxdma_host_buf_ring_mac1,
124d5c65159SKalle Valo 	rxdma2host_destination_ring_mac3,
125d5c65159SKalle Valo 	rxdma2host_destination_ring_mac2,
126d5c65159SKalle Valo 	rxdma2host_destination_ring_mac1,
127d5c65159SKalle Valo 	host2tcl_input_ring4,
128d5c65159SKalle Valo 	host2tcl_input_ring3,
129d5c65159SKalle Valo 	host2tcl_input_ring2,
130d5c65159SKalle Valo 	host2tcl_input_ring1,
131d5c65159SKalle Valo 	wbm2host_tx_completions_ring3,
132d5c65159SKalle Valo 	wbm2host_tx_completions_ring2,
133d5c65159SKalle Valo 	wbm2host_tx_completions_ring1,
134d5c65159SKalle Valo 	tcl2host_status_ring,
135d5c65159SKalle Valo };
136d5c65159SKalle Valo 
13731858805SGovind Singh static inline u32 ath11k_ahb_read32(struct ath11k_base *ab, u32 offset)
13831858805SGovind Singh {
13931858805SGovind Singh 	return ioread32(ab->mem + offset);
14031858805SGovind Singh }
14131858805SGovind Singh 
14231858805SGovind Singh static inline void ath11k_ahb_write32(struct ath11k_base *ab, u32 offset, u32 value)
14331858805SGovind Singh {
14431858805SGovind Singh 	iowrite32(value, ab->mem + offset);
14531858805SGovind Singh }
14631858805SGovind Singh 
147d5c65159SKalle Valo static void ath11k_ahb_kill_tasklets(struct ath11k_base *ab)
148d5c65159SKalle Valo {
149d5c65159SKalle Valo 	int i;
150d5c65159SKalle Valo 
151d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
152d5c65159SKalle Valo 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
153d5c65159SKalle Valo 
154e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
155d5c65159SKalle Valo 			continue;
156d5c65159SKalle Valo 
157d5c65159SKalle Valo 		tasklet_kill(&ce_pipe->intr_tq);
158d5c65159SKalle Valo 	}
159d5c65159SKalle Valo }
160d5c65159SKalle Valo 
161d5c65159SKalle Valo static void ath11k_ahb_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
162d5c65159SKalle Valo {
163d5c65159SKalle Valo 	int i;
164d5c65159SKalle Valo 
165d5c65159SKalle Valo 	for (i = 0; i < irq_grp->num_irq; i++)
166d5c65159SKalle Valo 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
167d5c65159SKalle Valo }
168d5c65159SKalle Valo 
169d5c65159SKalle Valo static void __ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)
170d5c65159SKalle Valo {
171d5c65159SKalle Valo 	int i;
172d5c65159SKalle Valo 
173d5c65159SKalle Valo 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
174d5c65159SKalle Valo 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
175d5c65159SKalle Valo 
176d5c65159SKalle Valo 		ath11k_ahb_ext_grp_disable(irq_grp);
177d5c65159SKalle Valo 
178d5c65159SKalle Valo 		napi_synchronize(&irq_grp->napi);
179d5c65159SKalle Valo 		napi_disable(&irq_grp->napi);
180d5c65159SKalle Valo 	}
181d5c65159SKalle Valo }
182d5c65159SKalle Valo 
183d5c65159SKalle Valo static void ath11k_ahb_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
184d5c65159SKalle Valo {
185d5c65159SKalle Valo 	int i;
186d5c65159SKalle Valo 
187d5c65159SKalle Valo 	for (i = 0; i < irq_grp->num_irq; i++)
188d5c65159SKalle Valo 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
189d5c65159SKalle Valo }
190d5c65159SKalle Valo 
191d5c65159SKalle Valo static void ath11k_ahb_setbit32(struct ath11k_base *ab, u8 bit, u32 offset)
192d5c65159SKalle Valo {
193d5c65159SKalle Valo 	u32 val;
194d5c65159SKalle Valo 
195d5c65159SKalle Valo 	val = ath11k_ahb_read32(ab, offset);
196d5c65159SKalle Valo 	ath11k_ahb_write32(ab, offset, val | BIT(bit));
197d5c65159SKalle Valo }
198d5c65159SKalle Valo 
199d5c65159SKalle Valo static void ath11k_ahb_clearbit32(struct ath11k_base *ab, u8 bit, u32 offset)
200d5c65159SKalle Valo {
201d5c65159SKalle Valo 	u32 val;
202d5c65159SKalle Valo 
203d5c65159SKalle Valo 	val = ath11k_ahb_read32(ab, offset);
204d5c65159SKalle Valo 	ath11k_ahb_write32(ab, offset, val & ~BIT(bit));
205d5c65159SKalle Valo }
206d5c65159SKalle Valo 
207d5c65159SKalle Valo static void ath11k_ahb_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
208d5c65159SKalle Valo {
209d5c65159SKalle Valo 	const struct ce_pipe_config *ce_config;
210d5c65159SKalle Valo 
211967c1d11SAnilkumar Kolli 	ce_config = &ab->hw_params.target_ce_config[ce_id];
212d5c65159SKalle Valo 	if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_OUT)
213d5c65159SKalle Valo 		ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_ADDRESS);
214d5c65159SKalle Valo 
215d5c65159SKalle Valo 	if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_IN) {
216d5c65159SKalle Valo 		ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS);
217d5c65159SKalle Valo 		ath11k_ahb_setbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
218d5c65159SKalle Valo 				    CE_HOST_IE_3_ADDRESS);
219d5c65159SKalle Valo 	}
220d5c65159SKalle Valo }
221d5c65159SKalle Valo 
222d5c65159SKalle Valo static void ath11k_ahb_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
223d5c65159SKalle Valo {
224d5c65159SKalle Valo 	const struct ce_pipe_config *ce_config;
225d5c65159SKalle Valo 
226967c1d11SAnilkumar Kolli 	ce_config = &ab->hw_params.target_ce_config[ce_id];
227d5c65159SKalle Valo 	if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_OUT)
228d5c65159SKalle Valo 		ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_ADDRESS);
229d5c65159SKalle Valo 
230d5c65159SKalle Valo 	if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_IN) {
231d5c65159SKalle Valo 		ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS);
232d5c65159SKalle Valo 		ath11k_ahb_clearbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
233d5c65159SKalle Valo 				      CE_HOST_IE_3_ADDRESS);
234d5c65159SKalle Valo 	}
235d5c65159SKalle Valo }
236d5c65159SKalle Valo 
237d5c65159SKalle Valo static void ath11k_ahb_sync_ce_irqs(struct ath11k_base *ab)
238d5c65159SKalle Valo {
239d5c65159SKalle Valo 	int i;
240d5c65159SKalle Valo 	int irq_idx;
241d5c65159SKalle Valo 
242d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
243e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
244d5c65159SKalle Valo 			continue;
245d5c65159SKalle Valo 
246d5c65159SKalle Valo 		irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
247d5c65159SKalle Valo 		synchronize_irq(ab->irq_num[irq_idx]);
248d5c65159SKalle Valo 	}
249d5c65159SKalle Valo }
250d5c65159SKalle Valo 
251d5c65159SKalle Valo static void ath11k_ahb_sync_ext_irqs(struct ath11k_base *ab)
252d5c65159SKalle Valo {
253d5c65159SKalle Valo 	int i, j;
254d5c65159SKalle Valo 	int irq_idx;
255d5c65159SKalle Valo 
256d5c65159SKalle Valo 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
257d5c65159SKalle Valo 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
258d5c65159SKalle Valo 
259d5c65159SKalle Valo 		for (j = 0; j < irq_grp->num_irq; j++) {
260d5c65159SKalle Valo 			irq_idx = irq_grp->irqs[j];
261d5c65159SKalle Valo 			synchronize_irq(ab->irq_num[irq_idx]);
262d5c65159SKalle Valo 		}
263d5c65159SKalle Valo 	}
264d5c65159SKalle Valo }
265d5c65159SKalle Valo 
266d5c65159SKalle Valo static void ath11k_ahb_ce_irqs_enable(struct ath11k_base *ab)
267d5c65159SKalle Valo {
268d5c65159SKalle Valo 	int i;
269d5c65159SKalle Valo 
270d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
271e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
272d5c65159SKalle Valo 			continue;
273d5c65159SKalle Valo 		ath11k_ahb_ce_irq_enable(ab, i);
274d5c65159SKalle Valo 	}
275d5c65159SKalle Valo }
276d5c65159SKalle Valo 
277d5c65159SKalle Valo static void ath11k_ahb_ce_irqs_disable(struct ath11k_base *ab)
278d5c65159SKalle Valo {
279d5c65159SKalle Valo 	int i;
280d5c65159SKalle Valo 
281d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
282e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
283d5c65159SKalle Valo 			continue;
284d5c65159SKalle Valo 		ath11k_ahb_ce_irq_disable(ab, i);
285d5c65159SKalle Valo 	}
286d5c65159SKalle Valo }
287d5c65159SKalle Valo 
28831858805SGovind Singh static int ath11k_ahb_start(struct ath11k_base *ab)
289d5c65159SKalle Valo {
290d5c65159SKalle Valo 	ath11k_ahb_ce_irqs_enable(ab);
291d5c65159SKalle Valo 	ath11k_ce_rx_post_buf(ab);
292d5c65159SKalle Valo 
293d5c65159SKalle Valo 	return 0;
294d5c65159SKalle Valo }
295d5c65159SKalle Valo 
29631858805SGovind Singh static void ath11k_ahb_ext_irq_enable(struct ath11k_base *ab)
297d5c65159SKalle Valo {
298d5c65159SKalle Valo 	int i;
299d5c65159SKalle Valo 
300d5c65159SKalle Valo 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
301d5c65159SKalle Valo 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
302d5c65159SKalle Valo 
303d5c65159SKalle Valo 		napi_enable(&irq_grp->napi);
304d5c65159SKalle Valo 		ath11k_ahb_ext_grp_enable(irq_grp);
305d5c65159SKalle Valo 	}
306d5c65159SKalle Valo }
307d5c65159SKalle Valo 
30831858805SGovind Singh static void ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)
309d5c65159SKalle Valo {
310d5c65159SKalle Valo 	__ath11k_ahb_ext_irq_disable(ab);
311d5c65159SKalle Valo 	ath11k_ahb_sync_ext_irqs(ab);
312d5c65159SKalle Valo }
313d5c65159SKalle Valo 
31431858805SGovind Singh static void ath11k_ahb_stop(struct ath11k_base *ab)
315d5c65159SKalle Valo {
316d5c65159SKalle Valo 	if (!test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags))
317d5c65159SKalle Valo 		ath11k_ahb_ce_irqs_disable(ab);
318d5c65159SKalle Valo 	ath11k_ahb_sync_ce_irqs(ab);
319d5c65159SKalle Valo 	ath11k_ahb_kill_tasklets(ab);
320d5c65159SKalle Valo 	del_timer_sync(&ab->rx_replenish_retry);
321d5c65159SKalle Valo 	ath11k_ce_cleanup_pipes(ab);
322d5c65159SKalle Valo }
323d5c65159SKalle Valo 
32431858805SGovind Singh static int ath11k_ahb_power_up(struct ath11k_base *ab)
325d5c65159SKalle Valo {
326ba929d6fSGovind Singh 	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
327d5c65159SKalle Valo 	int ret;
328d5c65159SKalle Valo 
329ba929d6fSGovind Singh 	ret = rproc_boot(ab_ahb->tgt_rproc);
330d5c65159SKalle Valo 	if (ret)
331d5c65159SKalle Valo 		ath11k_err(ab, "failed to boot the remote processor Q6\n");
332d5c65159SKalle Valo 
333d5c65159SKalle Valo 	return ret;
334d5c65159SKalle Valo }
335d5c65159SKalle Valo 
33631858805SGovind Singh static void ath11k_ahb_power_down(struct ath11k_base *ab)
337d5c65159SKalle Valo {
338ba929d6fSGovind Singh 	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
339ba929d6fSGovind Singh 
340ba929d6fSGovind Singh 	rproc_shutdown(ab_ahb->tgt_rproc);
341d5c65159SKalle Valo }
342d5c65159SKalle Valo 
343d5c65159SKalle Valo static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)
344d5c65159SKalle Valo {
345d5c65159SKalle Valo 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
346d5c65159SKalle Valo 
347967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
348967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
349967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
350967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
351eb8de049SGovind Singh 	ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074;
352d5c65159SKalle Valo }
353d5c65159SKalle Valo 
354d5c65159SKalle Valo static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab)
355d5c65159SKalle Valo {
356d5c65159SKalle Valo 	int i, j;
357d5c65159SKalle Valo 
358d5c65159SKalle Valo 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
359d5c65159SKalle Valo 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
360d5c65159SKalle Valo 
361d5c65159SKalle Valo 		for (j = 0; j < irq_grp->num_irq; j++)
362d5c65159SKalle Valo 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
363d5c65159SKalle Valo 	}
364d5c65159SKalle Valo }
365d5c65159SKalle Valo 
366d5c65159SKalle Valo static void ath11k_ahb_free_irq(struct ath11k_base *ab)
367d5c65159SKalle Valo {
368d5c65159SKalle Valo 	int irq_idx;
369d5c65159SKalle Valo 	int i;
370d5c65159SKalle Valo 
371d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
372e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
373d5c65159SKalle Valo 			continue;
374d5c65159SKalle Valo 		irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
375d5c65159SKalle Valo 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
376d5c65159SKalle Valo 	}
377d5c65159SKalle Valo 
378d5c65159SKalle Valo 	ath11k_ahb_free_ext_irq(ab);
379d5c65159SKalle Valo }
380d5c65159SKalle Valo 
381c08279a9SAllen Pais static void ath11k_ahb_ce_tasklet(struct tasklet_struct *t)
382d5c65159SKalle Valo {
383c08279a9SAllen Pais 	struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
384d5c65159SKalle Valo 
385d5c65159SKalle Valo 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
386d5c65159SKalle Valo 
387d5c65159SKalle Valo 	ath11k_ahb_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
388d5c65159SKalle Valo }
389d5c65159SKalle Valo 
390d5c65159SKalle Valo static irqreturn_t ath11k_ahb_ce_interrupt_handler(int irq, void *arg)
391d5c65159SKalle Valo {
392d5c65159SKalle Valo 	struct ath11k_ce_pipe *ce_pipe = arg;
393d5c65159SKalle Valo 
3945118935bSManikanta Pubbisetty 	/* last interrupt received for this CE */
3955118935bSManikanta Pubbisetty 	ce_pipe->timestamp = jiffies;
3965118935bSManikanta Pubbisetty 
397d5c65159SKalle Valo 	ath11k_ahb_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
398d5c65159SKalle Valo 
399d5c65159SKalle Valo 	tasklet_schedule(&ce_pipe->intr_tq);
400d5c65159SKalle Valo 
401d5c65159SKalle Valo 	return IRQ_HANDLED;
402d5c65159SKalle Valo }
403d5c65159SKalle Valo 
404d5c65159SKalle Valo static int ath11k_ahb_ext_grp_napi_poll(struct napi_struct *napi, int budget)
405d5c65159SKalle Valo {
406d5c65159SKalle Valo 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
407d5c65159SKalle Valo 						struct ath11k_ext_irq_grp,
408d5c65159SKalle Valo 						napi);
409d5c65159SKalle Valo 	struct ath11k_base *ab = irq_grp->ab;
410d5c65159SKalle Valo 	int work_done;
411d5c65159SKalle Valo 
412d5c65159SKalle Valo 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
413d5c65159SKalle Valo 	if (work_done < budget) {
414d5c65159SKalle Valo 		napi_complete_done(napi, work_done);
415d5c65159SKalle Valo 		ath11k_ahb_ext_grp_enable(irq_grp);
416d5c65159SKalle Valo 	}
417d5c65159SKalle Valo 
418d5c65159SKalle Valo 	if (work_done > budget)
419d5c65159SKalle Valo 		work_done = budget;
420d5c65159SKalle Valo 
421d5c65159SKalle Valo 	return work_done;
422d5c65159SKalle Valo }
423d5c65159SKalle Valo 
424d5c65159SKalle Valo static irqreturn_t ath11k_ahb_ext_interrupt_handler(int irq, void *arg)
425d5c65159SKalle Valo {
426d5c65159SKalle Valo 	struct ath11k_ext_irq_grp *irq_grp = arg;
427d5c65159SKalle Valo 
4285118935bSManikanta Pubbisetty 	/* last interrupt received for this group */
4295118935bSManikanta Pubbisetty 	irq_grp->timestamp = jiffies;
4305118935bSManikanta Pubbisetty 
431d5c65159SKalle Valo 	ath11k_ahb_ext_grp_disable(irq_grp);
432d5c65159SKalle Valo 
433d5c65159SKalle Valo 	napi_schedule(&irq_grp->napi);
434d5c65159SKalle Valo 
435d5c65159SKalle Valo 	return IRQ_HANDLED;
436d5c65159SKalle Valo }
437d5c65159SKalle Valo 
438d5c65159SKalle Valo static int ath11k_ahb_ext_irq_config(struct ath11k_base *ab)
439d5c65159SKalle Valo {
440d547ca4cSAnilkumar Kolli 	struct ath11k_hw_params *hw = &ab->hw_params;
441d5c65159SKalle Valo 	int i, j;
442d5c65159SKalle Valo 	int irq;
443d5c65159SKalle Valo 	int ret;
444d5c65159SKalle Valo 
445d5c65159SKalle Valo 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
446d5c65159SKalle Valo 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
447d5c65159SKalle Valo 		u32 num_irq = 0;
448d5c65159SKalle Valo 
449d5c65159SKalle Valo 		irq_grp->ab = ab;
450d5c65159SKalle Valo 		irq_grp->grp_id = i;
451d5c65159SKalle Valo 		init_dummy_netdev(&irq_grp->napi_ndev);
452d5c65159SKalle Valo 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
453d5c65159SKalle Valo 			       ath11k_ahb_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
454d5c65159SKalle Valo 
455d5c65159SKalle Valo 		for (j = 0; j < ATH11K_EXT_IRQ_NUM_MAX; j++) {
45634d5a3a8SKalle Valo 			if (ab->hw_params.ring_mask->tx[i] & BIT(j)) {
457d5c65159SKalle Valo 				irq_grp->irqs[num_irq++] =
458d5c65159SKalle Valo 					wbm2host_tx_completions_ring1 - j;
459d5c65159SKalle Valo 			}
460d5c65159SKalle Valo 
46134d5a3a8SKalle Valo 			if (ab->hw_params.ring_mask->rx[i] & BIT(j)) {
462d5c65159SKalle Valo 				irq_grp->irqs[num_irq++] =
463d5c65159SKalle Valo 					reo2host_destination_ring1 - j;
464d5c65159SKalle Valo 			}
465d5c65159SKalle Valo 
46634d5a3a8SKalle Valo 			if (ab->hw_params.ring_mask->rx_err[i] & BIT(j))
467d5c65159SKalle Valo 				irq_grp->irqs[num_irq++] = reo2host_exception;
468d5c65159SKalle Valo 
46934d5a3a8SKalle Valo 			if (ab->hw_params.ring_mask->rx_wbm_rel[i] & BIT(j))
470d5c65159SKalle Valo 				irq_grp->irqs[num_irq++] = wbm2host_rx_release;
471d5c65159SKalle Valo 
47234d5a3a8SKalle Valo 			if (ab->hw_params.ring_mask->reo_status[i] & BIT(j))
473d5c65159SKalle Valo 				irq_grp->irqs[num_irq++] = reo2host_status;
474d5c65159SKalle Valo 
475d547ca4cSAnilkumar Kolli 			if (j < ab->hw_params.max_radios) {
47634d5a3a8SKalle Valo 				if (ab->hw_params.ring_mask->rxdma2host[i] & BIT(j)) {
477d5c65159SKalle Valo 					irq_grp->irqs[num_irq++] =
478d547ca4cSAnilkumar Kolli 						rxdma2host_destination_ring_mac1 -
479d547ca4cSAnilkumar Kolli 						ath11k_hw_get_mac_from_pdev_id(hw, j);
480d5c65159SKalle Valo 				}
481d5c65159SKalle Valo 
48234d5a3a8SKalle Valo 				if (ab->hw_params.ring_mask->host2rxdma[i] & BIT(j)) {
483d5c65159SKalle Valo 					irq_grp->irqs[num_irq++] =
484d547ca4cSAnilkumar Kolli 						host2rxdma_host_buf_ring_mac1 -
485d547ca4cSAnilkumar Kolli 						ath11k_hw_get_mac_from_pdev_id(hw, j);
486d5c65159SKalle Valo 				}
487d5c65159SKalle Valo 
48834d5a3a8SKalle Valo 				if (ab->hw_params.ring_mask->rx_mon_status[i] & BIT(j)) {
489d5c65159SKalle Valo 					irq_grp->irqs[num_irq++] =
490d5c65159SKalle Valo 						ppdu_end_interrupts_mac1 -
491d547ca4cSAnilkumar Kolli 						ath11k_hw_get_mac_from_pdev_id(hw, j);
492d5c65159SKalle Valo 					irq_grp->irqs[num_irq++] =
493d5c65159SKalle Valo 						rxdma2host_monitor_status_ring_mac1 -
494d547ca4cSAnilkumar Kolli 						ath11k_hw_get_mac_from_pdev_id(hw, j);
495d5c65159SKalle Valo 				}
496d5c65159SKalle Valo 			}
497d5c65159SKalle Valo 		}
498d5c65159SKalle Valo 		irq_grp->num_irq = num_irq;
499d5c65159SKalle Valo 
500d5c65159SKalle Valo 		for (j = 0; j < irq_grp->num_irq; j++) {
501d5c65159SKalle Valo 			int irq_idx = irq_grp->irqs[j];
502d5c65159SKalle Valo 
503d5c65159SKalle Valo 			irq = platform_get_irq_byname(ab->pdev,
504d5c65159SKalle Valo 						      irq_name[irq_idx]);
505d5c65159SKalle Valo 			ab->irq_num[irq_idx] = irq;
50605090864SManikanta Pubbisetty 			irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_DISABLE_UNLAZY);
507d5c65159SKalle Valo 			ret = request_irq(irq, ath11k_ahb_ext_interrupt_handler,
508d5c65159SKalle Valo 					  IRQF_TRIGGER_RISING,
509d5c65159SKalle Valo 					  irq_name[irq_idx], irq_grp);
510d5c65159SKalle Valo 			if (ret) {
511d5c65159SKalle Valo 				ath11k_err(ab, "failed request_irq for %d\n",
512d5c65159SKalle Valo 					   irq);
513d5c65159SKalle Valo 			}
514d5c65159SKalle Valo 		}
515d5c65159SKalle Valo 	}
516d5c65159SKalle Valo 
517d5c65159SKalle Valo 	return 0;
518d5c65159SKalle Valo }
519d5c65159SKalle Valo 
520d5c65159SKalle Valo static int ath11k_ahb_config_irq(struct ath11k_base *ab)
521d5c65159SKalle Valo {
522d5c65159SKalle Valo 	int irq, irq_idx, i;
523d5c65159SKalle Valo 	int ret;
524d5c65159SKalle Valo 
525d5c65159SKalle Valo 	/* Configure CE irqs */
526d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
527d5c65159SKalle Valo 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
528d5c65159SKalle Valo 
529e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
530d5c65159SKalle Valo 			continue;
531d5c65159SKalle Valo 
532d5c65159SKalle Valo 		irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
533d5c65159SKalle Valo 
534c08279a9SAllen Pais 		tasklet_setup(&ce_pipe->intr_tq, ath11k_ahb_ce_tasklet);
535d5c65159SKalle Valo 		irq = platform_get_irq_byname(ab->pdev, irq_name[irq_idx]);
536d5c65159SKalle Valo 		ret = request_irq(irq, ath11k_ahb_ce_interrupt_handler,
537d5c65159SKalle Valo 				  IRQF_TRIGGER_RISING, irq_name[irq_idx],
538d5c65159SKalle Valo 				  ce_pipe);
539d5c65159SKalle Valo 		if (ret)
540d5c65159SKalle Valo 			return ret;
541d5c65159SKalle Valo 
542d5c65159SKalle Valo 		ab->irq_num[irq_idx] = irq;
543d5c65159SKalle Valo 	}
544d5c65159SKalle Valo 
545d5c65159SKalle Valo 	/* Configure external interrupts */
546d5c65159SKalle Valo 	ret = ath11k_ahb_ext_irq_config(ab);
547d5c65159SKalle Valo 
548d5c65159SKalle Valo 	return ret;
549d5c65159SKalle Valo }
550d5c65159SKalle Valo 
55131858805SGovind Singh static int ath11k_ahb_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
552d5c65159SKalle Valo 					  u8 *ul_pipe, u8 *dl_pipe)
553d5c65159SKalle Valo {
554d5c65159SKalle Valo 	const struct service_to_pipe *entry;
555d5c65159SKalle Valo 	bool ul_set = false, dl_set = false;
556d5c65159SKalle Valo 	int i;
557d5c65159SKalle Valo 
558967c1d11SAnilkumar Kolli 	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
559967c1d11SAnilkumar Kolli 		entry = &ab->hw_params.svc_to_ce_map[i];
560d5c65159SKalle Valo 
561d5c65159SKalle Valo 		if (__le32_to_cpu(entry->service_id) != service_id)
562d5c65159SKalle Valo 			continue;
563d5c65159SKalle Valo 
564d5c65159SKalle Valo 		switch (__le32_to_cpu(entry->pipedir)) {
565d5c65159SKalle Valo 		case PIPEDIR_NONE:
566d5c65159SKalle Valo 			break;
567d5c65159SKalle Valo 		case PIPEDIR_IN:
568d5c65159SKalle Valo 			WARN_ON(dl_set);
569d5c65159SKalle Valo 			*dl_pipe = __le32_to_cpu(entry->pipenum);
570d5c65159SKalle Valo 			dl_set = true;
571d5c65159SKalle Valo 			break;
572d5c65159SKalle Valo 		case PIPEDIR_OUT:
573d5c65159SKalle Valo 			WARN_ON(ul_set);
574d5c65159SKalle Valo 			*ul_pipe = __le32_to_cpu(entry->pipenum);
575d5c65159SKalle Valo 			ul_set = true;
576d5c65159SKalle Valo 			break;
577d5c65159SKalle Valo 		case PIPEDIR_INOUT:
578d5c65159SKalle Valo 			WARN_ON(dl_set);
579d5c65159SKalle Valo 			WARN_ON(ul_set);
580d5c65159SKalle Valo 			*dl_pipe = __le32_to_cpu(entry->pipenum);
581d5c65159SKalle Valo 			*ul_pipe = __le32_to_cpu(entry->pipenum);
582d5c65159SKalle Valo 			dl_set = true;
583d5c65159SKalle Valo 			ul_set = true;
584d5c65159SKalle Valo 			break;
585d5c65159SKalle Valo 		}
586d5c65159SKalle Valo 	}
587d5c65159SKalle Valo 
588d5c65159SKalle Valo 	if (WARN_ON(!ul_set || !dl_set))
589d5c65159SKalle Valo 		return -ENOENT;
590d5c65159SKalle Valo 
591d5c65159SKalle Valo 	return 0;
592d5c65159SKalle Valo }
593d5c65159SKalle Valo 
59431858805SGovind Singh static const struct ath11k_hif_ops ath11k_ahb_hif_ops = {
59531858805SGovind Singh 	.start = ath11k_ahb_start,
59631858805SGovind Singh 	.stop = ath11k_ahb_stop,
59731858805SGovind Singh 	.read32 = ath11k_ahb_read32,
59831858805SGovind Singh 	.write32 = ath11k_ahb_write32,
59931858805SGovind Singh 	.irq_enable = ath11k_ahb_ext_irq_enable,
60031858805SGovind Singh 	.irq_disable = ath11k_ahb_ext_irq_disable,
60131858805SGovind Singh 	.map_service_to_pipe = ath11k_ahb_map_service_to_pipe,
60231858805SGovind Singh 	.power_down = ath11k_ahb_power_down,
60331858805SGovind Singh 	.power_up = ath11k_ahb_power_up,
60431858805SGovind Singh };
60531858805SGovind Singh 
606ba929d6fSGovind Singh static int ath11k_core_get_rproc(struct ath11k_base *ab)
607ba929d6fSGovind Singh {
608ba929d6fSGovind Singh 	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
609ba929d6fSGovind Singh 	struct device *dev = ab->dev;
610ba929d6fSGovind Singh 	struct rproc *prproc;
611ba929d6fSGovind Singh 	phandle rproc_phandle;
612ba929d6fSGovind Singh 
613ba929d6fSGovind Singh 	if (of_property_read_u32(dev->of_node, "qcom,rproc", &rproc_phandle)) {
614ba929d6fSGovind Singh 		ath11k_err(ab, "failed to get q6_rproc handle\n");
615ba929d6fSGovind Singh 		return -ENOENT;
616ba929d6fSGovind Singh 	}
617ba929d6fSGovind Singh 
618ba929d6fSGovind Singh 	prproc = rproc_get_by_phandle(rproc_phandle);
619ba929d6fSGovind Singh 	if (!prproc) {
620ba929d6fSGovind Singh 		ath11k_err(ab, "failed to get rproc\n");
621ba929d6fSGovind Singh 		return -EINVAL;
622ba929d6fSGovind Singh 	}
623ba929d6fSGovind Singh 	ab_ahb->tgt_rproc = prproc;
624ba929d6fSGovind Singh 
625ba929d6fSGovind Singh 	return 0;
626ba929d6fSGovind Singh }
627ba929d6fSGovind Singh 
628d5c65159SKalle Valo static int ath11k_ahb_probe(struct platform_device *pdev)
629d5c65159SKalle Valo {
630d5c65159SKalle Valo 	struct ath11k_base *ab;
631d5c65159SKalle Valo 	const struct of_device_id *of_id;
632d5c65159SKalle Valo 	struct resource *mem_res;
633d5c65159SKalle Valo 	void __iomem *mem;
634d5c65159SKalle Valo 	int ret;
635d5c65159SKalle Valo 
636d5c65159SKalle Valo 	of_id = of_match_device(ath11k_ahb_of_match, &pdev->dev);
637d5c65159SKalle Valo 	if (!of_id) {
638d5c65159SKalle Valo 		dev_err(&pdev->dev, "failed to find matching device tree id\n");
639d5c65159SKalle Valo 		return -EINVAL;
640d5c65159SKalle Valo 	}
641d5c65159SKalle Valo 
642c8ffcd12SWei Yongjun 	mem = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res);
643d5c65159SKalle Valo 	if (IS_ERR(mem)) {
644d5c65159SKalle Valo 		dev_err(&pdev->dev, "ioremap error\n");
645d5c65159SKalle Valo 		return PTR_ERR(mem);
646d5c65159SKalle Valo 	}
647d5c65159SKalle Valo 
648d5c65159SKalle Valo 	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
649d5c65159SKalle Valo 	if (ret) {
650d5c65159SKalle Valo 		dev_err(&pdev->dev, "failed to set 32-bit consistent dma\n");
651d5c65159SKalle Valo 		return ret;
652d5c65159SKalle Valo 	}
653d5c65159SKalle Valo 
654ba929d6fSGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(struct ath11k_ahb),
655ba929d6fSGovind Singh 			       ATH11K_BUS_AHB,
656ba929d6fSGovind Singh 			       &ath11k_ahb_bus_params);
657d5c65159SKalle Valo 	if (!ab) {
658d5c65159SKalle Valo 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
659d5c65159SKalle Valo 		return -ENOMEM;
660d5c65159SKalle Valo 	}
661d5c65159SKalle Valo 
66231858805SGovind Singh 	ab->hif.ops = &ath11k_ahb_hif_ops;
663d5c65159SKalle Valo 	ab->pdev = pdev;
664d5c65159SKalle Valo 	ab->hw_rev = (enum ath11k_hw_rev)of_id->data;
665d5c65159SKalle Valo 	ab->mem = mem;
666d5c65159SKalle Valo 	ab->mem_len = resource_size(mem_res);
667d5c65159SKalle Valo 	platform_set_drvdata(pdev, ab);
668d5c65159SKalle Valo 
669b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
670b8246f88SKalle Valo 	if (ret)
671b8246f88SKalle Valo 		goto err_core_free;
672b8246f88SKalle Valo 
673d5c65159SKalle Valo 	ret = ath11k_hal_srng_init(ab);
674d5c65159SKalle Valo 	if (ret)
675d5c65159SKalle Valo 		goto err_core_free;
676d5c65159SKalle Valo 
677d5c65159SKalle Valo 	ret = ath11k_ce_alloc_pipes(ab);
678d5c65159SKalle Valo 	if (ret) {
679d5c65159SKalle Valo 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
680d5c65159SKalle Valo 		goto err_hal_srng_deinit;
681d5c65159SKalle Valo 	}
682d5c65159SKalle Valo 
683d5c65159SKalle Valo 	ath11k_ahb_init_qmi_ce_config(ab);
684d5c65159SKalle Valo 
685ba929d6fSGovind Singh 	ret = ath11k_core_get_rproc(ab);
686ba929d6fSGovind Singh 	if (ret) {
687ba929d6fSGovind Singh 		ath11k_err(ab, "failed to get rproc: %d\n", ret);
688ba929d6fSGovind Singh 		goto err_ce_free;
689ba929d6fSGovind Singh 	}
690ba929d6fSGovind Singh 
691d5c65159SKalle Valo 	ret = ath11k_core_init(ab);
692d5c65159SKalle Valo 	if (ret) {
693d5c65159SKalle Valo 		ath11k_err(ab, "failed to init core: %d\n", ret);
694d5c65159SKalle Valo 		goto err_ce_free;
695d5c65159SKalle Valo 	}
696d5c65159SKalle Valo 
697166e22b3SAnilkumar Kolli 	ret = ath11k_ahb_config_irq(ab);
698166e22b3SAnilkumar Kolli 	if (ret) {
699166e22b3SAnilkumar Kolli 		ath11k_err(ab, "failed to configure irq: %d\n", ret);
700166e22b3SAnilkumar Kolli 		goto err_ce_free;
701166e22b3SAnilkumar Kolli 	}
702166e22b3SAnilkumar Kolli 
703d5c65159SKalle Valo 	return 0;
704d5c65159SKalle Valo 
705d5c65159SKalle Valo err_ce_free:
706d5c65159SKalle Valo 	ath11k_ce_free_pipes(ab);
707d5c65159SKalle Valo 
708d5c65159SKalle Valo err_hal_srng_deinit:
709d5c65159SKalle Valo 	ath11k_hal_srng_deinit(ab);
710d5c65159SKalle Valo 
711d5c65159SKalle Valo err_core_free:
712d5c65159SKalle Valo 	ath11k_core_free(ab);
713d5c65159SKalle Valo 	platform_set_drvdata(pdev, NULL);
714d5c65159SKalle Valo 
715d5c65159SKalle Valo 	return ret;
716d5c65159SKalle Valo }
717d5c65159SKalle Valo 
718d5c65159SKalle Valo static int ath11k_ahb_remove(struct platform_device *pdev)
719d5c65159SKalle Valo {
720d5c65159SKalle Valo 	struct ath11k_base *ab = platform_get_drvdata(pdev);
721d5c65159SKalle Valo 
722d5c65159SKalle Valo 	reinit_completion(&ab->driver_recovery);
723d5c65159SKalle Valo 
724d5c65159SKalle Valo 	if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags))
725d5c65159SKalle Valo 		wait_for_completion_timeout(&ab->driver_recovery,
726d5c65159SKalle Valo 					    ATH11K_AHB_RECOVERY_TIMEOUT);
727d5c65159SKalle Valo 
728d5c65159SKalle Valo 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
729d5c65159SKalle Valo 	cancel_work_sync(&ab->restart_work);
730d5c65159SKalle Valo 
731d5c65159SKalle Valo 	ath11k_core_deinit(ab);
732d5c65159SKalle Valo 	ath11k_ahb_free_irq(ab);
733d5c65159SKalle Valo 
734d5c65159SKalle Valo 	ath11k_hal_srng_deinit(ab);
735d5c65159SKalle Valo 	ath11k_ce_free_pipes(ab);
736d5c65159SKalle Valo 	ath11k_core_free(ab);
737d5c65159SKalle Valo 	platform_set_drvdata(pdev, NULL);
738d5c65159SKalle Valo 
739d5c65159SKalle Valo 	return 0;
740d5c65159SKalle Valo }
741d5c65159SKalle Valo 
742d5c65159SKalle Valo static struct platform_driver ath11k_ahb_driver = {
743d5c65159SKalle Valo 	.driver         = {
744d5c65159SKalle Valo 		.name   = "ath11k",
745d5c65159SKalle Valo 		.of_match_table = ath11k_ahb_of_match,
746d5c65159SKalle Valo 	},
747d5c65159SKalle Valo 	.probe  = ath11k_ahb_probe,
748d5c65159SKalle Valo 	.remove = ath11k_ahb_remove,
749d5c65159SKalle Valo };
750d5c65159SKalle Valo 
75131858805SGovind Singh static int ath11k_ahb_init(void)
752d5c65159SKalle Valo {
753d5c65159SKalle Valo 	return platform_driver_register(&ath11k_ahb_driver);
754d5c65159SKalle Valo }
75531858805SGovind Singh module_init(ath11k_ahb_init);
756d5c65159SKalle Valo 
75731858805SGovind Singh static void ath11k_ahb_exit(void)
758d5c65159SKalle Valo {
759d5c65159SKalle Valo 	platform_driver_unregister(&ath11k_ahb_driver);
760d5c65159SKalle Valo }
76131858805SGovind Singh module_exit(ath11k_ahb_exit);
76231858805SGovind Singh 
7636e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN AHB devices");
76431858805SGovind Singh MODULE_LICENSE("Dual BSD/GPL");
765