xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/ahb.c (revision e9327c72)
1d5c65159SKalle Valo // SPDX-License-Identifier: BSD-3-Clause-Clear
2d5c65159SKalle Valo /*
3d5c65159SKalle Valo  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
4b43310e4SGovindaraj Saminathan  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
5d5c65159SKalle Valo  */
6d5c65159SKalle Valo 
7d5c65159SKalle Valo #include <linux/module.h>
8d5c65159SKalle Valo #include <linux/platform_device.h>
9d5c65159SKalle Valo #include <linux/of_device.h>
10d5c65159SKalle Valo #include <linux/of.h>
11d5c65159SKalle Valo #include <linux/dma-mapping.h>
12f9eec494SManikanta Pubbisetty #include <linux/of_address.h>
13f9eec494SManikanta Pubbisetty #include <linux/iommu.h>
14d5c65159SKalle Valo #include "ahb.h"
15d5c65159SKalle Valo #include "debug.h"
1631858805SGovind Singh #include "hif.h"
17bdfc967bSAnilkumar Kolli #include "qmi.h"
18d5c65159SKalle Valo #include <linux/remoteproc.h>
1900402f49SManikanta Pubbisetty #include "pcic.h"
2069ccee61SManikanta Pubbisetty #include <linux/soc/qcom/smem.h>
2169ccee61SManikanta Pubbisetty #include <linux/soc/qcom/smem_state.h>
22d5c65159SKalle Valo 
23d5c65159SKalle Valo static const struct of_device_id ath11k_ahb_of_match[] = {
24d5c65159SKalle Valo 	/* TODO: Should we change the compatible string to something similar
25d5c65159SKalle Valo 	 * to one that ath10k uses?
26d5c65159SKalle Valo 	 */
27d5c65159SKalle Valo 	{ .compatible = "qcom,ipq8074-wifi",
28d5c65159SKalle Valo 	  .data = (void *)ATH11K_HW_IPQ8074,
29d5c65159SKalle Valo 	},
30b129699aSAnilkumar Kolli 	{ .compatible = "qcom,ipq6018-wifi",
31b129699aSAnilkumar Kolli 	  .data = (void *)ATH11K_HW_IPQ6018_HW10,
32b129699aSAnilkumar Kolli 	},
3300402f49SManikanta Pubbisetty 	{ .compatible = "qcom,wcn6750-wifi",
3400402f49SManikanta Pubbisetty 	  .data = (void *)ATH11K_HW_WCN6750_HW10,
3500402f49SManikanta Pubbisetty 	},
3625edca7bSSriram R 	{ .compatible = "qcom,ipq5018-wifi",
3725edca7bSSriram R 	  .data = (void *)ATH11K_HW_IPQ5018_HW10,
3825edca7bSSriram R 	},
39d5c65159SKalle Valo 	{ }
40d5c65159SKalle Valo };
41d5c65159SKalle Valo 
42d5c65159SKalle Valo MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match);
43d5c65159SKalle Valo 
44d5c65159SKalle Valo #define ATH11K_IRQ_CE0_OFFSET 4
45d5c65159SKalle Valo 
46d5c65159SKalle Valo static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
47d5c65159SKalle Valo 	"misc-pulse1",
48d5c65159SKalle Valo 	"misc-latch",
49d5c65159SKalle Valo 	"sw-exception",
50d5c65159SKalle Valo 	"watchdog",
51d5c65159SKalle Valo 	"ce0",
52d5c65159SKalle Valo 	"ce1",
53d5c65159SKalle Valo 	"ce2",
54d5c65159SKalle Valo 	"ce3",
55d5c65159SKalle Valo 	"ce4",
56d5c65159SKalle Valo 	"ce5",
57d5c65159SKalle Valo 	"ce6",
58d5c65159SKalle Valo 	"ce7",
59d5c65159SKalle Valo 	"ce8",
60d5c65159SKalle Valo 	"ce9",
61d5c65159SKalle Valo 	"ce10",
62d5c65159SKalle Valo 	"ce11",
63d5c65159SKalle Valo 	"host2wbm-desc-feed",
64d5c65159SKalle Valo 	"host2reo-re-injection",
65d5c65159SKalle Valo 	"host2reo-command",
66d5c65159SKalle Valo 	"host2rxdma-monitor-ring3",
67d5c65159SKalle Valo 	"host2rxdma-monitor-ring2",
68d5c65159SKalle Valo 	"host2rxdma-monitor-ring1",
69d5c65159SKalle Valo 	"reo2ost-exception",
70d5c65159SKalle Valo 	"wbm2host-rx-release",
71d5c65159SKalle Valo 	"reo2host-status",
72d5c65159SKalle Valo 	"reo2host-destination-ring4",
73d5c65159SKalle Valo 	"reo2host-destination-ring3",
74d5c65159SKalle Valo 	"reo2host-destination-ring2",
75d5c65159SKalle Valo 	"reo2host-destination-ring1",
76d5c65159SKalle Valo 	"rxdma2host-monitor-destination-mac3",
77d5c65159SKalle Valo 	"rxdma2host-monitor-destination-mac2",
78d5c65159SKalle Valo 	"rxdma2host-monitor-destination-mac1",
79d5c65159SKalle Valo 	"ppdu-end-interrupts-mac3",
80d5c65159SKalle Valo 	"ppdu-end-interrupts-mac2",
81d5c65159SKalle Valo 	"ppdu-end-interrupts-mac1",
82d5c65159SKalle Valo 	"rxdma2host-monitor-status-ring-mac3",
83d5c65159SKalle Valo 	"rxdma2host-monitor-status-ring-mac2",
84d5c65159SKalle Valo 	"rxdma2host-monitor-status-ring-mac1",
85d5c65159SKalle Valo 	"host2rxdma-host-buf-ring-mac3",
86d5c65159SKalle Valo 	"host2rxdma-host-buf-ring-mac2",
87d5c65159SKalle Valo 	"host2rxdma-host-buf-ring-mac1",
88d5c65159SKalle Valo 	"rxdma2host-destination-ring-mac3",
89d5c65159SKalle Valo 	"rxdma2host-destination-ring-mac2",
90d5c65159SKalle Valo 	"rxdma2host-destination-ring-mac1",
91d5c65159SKalle Valo 	"host2tcl-input-ring4",
92d5c65159SKalle Valo 	"host2tcl-input-ring3",
93d5c65159SKalle Valo 	"host2tcl-input-ring2",
94d5c65159SKalle Valo 	"host2tcl-input-ring1",
95d5c65159SKalle Valo 	"wbm2host-tx-completions-ring3",
96d5c65159SKalle Valo 	"wbm2host-tx-completions-ring2",
97d5c65159SKalle Valo 	"wbm2host-tx-completions-ring1",
98d5c65159SKalle Valo 	"tcl2host-status-ring",
99d5c65159SKalle Valo };
100d5c65159SKalle Valo 
101d5c65159SKalle Valo /* enum ext_irq_num - irq numbers that can be used by external modules
102d5c65159SKalle Valo  * like datapath
103d5c65159SKalle Valo  */
104d5c65159SKalle Valo enum ext_irq_num {
105d5c65159SKalle Valo 	host2wbm_desc_feed = 16,
106d5c65159SKalle Valo 	host2reo_re_injection,
107d5c65159SKalle Valo 	host2reo_command,
108d5c65159SKalle Valo 	host2rxdma_monitor_ring3,
109d5c65159SKalle Valo 	host2rxdma_monitor_ring2,
110d5c65159SKalle Valo 	host2rxdma_monitor_ring1,
111d5c65159SKalle Valo 	reo2host_exception,
112d5c65159SKalle Valo 	wbm2host_rx_release,
113d5c65159SKalle Valo 	reo2host_status,
114d5c65159SKalle Valo 	reo2host_destination_ring4,
115d5c65159SKalle Valo 	reo2host_destination_ring3,
116d5c65159SKalle Valo 	reo2host_destination_ring2,
117d5c65159SKalle Valo 	reo2host_destination_ring1,
118d5c65159SKalle Valo 	rxdma2host_monitor_destination_mac3,
119d5c65159SKalle Valo 	rxdma2host_monitor_destination_mac2,
120d5c65159SKalle Valo 	rxdma2host_monitor_destination_mac1,
121d5c65159SKalle Valo 	ppdu_end_interrupts_mac3,
122d5c65159SKalle Valo 	ppdu_end_interrupts_mac2,
123d5c65159SKalle Valo 	ppdu_end_interrupts_mac1,
124d5c65159SKalle Valo 	rxdma2host_monitor_status_ring_mac3,
125d5c65159SKalle Valo 	rxdma2host_monitor_status_ring_mac2,
126d5c65159SKalle Valo 	rxdma2host_monitor_status_ring_mac1,
127d5c65159SKalle Valo 	host2rxdma_host_buf_ring_mac3,
128d5c65159SKalle Valo 	host2rxdma_host_buf_ring_mac2,
129d5c65159SKalle Valo 	host2rxdma_host_buf_ring_mac1,
130d5c65159SKalle Valo 	rxdma2host_destination_ring_mac3,
131d5c65159SKalle Valo 	rxdma2host_destination_ring_mac2,
132d5c65159SKalle Valo 	rxdma2host_destination_ring_mac1,
133d5c65159SKalle Valo 	host2tcl_input_ring4,
134d5c65159SKalle Valo 	host2tcl_input_ring3,
135d5c65159SKalle Valo 	host2tcl_input_ring2,
136d5c65159SKalle Valo 	host2tcl_input_ring1,
137d5c65159SKalle Valo 	wbm2host_tx_completions_ring3,
138d5c65159SKalle Valo 	wbm2host_tx_completions_ring2,
139d5c65159SKalle Valo 	wbm2host_tx_completions_ring1,
140d5c65159SKalle Valo 	tcl2host_status_ring,
141d5c65159SKalle Valo };
142d5c65159SKalle Valo 
14300402f49SManikanta Pubbisetty static int
ath11k_ahb_get_msi_irq_wcn6750(struct ath11k_base * ab,unsigned int vector)14400402f49SManikanta Pubbisetty ath11k_ahb_get_msi_irq_wcn6750(struct ath11k_base *ab, unsigned int vector)
14500402f49SManikanta Pubbisetty {
14600402f49SManikanta Pubbisetty 	return ab->pci.msi.irqs[vector];
14700402f49SManikanta Pubbisetty }
14800402f49SManikanta Pubbisetty 
149867f4eeeSManikanta Pubbisetty static inline u32
ath11k_ahb_get_window_start_wcn6750(struct ath11k_base * ab,u32 offset)150867f4eeeSManikanta Pubbisetty ath11k_ahb_get_window_start_wcn6750(struct ath11k_base *ab, u32 offset)
151867f4eeeSManikanta Pubbisetty {
152867f4eeeSManikanta Pubbisetty 	u32 window_start = 0;
153867f4eeeSManikanta Pubbisetty 
154867f4eeeSManikanta Pubbisetty 	/* If offset lies within DP register range, use 1st window */
155867f4eeeSManikanta Pubbisetty 	if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < ATH11K_PCI_WINDOW_RANGE_MASK)
156867f4eeeSManikanta Pubbisetty 		window_start = ATH11K_PCI_WINDOW_START;
157867f4eeeSManikanta Pubbisetty 	/* If offset lies within CE register range, use 2nd window */
158867f4eeeSManikanta Pubbisetty 	else if ((offset ^ HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab)) <
159867f4eeeSManikanta Pubbisetty 		 ATH11K_PCI_WINDOW_RANGE_MASK)
160867f4eeeSManikanta Pubbisetty 		window_start = 2 * ATH11K_PCI_WINDOW_START;
161867f4eeeSManikanta Pubbisetty 
162867f4eeeSManikanta Pubbisetty 	return window_start;
163867f4eeeSManikanta Pubbisetty }
164867f4eeeSManikanta Pubbisetty 
165867f4eeeSManikanta Pubbisetty static void
ath11k_ahb_window_write32_wcn6750(struct ath11k_base * ab,u32 offset,u32 value)166867f4eeeSManikanta Pubbisetty ath11k_ahb_window_write32_wcn6750(struct ath11k_base *ab, u32 offset, u32 value)
167867f4eeeSManikanta Pubbisetty {
168867f4eeeSManikanta Pubbisetty 	u32 window_start;
169867f4eeeSManikanta Pubbisetty 
170867f4eeeSManikanta Pubbisetty 	/* WCN6750 uses static window based register access*/
171867f4eeeSManikanta Pubbisetty 	window_start = ath11k_ahb_get_window_start_wcn6750(ab, offset);
172867f4eeeSManikanta Pubbisetty 
173867f4eeeSManikanta Pubbisetty 	iowrite32(value, ab->mem + window_start +
174867f4eeeSManikanta Pubbisetty 		  (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
175867f4eeeSManikanta Pubbisetty }
176867f4eeeSManikanta Pubbisetty 
ath11k_ahb_window_read32_wcn6750(struct ath11k_base * ab,u32 offset)177867f4eeeSManikanta Pubbisetty static u32 ath11k_ahb_window_read32_wcn6750(struct ath11k_base *ab, u32 offset)
178867f4eeeSManikanta Pubbisetty {
179867f4eeeSManikanta Pubbisetty 	u32 window_start;
180867f4eeeSManikanta Pubbisetty 	u32 val;
181867f4eeeSManikanta Pubbisetty 
182867f4eeeSManikanta Pubbisetty 	/* WCN6750 uses static window based register access */
183867f4eeeSManikanta Pubbisetty 	window_start = ath11k_ahb_get_window_start_wcn6750(ab, offset);
184867f4eeeSManikanta Pubbisetty 
185867f4eeeSManikanta Pubbisetty 	val = ioread32(ab->mem + window_start +
186867f4eeeSManikanta Pubbisetty 		       (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
187867f4eeeSManikanta Pubbisetty 	return val;
188867f4eeeSManikanta Pubbisetty }
189867f4eeeSManikanta Pubbisetty 
19000402f49SManikanta Pubbisetty static const struct ath11k_pci_ops ath11k_ahb_pci_ops_wcn6750 = {
191867f4eeeSManikanta Pubbisetty 	.wakeup = NULL,
192867f4eeeSManikanta Pubbisetty 	.release = NULL,
19300402f49SManikanta Pubbisetty 	.get_msi_irq = ath11k_ahb_get_msi_irq_wcn6750,
194867f4eeeSManikanta Pubbisetty 	.window_write32 = ath11k_ahb_window_write32_wcn6750,
195867f4eeeSManikanta Pubbisetty 	.window_read32 = ath11k_ahb_window_read32_wcn6750,
19600402f49SManikanta Pubbisetty };
19700402f49SManikanta Pubbisetty 
ath11k_ahb_read32(struct ath11k_base * ab,u32 offset)19831858805SGovind Singh static inline u32 ath11k_ahb_read32(struct ath11k_base *ab, u32 offset)
19931858805SGovind Singh {
20031858805SGovind Singh 	return ioread32(ab->mem + offset);
20131858805SGovind Singh }
20231858805SGovind Singh 
ath11k_ahb_write32(struct ath11k_base * ab,u32 offset,u32 value)20331858805SGovind Singh static inline void ath11k_ahb_write32(struct ath11k_base *ab, u32 offset, u32 value)
20431858805SGovind Singh {
20531858805SGovind Singh 	iowrite32(value, ab->mem + offset);
20631858805SGovind Singh }
20731858805SGovind Singh 
ath11k_ahb_kill_tasklets(struct ath11k_base * ab)208d5c65159SKalle Valo static void ath11k_ahb_kill_tasklets(struct ath11k_base *ab)
209d5c65159SKalle Valo {
210d5c65159SKalle Valo 	int i;
211d5c65159SKalle Valo 
212d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
213d5c65159SKalle Valo 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
214d5c65159SKalle Valo 
215e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
216d5c65159SKalle Valo 			continue;
217d5c65159SKalle Valo 
218d5c65159SKalle Valo 		tasklet_kill(&ce_pipe->intr_tq);
219d5c65159SKalle Valo 	}
220d5c65159SKalle Valo }
221d5c65159SKalle Valo 
ath11k_ahb_ext_grp_disable(struct ath11k_ext_irq_grp * irq_grp)222d5c65159SKalle Valo static void ath11k_ahb_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
223d5c65159SKalle Valo {
224d5c65159SKalle Valo 	int i;
225d5c65159SKalle Valo 
226d5c65159SKalle Valo 	for (i = 0; i < irq_grp->num_irq; i++)
227d5c65159SKalle Valo 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
228d5c65159SKalle Valo }
229d5c65159SKalle Valo 
__ath11k_ahb_ext_irq_disable(struct ath11k_base * ab)230d5c65159SKalle Valo static void __ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)
231d5c65159SKalle Valo {
232d5c65159SKalle Valo 	int i;
233d5c65159SKalle Valo 
234d5c65159SKalle Valo 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
235d5c65159SKalle Valo 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
236d5c65159SKalle Valo 
237d5c65159SKalle Valo 		ath11k_ahb_ext_grp_disable(irq_grp);
238d5c65159SKalle Valo 
239d943fdadSBen Greear 		if (irq_grp->napi_enabled) {
240d5c65159SKalle Valo 			napi_synchronize(&irq_grp->napi);
241d5c65159SKalle Valo 			napi_disable(&irq_grp->napi);
242d943fdadSBen Greear 			irq_grp->napi_enabled = false;
243d943fdadSBen Greear 		}
244d5c65159SKalle Valo 	}
245d5c65159SKalle Valo }
246d5c65159SKalle Valo 
ath11k_ahb_ext_grp_enable(struct ath11k_ext_irq_grp * irq_grp)247d5c65159SKalle Valo static void ath11k_ahb_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
248d5c65159SKalle Valo {
249d5c65159SKalle Valo 	int i;
250d5c65159SKalle Valo 
251d5c65159SKalle Valo 	for (i = 0; i < irq_grp->num_irq; i++)
252d5c65159SKalle Valo 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
253d5c65159SKalle Valo }
254d5c65159SKalle Valo 
ath11k_ahb_setbit32(struct ath11k_base * ab,u8 bit,u32 offset)255d5c65159SKalle Valo static void ath11k_ahb_setbit32(struct ath11k_base *ab, u8 bit, u32 offset)
256d5c65159SKalle Valo {
257d5c65159SKalle Valo 	u32 val;
258d5c65159SKalle Valo 
259d5c65159SKalle Valo 	val = ath11k_ahb_read32(ab, offset);
260d5c65159SKalle Valo 	ath11k_ahb_write32(ab, offset, val | BIT(bit));
261d5c65159SKalle Valo }
262d5c65159SKalle Valo 
ath11k_ahb_clearbit32(struct ath11k_base * ab,u8 bit,u32 offset)263d5c65159SKalle Valo static void ath11k_ahb_clearbit32(struct ath11k_base *ab, u8 bit, u32 offset)
264d5c65159SKalle Valo {
265d5c65159SKalle Valo 	u32 val;
266d5c65159SKalle Valo 
267d5c65159SKalle Valo 	val = ath11k_ahb_read32(ab, offset);
268d5c65159SKalle Valo 	ath11k_ahb_write32(ab, offset, val & ~BIT(bit));
269d5c65159SKalle Valo }
270d5c65159SKalle Valo 
ath11k_ahb_ce_irq_enable(struct ath11k_base * ab,u16 ce_id)271d5c65159SKalle Valo static void ath11k_ahb_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
272d5c65159SKalle Valo {
273b689f091SAnilkumar Kolli 	const struct ce_attr *ce_attr;
274b42b3678SSriram R 	const struct ce_ie_addr *ce_ie_addr = ab->hw_params.ce_ie_addr;
275b42b3678SSriram R 	u32 ie1_reg_addr, ie2_reg_addr, ie3_reg_addr;
276b42b3678SSriram R 
277b42b3678SSriram R 	ie1_reg_addr = ce_ie_addr->ie1_reg_addr + ATH11K_CE_OFFSET(ab);
278b42b3678SSriram R 	ie2_reg_addr = ce_ie_addr->ie2_reg_addr + ATH11K_CE_OFFSET(ab);
279b42b3678SSriram R 	ie3_reg_addr = ce_ie_addr->ie3_reg_addr + ATH11K_CE_OFFSET(ab);
280d5c65159SKalle Valo 
281b689f091SAnilkumar Kolli 	ce_attr = &ab->hw_params.host_ce_config[ce_id];
282b689f091SAnilkumar Kolli 	if (ce_attr->src_nentries)
283b42b3678SSriram R 		ath11k_ahb_setbit32(ab, ce_id, ie1_reg_addr);
284d5c65159SKalle Valo 
285b689f091SAnilkumar Kolli 	if (ce_attr->dest_nentries) {
286b42b3678SSriram R 		ath11k_ahb_setbit32(ab, ce_id, ie2_reg_addr);
287d5c65159SKalle Valo 		ath11k_ahb_setbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
288b42b3678SSriram R 				    ie3_reg_addr);
289d5c65159SKalle Valo 	}
290d5c65159SKalle Valo }
291d5c65159SKalle Valo 
ath11k_ahb_ce_irq_disable(struct ath11k_base * ab,u16 ce_id)292d5c65159SKalle Valo static void ath11k_ahb_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
293d5c65159SKalle Valo {
294b689f091SAnilkumar Kolli 	const struct ce_attr *ce_attr;
295b42b3678SSriram R 	const struct ce_ie_addr *ce_ie_addr = ab->hw_params.ce_ie_addr;
296b42b3678SSriram R 	u32 ie1_reg_addr, ie2_reg_addr, ie3_reg_addr;
297b42b3678SSriram R 
298b42b3678SSriram R 	ie1_reg_addr = ce_ie_addr->ie1_reg_addr + ATH11K_CE_OFFSET(ab);
299b42b3678SSriram R 	ie2_reg_addr = ce_ie_addr->ie2_reg_addr + ATH11K_CE_OFFSET(ab);
300b42b3678SSriram R 	ie3_reg_addr = ce_ie_addr->ie3_reg_addr + ATH11K_CE_OFFSET(ab);
301d5c65159SKalle Valo 
302b689f091SAnilkumar Kolli 	ce_attr = &ab->hw_params.host_ce_config[ce_id];
303b689f091SAnilkumar Kolli 	if (ce_attr->src_nentries)
304b42b3678SSriram R 		ath11k_ahb_clearbit32(ab, ce_id, ie1_reg_addr);
305d5c65159SKalle Valo 
306b689f091SAnilkumar Kolli 	if (ce_attr->dest_nentries) {
307b42b3678SSriram R 		ath11k_ahb_clearbit32(ab, ce_id, ie2_reg_addr);
308d5c65159SKalle Valo 		ath11k_ahb_clearbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
309b42b3678SSriram R 				      ie3_reg_addr);
310d5c65159SKalle Valo 	}
311d5c65159SKalle Valo }
312d5c65159SKalle Valo 
ath11k_ahb_sync_ce_irqs(struct ath11k_base * ab)313d5c65159SKalle Valo static void ath11k_ahb_sync_ce_irqs(struct ath11k_base *ab)
314d5c65159SKalle Valo {
315d5c65159SKalle Valo 	int i;
316d5c65159SKalle Valo 	int irq_idx;
317d5c65159SKalle Valo 
318d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
319e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
320d5c65159SKalle Valo 			continue;
321d5c65159SKalle Valo 
322d5c65159SKalle Valo 		irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
323d5c65159SKalle Valo 		synchronize_irq(ab->irq_num[irq_idx]);
324d5c65159SKalle Valo 	}
325d5c65159SKalle Valo }
326d5c65159SKalle Valo 
ath11k_ahb_sync_ext_irqs(struct ath11k_base * ab)327d5c65159SKalle Valo static void ath11k_ahb_sync_ext_irqs(struct ath11k_base *ab)
328d5c65159SKalle Valo {
329d5c65159SKalle Valo 	int i, j;
330d5c65159SKalle Valo 	int irq_idx;
331d5c65159SKalle Valo 
332d5c65159SKalle Valo 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
333d5c65159SKalle Valo 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
334d5c65159SKalle Valo 
335d5c65159SKalle Valo 		for (j = 0; j < irq_grp->num_irq; j++) {
336d5c65159SKalle Valo 			irq_idx = irq_grp->irqs[j];
337d5c65159SKalle Valo 			synchronize_irq(ab->irq_num[irq_idx]);
338d5c65159SKalle Valo 		}
339d5c65159SKalle Valo 	}
340d5c65159SKalle Valo }
341d5c65159SKalle Valo 
ath11k_ahb_ce_irqs_enable(struct ath11k_base * ab)342d5c65159SKalle Valo static void ath11k_ahb_ce_irqs_enable(struct ath11k_base *ab)
343d5c65159SKalle Valo {
344d5c65159SKalle Valo 	int i;
345d5c65159SKalle Valo 
346d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
347e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
348d5c65159SKalle Valo 			continue;
349d5c65159SKalle Valo 		ath11k_ahb_ce_irq_enable(ab, i);
350d5c65159SKalle Valo 	}
351d5c65159SKalle Valo }
352d5c65159SKalle Valo 
ath11k_ahb_ce_irqs_disable(struct ath11k_base * ab)353d5c65159SKalle Valo static void ath11k_ahb_ce_irqs_disable(struct ath11k_base *ab)
354d5c65159SKalle Valo {
355d5c65159SKalle Valo 	int i;
356d5c65159SKalle Valo 
357d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
358e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
359d5c65159SKalle Valo 			continue;
360d5c65159SKalle Valo 		ath11k_ahb_ce_irq_disable(ab, i);
361d5c65159SKalle Valo 	}
362d5c65159SKalle Valo }
363d5c65159SKalle Valo 
ath11k_ahb_start(struct ath11k_base * ab)36431858805SGovind Singh static int ath11k_ahb_start(struct ath11k_base *ab)
365d5c65159SKalle Valo {
366d5c65159SKalle Valo 	ath11k_ahb_ce_irqs_enable(ab);
367d5c65159SKalle Valo 	ath11k_ce_rx_post_buf(ab);
368d5c65159SKalle Valo 
369d5c65159SKalle Valo 	return 0;
370d5c65159SKalle Valo }
371d5c65159SKalle Valo 
ath11k_ahb_ext_irq_enable(struct ath11k_base * ab)37231858805SGovind Singh static void ath11k_ahb_ext_irq_enable(struct ath11k_base *ab)
373d5c65159SKalle Valo {
374d5c65159SKalle Valo 	int i;
375d5c65159SKalle Valo 
376d5c65159SKalle Valo 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
377d5c65159SKalle Valo 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
378d5c65159SKalle Valo 
379d943fdadSBen Greear 		if (!irq_grp->napi_enabled) {
380d5c65159SKalle Valo 			napi_enable(&irq_grp->napi);
381d943fdadSBen Greear 			irq_grp->napi_enabled = true;
382d943fdadSBen Greear 		}
383d5c65159SKalle Valo 		ath11k_ahb_ext_grp_enable(irq_grp);
384d5c65159SKalle Valo 	}
385d5c65159SKalle Valo }
386d5c65159SKalle Valo 
ath11k_ahb_ext_irq_disable(struct ath11k_base * ab)38731858805SGovind Singh static void ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)
388d5c65159SKalle Valo {
389d5c65159SKalle Valo 	__ath11k_ahb_ext_irq_disable(ab);
390d5c65159SKalle Valo 	ath11k_ahb_sync_ext_irqs(ab);
391d5c65159SKalle Valo }
392d5c65159SKalle Valo 
ath11k_ahb_stop(struct ath11k_base * ab)39331858805SGovind Singh static void ath11k_ahb_stop(struct ath11k_base *ab)
394d5c65159SKalle Valo {
395d5c65159SKalle Valo 	if (!test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags))
396d5c65159SKalle Valo 		ath11k_ahb_ce_irqs_disable(ab);
397d5c65159SKalle Valo 	ath11k_ahb_sync_ce_irqs(ab);
398d5c65159SKalle Valo 	ath11k_ahb_kill_tasklets(ab);
399d5c65159SKalle Valo 	del_timer_sync(&ab->rx_replenish_retry);
400d5c65159SKalle Valo 	ath11k_ce_cleanup_pipes(ab);
401d5c65159SKalle Valo }
402d5c65159SKalle Valo 
ath11k_ahb_power_up(struct ath11k_base * ab)40331858805SGovind Singh static int ath11k_ahb_power_up(struct ath11k_base *ab)
404d5c65159SKalle Valo {
405ba929d6fSGovind Singh 	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
406d5c65159SKalle Valo 	int ret;
407d5c65159SKalle Valo 
408ba929d6fSGovind Singh 	ret = rproc_boot(ab_ahb->tgt_rproc);
409d5c65159SKalle Valo 	if (ret)
410d5c65159SKalle Valo 		ath11k_err(ab, "failed to boot the remote processor Q6\n");
411d5c65159SKalle Valo 
412d5c65159SKalle Valo 	return ret;
413d5c65159SKalle Valo }
414d5c65159SKalle Valo 
ath11k_ahb_power_down(struct ath11k_base * ab)41531858805SGovind Singh static void ath11k_ahb_power_down(struct ath11k_base *ab)
416d5c65159SKalle Valo {
417ba929d6fSGovind Singh 	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
418ba929d6fSGovind Singh 
419ba929d6fSGovind Singh 	rproc_shutdown(ab_ahb->tgt_rproc);
420d5c65159SKalle Valo }
421d5c65159SKalle Valo 
ath11k_ahb_init_qmi_ce_config(struct ath11k_base * ab)422d5c65159SKalle Valo static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)
423d5c65159SKalle Valo {
424d5c65159SKalle Valo 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
425d5c65159SKalle Valo 
426967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
427967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
428967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
429967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
43016001e4bSAnilkumar Kolli 	ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
431d5c65159SKalle Valo }
432d5c65159SKalle Valo 
ath11k_ahb_free_ext_irq(struct ath11k_base * ab)433d5c65159SKalle Valo static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab)
434d5c65159SKalle Valo {
435d5c65159SKalle Valo 	int i, j;
436d5c65159SKalle Valo 
437d5c65159SKalle Valo 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
438d5c65159SKalle Valo 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
439d5c65159SKalle Valo 
440d5c65159SKalle Valo 		for (j = 0; j < irq_grp->num_irq; j++)
441d5c65159SKalle Valo 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
44222b59cb9SVenkateswara Naralasetty 
44322b59cb9SVenkateswara Naralasetty 		netif_napi_del(&irq_grp->napi);
444d5c65159SKalle Valo 	}
445d5c65159SKalle Valo }
446d5c65159SKalle Valo 
ath11k_ahb_free_irq(struct ath11k_base * ab)447d5c65159SKalle Valo static void ath11k_ahb_free_irq(struct ath11k_base *ab)
448d5c65159SKalle Valo {
449d5c65159SKalle Valo 	int irq_idx;
450d5c65159SKalle Valo 	int i;
451d5c65159SKalle Valo 
45200402f49SManikanta Pubbisetty 	if (ab->hw_params.hybrid_bus_type)
45300402f49SManikanta Pubbisetty 		return ath11k_pcic_free_irq(ab);
45400402f49SManikanta Pubbisetty 
455d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
456e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
457d5c65159SKalle Valo 			continue;
458d5c65159SKalle Valo 		irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
459d5c65159SKalle Valo 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
460d5c65159SKalle Valo 	}
461d5c65159SKalle Valo 
462d5c65159SKalle Valo 	ath11k_ahb_free_ext_irq(ab);
463d5c65159SKalle Valo }
464d5c65159SKalle Valo 
ath11k_ahb_ce_tasklet(struct tasklet_struct * t)465c08279a9SAllen Pais static void ath11k_ahb_ce_tasklet(struct tasklet_struct *t)
466d5c65159SKalle Valo {
467c08279a9SAllen Pais 	struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
468d5c65159SKalle Valo 
469d5c65159SKalle Valo 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
470d5c65159SKalle Valo 
471d5c65159SKalle Valo 	ath11k_ahb_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
472d5c65159SKalle Valo }
473d5c65159SKalle Valo 
ath11k_ahb_ce_interrupt_handler(int irq,void * arg)474d5c65159SKalle Valo static irqreturn_t ath11k_ahb_ce_interrupt_handler(int irq, void *arg)
475d5c65159SKalle Valo {
476d5c65159SKalle Valo 	struct ath11k_ce_pipe *ce_pipe = arg;
477d5c65159SKalle Valo 
4785118935bSManikanta Pubbisetty 	/* last interrupt received for this CE */
4795118935bSManikanta Pubbisetty 	ce_pipe->timestamp = jiffies;
4805118935bSManikanta Pubbisetty 
481d5c65159SKalle Valo 	ath11k_ahb_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
482d5c65159SKalle Valo 
483d5c65159SKalle Valo 	tasklet_schedule(&ce_pipe->intr_tq);
484d5c65159SKalle Valo 
485d5c65159SKalle Valo 	return IRQ_HANDLED;
486d5c65159SKalle Valo }
487d5c65159SKalle Valo 
ath11k_ahb_ext_grp_napi_poll(struct napi_struct * napi,int budget)488d5c65159SKalle Valo static int ath11k_ahb_ext_grp_napi_poll(struct napi_struct *napi, int budget)
489d5c65159SKalle Valo {
490d5c65159SKalle Valo 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
491d5c65159SKalle Valo 						struct ath11k_ext_irq_grp,
492d5c65159SKalle Valo 						napi);
493d5c65159SKalle Valo 	struct ath11k_base *ab = irq_grp->ab;
494d5c65159SKalle Valo 	int work_done;
495d5c65159SKalle Valo 
496d5c65159SKalle Valo 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
497d5c65159SKalle Valo 	if (work_done < budget) {
498d5c65159SKalle Valo 		napi_complete_done(napi, work_done);
499d5c65159SKalle Valo 		ath11k_ahb_ext_grp_enable(irq_grp);
500d5c65159SKalle Valo 	}
501d5c65159SKalle Valo 
502d5c65159SKalle Valo 	if (work_done > budget)
503d5c65159SKalle Valo 		work_done = budget;
504d5c65159SKalle Valo 
505d5c65159SKalle Valo 	return work_done;
506d5c65159SKalle Valo }
507d5c65159SKalle Valo 
ath11k_ahb_ext_interrupt_handler(int irq,void * arg)508d5c65159SKalle Valo static irqreturn_t ath11k_ahb_ext_interrupt_handler(int irq, void *arg)
509d5c65159SKalle Valo {
510d5c65159SKalle Valo 	struct ath11k_ext_irq_grp *irq_grp = arg;
511d5c65159SKalle Valo 
5125118935bSManikanta Pubbisetty 	/* last interrupt received for this group */
5135118935bSManikanta Pubbisetty 	irq_grp->timestamp = jiffies;
5145118935bSManikanta Pubbisetty 
515d5c65159SKalle Valo 	ath11k_ahb_ext_grp_disable(irq_grp);
516d5c65159SKalle Valo 
517d5c65159SKalle Valo 	napi_schedule(&irq_grp->napi);
518d5c65159SKalle Valo 
519d5c65159SKalle Valo 	return IRQ_HANDLED;
520d5c65159SKalle Valo }
521d5c65159SKalle Valo 
ath11k_ahb_config_ext_irq(struct ath11k_base * ab)522a76ed591SVenkateswara Naralasetty static int ath11k_ahb_config_ext_irq(struct ath11k_base *ab)
523d5c65159SKalle Valo {
524d547ca4cSAnilkumar Kolli 	struct ath11k_hw_params *hw = &ab->hw_params;
525d5c65159SKalle Valo 	int i, j;
526d5c65159SKalle Valo 	int irq;
527d5c65159SKalle Valo 	int ret;
528d5c65159SKalle Valo 
529d5c65159SKalle Valo 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
530d5c65159SKalle Valo 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
531d5c65159SKalle Valo 		u32 num_irq = 0;
532d5c65159SKalle Valo 
533d5c65159SKalle Valo 		irq_grp->ab = ab;
534d5c65159SKalle Valo 		irq_grp->grp_id = i;
535d5c65159SKalle Valo 		init_dummy_netdev(&irq_grp->napi_ndev);
536d5c65159SKalle Valo 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
537b48b89f9SJakub Kicinski 			       ath11k_ahb_ext_grp_napi_poll);
538d5c65159SKalle Valo 
539d5c65159SKalle Valo 		for (j = 0; j < ATH11K_EXT_IRQ_NUM_MAX; j++) {
54034d5a3a8SKalle Valo 			if (ab->hw_params.ring_mask->tx[i] & BIT(j)) {
541d5c65159SKalle Valo 				irq_grp->irqs[num_irq++] =
542d5c65159SKalle Valo 					wbm2host_tx_completions_ring1 - j;
543d5c65159SKalle Valo 			}
544d5c65159SKalle Valo 
54534d5a3a8SKalle Valo 			if (ab->hw_params.ring_mask->rx[i] & BIT(j)) {
546d5c65159SKalle Valo 				irq_grp->irqs[num_irq++] =
547d5c65159SKalle Valo 					reo2host_destination_ring1 - j;
548d5c65159SKalle Valo 			}
549d5c65159SKalle Valo 
55034d5a3a8SKalle Valo 			if (ab->hw_params.ring_mask->rx_err[i] & BIT(j))
551d5c65159SKalle Valo 				irq_grp->irqs[num_irq++] = reo2host_exception;
552d5c65159SKalle Valo 
55334d5a3a8SKalle Valo 			if (ab->hw_params.ring_mask->rx_wbm_rel[i] & BIT(j))
554d5c65159SKalle Valo 				irq_grp->irqs[num_irq++] = wbm2host_rx_release;
555d5c65159SKalle Valo 
55634d5a3a8SKalle Valo 			if (ab->hw_params.ring_mask->reo_status[i] & BIT(j))
557d5c65159SKalle Valo 				irq_grp->irqs[num_irq++] = reo2host_status;
558d5c65159SKalle Valo 
559d547ca4cSAnilkumar Kolli 			if (j < ab->hw_params.max_radios) {
56034d5a3a8SKalle Valo 				if (ab->hw_params.ring_mask->rxdma2host[i] & BIT(j)) {
561d5c65159SKalle Valo 					irq_grp->irqs[num_irq++] =
562d547ca4cSAnilkumar Kolli 						rxdma2host_destination_ring_mac1 -
563d547ca4cSAnilkumar Kolli 						ath11k_hw_get_mac_from_pdev_id(hw, j);
564d5c65159SKalle Valo 				}
565d5c65159SKalle Valo 
56634d5a3a8SKalle Valo 				if (ab->hw_params.ring_mask->host2rxdma[i] & BIT(j)) {
567d5c65159SKalle Valo 					irq_grp->irqs[num_irq++] =
568d547ca4cSAnilkumar Kolli 						host2rxdma_host_buf_ring_mac1 -
569d547ca4cSAnilkumar Kolli 						ath11k_hw_get_mac_from_pdev_id(hw, j);
570d5c65159SKalle Valo 				}
571d5c65159SKalle Valo 
57234d5a3a8SKalle Valo 				if (ab->hw_params.ring_mask->rx_mon_status[i] & BIT(j)) {
573d5c65159SKalle Valo 					irq_grp->irqs[num_irq++] =
574d5c65159SKalle Valo 						ppdu_end_interrupts_mac1 -
575d547ca4cSAnilkumar Kolli 						ath11k_hw_get_mac_from_pdev_id(hw, j);
576d5c65159SKalle Valo 					irq_grp->irqs[num_irq++] =
577d5c65159SKalle Valo 						rxdma2host_monitor_status_ring_mac1 -
578d547ca4cSAnilkumar Kolli 						ath11k_hw_get_mac_from_pdev_id(hw, j);
579d5c65159SKalle Valo 				}
580d5c65159SKalle Valo 			}
581d5c65159SKalle Valo 		}
582d5c65159SKalle Valo 		irq_grp->num_irq = num_irq;
583d5c65159SKalle Valo 
584d5c65159SKalle Valo 		for (j = 0; j < irq_grp->num_irq; j++) {
585d5c65159SKalle Valo 			int irq_idx = irq_grp->irqs[j];
586d5c65159SKalle Valo 
587d5c65159SKalle Valo 			irq = platform_get_irq_byname(ab->pdev,
588d5c65159SKalle Valo 						      irq_name[irq_idx]);
589d5c65159SKalle Valo 			ab->irq_num[irq_idx] = irq;
59005090864SManikanta Pubbisetty 			irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_DISABLE_UNLAZY);
591d5c65159SKalle Valo 			ret = request_irq(irq, ath11k_ahb_ext_interrupt_handler,
592d5c65159SKalle Valo 					  IRQF_TRIGGER_RISING,
593d5c65159SKalle Valo 					  irq_name[irq_idx], irq_grp);
594d5c65159SKalle Valo 			if (ret) {
595d5c65159SKalle Valo 				ath11k_err(ab, "failed request_irq for %d\n",
596d5c65159SKalle Valo 					   irq);
597d5c65159SKalle Valo 			}
598d5c65159SKalle Valo 		}
599d5c65159SKalle Valo 	}
600d5c65159SKalle Valo 
601d5c65159SKalle Valo 	return 0;
602d5c65159SKalle Valo }
603d5c65159SKalle Valo 
ath11k_ahb_config_irq(struct ath11k_base * ab)604d5c65159SKalle Valo static int ath11k_ahb_config_irq(struct ath11k_base *ab)
605d5c65159SKalle Valo {
606d5c65159SKalle Valo 	int irq, irq_idx, i;
607d5c65159SKalle Valo 	int ret;
608d5c65159SKalle Valo 
60900402f49SManikanta Pubbisetty 	if (ab->hw_params.hybrid_bus_type)
61000402f49SManikanta Pubbisetty 		return ath11k_pcic_config_irq(ab);
61100402f49SManikanta Pubbisetty 
612d5c65159SKalle Valo 	/* Configure CE irqs */
613d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
614d5c65159SKalle Valo 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
615d5c65159SKalle Valo 
616e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
617d5c65159SKalle Valo 			continue;
618d5c65159SKalle Valo 
619d5c65159SKalle Valo 		irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
620d5c65159SKalle Valo 
621c08279a9SAllen Pais 		tasklet_setup(&ce_pipe->intr_tq, ath11k_ahb_ce_tasklet);
622d5c65159SKalle Valo 		irq = platform_get_irq_byname(ab->pdev, irq_name[irq_idx]);
623d5c65159SKalle Valo 		ret = request_irq(irq, ath11k_ahb_ce_interrupt_handler,
624d5c65159SKalle Valo 				  IRQF_TRIGGER_RISING, irq_name[irq_idx],
625d5c65159SKalle Valo 				  ce_pipe);
626d5c65159SKalle Valo 		if (ret)
627d5c65159SKalle Valo 			return ret;
628d5c65159SKalle Valo 
629d5c65159SKalle Valo 		ab->irq_num[irq_idx] = irq;
630d5c65159SKalle Valo 	}
631d5c65159SKalle Valo 
632d5c65159SKalle Valo 	/* Configure external interrupts */
633a76ed591SVenkateswara Naralasetty 	ret = ath11k_ahb_config_ext_irq(ab);
634d5c65159SKalle Valo 
635d5c65159SKalle Valo 	return ret;
636d5c65159SKalle Valo }
637d5c65159SKalle Valo 
ath11k_ahb_map_service_to_pipe(struct ath11k_base * ab,u16 service_id,u8 * ul_pipe,u8 * dl_pipe)63831858805SGovind Singh static int ath11k_ahb_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
639d5c65159SKalle Valo 					  u8 *ul_pipe, u8 *dl_pipe)
640d5c65159SKalle Valo {
641d5c65159SKalle Valo 	const struct service_to_pipe *entry;
642d5c65159SKalle Valo 	bool ul_set = false, dl_set = false;
643d5c65159SKalle Valo 	int i;
644d5c65159SKalle Valo 
645967c1d11SAnilkumar Kolli 	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
646967c1d11SAnilkumar Kolli 		entry = &ab->hw_params.svc_to_ce_map[i];
647d5c65159SKalle Valo 
648d5c65159SKalle Valo 		if (__le32_to_cpu(entry->service_id) != service_id)
649d5c65159SKalle Valo 			continue;
650d5c65159SKalle Valo 
651d5c65159SKalle Valo 		switch (__le32_to_cpu(entry->pipedir)) {
652d5c65159SKalle Valo 		case PIPEDIR_NONE:
653d5c65159SKalle Valo 			break;
654d5c65159SKalle Valo 		case PIPEDIR_IN:
655d5c65159SKalle Valo 			WARN_ON(dl_set);
656d5c65159SKalle Valo 			*dl_pipe = __le32_to_cpu(entry->pipenum);
657d5c65159SKalle Valo 			dl_set = true;
658d5c65159SKalle Valo 			break;
659d5c65159SKalle Valo 		case PIPEDIR_OUT:
660d5c65159SKalle Valo 			WARN_ON(ul_set);
661d5c65159SKalle Valo 			*ul_pipe = __le32_to_cpu(entry->pipenum);
662d5c65159SKalle Valo 			ul_set = true;
663d5c65159SKalle Valo 			break;
664d5c65159SKalle Valo 		case PIPEDIR_INOUT:
665d5c65159SKalle Valo 			WARN_ON(dl_set);
666d5c65159SKalle Valo 			WARN_ON(ul_set);
667d5c65159SKalle Valo 			*dl_pipe = __le32_to_cpu(entry->pipenum);
668d5c65159SKalle Valo 			*ul_pipe = __le32_to_cpu(entry->pipenum);
669d5c65159SKalle Valo 			dl_set = true;
670d5c65159SKalle Valo 			ul_set = true;
671d5c65159SKalle Valo 			break;
672d5c65159SKalle Valo 		}
673d5c65159SKalle Valo 	}
674d5c65159SKalle Valo 
675d5c65159SKalle Valo 	if (WARN_ON(!ul_set || !dl_set))
676d5c65159SKalle Valo 		return -ENOENT;
677d5c65159SKalle Valo 
678d5c65159SKalle Valo 	return 0;
679d5c65159SKalle Valo }
680d5c65159SKalle Valo 
ath11k_ahb_hif_suspend(struct ath11k_base * ab)68169ccee61SManikanta Pubbisetty static int ath11k_ahb_hif_suspend(struct ath11k_base *ab)
68269ccee61SManikanta Pubbisetty {
68369ccee61SManikanta Pubbisetty 	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
68469ccee61SManikanta Pubbisetty 	u32 wake_irq;
68569ccee61SManikanta Pubbisetty 	u32 value = 0;
68669ccee61SManikanta Pubbisetty 	int ret;
68769ccee61SManikanta Pubbisetty 
68869ccee61SManikanta Pubbisetty 	if (!device_may_wakeup(ab->dev))
68969ccee61SManikanta Pubbisetty 		return -EPERM;
69069ccee61SManikanta Pubbisetty 
69169ccee61SManikanta Pubbisetty 	wake_irq = ab->irq_num[ATH11K_PCI_IRQ_CE0_OFFSET + ATH11K_PCI_CE_WAKE_IRQ];
69269ccee61SManikanta Pubbisetty 
69369ccee61SManikanta Pubbisetty 	ret = enable_irq_wake(wake_irq);
69469ccee61SManikanta Pubbisetty 	if (ret) {
69569ccee61SManikanta Pubbisetty 		ath11k_err(ab, "failed to enable wakeup irq :%d\n", ret);
69669ccee61SManikanta Pubbisetty 		return ret;
69769ccee61SManikanta Pubbisetty 	}
69869ccee61SManikanta Pubbisetty 
69969ccee61SManikanta Pubbisetty 	value = u32_encode_bits(ab_ahb->smp2p_info.seq_no++,
70069ccee61SManikanta Pubbisetty 				ATH11K_AHB_SMP2P_SMEM_SEQ_NO);
70169ccee61SManikanta Pubbisetty 	value |= u32_encode_bits(ATH11K_AHB_POWER_SAVE_ENTER,
70269ccee61SManikanta Pubbisetty 				 ATH11K_AHB_SMP2P_SMEM_MSG);
70369ccee61SManikanta Pubbisetty 
70469ccee61SManikanta Pubbisetty 	ret = qcom_smem_state_update_bits(ab_ahb->smp2p_info.smem_state,
70569ccee61SManikanta Pubbisetty 					  ATH11K_AHB_SMP2P_SMEM_VALUE_MASK, value);
70669ccee61SManikanta Pubbisetty 	if (ret) {
70769ccee61SManikanta Pubbisetty 		ath11k_err(ab, "failed to send smp2p power save enter cmd :%d\n", ret);
70869ccee61SManikanta Pubbisetty 		return ret;
70969ccee61SManikanta Pubbisetty 	}
71069ccee61SManikanta Pubbisetty 
711fc3b984aSKalle Valo 	ath11k_dbg(ab, ATH11K_DBG_AHB, "device suspended\n");
71269ccee61SManikanta Pubbisetty 
71369ccee61SManikanta Pubbisetty 	return ret;
71469ccee61SManikanta Pubbisetty }
71569ccee61SManikanta Pubbisetty 
ath11k_ahb_hif_resume(struct ath11k_base * ab)71669ccee61SManikanta Pubbisetty static int ath11k_ahb_hif_resume(struct ath11k_base *ab)
71769ccee61SManikanta Pubbisetty {
71869ccee61SManikanta Pubbisetty 	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
71969ccee61SManikanta Pubbisetty 	u32 wake_irq;
72069ccee61SManikanta Pubbisetty 	u32 value = 0;
72169ccee61SManikanta Pubbisetty 	int ret;
72269ccee61SManikanta Pubbisetty 
72369ccee61SManikanta Pubbisetty 	if (!device_may_wakeup(ab->dev))
72469ccee61SManikanta Pubbisetty 		return -EPERM;
72569ccee61SManikanta Pubbisetty 
72669ccee61SManikanta Pubbisetty 	wake_irq = ab->irq_num[ATH11K_PCI_IRQ_CE0_OFFSET + ATH11K_PCI_CE_WAKE_IRQ];
72769ccee61SManikanta Pubbisetty 
72869ccee61SManikanta Pubbisetty 	ret = disable_irq_wake(wake_irq);
72969ccee61SManikanta Pubbisetty 	if (ret) {
73069ccee61SManikanta Pubbisetty 		ath11k_err(ab, "failed to disable wakeup irq: %d\n", ret);
73169ccee61SManikanta Pubbisetty 		return ret;
73269ccee61SManikanta Pubbisetty 	}
73369ccee61SManikanta Pubbisetty 
73469ccee61SManikanta Pubbisetty 	reinit_completion(&ab->wow.wakeup_completed);
73569ccee61SManikanta Pubbisetty 
73669ccee61SManikanta Pubbisetty 	value = u32_encode_bits(ab_ahb->smp2p_info.seq_no++,
73769ccee61SManikanta Pubbisetty 				ATH11K_AHB_SMP2P_SMEM_SEQ_NO);
73869ccee61SManikanta Pubbisetty 	value |= u32_encode_bits(ATH11K_AHB_POWER_SAVE_EXIT,
73969ccee61SManikanta Pubbisetty 				 ATH11K_AHB_SMP2P_SMEM_MSG);
74069ccee61SManikanta Pubbisetty 
74169ccee61SManikanta Pubbisetty 	ret = qcom_smem_state_update_bits(ab_ahb->smp2p_info.smem_state,
74269ccee61SManikanta Pubbisetty 					  ATH11K_AHB_SMP2P_SMEM_VALUE_MASK, value);
74369ccee61SManikanta Pubbisetty 	if (ret) {
74469ccee61SManikanta Pubbisetty 		ath11k_err(ab, "failed to send smp2p power save enter cmd :%d\n", ret);
74569ccee61SManikanta Pubbisetty 		return ret;
74669ccee61SManikanta Pubbisetty 	}
74769ccee61SManikanta Pubbisetty 
74869ccee61SManikanta Pubbisetty 	ret = wait_for_completion_timeout(&ab->wow.wakeup_completed, 3 * HZ);
74969ccee61SManikanta Pubbisetty 	if (ret == 0) {
75069ccee61SManikanta Pubbisetty 		ath11k_warn(ab, "timed out while waiting for wow wakeup completion\n");
75169ccee61SManikanta Pubbisetty 		return -ETIMEDOUT;
75269ccee61SManikanta Pubbisetty 	}
75369ccee61SManikanta Pubbisetty 
754fc3b984aSKalle Valo 	ath11k_dbg(ab, ATH11K_DBG_AHB, "device resumed\n");
75569ccee61SManikanta Pubbisetty 
75669ccee61SManikanta Pubbisetty 	return 0;
75769ccee61SManikanta Pubbisetty }
75869ccee61SManikanta Pubbisetty 
75900402f49SManikanta Pubbisetty static const struct ath11k_hif_ops ath11k_ahb_hif_ops_ipq8074 = {
76031858805SGovind Singh 	.start = ath11k_ahb_start,
76131858805SGovind Singh 	.stop = ath11k_ahb_stop,
76231858805SGovind Singh 	.read32 = ath11k_ahb_read32,
76331858805SGovind Singh 	.write32 = ath11k_ahb_write32,
764876eb848SBaochen Qiang 	.read = NULL,
76531858805SGovind Singh 	.irq_enable = ath11k_ahb_ext_irq_enable,
76631858805SGovind Singh 	.irq_disable = ath11k_ahb_ext_irq_disable,
76731858805SGovind Singh 	.map_service_to_pipe = ath11k_ahb_map_service_to_pipe,
76831858805SGovind Singh 	.power_down = ath11k_ahb_power_down,
76931858805SGovind Singh 	.power_up = ath11k_ahb_power_up,
77031858805SGovind Singh };
77131858805SGovind Singh 
77200402f49SManikanta Pubbisetty static const struct ath11k_hif_ops ath11k_ahb_hif_ops_wcn6750 = {
77300402f49SManikanta Pubbisetty 	.start = ath11k_pcic_start,
77400402f49SManikanta Pubbisetty 	.stop = ath11k_pcic_stop,
77500402f49SManikanta Pubbisetty 	.read32 = ath11k_pcic_read32,
77600402f49SManikanta Pubbisetty 	.write32 = ath11k_pcic_write32,
777876eb848SBaochen Qiang 	.read = NULL,
77800402f49SManikanta Pubbisetty 	.irq_enable = ath11k_pcic_ext_irq_enable,
77900402f49SManikanta Pubbisetty 	.irq_disable = ath11k_pcic_ext_irq_disable,
78000402f49SManikanta Pubbisetty 	.get_msi_address =  ath11k_pcic_get_msi_address,
78100402f49SManikanta Pubbisetty 	.get_user_msi_vector = ath11k_pcic_get_user_msi_assignment,
78200402f49SManikanta Pubbisetty 	.map_service_to_pipe = ath11k_pcic_map_service_to_pipe,
78300402f49SManikanta Pubbisetty 	.power_down = ath11k_ahb_power_down,
78400402f49SManikanta Pubbisetty 	.power_up = ath11k_ahb_power_up,
78569ccee61SManikanta Pubbisetty 	.suspend = ath11k_ahb_hif_suspend,
78669ccee61SManikanta Pubbisetty 	.resume = ath11k_ahb_hif_resume,
78769ccee61SManikanta Pubbisetty 	.ce_irq_enable = ath11k_pci_enable_ce_irqs_except_wake_irq,
78869ccee61SManikanta Pubbisetty 	.ce_irq_disable = ath11k_pci_disable_ce_irqs_except_wake_irq,
78900402f49SManikanta Pubbisetty };
79000402f49SManikanta Pubbisetty 
ath11k_core_get_rproc(struct ath11k_base * ab)791ba929d6fSGovind Singh static int ath11k_core_get_rproc(struct ath11k_base *ab)
792ba929d6fSGovind Singh {
793ba929d6fSGovind Singh 	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
794ba929d6fSGovind Singh 	struct device *dev = ab->dev;
795ba929d6fSGovind Singh 	struct rproc *prproc;
796ba929d6fSGovind Singh 	phandle rproc_phandle;
797ba929d6fSGovind Singh 
798ba929d6fSGovind Singh 	if (of_property_read_u32(dev->of_node, "qcom,rproc", &rproc_phandle)) {
799ba929d6fSGovind Singh 		ath11k_err(ab, "failed to get q6_rproc handle\n");
800ba929d6fSGovind Singh 		return -ENOENT;
801ba929d6fSGovind Singh 	}
802ba929d6fSGovind Singh 
803ba929d6fSGovind Singh 	prproc = rproc_get_by_phandle(rproc_phandle);
804ba929d6fSGovind Singh 	if (!prproc) {
805*e9327c72SLuca Weiss 		ath11k_dbg(ab, ATH11K_DBG_AHB, "failed to get rproc, deferring\n");
806*e9327c72SLuca Weiss 		return -EPROBE_DEFER;
807ba929d6fSGovind Singh 	}
808ba929d6fSGovind Singh 	ab_ahb->tgt_rproc = prproc;
809ba929d6fSGovind Singh 
810ba929d6fSGovind Singh 	return 0;
811ba929d6fSGovind Singh }
812ba929d6fSGovind Singh 
ath11k_ahb_setup_msi_resources(struct ath11k_base * ab)81300402f49SManikanta Pubbisetty static int ath11k_ahb_setup_msi_resources(struct ath11k_base *ab)
81400402f49SManikanta Pubbisetty {
81500402f49SManikanta Pubbisetty 	struct platform_device *pdev = ab->pdev;
81600402f49SManikanta Pubbisetty 	phys_addr_t msi_addr_pa;
81700402f49SManikanta Pubbisetty 	dma_addr_t msi_addr_iova;
81800402f49SManikanta Pubbisetty 	struct resource *res;
81900402f49SManikanta Pubbisetty 	int int_prop;
82000402f49SManikanta Pubbisetty 	int ret;
82100402f49SManikanta Pubbisetty 	int i;
82200402f49SManikanta Pubbisetty 
82300402f49SManikanta Pubbisetty 	ret = ath11k_pcic_init_msi_config(ab);
82400402f49SManikanta Pubbisetty 	if (ret) {
82500402f49SManikanta Pubbisetty 		ath11k_err(ab, "failed to init msi config: %d\n", ret);
82600402f49SManikanta Pubbisetty 		return ret;
82700402f49SManikanta Pubbisetty 	}
82800402f49SManikanta Pubbisetty 
82900402f49SManikanta Pubbisetty 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
83000402f49SManikanta Pubbisetty 	if (!res) {
83100402f49SManikanta Pubbisetty 		ath11k_err(ab, "failed to fetch msi_addr\n");
83200402f49SManikanta Pubbisetty 		return -ENOENT;
83300402f49SManikanta Pubbisetty 	}
83400402f49SManikanta Pubbisetty 
83500402f49SManikanta Pubbisetty 	msi_addr_pa = res->start;
83600402f49SManikanta Pubbisetty 	msi_addr_iova = dma_map_resource(ab->dev, msi_addr_pa, PAGE_SIZE,
83700402f49SManikanta Pubbisetty 					 DMA_FROM_DEVICE, 0);
83800402f49SManikanta Pubbisetty 	if (dma_mapping_error(ab->dev, msi_addr_iova))
83900402f49SManikanta Pubbisetty 		return -ENOMEM;
84000402f49SManikanta Pubbisetty 
84100402f49SManikanta Pubbisetty 	ab->pci.msi.addr_lo = lower_32_bits(msi_addr_iova);
84200402f49SManikanta Pubbisetty 	ab->pci.msi.addr_hi = upper_32_bits(msi_addr_iova);
84300402f49SManikanta Pubbisetty 
84400402f49SManikanta Pubbisetty 	ret = of_property_read_u32_index(ab->dev->of_node, "interrupts", 1, &int_prop);
84500402f49SManikanta Pubbisetty 	if (ret)
84600402f49SManikanta Pubbisetty 		return ret;
84700402f49SManikanta Pubbisetty 
84800402f49SManikanta Pubbisetty 	ab->pci.msi.ep_base_data = int_prop + 32;
84900402f49SManikanta Pubbisetty 
85000402f49SManikanta Pubbisetty 	for (i = 0; i < ab->pci.msi.config->total_vectors; i++) {
851f1172766SDouglas Anderson 		ret = platform_get_irq(pdev, i);
852f1172766SDouglas Anderson 		if (ret < 0)
853f1172766SDouglas Anderson 			return ret;
85400402f49SManikanta Pubbisetty 
855f1172766SDouglas Anderson 		ab->pci.msi.irqs[i] = ret;
85600402f49SManikanta Pubbisetty 	}
85700402f49SManikanta Pubbisetty 
85800402f49SManikanta Pubbisetty 	set_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags);
85900402f49SManikanta Pubbisetty 
86000402f49SManikanta Pubbisetty 	return 0;
86100402f49SManikanta Pubbisetty }
86200402f49SManikanta Pubbisetty 
ath11k_ahb_setup_smp2p_handle(struct ath11k_base * ab)86369ccee61SManikanta Pubbisetty static int ath11k_ahb_setup_smp2p_handle(struct ath11k_base *ab)
86469ccee61SManikanta Pubbisetty {
86569ccee61SManikanta Pubbisetty 	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
86669ccee61SManikanta Pubbisetty 
86769ccee61SManikanta Pubbisetty 	if (!ab->hw_params.smp2p_wow_exit)
86869ccee61SManikanta Pubbisetty 		return 0;
86969ccee61SManikanta Pubbisetty 
87069ccee61SManikanta Pubbisetty 	ab_ahb->smp2p_info.smem_state = qcom_smem_state_get(ab->dev, "wlan-smp2p-out",
87169ccee61SManikanta Pubbisetty 							    &ab_ahb->smp2p_info.smem_bit);
87269ccee61SManikanta Pubbisetty 	if (IS_ERR(ab_ahb->smp2p_info.smem_state)) {
87369ccee61SManikanta Pubbisetty 		ath11k_err(ab, "failed to fetch smem state: %ld\n",
87469ccee61SManikanta Pubbisetty 			   PTR_ERR(ab_ahb->smp2p_info.smem_state));
87569ccee61SManikanta Pubbisetty 		return PTR_ERR(ab_ahb->smp2p_info.smem_state);
87669ccee61SManikanta Pubbisetty 	}
87769ccee61SManikanta Pubbisetty 
87869ccee61SManikanta Pubbisetty 	return 0;
87969ccee61SManikanta Pubbisetty }
88069ccee61SManikanta Pubbisetty 
ath11k_ahb_release_smp2p_handle(struct ath11k_base * ab)88169ccee61SManikanta Pubbisetty static void ath11k_ahb_release_smp2p_handle(struct ath11k_base *ab)
88269ccee61SManikanta Pubbisetty {
88369ccee61SManikanta Pubbisetty 	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
88469ccee61SManikanta Pubbisetty 
88569ccee61SManikanta Pubbisetty 	if (!ab->hw_params.smp2p_wow_exit)
88669ccee61SManikanta Pubbisetty 		return;
88769ccee61SManikanta Pubbisetty 
88869ccee61SManikanta Pubbisetty 	qcom_smem_state_put(ab_ahb->smp2p_info.smem_state);
88969ccee61SManikanta Pubbisetty }
89069ccee61SManikanta Pubbisetty 
ath11k_ahb_setup_resources(struct ath11k_base * ab)89100402f49SManikanta Pubbisetty static int ath11k_ahb_setup_resources(struct ath11k_base *ab)
89200402f49SManikanta Pubbisetty {
89300402f49SManikanta Pubbisetty 	struct platform_device *pdev = ab->pdev;
89400402f49SManikanta Pubbisetty 	struct resource *mem_res;
89500402f49SManikanta Pubbisetty 	void __iomem *mem;
89600402f49SManikanta Pubbisetty 
89700402f49SManikanta Pubbisetty 	if (ab->hw_params.hybrid_bus_type)
89800402f49SManikanta Pubbisetty 		return ath11k_ahb_setup_msi_resources(ab);
89900402f49SManikanta Pubbisetty 
90000402f49SManikanta Pubbisetty 	mem = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res);
90100402f49SManikanta Pubbisetty 	if (IS_ERR(mem)) {
90200402f49SManikanta Pubbisetty 		dev_err(&pdev->dev, "ioremap error\n");
90300402f49SManikanta Pubbisetty 		return PTR_ERR(mem);
90400402f49SManikanta Pubbisetty 	}
90500402f49SManikanta Pubbisetty 
90600402f49SManikanta Pubbisetty 	ab->mem = mem;
90700402f49SManikanta Pubbisetty 	ab->mem_len = resource_size(mem_res);
90800402f49SManikanta Pubbisetty 
90900402f49SManikanta Pubbisetty 	return 0;
91000402f49SManikanta Pubbisetty }
91100402f49SManikanta Pubbisetty 
ath11k_ahb_setup_msa_resources(struct ath11k_base * ab)912f9eec494SManikanta Pubbisetty static int ath11k_ahb_setup_msa_resources(struct ath11k_base *ab)
913f9eec494SManikanta Pubbisetty {
914f9eec494SManikanta Pubbisetty 	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
915f9eec494SManikanta Pubbisetty 	struct device *dev = ab->dev;
916f9eec494SManikanta Pubbisetty 	struct device_node *node;
917f9eec494SManikanta Pubbisetty 	struct resource r;
918f9eec494SManikanta Pubbisetty 	int ret;
919f9eec494SManikanta Pubbisetty 
920f9eec494SManikanta Pubbisetty 	node = of_parse_phandle(dev->of_node, "memory-region", 0);
921f9eec494SManikanta Pubbisetty 	if (!node)
922f9eec494SManikanta Pubbisetty 		return -ENOENT;
923f9eec494SManikanta Pubbisetty 
924f9eec494SManikanta Pubbisetty 	ret = of_address_to_resource(node, 0, &r);
925f9eec494SManikanta Pubbisetty 	of_node_put(node);
926f9eec494SManikanta Pubbisetty 	if (ret) {
927f9eec494SManikanta Pubbisetty 		dev_err(dev, "failed to resolve msa fixed region\n");
928f9eec494SManikanta Pubbisetty 		return ret;
929f9eec494SManikanta Pubbisetty 	}
930f9eec494SManikanta Pubbisetty 
931f9eec494SManikanta Pubbisetty 	ab_ahb->fw.msa_paddr = r.start;
932f9eec494SManikanta Pubbisetty 	ab_ahb->fw.msa_size = resource_size(&r);
933f9eec494SManikanta Pubbisetty 
934f9eec494SManikanta Pubbisetty 	node = of_parse_phandle(dev->of_node, "memory-region", 1);
935f9eec494SManikanta Pubbisetty 	if (!node)
936f9eec494SManikanta Pubbisetty 		return -ENOENT;
937f9eec494SManikanta Pubbisetty 
938f9eec494SManikanta Pubbisetty 	ret = of_address_to_resource(node, 0, &r);
939f9eec494SManikanta Pubbisetty 	of_node_put(node);
940f9eec494SManikanta Pubbisetty 	if (ret) {
941f9eec494SManikanta Pubbisetty 		dev_err(dev, "failed to resolve ce fixed region\n");
942f9eec494SManikanta Pubbisetty 		return ret;
943f9eec494SManikanta Pubbisetty 	}
944f9eec494SManikanta Pubbisetty 
945f9eec494SManikanta Pubbisetty 	ab_ahb->fw.ce_paddr = r.start;
946f9eec494SManikanta Pubbisetty 	ab_ahb->fw.ce_size = resource_size(&r);
947f9eec494SManikanta Pubbisetty 
948f9eec494SManikanta Pubbisetty 	return 0;
949f9eec494SManikanta Pubbisetty }
950f9eec494SManikanta Pubbisetty 
ath11k_ahb_fw_resources_init(struct ath11k_base * ab)951f9eec494SManikanta Pubbisetty static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab)
952f9eec494SManikanta Pubbisetty {
953f9eec494SManikanta Pubbisetty 	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
954f9eec494SManikanta Pubbisetty 	struct device *host_dev = ab->dev;
955f9eec494SManikanta Pubbisetty 	struct platform_device_info info = {0};
956f9eec494SManikanta Pubbisetty 	struct iommu_domain *iommu_dom;
957f9eec494SManikanta Pubbisetty 	struct platform_device *pdev;
958f9eec494SManikanta Pubbisetty 	struct device_node *node;
959f9eec494SManikanta Pubbisetty 	int ret;
960f9eec494SManikanta Pubbisetty 
961f9eec494SManikanta Pubbisetty 	/* Chipsets not requiring MSA need not initialize
962f9eec494SManikanta Pubbisetty 	 * MSA resources, return success in such cases.
963f9eec494SManikanta Pubbisetty 	 */
964f9eec494SManikanta Pubbisetty 	if (!ab->hw_params.fixed_fw_mem)
965f9eec494SManikanta Pubbisetty 		return 0;
966f9eec494SManikanta Pubbisetty 
967f9eec494SManikanta Pubbisetty 	ret = ath11k_ahb_setup_msa_resources(ab);
968f9eec494SManikanta Pubbisetty 	if (ret) {
969f9eec494SManikanta Pubbisetty 		ath11k_err(ab, "failed to setup msa resources\n");
970f9eec494SManikanta Pubbisetty 		return ret;
971f9eec494SManikanta Pubbisetty 	}
972f9eec494SManikanta Pubbisetty 
973f9eec494SManikanta Pubbisetty 	node = of_get_child_by_name(host_dev->of_node, "wifi-firmware");
974f9eec494SManikanta Pubbisetty 	if (!node) {
975f9eec494SManikanta Pubbisetty 		ab_ahb->fw.use_tz = true;
976f9eec494SManikanta Pubbisetty 		return 0;
977f9eec494SManikanta Pubbisetty 	}
978f9eec494SManikanta Pubbisetty 
979f9eec494SManikanta Pubbisetty 	info.fwnode = &node->fwnode;
980f9eec494SManikanta Pubbisetty 	info.parent = host_dev;
981f9eec494SManikanta Pubbisetty 	info.name = node->name;
982f9eec494SManikanta Pubbisetty 	info.dma_mask = DMA_BIT_MASK(32);
983f9eec494SManikanta Pubbisetty 
984f9eec494SManikanta Pubbisetty 	pdev = platform_device_register_full(&info);
985f9eec494SManikanta Pubbisetty 	if (IS_ERR(pdev)) {
986f9eec494SManikanta Pubbisetty 		of_node_put(node);
987f9eec494SManikanta Pubbisetty 		return PTR_ERR(pdev);
988f9eec494SManikanta Pubbisetty 	}
989f9eec494SManikanta Pubbisetty 
990f9eec494SManikanta Pubbisetty 	ret = of_dma_configure(&pdev->dev, node, true);
991f9eec494SManikanta Pubbisetty 	if (ret) {
992f9eec494SManikanta Pubbisetty 		ath11k_err(ab, "dma configure fail: %d\n", ret);
993f9eec494SManikanta Pubbisetty 		goto err_unregister;
994f9eec494SManikanta Pubbisetty 	}
995f9eec494SManikanta Pubbisetty 
996f9eec494SManikanta Pubbisetty 	ab_ahb->fw.dev = &pdev->dev;
997f9eec494SManikanta Pubbisetty 
998f9eec494SManikanta Pubbisetty 	iommu_dom = iommu_domain_alloc(&platform_bus_type);
999f9eec494SManikanta Pubbisetty 	if (!iommu_dom) {
1000f9eec494SManikanta Pubbisetty 		ath11k_err(ab, "failed to allocate iommu domain\n");
1001f9eec494SManikanta Pubbisetty 		ret = -ENOMEM;
1002f9eec494SManikanta Pubbisetty 		goto err_unregister;
1003f9eec494SManikanta Pubbisetty 	}
1004f9eec494SManikanta Pubbisetty 
1005f9eec494SManikanta Pubbisetty 	ret = iommu_attach_device(iommu_dom, ab_ahb->fw.dev);
1006f9eec494SManikanta Pubbisetty 	if (ret) {
1007f9eec494SManikanta Pubbisetty 		ath11k_err(ab, "could not attach device: %d\n", ret);
1008f9eec494SManikanta Pubbisetty 		goto err_iommu_free;
1009f9eec494SManikanta Pubbisetty 	}
1010f9eec494SManikanta Pubbisetty 
1011f9eec494SManikanta Pubbisetty 	ret = iommu_map(iommu_dom, ab_ahb->fw.msa_paddr,
1012f9eec494SManikanta Pubbisetty 			ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size,
10131369459bSJason Gunthorpe 			IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);
1014f9eec494SManikanta Pubbisetty 	if (ret) {
1015f9eec494SManikanta Pubbisetty 		ath11k_err(ab, "failed to map firmware region: %d\n", ret);
1016f9eec494SManikanta Pubbisetty 		goto err_iommu_detach;
1017f9eec494SManikanta Pubbisetty 	}
1018f9eec494SManikanta Pubbisetty 
1019f9eec494SManikanta Pubbisetty 	ret = iommu_map(iommu_dom, ab_ahb->fw.ce_paddr,
1020f9eec494SManikanta Pubbisetty 			ab_ahb->fw.ce_paddr, ab_ahb->fw.ce_size,
10211369459bSJason Gunthorpe 			IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);
1022f9eec494SManikanta Pubbisetty 	if (ret) {
1023f9eec494SManikanta Pubbisetty 		ath11k_err(ab, "failed to map firmware CE region: %d\n", ret);
1024f9eec494SManikanta Pubbisetty 		goto err_iommu_unmap;
1025f9eec494SManikanta Pubbisetty 	}
1026f9eec494SManikanta Pubbisetty 
1027f9eec494SManikanta Pubbisetty 	ab_ahb->fw.use_tz = false;
1028f9eec494SManikanta Pubbisetty 	ab_ahb->fw.iommu_domain = iommu_dom;
1029f9eec494SManikanta Pubbisetty 	of_node_put(node);
1030f9eec494SManikanta Pubbisetty 
1031f9eec494SManikanta Pubbisetty 	return 0;
1032f9eec494SManikanta Pubbisetty 
1033f9eec494SManikanta Pubbisetty err_iommu_unmap:
1034f9eec494SManikanta Pubbisetty 	iommu_unmap(iommu_dom, ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size);
1035f9eec494SManikanta Pubbisetty 
1036f9eec494SManikanta Pubbisetty err_iommu_detach:
1037f9eec494SManikanta Pubbisetty 	iommu_detach_device(iommu_dom, ab_ahb->fw.dev);
1038f9eec494SManikanta Pubbisetty 
1039f9eec494SManikanta Pubbisetty err_iommu_free:
1040f9eec494SManikanta Pubbisetty 	iommu_domain_free(iommu_dom);
1041f9eec494SManikanta Pubbisetty 
1042f9eec494SManikanta Pubbisetty err_unregister:
1043f9eec494SManikanta Pubbisetty 	platform_device_unregister(pdev);
1044f9eec494SManikanta Pubbisetty 	of_node_put(node);
1045f9eec494SManikanta Pubbisetty 
1046f9eec494SManikanta Pubbisetty 	return ret;
1047f9eec494SManikanta Pubbisetty }
1048f9eec494SManikanta Pubbisetty 
ath11k_ahb_fw_resource_deinit(struct ath11k_base * ab)1049f9eec494SManikanta Pubbisetty static int ath11k_ahb_fw_resource_deinit(struct ath11k_base *ab)
1050f9eec494SManikanta Pubbisetty {
1051f9eec494SManikanta Pubbisetty 	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
1052f9eec494SManikanta Pubbisetty 	struct iommu_domain *iommu;
1053f9eec494SManikanta Pubbisetty 	size_t unmapped_size;
1054f9eec494SManikanta Pubbisetty 
10555a78ac33SAditya Kumar Singh 	/* Chipsets not requiring MSA would have not initialized
10565a78ac33SAditya Kumar Singh 	 * MSA resources, return success in such cases.
10575a78ac33SAditya Kumar Singh 	 */
10585a78ac33SAditya Kumar Singh 	if (!ab->hw_params.fixed_fw_mem)
10595a78ac33SAditya Kumar Singh 		return 0;
10605a78ac33SAditya Kumar Singh 
1061f9eec494SManikanta Pubbisetty 	if (ab_ahb->fw.use_tz)
1062f9eec494SManikanta Pubbisetty 		return 0;
1063f9eec494SManikanta Pubbisetty 
1064f9eec494SManikanta Pubbisetty 	iommu = ab_ahb->fw.iommu_domain;
1065f9eec494SManikanta Pubbisetty 
1066f9eec494SManikanta Pubbisetty 	unmapped_size = iommu_unmap(iommu, ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size);
1067f9eec494SManikanta Pubbisetty 	if (unmapped_size != ab_ahb->fw.msa_size)
1068f9eec494SManikanta Pubbisetty 		ath11k_err(ab, "failed to unmap firmware: %zu\n",
1069f9eec494SManikanta Pubbisetty 			   unmapped_size);
1070f9eec494SManikanta Pubbisetty 
1071f9eec494SManikanta Pubbisetty 	unmapped_size = iommu_unmap(iommu, ab_ahb->fw.ce_paddr, ab_ahb->fw.ce_size);
1072f9eec494SManikanta Pubbisetty 	if (unmapped_size != ab_ahb->fw.ce_size)
1073f9eec494SManikanta Pubbisetty 		ath11k_err(ab, "failed to unmap firmware CE memory: %zu\n",
1074f9eec494SManikanta Pubbisetty 			   unmapped_size);
1075f9eec494SManikanta Pubbisetty 
1076f9eec494SManikanta Pubbisetty 	iommu_detach_device(iommu, ab_ahb->fw.dev);
1077f9eec494SManikanta Pubbisetty 	iommu_domain_free(iommu);
1078f9eec494SManikanta Pubbisetty 
1079f9eec494SManikanta Pubbisetty 	platform_device_unregister(to_platform_device(ab_ahb->fw.dev));
1080f9eec494SManikanta Pubbisetty 
1081f9eec494SManikanta Pubbisetty 	return 0;
1082f9eec494SManikanta Pubbisetty }
1083f9eec494SManikanta Pubbisetty 
ath11k_ahb_probe(struct platform_device * pdev)1084d5c65159SKalle Valo static int ath11k_ahb_probe(struct platform_device *pdev)
1085d5c65159SKalle Valo {
1086d5c65159SKalle Valo 	struct ath11k_base *ab;
1087d5c65159SKalle Valo 	const struct of_device_id *of_id;
108800402f49SManikanta Pubbisetty 	const struct ath11k_hif_ops *hif_ops;
108900402f49SManikanta Pubbisetty 	const struct ath11k_pci_ops *pci_ops;
109000402f49SManikanta Pubbisetty 	enum ath11k_hw_rev hw_rev;
1091d5c65159SKalle Valo 	int ret;
1092d5c65159SKalle Valo 
1093d5c65159SKalle Valo 	of_id = of_match_device(ath11k_ahb_of_match, &pdev->dev);
1094d5c65159SKalle Valo 	if (!of_id) {
1095d5c65159SKalle Valo 		dev_err(&pdev->dev, "failed to find matching device tree id\n");
1096d5c65159SKalle Valo 		return -EINVAL;
1097d5c65159SKalle Valo 	}
1098d5c65159SKalle Valo 
10996763ef19SKrzysztof Kozlowski 	hw_rev = (uintptr_t)of_id->data;
110000402f49SManikanta Pubbisetty 
110100402f49SManikanta Pubbisetty 	switch (hw_rev) {
110200402f49SManikanta Pubbisetty 	case ATH11K_HW_IPQ8074:
110300402f49SManikanta Pubbisetty 	case ATH11K_HW_IPQ6018_HW10:
1104469ddb20SZiyang Huang 	case ATH11K_HW_IPQ5018_HW10:
110500402f49SManikanta Pubbisetty 		hif_ops = &ath11k_ahb_hif_ops_ipq8074;
110600402f49SManikanta Pubbisetty 		pci_ops = NULL;
110700402f49SManikanta Pubbisetty 		break;
110800402f49SManikanta Pubbisetty 	case ATH11K_HW_WCN6750_HW10:
110900402f49SManikanta Pubbisetty 		hif_ops = &ath11k_ahb_hif_ops_wcn6750;
111000402f49SManikanta Pubbisetty 		pci_ops = &ath11k_ahb_pci_ops_wcn6750;
111100402f49SManikanta Pubbisetty 		break;
111200402f49SManikanta Pubbisetty 	default:
111300402f49SManikanta Pubbisetty 		dev_err(&pdev->dev, "unsupported device type %d\n", hw_rev);
111400402f49SManikanta Pubbisetty 		return -EOPNOTSUPP;
1115d5c65159SKalle Valo 	}
1116d5c65159SKalle Valo 
1117d5c65159SKalle Valo 	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
1118d5c65159SKalle Valo 	if (ret) {
1119d5c65159SKalle Valo 		dev_err(&pdev->dev, "failed to set 32-bit consistent dma\n");
1120d5c65159SKalle Valo 		return ret;
1121d5c65159SKalle Valo 	}
1122d5c65159SKalle Valo 
1123ba929d6fSGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(struct ath11k_ahb),
112492c1858eSManikanta Pubbisetty 			       ATH11K_BUS_AHB);
1125d5c65159SKalle Valo 	if (!ab) {
1126d5c65159SKalle Valo 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
1127d5c65159SKalle Valo 		return -ENOMEM;
1128d5c65159SKalle Valo 	}
1129d5c65159SKalle Valo 
113000402f49SManikanta Pubbisetty 	ab->hif.ops = hif_ops;
1131d5c65159SKalle Valo 	ab->pdev = pdev;
113200402f49SManikanta Pubbisetty 	ab->hw_rev = hw_rev;
1133b43310e4SGovindaraj Saminathan 	ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL;
1134d5c65159SKalle Valo 	platform_set_drvdata(pdev, ab);
1135d5c65159SKalle Valo 
1136867f4eeeSManikanta Pubbisetty 	ret = ath11k_pcic_register_pci_ops(ab, pci_ops);
1137867f4eeeSManikanta Pubbisetty 	if (ret) {
1138867f4eeeSManikanta Pubbisetty 		ath11k_err(ab, "failed to register PCI ops: %d\n", ret);
1139867f4eeeSManikanta Pubbisetty 		goto err_core_free;
1140867f4eeeSManikanta Pubbisetty 	}
1141867f4eeeSManikanta Pubbisetty 
1142bebcfd25SManikanta Pubbisetty 	ret = ath11k_core_pre_init(ab);
114300402f49SManikanta Pubbisetty 	if (ret)
114400402f49SManikanta Pubbisetty 		goto err_core_free;
114500402f49SManikanta Pubbisetty 
114653a998c4SRaj Kumar Bhagat 	ret = ath11k_ahb_setup_resources(ab);
114753a998c4SRaj Kumar Bhagat 	if (ret)
114853a998c4SRaj Kumar Bhagat 		goto err_core_free;
114953a998c4SRaj Kumar Bhagat 
115053a998c4SRaj Kumar Bhagat 	ab->mem_ce = ab->mem;
115153a998c4SRaj Kumar Bhagat 
1152b42b3678SSriram R 	if (ab->hw_params.ce_remap) {
1153b42b3678SSriram R 		const struct ce_remap *ce_remap = ab->hw_params.ce_remap;
1154b42b3678SSriram R 		/* ce register space is moved out of wcss unlike ipq8074 or ipq6018
1155b42b3678SSriram R 		 * and the space is not contiguous, hence remapping the CE registers
1156b42b3678SSriram R 		 * to a new space for accessing them.
1157b42b3678SSriram R 		 */
1158b42b3678SSriram R 		ab->mem_ce = ioremap(ce_remap->base, ce_remap->size);
1159342fcde9SYang Yingliang 		if (!ab->mem_ce) {
1160b42b3678SSriram R 			dev_err(&pdev->dev, "ce ioremap error\n");
1161b42b3678SSriram R 			ret = -ENOMEM;
1162b42b3678SSriram R 			goto err_core_free;
1163b42b3678SSriram R 		}
1164b42b3678SSriram R 	}
1165b42b3678SSriram R 
1166f9eec494SManikanta Pubbisetty 	ret = ath11k_ahb_fw_resources_init(ab);
1167d5c65159SKalle Valo 	if (ret)
1168d5c65159SKalle Valo 		goto err_core_free;
1169d5c65159SKalle Valo 
117069ccee61SManikanta Pubbisetty 	ret = ath11k_ahb_setup_smp2p_handle(ab);
1171f9eec494SManikanta Pubbisetty 	if (ret)
1172f9eec494SManikanta Pubbisetty 		goto err_fw_deinit;
1173f9eec494SManikanta Pubbisetty 
117469ccee61SManikanta Pubbisetty 	ret = ath11k_hal_srng_init(ab);
117569ccee61SManikanta Pubbisetty 	if (ret)
117669ccee61SManikanta Pubbisetty 		goto err_release_smp2p_handle;
117769ccee61SManikanta Pubbisetty 
1178d5c65159SKalle Valo 	ret = ath11k_ce_alloc_pipes(ab);
1179d5c65159SKalle Valo 	if (ret) {
1180d5c65159SKalle Valo 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
1181d5c65159SKalle Valo 		goto err_hal_srng_deinit;
1182d5c65159SKalle Valo 	}
1183d5c65159SKalle Valo 
1184d5c65159SKalle Valo 	ath11k_ahb_init_qmi_ce_config(ab);
1185d5c65159SKalle Valo 
1186ba929d6fSGovind Singh 	ret = ath11k_core_get_rproc(ab);
1187ba929d6fSGovind Singh 	if (ret) {
1188ba929d6fSGovind Singh 		ath11k_err(ab, "failed to get rproc: %d\n", ret);
1189ba929d6fSGovind Singh 		goto err_ce_free;
1190ba929d6fSGovind Singh 	}
1191ba929d6fSGovind Singh 
1192d5c65159SKalle Valo 	ret = ath11k_core_init(ab);
1193d5c65159SKalle Valo 	if (ret) {
1194d5c65159SKalle Valo 		ath11k_err(ab, "failed to init core: %d\n", ret);
1195d5c65159SKalle Valo 		goto err_ce_free;
1196d5c65159SKalle Valo 	}
1197d5c65159SKalle Valo 
1198166e22b3SAnilkumar Kolli 	ret = ath11k_ahb_config_irq(ab);
1199166e22b3SAnilkumar Kolli 	if (ret) {
1200166e22b3SAnilkumar Kolli 		ath11k_err(ab, "failed to configure irq: %d\n", ret);
1201166e22b3SAnilkumar Kolli 		goto err_ce_free;
1202166e22b3SAnilkumar Kolli 	}
1203166e22b3SAnilkumar Kolli 
1204bdfc967bSAnilkumar Kolli 	ath11k_qmi_fwreset_from_cold_boot(ab);
120502f9d3c1SGovindaraj Saminathan 
1206d5c65159SKalle Valo 	return 0;
1207d5c65159SKalle Valo 
1208d5c65159SKalle Valo err_ce_free:
1209d5c65159SKalle Valo 	ath11k_ce_free_pipes(ab);
1210d5c65159SKalle Valo 
1211d5c65159SKalle Valo err_hal_srng_deinit:
1212d5c65159SKalle Valo 	ath11k_hal_srng_deinit(ab);
1213d5c65159SKalle Valo 
121469ccee61SManikanta Pubbisetty err_release_smp2p_handle:
121569ccee61SManikanta Pubbisetty 	ath11k_ahb_release_smp2p_handle(ab);
121669ccee61SManikanta Pubbisetty 
1217f9eec494SManikanta Pubbisetty err_fw_deinit:
1218f9eec494SManikanta Pubbisetty 	ath11k_ahb_fw_resource_deinit(ab);
1219f9eec494SManikanta Pubbisetty 
1220d5c65159SKalle Valo err_core_free:
1221d5c65159SKalle Valo 	ath11k_core_free(ab);
1222d5c65159SKalle Valo 	platform_set_drvdata(pdev, NULL);
1223d5c65159SKalle Valo 
1224d5c65159SKalle Valo 	return ret;
1225d5c65159SKalle Valo }
1226d5c65159SKalle Valo 
ath11k_ahb_remove_prepare(struct ath11k_base * ab)1227ac41c2b6SManikanta Pubbisetty static void ath11k_ahb_remove_prepare(struct ath11k_base *ab)
1228d5c65159SKalle Valo {
122980b892fcSBo YU 	unsigned long left;
1230d5c65159SKalle Valo 
123180b892fcSBo YU 	if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags)) {
123280b892fcSBo YU 		left = wait_for_completion_timeout(&ab->driver_recovery,
1233d5c65159SKalle Valo 						   ATH11K_AHB_RECOVERY_TIMEOUT);
123480b892fcSBo YU 		if (!left)
123580b892fcSBo YU 			ath11k_warn(ab, "failed to receive recovery response completion\n");
123680b892fcSBo YU 	}
1237d5c65159SKalle Valo 
1238d5c65159SKalle Valo 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
1239d5c65159SKalle Valo 	cancel_work_sync(&ab->restart_work);
1240ac41c2b6SManikanta Pubbisetty 	cancel_work_sync(&ab->qmi.event_work);
1241ac41c2b6SManikanta Pubbisetty }
1242d5c65159SKalle Valo 
ath11k_ahb_free_resources(struct ath11k_base * ab)1243ac41c2b6SManikanta Pubbisetty static void ath11k_ahb_free_resources(struct ath11k_base *ab)
1244ac41c2b6SManikanta Pubbisetty {
1245ac41c2b6SManikanta Pubbisetty 	struct platform_device *pdev = ab->pdev;
1246ac41c2b6SManikanta Pubbisetty 
1247d5c65159SKalle Valo 	ath11k_ahb_free_irq(ab);
1248d5c65159SKalle Valo 	ath11k_hal_srng_deinit(ab);
124969ccee61SManikanta Pubbisetty 	ath11k_ahb_release_smp2p_handle(ab);
1250f9eec494SManikanta Pubbisetty 	ath11k_ahb_fw_resource_deinit(ab);
1251d5c65159SKalle Valo 	ath11k_ce_free_pipes(ab);
1252b42b3678SSriram R 
1253b42b3678SSriram R 	if (ab->hw_params.ce_remap)
1254b42b3678SSriram R 		iounmap(ab->mem_ce);
1255b42b3678SSriram R 
1256d5c65159SKalle Valo 	ath11k_core_free(ab);
1257d5c65159SKalle Valo 	platform_set_drvdata(pdev, NULL);
1258ac41c2b6SManikanta Pubbisetty }
1259ac41c2b6SManikanta Pubbisetty 
ath11k_ahb_remove(struct platform_device * pdev)1260ac41c2b6SManikanta Pubbisetty static int ath11k_ahb_remove(struct platform_device *pdev)
1261ac41c2b6SManikanta Pubbisetty {
1262ac41c2b6SManikanta Pubbisetty 	struct ath11k_base *ab = platform_get_drvdata(pdev);
1263ac41c2b6SManikanta Pubbisetty 
1264ac41c2b6SManikanta Pubbisetty 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
1265ac41c2b6SManikanta Pubbisetty 		ath11k_ahb_power_down(ab);
1266ac41c2b6SManikanta Pubbisetty 		ath11k_debugfs_soc_destroy(ab);
1267ac41c2b6SManikanta Pubbisetty 		ath11k_qmi_deinit_service(ab);
1268ac41c2b6SManikanta Pubbisetty 		goto qmi_fail;
1269ac41c2b6SManikanta Pubbisetty 	}
1270ac41c2b6SManikanta Pubbisetty 
1271ac41c2b6SManikanta Pubbisetty 	ath11k_ahb_remove_prepare(ab);
1272ac41c2b6SManikanta Pubbisetty 	ath11k_core_deinit(ab);
1273ac41c2b6SManikanta Pubbisetty 
1274ac41c2b6SManikanta Pubbisetty qmi_fail:
1275ac41c2b6SManikanta Pubbisetty 	ath11k_ahb_free_resources(ab);
1276d5c65159SKalle Valo 
1277d5c65159SKalle Valo 	return 0;
1278d5c65159SKalle Valo }
1279d5c65159SKalle Valo 
ath11k_ahb_shutdown(struct platform_device * pdev)1280ac41c2b6SManikanta Pubbisetty static void ath11k_ahb_shutdown(struct platform_device *pdev)
1281ac41c2b6SManikanta Pubbisetty {
1282ac41c2b6SManikanta Pubbisetty 	struct ath11k_base *ab = platform_get_drvdata(pdev);
1283ac41c2b6SManikanta Pubbisetty 
1284ac41c2b6SManikanta Pubbisetty 	/* platform shutdown() & remove() are mutually exclusive.
1285ac41c2b6SManikanta Pubbisetty 	 * remove() is invoked during rmmod & shutdown() during
1286ac41c2b6SManikanta Pubbisetty 	 * system reboot/shutdown.
1287ac41c2b6SManikanta Pubbisetty 	 */
1288ac41c2b6SManikanta Pubbisetty 	ath11k_ahb_remove_prepare(ab);
1289ac41c2b6SManikanta Pubbisetty 
1290ac41c2b6SManikanta Pubbisetty 	if (!(test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)))
1291ac41c2b6SManikanta Pubbisetty 		goto free_resources;
1292ac41c2b6SManikanta Pubbisetty 
1293ac41c2b6SManikanta Pubbisetty 	ath11k_core_deinit(ab);
1294ac41c2b6SManikanta Pubbisetty 
1295ac41c2b6SManikanta Pubbisetty free_resources:
1296ac41c2b6SManikanta Pubbisetty 	ath11k_ahb_free_resources(ab);
1297ac41c2b6SManikanta Pubbisetty }
1298ac41c2b6SManikanta Pubbisetty 
1299d5c65159SKalle Valo static struct platform_driver ath11k_ahb_driver = {
1300d5c65159SKalle Valo 	.driver         = {
1301d5c65159SKalle Valo 		.name   = "ath11k",
1302d5c65159SKalle Valo 		.of_match_table = ath11k_ahb_of_match,
1303d5c65159SKalle Valo 	},
1304d5c65159SKalle Valo 	.probe  = ath11k_ahb_probe,
1305d5c65159SKalle Valo 	.remove = ath11k_ahb_remove,
1306ac41c2b6SManikanta Pubbisetty 	.shutdown = ath11k_ahb_shutdown,
1307d5c65159SKalle Valo };
1308d5c65159SKalle Valo 
1309749a660bSYang Yingliang module_platform_driver(ath11k_ahb_driver);
131031858805SGovind Singh 
13116e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN AHB devices");
131231858805SGovind Singh MODULE_LICENSE("Dual BSD/GPL");
1313