xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision babb0ced6acdbaa0b5e0721ec7b347fdbdfa0f6f)
16e0355afSGovind Singh // SPDX-License-Identifier: BSD-3-Clause-Clear
26e0355afSGovind Singh /*
36e0355afSGovind Singh  * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
46e0355afSGovind Singh  */
56e0355afSGovind Singh 
66e0355afSGovind Singh #include <linux/module.h>
75697a564SGovind Singh #include <linux/msi.h>
86e0355afSGovind Singh #include <linux/pci.h>
96e0355afSGovind Singh 
105762613eSGovind Singh #include "pci.h"
116e0355afSGovind Singh #include "core.h"
121399fb87SGovind Singh #include "hif.h"
131399fb87SGovind Singh #include "mhi.h"
146e0355afSGovind Singh #include "debug.h"
156e0355afSGovind Singh 
165762613eSGovind Singh #define ATH11K_PCI_BAR_NUM		0
175762613eSGovind Singh #define ATH11K_PCI_DMA_MASK		32
185762613eSGovind Singh 
197f4beda2SGovind Singh #define ATH11K_PCI_IRQ_CE0_OFFSET		3
207f4beda2SGovind Singh 
21654e959aSGovind Singh #define WINDOW_ENABLE_BIT		0x40000000
22654e959aSGovind Singh #define WINDOW_REG_ADDRESS		0x310c
23654e959aSGovind Singh #define WINDOW_VALUE_MASK		GENMASK(24, 19)
24654e959aSGovind Singh #define WINDOW_START			0x80000
25654e959aSGovind Singh #define WINDOW_RANGE_MASK		GENMASK(18, 0)
26654e959aSGovind Singh 
2718ac1665SKalle Valo #define TCSR_SOC_HW_VERSION		0x0224
2818ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MAJOR_MASK	GENMASK(16, 8)
2918ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MINOR_MASK	GENMASK(7, 0)
3018ac1665SKalle Valo 
31a05bd851SCarl Huang /* BAR0 + 4k is always accessible, and no
32a05bd851SCarl Huang  * need to force wakeup.
33a05bd851SCarl Huang  * 4K - 32 = 0xFE0
34a05bd851SCarl Huang  */
35a05bd851SCarl Huang #define ACCESS_ALWAYS_OFF 0xFE0
36a05bd851SCarl Huang 
376e0355afSGovind Singh #define QCA6390_DEVICE_ID		0x1101
386e0355afSGovind Singh 
396e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = {
406e0355afSGovind Singh 	{ PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) },
416e0355afSGovind Singh 	{0}
426e0355afSGovind Singh };
436e0355afSGovind Singh 
446e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table);
456e0355afSGovind Singh 
461ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = {
471ff8ed78SGovind Singh 	.mhi_support = true,
4856970454SGovind Singh 	.m3_fw_support = true,
496eb6ea51SGovind Singh 	.fixed_bdf_addr = false,
506eb6ea51SGovind Singh 	.fixed_mem_region = false,
511ff8ed78SGovind Singh };
521ff8ed78SGovind Singh 
535697a564SGovind Singh static const struct ath11k_msi_config msi_config = {
545697a564SGovind Singh 	.total_vectors = 32,
555697a564SGovind Singh 	.total_users = 4,
565697a564SGovind Singh 	.users = (struct ath11k_msi_user[]) {
575697a564SGovind Singh 		{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
585697a564SGovind Singh 		{ .name = "CE", .num_vectors = 10, .base_vector = 3 },
595697a564SGovind Singh 		{ .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
605697a564SGovind Singh 		{ .name = "DP", .num_vectors = 18, .base_vector = 14 },
615697a564SGovind Singh 	},
625697a564SGovind Singh };
635697a564SGovind Singh 
647f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
657f4beda2SGovind Singh 	"bhi",
667f4beda2SGovind Singh 	"mhi-er0",
677f4beda2SGovind Singh 	"mhi-er1",
687f4beda2SGovind Singh 	"ce0",
697f4beda2SGovind Singh 	"ce1",
707f4beda2SGovind Singh 	"ce2",
717f4beda2SGovind Singh 	"ce3",
727f4beda2SGovind Singh 	"ce4",
737f4beda2SGovind Singh 	"ce5",
747f4beda2SGovind Singh 	"ce6",
757f4beda2SGovind Singh 	"ce7",
767f4beda2SGovind Singh 	"ce8",
777f4beda2SGovind Singh 	"ce9",
787f4beda2SGovind Singh 	"ce10",
797f4beda2SGovind Singh 	"ce11",
807f4beda2SGovind Singh 	"host2wbm-desc-feed",
817f4beda2SGovind Singh 	"host2reo-re-injection",
827f4beda2SGovind Singh 	"host2reo-command",
837f4beda2SGovind Singh 	"host2rxdma-monitor-ring3",
847f4beda2SGovind Singh 	"host2rxdma-monitor-ring2",
857f4beda2SGovind Singh 	"host2rxdma-monitor-ring1",
867f4beda2SGovind Singh 	"reo2ost-exception",
877f4beda2SGovind Singh 	"wbm2host-rx-release",
887f4beda2SGovind Singh 	"reo2host-status",
897f4beda2SGovind Singh 	"reo2host-destination-ring4",
907f4beda2SGovind Singh 	"reo2host-destination-ring3",
917f4beda2SGovind Singh 	"reo2host-destination-ring2",
927f4beda2SGovind Singh 	"reo2host-destination-ring1",
937f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac3",
947f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac2",
957f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac1",
967f4beda2SGovind Singh 	"ppdu-end-interrupts-mac3",
977f4beda2SGovind Singh 	"ppdu-end-interrupts-mac2",
987f4beda2SGovind Singh 	"ppdu-end-interrupts-mac1",
997f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac3",
1007f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac2",
1017f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac1",
1027f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac3",
1037f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac2",
1047f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac1",
1057f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac3",
1067f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac2",
1077f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac1",
1087f4beda2SGovind Singh 	"host2tcl-input-ring4",
1097f4beda2SGovind Singh 	"host2tcl-input-ring3",
1107f4beda2SGovind Singh 	"host2tcl-input-ring2",
1117f4beda2SGovind Singh 	"host2tcl-input-ring1",
1127f4beda2SGovind Singh 	"wbm2host-tx-completions-ring3",
1137f4beda2SGovind Singh 	"wbm2host-tx-completions-ring2",
1147f4beda2SGovind Singh 	"wbm2host-tx-completions-ring1",
1157f4beda2SGovind Singh 	"tcl2host-status-ring",
1167f4beda2SGovind Singh };
1177f4beda2SGovind Singh 
118654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset)
119654e959aSGovind Singh {
120654e959aSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
121654e959aSGovind Singh 
122654e959aSGovind Singh 	u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset);
123654e959aSGovind Singh 
124654e959aSGovind Singh 	lockdep_assert_held(&ab_pci->window_lock);
125654e959aSGovind Singh 
126654e959aSGovind Singh 	if (window != ab_pci->register_window) {
127654e959aSGovind Singh 		iowrite32(WINDOW_ENABLE_BIT | window,
128654e959aSGovind Singh 			  ab->mem + WINDOW_REG_ADDRESS);
129654e959aSGovind Singh 		ab_pci->register_window = window;
130654e959aSGovind Singh 	}
131654e959aSGovind Singh }
132654e959aSGovind Singh 
133f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
134654e959aSGovind Singh {
135654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
136654e959aSGovind Singh 
137a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
138a05bd851SCarl Huang 	 * need to wakeup MHI to access.
139a05bd851SCarl Huang 	 */
140a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
141a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
142a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
143a05bd851SCarl Huang 
144654e959aSGovind Singh 	if (offset < WINDOW_START) {
145654e959aSGovind Singh 		iowrite32(value, ab->mem  + offset);
146654e959aSGovind Singh 	} else {
147654e959aSGovind Singh 		spin_lock_bh(&ab_pci->window_lock);
148654e959aSGovind Singh 		ath11k_pci_select_window(ab_pci, offset);
149654e959aSGovind Singh 		iowrite32(value, ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK));
150654e959aSGovind Singh 		spin_unlock_bh(&ab_pci->window_lock);
151654e959aSGovind Singh 	}
152a05bd851SCarl Huang 
153a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
154a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
155a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
156654e959aSGovind Singh }
157654e959aSGovind Singh 
158f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
159654e959aSGovind Singh {
160654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
161654e959aSGovind Singh 	u32 val;
162654e959aSGovind Singh 
163a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
164a05bd851SCarl Huang 	 * need to wakeup MHI to access.
165a05bd851SCarl Huang 	 */
166a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
167a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
168a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
169a05bd851SCarl Huang 
170654e959aSGovind Singh 	if (offset < WINDOW_START) {
171654e959aSGovind Singh 		val = ioread32(ab->mem + offset);
172654e959aSGovind Singh 	} else {
173654e959aSGovind Singh 		spin_lock_bh(&ab_pci->window_lock);
174654e959aSGovind Singh 		ath11k_pci_select_window(ab_pci, offset);
175654e959aSGovind Singh 		val = ioread32(ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK));
176654e959aSGovind Singh 		spin_unlock_bh(&ab_pci->window_lock);
177654e959aSGovind Singh 	}
178654e959aSGovind Singh 
179a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
180a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
181a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
182a05bd851SCarl Huang 
183654e959aSGovind Singh 	return val;
184654e959aSGovind Singh }
185654e959aSGovind Singh 
186f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
187f3c603d4SCarl Huang {
188f3c603d4SCarl Huang 	u32 val, delay;
189f3c603d4SCarl Huang 
190f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
191f3c603d4SCarl Huang 
192f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
193f3c603d4SCarl Huang 
194f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
195f3c603d4SCarl Huang 
196f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
197f3c603d4SCarl Huang 	delay = 10;
198f3c603d4SCarl Huang 	mdelay(delay);
199f3c603d4SCarl Huang 
200f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
201f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
202f3c603d4SCarl Huang 
203f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
204f3c603d4SCarl Huang 
205f3c603d4SCarl Huang 	mdelay(delay);
206f3c603d4SCarl Huang 
207f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
208f3c603d4SCarl Huang 	if (val == 0xffffffff)
209f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
210f3c603d4SCarl Huang }
211f3c603d4SCarl Huang 
212f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
213f3c603d4SCarl Huang {
214f3c603d4SCarl Huang 	u32 val;
215f3c603d4SCarl Huang 
216f3c603d4SCarl Huang 	/* read cookie */
217f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR);
218f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val);
219f3c603d4SCarl Huang 
220f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
221f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
222f3c603d4SCarl Huang 
223f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
224f3c603d4SCarl Huang 	mdelay(10);
225f3c603d4SCarl Huang 
226f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
227f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
228f3c603d4SCarl Huang 	 */
229f3c603d4SCarl Huang 	ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0);
230f3c603d4SCarl Huang 	mdelay(10);
231f3c603d4SCarl Huang 
232f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
233f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
234f3c603d4SCarl Huang 
235f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
236f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
237f3c603d4SCarl Huang 	 */
238f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
239f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
240f3c603d4SCarl Huang }
241f3c603d4SCarl Huang 
242*babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
243*babb0cedSCarl Huang {
244*babb0cedSCarl Huang 	u32 val;
245*babb0cedSCarl Huang 	int i;
246*babb0cedSCarl Huang 
247*babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
248*babb0cedSCarl Huang 
249*babb0cedSCarl Huang 	/* PCIE link seems very unstable after the Hot Reset*/
250*babb0cedSCarl Huang 	for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {
251*babb0cedSCarl Huang 		if (val == 0xffffffff)
252*babb0cedSCarl Huang 			mdelay(5);
253*babb0cedSCarl Huang 
254*babb0cedSCarl Huang 		ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
255*babb0cedSCarl Huang 		val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
256*babb0cedSCarl Huang 	}
257*babb0cedSCarl Huang 
258*babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val);
259*babb0cedSCarl Huang 
260*babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
261*babb0cedSCarl Huang 	val |= GCC_GCC_PCIE_HOT_RST_VAL | 0x10;
262*babb0cedSCarl Huang 	ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
263*babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
264*babb0cedSCarl Huang 
265*babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val);
266*babb0cedSCarl Huang 
267*babb0cedSCarl Huang 	mdelay(5);
268*babb0cedSCarl Huang }
269*babb0cedSCarl Huang 
270*babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
271*babb0cedSCarl Huang {
272*babb0cedSCarl Huang 	/* This is a WAR for PCIE Hotreset.
273*babb0cedSCarl Huang 	 * When target receive Hotreset, but will set the interrupt.
274*babb0cedSCarl Huang 	 * So when download SBL again, SBL will open Interrupt and
275*babb0cedSCarl Huang 	 * receive it, and crash immediately.
276*babb0cedSCarl Huang 	 */
277*babb0cedSCarl Huang 	ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
278*babb0cedSCarl Huang }
279*babb0cedSCarl Huang 
280f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
281f3c603d4SCarl Huang {
282f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
283f3c603d4SCarl Huang 	mdelay(5);
284f3c603d4SCarl Huang }
285f3c603d4SCarl Huang 
286*babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
287f3c603d4SCarl Huang {
288*babb0cedSCarl Huang 	if (power_on) {
289*babb0cedSCarl Huang 		ath11k_pci_enable_ltssm(ab);
290*babb0cedSCarl Huang 		ath11k_pci_clear_all_intrs(ab);
291*babb0cedSCarl Huang 	}
292*babb0cedSCarl Huang 
293f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
294f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
295f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
296f3c603d4SCarl Huang 	ath11k_pci_clear_dbg_registers(ab);
297f3c603d4SCarl Huang }
298f3c603d4SCarl Huang 
2991399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
3001399fb87SGovind Singh {
3011399fb87SGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(dev);
3021399fb87SGovind Singh 
3031399fb87SGovind Singh 	return pci_irq_vector(pci_dev, vector);
3041399fb87SGovind Singh }
3051399fb87SGovind Singh 
306c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
307c4eacabeSGovind Singh 				       u32 *msi_addr_hi)
308c4eacabeSGovind Singh {
309e8e55d89SAnilkumar Kolli 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
310c4eacabeSGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
311c4eacabeSGovind Singh 
312c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
313c4eacabeSGovind Singh 			      msi_addr_lo);
314c4eacabeSGovind Singh 
315e8e55d89SAnilkumar Kolli 	if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) {
316c4eacabeSGovind Singh 		pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
317c4eacabeSGovind Singh 				      msi_addr_hi);
318e8e55d89SAnilkumar Kolli 	} else {
319e8e55d89SAnilkumar Kolli 		*msi_addr_hi = 0;
320e8e55d89SAnilkumar Kolli 	}
321c4eacabeSGovind Singh }
322c4eacabeSGovind Singh 
3231399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
3241399fb87SGovind Singh 				       int *num_vectors, u32 *user_base_data,
3251399fb87SGovind Singh 				       u32 *base_vector)
3261399fb87SGovind Singh {
3271399fb87SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
3281399fb87SGovind Singh 	int idx;
3291399fb87SGovind Singh 
3301399fb87SGovind Singh 	for (idx = 0; idx < msi_config.total_users; idx++) {
3311399fb87SGovind Singh 		if (strcmp(user_name, msi_config.users[idx].name) == 0) {
3321399fb87SGovind Singh 			*num_vectors = msi_config.users[idx].num_vectors;
3331399fb87SGovind Singh 			*user_base_data = msi_config.users[idx].base_vector
3341399fb87SGovind Singh 				+ ab_pci->msi_ep_base_data;
3351399fb87SGovind Singh 			*base_vector = msi_config.users[idx].base_vector;
3361399fb87SGovind Singh 
3371399fb87SGovind Singh 			ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
3381399fb87SGovind Singh 				   user_name, *num_vectors, *user_base_data,
3391399fb87SGovind Singh 				   *base_vector);
3401399fb87SGovind Singh 
3411399fb87SGovind Singh 			return 0;
3421399fb87SGovind Singh 		}
3431399fb87SGovind Singh 	}
3441399fb87SGovind Singh 
3451399fb87SGovind Singh 	ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
3461399fb87SGovind Singh 
3471399fb87SGovind Singh 	return -EINVAL;
3481399fb87SGovind Singh }
3491399fb87SGovind Singh 
350c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
351c4eacabeSGovind Singh 					  int *num_vectors, u32 *user_base_data,
352c4eacabeSGovind Singh 					  u32 *base_vector)
353c4eacabeSGovind Singh {
354c4eacabeSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
355c4eacabeSGovind Singh 
356c4eacabeSGovind Singh 	return ath11k_pci_get_user_msi_assignment(ab_pci, user_name,
357c4eacabeSGovind Singh 						  num_vectors, user_base_data,
358c4eacabeSGovind Singh 						  base_vector);
359c4eacabeSGovind Singh }
360c4eacabeSGovind Singh 
361d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
362d4ecb90bSCarl Huang {
363d4ecb90bSCarl Huang 	int i, j;
364d4ecb90bSCarl Huang 
365d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
366d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
367d4ecb90bSCarl Huang 
368d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++)
369d4ecb90bSCarl Huang 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
370d4ecb90bSCarl Huang 
371d4ecb90bSCarl Huang 		netif_napi_del(&irq_grp->napi);
372d4ecb90bSCarl Huang 	}
373d4ecb90bSCarl Huang }
374d4ecb90bSCarl Huang 
3757f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab)
3767f4beda2SGovind Singh {
3777f4beda2SGovind Singh 	int i, irq_idx;
3787f4beda2SGovind Singh 
379d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
380e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
3817f4beda2SGovind Singh 			continue;
3827f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
3837f4beda2SGovind Singh 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
3847f4beda2SGovind Singh 	}
385d4ecb90bSCarl Huang 
386d4ecb90bSCarl Huang 	ath11k_pci_free_ext_irq(ab);
3877f4beda2SGovind Singh }
3887f4beda2SGovind Singh 
3892c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
3902c3960c2SGovind Singh {
3912c3960c2SGovind Singh 	u32 irq_idx;
3922c3960c2SGovind Singh 
3932c3960c2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
3942c3960c2SGovind Singh 	enable_irq(ab->irq_num[irq_idx]);
3952c3960c2SGovind Singh }
3962c3960c2SGovind Singh 
3977f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
3987f4beda2SGovind Singh {
3997f4beda2SGovind Singh 	u32 irq_idx;
4007f4beda2SGovind Singh 
4017f4beda2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
4027f4beda2SGovind Singh 	disable_irq_nosync(ab->irq_num[irq_idx]);
4037f4beda2SGovind Singh }
4047f4beda2SGovind Singh 
4052c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
4062c3960c2SGovind Singh {
4072c3960c2SGovind Singh 	int i;
4082c3960c2SGovind Singh 
409d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
410e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
4112c3960c2SGovind Singh 			continue;
4122c3960c2SGovind Singh 		ath11k_pci_ce_irq_disable(ab, i);
4132c3960c2SGovind Singh 	}
4142c3960c2SGovind Singh }
4152c3960c2SGovind Singh 
4162c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
4172c3960c2SGovind Singh {
4182c3960c2SGovind Singh 	int i;
4192c3960c2SGovind Singh 	int irq_idx;
4202c3960c2SGovind Singh 
421d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
422e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
4232c3960c2SGovind Singh 			continue;
4242c3960c2SGovind Singh 
4252c3960c2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
4262c3960c2SGovind Singh 		synchronize_irq(ab->irq_num[irq_idx]);
4272c3960c2SGovind Singh 	}
4282c3960c2SGovind Singh }
4292c3960c2SGovind Singh 
4300f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
4312c3960c2SGovind Singh {
4320f01dcb8SAllen Pais 	struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
4332c3960c2SGovind Singh 
4342c3960c2SGovind Singh 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
4352c3960c2SGovind Singh 
4362c3960c2SGovind Singh 	ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
4372c3960c2SGovind Singh }
4382c3960c2SGovind Singh 
4397f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
4407f4beda2SGovind Singh {
4417f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = arg;
4427f4beda2SGovind Singh 
4437f4beda2SGovind Singh 	ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
4442c3960c2SGovind Singh 	tasklet_schedule(&ce_pipe->intr_tq);
4457f4beda2SGovind Singh 
4467f4beda2SGovind Singh 	return IRQ_HANDLED;
4477f4beda2SGovind Singh }
4487f4beda2SGovind Singh 
449d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
450d4ecb90bSCarl Huang {
451d4ecb90bSCarl Huang 	int i;
452d4ecb90bSCarl Huang 
453d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
454d4ecb90bSCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
455d4ecb90bSCarl Huang }
456d4ecb90bSCarl Huang 
457d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
458d4ecb90bSCarl Huang {
459d4ecb90bSCarl Huang 	int i;
460d4ecb90bSCarl Huang 
461d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
462d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
463d4ecb90bSCarl Huang 
464d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
465d4ecb90bSCarl Huang 
466d4ecb90bSCarl Huang 		napi_synchronize(&irq_grp->napi);
467d4ecb90bSCarl Huang 		napi_disable(&irq_grp->napi);
468d4ecb90bSCarl Huang 	}
469d4ecb90bSCarl Huang }
470d4ecb90bSCarl Huang 
471d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
472d4ecb90bSCarl Huang {
473d4ecb90bSCarl Huang 	int i;
474d4ecb90bSCarl Huang 
475d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
476d4ecb90bSCarl Huang 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
477d4ecb90bSCarl Huang }
478d4ecb90bSCarl Huang 
479d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
480d4ecb90bSCarl Huang {
481d4ecb90bSCarl Huang 	int i;
482d4ecb90bSCarl Huang 
483d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
484d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
485d4ecb90bSCarl Huang 
486d4ecb90bSCarl Huang 		napi_enable(&irq_grp->napi);
487d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
488d4ecb90bSCarl Huang 	}
489d4ecb90bSCarl Huang }
490d4ecb90bSCarl Huang 
491d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
492d4ecb90bSCarl Huang {
493d4ecb90bSCarl Huang 	int i, j, irq_idx;
494d4ecb90bSCarl Huang 
495d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
496d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
497d4ecb90bSCarl Huang 
498d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
499d4ecb90bSCarl Huang 			irq_idx = irq_grp->irqs[j];
500d4ecb90bSCarl Huang 			synchronize_irq(ab->irq_num[irq_idx]);
501d4ecb90bSCarl Huang 		}
502d4ecb90bSCarl Huang 	}
503d4ecb90bSCarl Huang }
504d4ecb90bSCarl Huang 
505d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
506d4ecb90bSCarl Huang {
507d4ecb90bSCarl Huang 	__ath11k_pci_ext_irq_disable(ab);
508d4ecb90bSCarl Huang 	ath11k_pci_sync_ext_irqs(ab);
509d4ecb90bSCarl Huang }
510d4ecb90bSCarl Huang 
511d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
512d4ecb90bSCarl Huang {
513d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
514d4ecb90bSCarl Huang 						struct ath11k_ext_irq_grp,
515d4ecb90bSCarl Huang 						napi);
516d4ecb90bSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
517d4ecb90bSCarl Huang 	int work_done;
518d4ecb90bSCarl Huang 
519d4ecb90bSCarl Huang 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
520d4ecb90bSCarl Huang 	if (work_done < budget) {
521d4ecb90bSCarl Huang 		napi_complete_done(napi, work_done);
522d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
523d4ecb90bSCarl Huang 	}
524d4ecb90bSCarl Huang 
525d4ecb90bSCarl Huang 	if (work_done > budget)
526d4ecb90bSCarl Huang 		work_done = budget;
527d4ecb90bSCarl Huang 
528d4ecb90bSCarl Huang 	return work_done;
529d4ecb90bSCarl Huang }
530d4ecb90bSCarl Huang 
531d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
532d4ecb90bSCarl Huang {
533d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = arg;
534d4ecb90bSCarl Huang 
535d4ecb90bSCarl Huang 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
536d4ecb90bSCarl Huang 
537d4ecb90bSCarl Huang 	ath11k_pci_ext_grp_disable(irq_grp);
538d4ecb90bSCarl Huang 
539d4ecb90bSCarl Huang 	napi_schedule(&irq_grp->napi);
540d4ecb90bSCarl Huang 
541d4ecb90bSCarl Huang 	return IRQ_HANDLED;
542d4ecb90bSCarl Huang }
543d4ecb90bSCarl Huang 
544d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
545d4ecb90bSCarl Huang {
546d4ecb90bSCarl Huang 	int i, j, ret, num_vectors = 0;
547d4ecb90bSCarl Huang 	u32 user_base_data = 0, base_vector = 0;
548d4ecb90bSCarl Huang 
549b2c09458SColin Ian King 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
550b2c09458SColin Ian King 						 &num_vectors,
551b2c09458SColin Ian King 						 &user_base_data,
552d4ecb90bSCarl Huang 						 &base_vector);
553b2c09458SColin Ian King 	if (ret < 0)
554b2c09458SColin Ian King 		return ret;
555d4ecb90bSCarl Huang 
556d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
557d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
558d4ecb90bSCarl Huang 		u32 num_irq = 0;
559d4ecb90bSCarl Huang 
560d4ecb90bSCarl Huang 		irq_grp->ab = ab;
561d4ecb90bSCarl Huang 		irq_grp->grp_id = i;
562d4ecb90bSCarl Huang 		init_dummy_netdev(&irq_grp->napi_ndev);
563d4ecb90bSCarl Huang 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
564d4ecb90bSCarl Huang 			       ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
565d4ecb90bSCarl Huang 
566d4ecb90bSCarl Huang 		if (ab->hw_params.ring_mask->tx[i] ||
567d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx[i] ||
568d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_err[i] ||
569d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_wbm_rel[i] ||
570d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->reo_status[i] ||
571d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rxdma2host[i] ||
572d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->host2rxdma[i] ||
573d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_mon_status[i]) {
574d4ecb90bSCarl Huang 			num_irq = 1;
575d4ecb90bSCarl Huang 		}
576d4ecb90bSCarl Huang 
577d4ecb90bSCarl Huang 		irq_grp->num_irq = num_irq;
578d4ecb90bSCarl Huang 		irq_grp->irqs[0] = base_vector + i;
579d4ecb90bSCarl Huang 
580d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
581d4ecb90bSCarl Huang 			int irq_idx = irq_grp->irqs[j];
582d4ecb90bSCarl Huang 			int vector = (i % num_vectors) + base_vector;
583d4ecb90bSCarl Huang 			int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
584d4ecb90bSCarl Huang 
585d4ecb90bSCarl Huang 			ab->irq_num[irq_idx] = irq;
586d4ecb90bSCarl Huang 
587d4ecb90bSCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
588d4ecb90bSCarl Huang 				   "irq:%d group:%d\n", irq, i);
589d4ecb90bSCarl Huang 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
590d4ecb90bSCarl Huang 					  IRQF_SHARED,
591d4ecb90bSCarl Huang 					  "DP_EXT_IRQ", irq_grp);
592d4ecb90bSCarl Huang 			if (ret) {
593d4ecb90bSCarl Huang 				ath11k_err(ab, "failed request irq %d: %d\n",
594d4ecb90bSCarl Huang 					   vector, ret);
595d4ecb90bSCarl Huang 				return ret;
596d4ecb90bSCarl Huang 			}
597d4ecb90bSCarl Huang 
598d4ecb90bSCarl Huang 			disable_irq_nosync(ab->irq_num[irq_idx]);
599d4ecb90bSCarl Huang 		}
600d4ecb90bSCarl Huang 	}
601d4ecb90bSCarl Huang 
602d4ecb90bSCarl Huang 	return 0;
603d4ecb90bSCarl Huang }
604d4ecb90bSCarl Huang 
6057f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab)
6067f4beda2SGovind Singh {
6077f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe;
6087f4beda2SGovind Singh 	u32 msi_data_start;
6097f4beda2SGovind Singh 	u32 msi_data_count;
6107f4beda2SGovind Singh 	u32 msi_irq_start;
6117f4beda2SGovind Singh 	unsigned int msi_data;
6127f4beda2SGovind Singh 	int irq, i, ret, irq_idx;
6137f4beda2SGovind Singh 
6147f4beda2SGovind Singh 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab),
6157f4beda2SGovind Singh 						 "CE", &msi_data_count,
6167f4beda2SGovind Singh 						 &msi_data_start, &msi_irq_start);
6177f4beda2SGovind Singh 	if (ret)
6187f4beda2SGovind Singh 		return ret;
6197f4beda2SGovind Singh 
6207f4beda2SGovind Singh 	/* Configure CE irqs */
621d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
6227f4beda2SGovind Singh 		msi_data = (i % msi_data_count) + msi_irq_start;
6237f4beda2SGovind Singh 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
6247f4beda2SGovind Singh 		ce_pipe = &ab->ce.ce_pipe[i];
6257f4beda2SGovind Singh 
626e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
6277f4beda2SGovind Singh 			continue;
6287f4beda2SGovind Singh 
6297f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
6307f4beda2SGovind Singh 
6310f01dcb8SAllen Pais 		tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
6322c3960c2SGovind Singh 
6337f4beda2SGovind Singh 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
6347f4beda2SGovind Singh 				  IRQF_SHARED, irq_name[irq_idx],
6357f4beda2SGovind Singh 				  ce_pipe);
6367f4beda2SGovind Singh 		if (ret) {
6377f4beda2SGovind Singh 			ath11k_err(ab, "failed to request irq %d: %d\n",
6387f4beda2SGovind Singh 				   irq_idx, ret);
6397f4beda2SGovind Singh 			return ret;
6407f4beda2SGovind Singh 		}
6417f4beda2SGovind Singh 
6427f4beda2SGovind Singh 		ab->irq_num[irq_idx] = irq;
643e5c860e1SCarl Huang 		ath11k_pci_ce_irq_disable(ab, i);
6447f4beda2SGovind Singh 	}
6457f4beda2SGovind Singh 
646d4ecb90bSCarl Huang 	ret = ath11k_pci_ext_irq_config(ab);
647d4ecb90bSCarl Huang 	if (ret)
648d4ecb90bSCarl Huang 		return ret;
649d4ecb90bSCarl Huang 
6507f4beda2SGovind Singh 	return 0;
6517f4beda2SGovind Singh }
6527f4beda2SGovind Singh 
6537f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
6547f4beda2SGovind Singh {
6557f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
6567f4beda2SGovind Singh 
657967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
658967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
6597f4beda2SGovind Singh 
660967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
661967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
662eb8de049SGovind Singh 	ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390;
663e838c14aSCarl Huang 
664e838c14aSCarl Huang 	ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
665e838c14aSCarl Huang 				    &cfg->shadow_reg_v2_len);
6667f4beda2SGovind Singh }
6677f4beda2SGovind Singh 
6687f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
6697f4beda2SGovind Singh {
6707f4beda2SGovind Singh 	int i;
6717f4beda2SGovind Singh 
672d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
673e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
6747f4beda2SGovind Singh 			continue;
6757f4beda2SGovind Singh 		ath11k_pci_ce_irq_enable(ab, i);
6767f4beda2SGovind Singh 	}
6777f4beda2SGovind Singh }
6787f4beda2SGovind Singh 
6795697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
6805697a564SGovind Singh {
6815697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
6825697a564SGovind Singh 	struct msi_desc *msi_desc;
6835697a564SGovind Singh 	int num_vectors;
6845697a564SGovind Singh 	int ret;
6855697a564SGovind Singh 
6865697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
6875697a564SGovind Singh 					    msi_config.total_vectors,
6885697a564SGovind Singh 					    msi_config.total_vectors,
6895697a564SGovind Singh 					    PCI_IRQ_MSI);
6905697a564SGovind Singh 	if (num_vectors != msi_config.total_vectors) {
6915697a564SGovind Singh 		ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
6925697a564SGovind Singh 			   msi_config.total_vectors, num_vectors);
6935697a564SGovind Singh 
6945697a564SGovind Singh 		if (num_vectors >= 0)
6955697a564SGovind Singh 			return -EINVAL;
6965697a564SGovind Singh 		else
6975697a564SGovind Singh 			return num_vectors;
6985697a564SGovind Singh 	}
6995697a564SGovind Singh 
7005697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
7015697a564SGovind Singh 	if (!msi_desc) {
7025697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
7035697a564SGovind Singh 		ret = -EINVAL;
7045697a564SGovind Singh 		goto free_msi_vector;
7055697a564SGovind Singh 	}
7065697a564SGovind Singh 
7075697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
708e8e55d89SAnilkumar Kolli 	if (msi_desc->msi_attrib.is_64)
709e8e55d89SAnilkumar Kolli 		set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags);
7105697a564SGovind Singh 
7115697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
7125697a564SGovind Singh 
7135697a564SGovind Singh 	return 0;
7145697a564SGovind Singh 
7155697a564SGovind Singh free_msi_vector:
7165697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
7175697a564SGovind Singh 
7185697a564SGovind Singh 	return ret;
7195697a564SGovind Singh }
7205697a564SGovind Singh 
7215697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci)
7225697a564SGovind Singh {
7235697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
7245697a564SGovind Singh }
7255697a564SGovind Singh 
7265762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
7275762613eSGovind Singh {
7285762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
7295762613eSGovind Singh 	u16 device_id;
7305762613eSGovind Singh 	int ret = 0;
7315762613eSGovind Singh 
7325762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
7335762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
7345762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
7355762613eSGovind Singh 			   device_id, ab_pci->dev_id);
7365762613eSGovind Singh 		ret = -EIO;
7375762613eSGovind Singh 		goto out;
7385762613eSGovind Singh 	}
7395762613eSGovind Singh 
7405762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
7415762613eSGovind Singh 	if (ret) {
7425762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
7435762613eSGovind Singh 		goto out;
7445762613eSGovind Singh 	}
7455762613eSGovind Singh 
7465762613eSGovind Singh 	ret = pci_enable_device(pdev);
7475762613eSGovind Singh 	if (ret) {
7485762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
7495762613eSGovind Singh 		goto out;
7505762613eSGovind Singh 	}
7515762613eSGovind Singh 
7525762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
7535762613eSGovind Singh 	if (ret) {
7545762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
7555762613eSGovind Singh 		goto disable_device;
7565762613eSGovind Singh 	}
7575762613eSGovind Singh 
7585762613eSGovind Singh 	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
7595762613eSGovind Singh 	if (ret) {
7605762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
7615762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
7625762613eSGovind Singh 		goto release_region;
7635762613eSGovind Singh 	}
7645762613eSGovind Singh 
7655762613eSGovind Singh 	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
7665762613eSGovind Singh 	if (ret) {
7675762613eSGovind Singh 		ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n",
7685762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
7695762613eSGovind Singh 		goto release_region;
7705762613eSGovind Singh 	}
7715762613eSGovind Singh 
7725762613eSGovind Singh 	pci_set_master(pdev);
7735762613eSGovind Singh 
7745762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
7755762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
7765762613eSGovind Singh 	if (!ab->mem) {
7775762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
7785762613eSGovind Singh 		ret = -EIO;
7795762613eSGovind Singh 		goto clear_master;
7805762613eSGovind Singh 	}
7815762613eSGovind Singh 
7825762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
7835762613eSGovind Singh 	return 0;
7845762613eSGovind Singh 
7855762613eSGovind Singh clear_master:
7865762613eSGovind Singh 	pci_clear_master(pdev);
7875762613eSGovind Singh release_region:
7885762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
7895762613eSGovind Singh disable_device:
7905762613eSGovind Singh 	pci_disable_device(pdev);
7915762613eSGovind Singh out:
7925762613eSGovind Singh 	return ret;
7935762613eSGovind Singh }
7945762613eSGovind Singh 
7955762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
7965762613eSGovind Singh {
7975762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
7985762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
7995762613eSGovind Singh 
8005762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
8015762613eSGovind Singh 	ab->mem = NULL;
8025762613eSGovind Singh 	pci_clear_master(pci_dev);
8035762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
8045762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
8055762613eSGovind Singh 		pci_disable_device(pci_dev);
8065762613eSGovind Singh }
8075762613eSGovind Singh 
8081399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
8091399fb87SGovind Singh {
8101399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
8111399fb87SGovind Singh 	int ret;
8121399fb87SGovind Singh 
813a05bd851SCarl Huang 	ab_pci->register_window = 0;
814a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
815*babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, true);
816f3c603d4SCarl Huang 
8171399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
8181399fb87SGovind Singh 	if (ret) {
8191399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
8201399fb87SGovind Singh 		return ret;
8211399fb87SGovind Singh 	}
8221399fb87SGovind Singh 
8231399fb87SGovind Singh 	return 0;
8241399fb87SGovind Singh }
8251399fb87SGovind Singh 
8261399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
8271399fb87SGovind Singh {
8281399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
8291399fb87SGovind Singh 
830*babb0cedSCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
8311399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
832a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
833*babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, false);
8341399fb87SGovind Singh }
8351399fb87SGovind Singh 
8362c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
8372c3960c2SGovind Singh {
8382c3960c2SGovind Singh 	int i;
8392c3960c2SGovind Singh 
840d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
8412c3960c2SGovind Singh 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
8422c3960c2SGovind Singh 
843e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
8442c3960c2SGovind Singh 			continue;
8452c3960c2SGovind Singh 
8462c3960c2SGovind Singh 		tasklet_kill(&ce_pipe->intr_tq);
8472c3960c2SGovind Singh 	}
8482c3960c2SGovind Singh }
8492c3960c2SGovind Singh 
8507f4beda2SGovind Singh static void ath11k_pci_stop(struct ath11k_base *ab)
8517f4beda2SGovind Singh {
8522c3960c2SGovind Singh 	ath11k_pci_ce_irqs_disable(ab);
8532c3960c2SGovind Singh 	ath11k_pci_sync_ce_irqs(ab);
8542c3960c2SGovind Singh 	ath11k_pci_kill_tasklets(ab);
8557f4beda2SGovind Singh 	ath11k_ce_cleanup_pipes(ab);
8567f4beda2SGovind Singh }
8577f4beda2SGovind Singh 
8587f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab)
8597f4beda2SGovind Singh {
860a05bd851SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
861a05bd851SCarl Huang 
862a05bd851SCarl Huang 	set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
863a05bd851SCarl Huang 
8647f4beda2SGovind Singh 	ath11k_pci_ce_irqs_enable(ab);
8652c3960c2SGovind Singh 	ath11k_ce_rx_post_buf(ab);
8662c3960c2SGovind Singh 
8672c3960c2SGovind Singh 	return 0;
8682c3960c2SGovind Singh }
8692c3960c2SGovind Singh 
8702c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
8712c3960c2SGovind Singh 					  u8 *ul_pipe, u8 *dl_pipe)
8722c3960c2SGovind Singh {
8732c3960c2SGovind Singh 	const struct service_to_pipe *entry;
8742c3960c2SGovind Singh 	bool ul_set = false, dl_set = false;
8752c3960c2SGovind Singh 	int i;
8762c3960c2SGovind Singh 
877967c1d11SAnilkumar Kolli 	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
878967c1d11SAnilkumar Kolli 		entry = &ab->hw_params.svc_to_ce_map[i];
8792c3960c2SGovind Singh 
8802c3960c2SGovind Singh 		if (__le32_to_cpu(entry->service_id) != service_id)
8812c3960c2SGovind Singh 			continue;
8822c3960c2SGovind Singh 
8832c3960c2SGovind Singh 		switch (__le32_to_cpu(entry->pipedir)) {
8842c3960c2SGovind Singh 		case PIPEDIR_NONE:
8852c3960c2SGovind Singh 			break;
8862c3960c2SGovind Singh 		case PIPEDIR_IN:
8872c3960c2SGovind Singh 			WARN_ON(dl_set);
8882c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
8892c3960c2SGovind Singh 			dl_set = true;
8902c3960c2SGovind Singh 			break;
8912c3960c2SGovind Singh 		case PIPEDIR_OUT:
8922c3960c2SGovind Singh 			WARN_ON(ul_set);
8932c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
8942c3960c2SGovind Singh 			ul_set = true;
8952c3960c2SGovind Singh 			break;
8962c3960c2SGovind Singh 		case PIPEDIR_INOUT:
8972c3960c2SGovind Singh 			WARN_ON(dl_set);
8982c3960c2SGovind Singh 			WARN_ON(ul_set);
8992c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
9002c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
9012c3960c2SGovind Singh 			dl_set = true;
9022c3960c2SGovind Singh 			ul_set = true;
9032c3960c2SGovind Singh 			break;
9042c3960c2SGovind Singh 		}
9052c3960c2SGovind Singh 	}
9062c3960c2SGovind Singh 
9072c3960c2SGovind Singh 	if (WARN_ON(!ul_set || !dl_set))
9082c3960c2SGovind Singh 		return -ENOENT;
9097f4beda2SGovind Singh 
9107f4beda2SGovind Singh 	return 0;
9117f4beda2SGovind Singh }
9127f4beda2SGovind Singh 
9137f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
9147f4beda2SGovind Singh 	.start = ath11k_pci_start,
9157f4beda2SGovind Singh 	.stop = ath11k_pci_stop,
916654e959aSGovind Singh 	.read32 = ath11k_pci_read32,
917654e959aSGovind Singh 	.write32 = ath11k_pci_write32,
9181399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
9191399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
920d4ecb90bSCarl Huang 	.irq_enable = ath11k_pci_ext_irq_enable,
921d4ecb90bSCarl Huang 	.irq_disable = ath11k_pci_ext_irq_disable,
922c4eacabeSGovind Singh 	.get_msi_address =  ath11k_pci_get_msi_address,
923c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
9242c3960c2SGovind Singh 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
9251399fb87SGovind Singh };
9261399fb87SGovind Singh 
9276e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
9286e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
9296e0355afSGovind Singh {
9306e0355afSGovind Singh 	struct ath11k_base *ab;
9315762613eSGovind Singh 	struct ath11k_pci *ab_pci;
93218ac1665SKalle Valo 	u32 soc_hw_version, soc_hw_version_major, soc_hw_version_minor;
9335762613eSGovind Singh 	int ret;
9346e0355afSGovind Singh 
9356e0355afSGovind Singh 	dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n");
9366e0355afSGovind Singh 
9371ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
9381ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
9396e0355afSGovind Singh 	if (!ab) {
9406e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
9416e0355afSGovind Singh 		return -ENOMEM;
9426e0355afSGovind Singh 	}
9436e0355afSGovind Singh 
9446e0355afSGovind Singh 	ab->dev = &pdev->dev;
9456e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
9465762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
9475762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
9485762613eSGovind Singh 	ab_pci->ab = ab;
9495697a564SGovind Singh 	ab_pci->pdev = pdev;
9507f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
9515762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
952654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
9535762613eSGovind Singh 
9545762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
9555762613eSGovind Singh 	if (ret) {
9565762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
9575762613eSGovind Singh 		goto err_free_core;
9585762613eSGovind Singh 	}
9596e0355afSGovind Singh 
96018ac1665SKalle Valo 	switch (pci_dev->device) {
96118ac1665SKalle Valo 	case QCA6390_DEVICE_ID:
96218ac1665SKalle Valo 		soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION);
96318ac1665SKalle Valo 		soc_hw_version_major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
96418ac1665SKalle Valo 						 soc_hw_version);
96518ac1665SKalle Valo 		soc_hw_version_minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
96618ac1665SKalle Valo 						 soc_hw_version);
96718ac1665SKalle Valo 
96818ac1665SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
96918ac1665SKalle Valo 			   soc_hw_version_major, soc_hw_version_minor);
97018ac1665SKalle Valo 
97118ac1665SKalle Valo 		switch (soc_hw_version_major) {
97218ac1665SKalle Valo 		case 2:
97318ac1665SKalle Valo 			ab->hw_rev = ATH11K_HW_QCA6390_HW20;
97418ac1665SKalle Valo 			break;
97518ac1665SKalle Valo 		default:
97618ac1665SKalle Valo 			dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n",
97718ac1665SKalle Valo 				soc_hw_version_major, soc_hw_version_minor);
97818ac1665SKalle Valo 			ret = -EOPNOTSUPP;
97918ac1665SKalle Valo 			goto err_pci_free_region;
98018ac1665SKalle Valo 		}
98118ac1665SKalle Valo 		break;
98218ac1665SKalle Valo 	default:
98318ac1665SKalle Valo 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
98418ac1665SKalle Valo 			pci_dev->device);
98518ac1665SKalle Valo 		ret = -EOPNOTSUPP;
98618ac1665SKalle Valo 		goto err_pci_free_region;
98718ac1665SKalle Valo 	}
98818ac1665SKalle Valo 
9895697a564SGovind Singh 	ret = ath11k_pci_enable_msi(ab_pci);
9905697a564SGovind Singh 	if (ret) {
9915697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
9925697a564SGovind Singh 		goto err_pci_free_region;
9935697a564SGovind Singh 	}
9945697a564SGovind Singh 
995b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
996b8246f88SKalle Valo 	if (ret)
997b8246f88SKalle Valo 		goto err_pci_disable_msi;
998b8246f88SKalle Valo 
9991399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
10001399fb87SGovind Singh 	if (ret) {
10011399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
10021399fb87SGovind Singh 		goto err_pci_disable_msi;
10031399fb87SGovind Singh 	}
10041399fb87SGovind Singh 
10057f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
10067f4beda2SGovind Singh 	if (ret)
10077f4beda2SGovind Singh 		goto err_mhi_unregister;
10087f4beda2SGovind Singh 
10097f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
10107f4beda2SGovind Singh 	if (ret) {
10117f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
10127f4beda2SGovind Singh 		goto err_hal_srng_deinit;
10137f4beda2SGovind Singh 	}
10147f4beda2SGovind Singh 
10157f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
10167f4beda2SGovind Singh 
10177f4beda2SGovind Singh 	ret = ath11k_pci_config_irq(ab);
10187f4beda2SGovind Singh 	if (ret) {
10197f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
10207f4beda2SGovind Singh 		goto err_ce_free;
10217f4beda2SGovind Singh 	}
10227f4beda2SGovind Singh 
10237f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
10247f4beda2SGovind Singh 	if (ret) {
10257f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
10267f4beda2SGovind Singh 		goto err_free_irq;
10277f4beda2SGovind Singh 	}
10286e0355afSGovind Singh 	return 0;
10295762613eSGovind Singh 
10307f4beda2SGovind Singh err_free_irq:
10317f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
10327f4beda2SGovind Singh 
10337f4beda2SGovind Singh err_ce_free:
10347f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
10357f4beda2SGovind Singh 
10367f4beda2SGovind Singh err_hal_srng_deinit:
10377f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
10387f4beda2SGovind Singh 
10397f4beda2SGovind Singh err_mhi_unregister:
10407f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
10417f4beda2SGovind Singh 
1042b8246f88SKalle Valo err_pci_disable_msi:
1043b8246f88SKalle Valo 	ath11k_pci_disable_msi(ab_pci);
1044b8246f88SKalle Valo 
10455697a564SGovind Singh err_pci_free_region:
10465697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
10475697a564SGovind Singh 
10485762613eSGovind Singh err_free_core:
10495762613eSGovind Singh 	ath11k_core_free(ab);
10505697a564SGovind Singh 
10515762613eSGovind Singh 	return ret;
10526e0355afSGovind Singh }
10536e0355afSGovind Singh 
10546e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
10556e0355afSGovind Singh {
10566e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
10575762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
10586e0355afSGovind Singh 
105961a57e51SAnilkumar Kolli 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
106061a57e51SAnilkumar Kolli 		ath11k_pci_power_down(ab);
106161a57e51SAnilkumar Kolli 		ath11k_debugfs_soc_destroy(ab);
106261a57e51SAnilkumar Kolli 		ath11k_qmi_deinit_service(ab);
106361a57e51SAnilkumar Kolli 		goto qmi_fail;
106461a57e51SAnilkumar Kolli 	}
106561a57e51SAnilkumar Kolli 
10666e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
10676fbd8898SCarl Huang 
10686fbd8898SCarl Huang 	ath11k_core_deinit(ab);
10696fbd8898SCarl Huang 
107061a57e51SAnilkumar Kolli qmi_fail:
10711399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
10726fbd8898SCarl Huang 
10736fbd8898SCarl Huang 	ath11k_pci_free_irq(ab);
10745697a564SGovind Singh 	ath11k_pci_disable_msi(ab_pci);
10755762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
10766fbd8898SCarl Huang 
10776fbd8898SCarl Huang 	ath11k_hal_srng_deinit(ab);
10786fbd8898SCarl Huang 	ath11k_ce_free_pipes(ab);
10796e0355afSGovind Singh 	ath11k_core_free(ab);
10806e0355afSGovind Singh }
10816e0355afSGovind Singh 
10821399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
10831399fb87SGovind Singh {
10841399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
10851399fb87SGovind Singh 
10861399fb87SGovind Singh 	ath11k_pci_power_down(ab);
10871399fb87SGovind Singh }
10881399fb87SGovind Singh 
10896e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
10906e0355afSGovind Singh 	.name = "ath11k_pci",
10916e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
10926e0355afSGovind Singh 	.probe = ath11k_pci_probe,
10936e0355afSGovind Singh 	.remove = ath11k_pci_remove,
10941399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
10956e0355afSGovind Singh };
10966e0355afSGovind Singh 
10976e0355afSGovind Singh static int ath11k_pci_init(void)
10986e0355afSGovind Singh {
10996e0355afSGovind Singh 	int ret;
11006e0355afSGovind Singh 
11016e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
11026e0355afSGovind Singh 	if (ret)
11036e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
11046e0355afSGovind Singh 		       ret);
11056e0355afSGovind Singh 
11066e0355afSGovind Singh 	return ret;
11076e0355afSGovind Singh }
11086e0355afSGovind Singh module_init(ath11k_pci_init);
11096e0355afSGovind Singh 
11106e0355afSGovind Singh static void ath11k_pci_exit(void)
11116e0355afSGovind Singh {
11126e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
11136e0355afSGovind Singh }
11146e0355afSGovind Singh 
11156e0355afSGovind Singh module_exit(ath11k_pci_exit);
11166e0355afSGovind Singh 
11176e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
11186e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
11193dbd7fe7SDevin Bayer 
11203dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */
11213dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE);
11223dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE);
11233dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE);
1124