xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision 0ccdf43988279eed70dece82ffff08fb15278d2c)
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 
24206999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab,
24306999407SCarl Huang 				   u32 offset, u32 value, u32 mask)
24406999407SCarl Huang {
24506999407SCarl Huang 	u32 v;
24606999407SCarl Huang 	int i;
24706999407SCarl Huang 
24806999407SCarl Huang 	v = ath11k_pci_read32(ab, offset);
24906999407SCarl Huang 	if ((v & mask) == value)
25006999407SCarl Huang 		return 0;
25106999407SCarl Huang 
25206999407SCarl Huang 	for (i = 0; i < 10; i++) {
25306999407SCarl Huang 		ath11k_pci_write32(ab, offset, (v & ~mask) | value);
25406999407SCarl Huang 
25506999407SCarl Huang 		v = ath11k_pci_read32(ab, offset);
25606999407SCarl Huang 		if ((v & mask) == value)
25706999407SCarl Huang 			return 0;
25806999407SCarl Huang 
25906999407SCarl Huang 		mdelay(2);
26006999407SCarl Huang 	}
26106999407SCarl Huang 
26206999407SCarl Huang 	ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n",
26306999407SCarl Huang 		    offset, v & mask, value);
26406999407SCarl Huang 
26506999407SCarl Huang 	return -ETIMEDOUT;
26606999407SCarl Huang }
26706999407SCarl Huang 
26806999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
26906999407SCarl Huang {
27006999407SCarl Huang 	int ret;
27106999407SCarl Huang 
27206999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
27306999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG,
27406999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL,
27506999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK);
27606999407SCarl Huang 	if (!ret) {
27706999407SCarl Huang 		ath11k_warn(ab, "failed to set sysclk: %d\n", ret);
27806999407SCarl Huang 		return ret;
27906999407SCarl Huang 	}
28006999407SCarl Huang 
28106999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
28206999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_REG,
28306999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_VAL,
28406999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK);
28506999407SCarl Huang 	if (!ret) {
28606999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret);
28706999407SCarl Huang 		return ret;
28806999407SCarl Huang 	}
28906999407SCarl Huang 
29006999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
29106999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_REG,
29206999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_VAL,
29306999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK);
29406999407SCarl Huang 	if (!ret) {
29506999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config2: %d\n", ret);
29606999407SCarl Huang 		return ret;
29706999407SCarl Huang 	}
29806999407SCarl Huang 
29906999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
30006999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_REG,
30106999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_VAL,
30206999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK);
30306999407SCarl Huang 	if (!ret) {
30406999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config4: %d\n", ret);
30506999407SCarl Huang 		return ret;
30606999407SCarl Huang 	}
30706999407SCarl Huang 
30806999407SCarl Huang 	return 0;
30906999407SCarl Huang }
31006999407SCarl Huang 
311babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
312babb0cedSCarl Huang {
313babb0cedSCarl Huang 	u32 val;
314babb0cedSCarl Huang 	int i;
315babb0cedSCarl Huang 
316babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
317babb0cedSCarl Huang 
318babb0cedSCarl Huang 	/* PCIE link seems very unstable after the Hot Reset*/
319babb0cedSCarl Huang 	for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {
320babb0cedSCarl Huang 		if (val == 0xffffffff)
321babb0cedSCarl Huang 			mdelay(5);
322babb0cedSCarl Huang 
323babb0cedSCarl Huang 		ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
324babb0cedSCarl Huang 		val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
325babb0cedSCarl Huang 	}
326babb0cedSCarl Huang 
327babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val);
328babb0cedSCarl Huang 
329babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
330babb0cedSCarl Huang 	val |= GCC_GCC_PCIE_HOT_RST_VAL | 0x10;
331babb0cedSCarl Huang 	ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
332babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
333babb0cedSCarl Huang 
334babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val);
335babb0cedSCarl Huang 
336babb0cedSCarl Huang 	mdelay(5);
337babb0cedSCarl Huang }
338babb0cedSCarl Huang 
339babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
340babb0cedSCarl Huang {
341babb0cedSCarl Huang 	/* This is a WAR for PCIE Hotreset.
342babb0cedSCarl Huang 	 * When target receive Hotreset, but will set the interrupt.
343babb0cedSCarl Huang 	 * So when download SBL again, SBL will open Interrupt and
344babb0cedSCarl Huang 	 * receive it, and crash immediately.
345babb0cedSCarl Huang 	 */
346babb0cedSCarl Huang 	ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
347babb0cedSCarl Huang }
348babb0cedSCarl Huang 
349*0ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab)
350*0ccdf439SCarl Huang {
351*0ccdf439SCarl Huang 	u32 val;
352*0ccdf439SCarl Huang 
353*0ccdf439SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG);
354*0ccdf439SCarl Huang 	val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK;
355*0ccdf439SCarl Huang 	ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val);
356*0ccdf439SCarl Huang }
357*0ccdf439SCarl Huang 
358f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
359f3c603d4SCarl Huang {
360f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
361f3c603d4SCarl Huang 	mdelay(5);
362f3c603d4SCarl Huang }
363f3c603d4SCarl Huang 
364babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
365f3c603d4SCarl Huang {
366babb0cedSCarl Huang 	if (power_on) {
367babb0cedSCarl Huang 		ath11k_pci_enable_ltssm(ab);
368babb0cedSCarl Huang 		ath11k_pci_clear_all_intrs(ab);
369*0ccdf439SCarl Huang 		ath11k_pci_set_wlaon_pwr_ctrl(ab);
37006999407SCarl Huang 		ath11k_pci_fix_l1ss(ab);
371babb0cedSCarl Huang 	}
372babb0cedSCarl Huang 
373f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
374f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
375f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
376f3c603d4SCarl Huang 	ath11k_pci_clear_dbg_registers(ab);
377f3c603d4SCarl Huang }
378f3c603d4SCarl Huang 
3791399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
3801399fb87SGovind Singh {
3811399fb87SGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(dev);
3821399fb87SGovind Singh 
3831399fb87SGovind Singh 	return pci_irq_vector(pci_dev, vector);
3841399fb87SGovind Singh }
3851399fb87SGovind Singh 
386c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
387c4eacabeSGovind Singh 				       u32 *msi_addr_hi)
388c4eacabeSGovind Singh {
389e8e55d89SAnilkumar Kolli 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
390c4eacabeSGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
391c4eacabeSGovind Singh 
392c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
393c4eacabeSGovind Singh 			      msi_addr_lo);
394c4eacabeSGovind Singh 
395e8e55d89SAnilkumar Kolli 	if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) {
396c4eacabeSGovind Singh 		pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
397c4eacabeSGovind Singh 				      msi_addr_hi);
398e8e55d89SAnilkumar Kolli 	} else {
399e8e55d89SAnilkumar Kolli 		*msi_addr_hi = 0;
400e8e55d89SAnilkumar Kolli 	}
401c4eacabeSGovind Singh }
402c4eacabeSGovind Singh 
4031399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
4041399fb87SGovind Singh 				       int *num_vectors, u32 *user_base_data,
4051399fb87SGovind Singh 				       u32 *base_vector)
4061399fb87SGovind Singh {
4071399fb87SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4081399fb87SGovind Singh 	int idx;
4091399fb87SGovind Singh 
4101399fb87SGovind Singh 	for (idx = 0; idx < msi_config.total_users; idx++) {
4111399fb87SGovind Singh 		if (strcmp(user_name, msi_config.users[idx].name) == 0) {
4121399fb87SGovind Singh 			*num_vectors = msi_config.users[idx].num_vectors;
4131399fb87SGovind Singh 			*user_base_data = msi_config.users[idx].base_vector
4141399fb87SGovind Singh 				+ ab_pci->msi_ep_base_data;
4151399fb87SGovind Singh 			*base_vector = msi_config.users[idx].base_vector;
4161399fb87SGovind Singh 
4171399fb87SGovind Singh 			ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
4181399fb87SGovind Singh 				   user_name, *num_vectors, *user_base_data,
4191399fb87SGovind Singh 				   *base_vector);
4201399fb87SGovind Singh 
4211399fb87SGovind Singh 			return 0;
4221399fb87SGovind Singh 		}
4231399fb87SGovind Singh 	}
4241399fb87SGovind Singh 
4251399fb87SGovind Singh 	ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
4261399fb87SGovind Singh 
4271399fb87SGovind Singh 	return -EINVAL;
4281399fb87SGovind Singh }
4291399fb87SGovind Singh 
430c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
431c4eacabeSGovind Singh 					  int *num_vectors, u32 *user_base_data,
432c4eacabeSGovind Singh 					  u32 *base_vector)
433c4eacabeSGovind Singh {
434c4eacabeSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
435c4eacabeSGovind Singh 
436c4eacabeSGovind Singh 	return ath11k_pci_get_user_msi_assignment(ab_pci, user_name,
437c4eacabeSGovind Singh 						  num_vectors, user_base_data,
438c4eacabeSGovind Singh 						  base_vector);
439c4eacabeSGovind Singh }
440c4eacabeSGovind Singh 
441d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
442d4ecb90bSCarl Huang {
443d4ecb90bSCarl Huang 	int i, j;
444d4ecb90bSCarl Huang 
445d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
446d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
447d4ecb90bSCarl Huang 
448d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++)
449d4ecb90bSCarl Huang 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
450d4ecb90bSCarl Huang 
451d4ecb90bSCarl Huang 		netif_napi_del(&irq_grp->napi);
452d4ecb90bSCarl Huang 	}
453d4ecb90bSCarl Huang }
454d4ecb90bSCarl Huang 
4557f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab)
4567f4beda2SGovind Singh {
4577f4beda2SGovind Singh 	int i, irq_idx;
4587f4beda2SGovind Singh 
459d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
460e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
4617f4beda2SGovind Singh 			continue;
4627f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
4637f4beda2SGovind Singh 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
4647f4beda2SGovind Singh 	}
465d4ecb90bSCarl Huang 
466d4ecb90bSCarl Huang 	ath11k_pci_free_ext_irq(ab);
4677f4beda2SGovind Singh }
4687f4beda2SGovind Singh 
4692c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
4702c3960c2SGovind Singh {
4712c3960c2SGovind Singh 	u32 irq_idx;
4722c3960c2SGovind Singh 
4732c3960c2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
4742c3960c2SGovind Singh 	enable_irq(ab->irq_num[irq_idx]);
4752c3960c2SGovind Singh }
4762c3960c2SGovind Singh 
4777f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
4787f4beda2SGovind Singh {
4797f4beda2SGovind Singh 	u32 irq_idx;
4807f4beda2SGovind Singh 
4817f4beda2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
4827f4beda2SGovind Singh 	disable_irq_nosync(ab->irq_num[irq_idx]);
4837f4beda2SGovind Singh }
4847f4beda2SGovind Singh 
4852c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
4862c3960c2SGovind Singh {
4872c3960c2SGovind Singh 	int i;
4882c3960c2SGovind Singh 
489d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
490e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
4912c3960c2SGovind Singh 			continue;
4922c3960c2SGovind Singh 		ath11k_pci_ce_irq_disable(ab, i);
4932c3960c2SGovind Singh 	}
4942c3960c2SGovind Singh }
4952c3960c2SGovind Singh 
4962c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
4972c3960c2SGovind Singh {
4982c3960c2SGovind Singh 	int i;
4992c3960c2SGovind Singh 	int irq_idx;
5002c3960c2SGovind Singh 
501d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
502e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5032c3960c2SGovind Singh 			continue;
5042c3960c2SGovind Singh 
5052c3960c2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5062c3960c2SGovind Singh 		synchronize_irq(ab->irq_num[irq_idx]);
5072c3960c2SGovind Singh 	}
5082c3960c2SGovind Singh }
5092c3960c2SGovind Singh 
5100f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
5112c3960c2SGovind Singh {
5120f01dcb8SAllen Pais 	struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
5132c3960c2SGovind Singh 
5142c3960c2SGovind Singh 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
5152c3960c2SGovind Singh 
5162c3960c2SGovind Singh 	ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
5172c3960c2SGovind Singh }
5182c3960c2SGovind Singh 
5197f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
5207f4beda2SGovind Singh {
5217f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = arg;
5227f4beda2SGovind Singh 
5237f4beda2SGovind Singh 	ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
5242c3960c2SGovind Singh 	tasklet_schedule(&ce_pipe->intr_tq);
5257f4beda2SGovind Singh 
5267f4beda2SGovind Singh 	return IRQ_HANDLED;
5277f4beda2SGovind Singh }
5287f4beda2SGovind Singh 
529d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
530d4ecb90bSCarl Huang {
531d4ecb90bSCarl Huang 	int i;
532d4ecb90bSCarl Huang 
533d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
534d4ecb90bSCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
535d4ecb90bSCarl Huang }
536d4ecb90bSCarl Huang 
537d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
538d4ecb90bSCarl Huang {
539d4ecb90bSCarl Huang 	int i;
540d4ecb90bSCarl Huang 
541d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
542d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
543d4ecb90bSCarl Huang 
544d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
545d4ecb90bSCarl Huang 
546d4ecb90bSCarl Huang 		napi_synchronize(&irq_grp->napi);
547d4ecb90bSCarl Huang 		napi_disable(&irq_grp->napi);
548d4ecb90bSCarl Huang 	}
549d4ecb90bSCarl Huang }
550d4ecb90bSCarl Huang 
551d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
552d4ecb90bSCarl Huang {
553d4ecb90bSCarl Huang 	int i;
554d4ecb90bSCarl Huang 
555d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
556d4ecb90bSCarl Huang 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
557d4ecb90bSCarl Huang }
558d4ecb90bSCarl Huang 
559d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
560d4ecb90bSCarl Huang {
561d4ecb90bSCarl Huang 	int i;
562d4ecb90bSCarl Huang 
563d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
564d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
565d4ecb90bSCarl Huang 
566d4ecb90bSCarl Huang 		napi_enable(&irq_grp->napi);
567d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
568d4ecb90bSCarl Huang 	}
569d4ecb90bSCarl Huang }
570d4ecb90bSCarl Huang 
571d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
572d4ecb90bSCarl Huang {
573d4ecb90bSCarl Huang 	int i, j, irq_idx;
574d4ecb90bSCarl Huang 
575d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
576d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
577d4ecb90bSCarl Huang 
578d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
579d4ecb90bSCarl Huang 			irq_idx = irq_grp->irqs[j];
580d4ecb90bSCarl Huang 			synchronize_irq(ab->irq_num[irq_idx]);
581d4ecb90bSCarl Huang 		}
582d4ecb90bSCarl Huang 	}
583d4ecb90bSCarl Huang }
584d4ecb90bSCarl Huang 
585d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
586d4ecb90bSCarl Huang {
587d4ecb90bSCarl Huang 	__ath11k_pci_ext_irq_disable(ab);
588d4ecb90bSCarl Huang 	ath11k_pci_sync_ext_irqs(ab);
589d4ecb90bSCarl Huang }
590d4ecb90bSCarl Huang 
591d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
592d4ecb90bSCarl Huang {
593d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
594d4ecb90bSCarl Huang 						struct ath11k_ext_irq_grp,
595d4ecb90bSCarl Huang 						napi);
596d4ecb90bSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
597d4ecb90bSCarl Huang 	int work_done;
598d4ecb90bSCarl Huang 
599d4ecb90bSCarl Huang 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
600d4ecb90bSCarl Huang 	if (work_done < budget) {
601d4ecb90bSCarl Huang 		napi_complete_done(napi, work_done);
602d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
603d4ecb90bSCarl Huang 	}
604d4ecb90bSCarl Huang 
605d4ecb90bSCarl Huang 	if (work_done > budget)
606d4ecb90bSCarl Huang 		work_done = budget;
607d4ecb90bSCarl Huang 
608d4ecb90bSCarl Huang 	return work_done;
609d4ecb90bSCarl Huang }
610d4ecb90bSCarl Huang 
611d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
612d4ecb90bSCarl Huang {
613d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = arg;
614d4ecb90bSCarl Huang 
615d4ecb90bSCarl Huang 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
616d4ecb90bSCarl Huang 
617d4ecb90bSCarl Huang 	ath11k_pci_ext_grp_disable(irq_grp);
618d4ecb90bSCarl Huang 
619d4ecb90bSCarl Huang 	napi_schedule(&irq_grp->napi);
620d4ecb90bSCarl Huang 
621d4ecb90bSCarl Huang 	return IRQ_HANDLED;
622d4ecb90bSCarl Huang }
623d4ecb90bSCarl Huang 
624d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
625d4ecb90bSCarl Huang {
626d4ecb90bSCarl Huang 	int i, j, ret, num_vectors = 0;
627d4ecb90bSCarl Huang 	u32 user_base_data = 0, base_vector = 0;
628d4ecb90bSCarl Huang 
629b2c09458SColin Ian King 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
630b2c09458SColin Ian King 						 &num_vectors,
631b2c09458SColin Ian King 						 &user_base_data,
632d4ecb90bSCarl Huang 						 &base_vector);
633b2c09458SColin Ian King 	if (ret < 0)
634b2c09458SColin Ian King 		return ret;
635d4ecb90bSCarl Huang 
636d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
637d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
638d4ecb90bSCarl Huang 		u32 num_irq = 0;
639d4ecb90bSCarl Huang 
640d4ecb90bSCarl Huang 		irq_grp->ab = ab;
641d4ecb90bSCarl Huang 		irq_grp->grp_id = i;
642d4ecb90bSCarl Huang 		init_dummy_netdev(&irq_grp->napi_ndev);
643d4ecb90bSCarl Huang 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
644d4ecb90bSCarl Huang 			       ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
645d4ecb90bSCarl Huang 
646d4ecb90bSCarl Huang 		if (ab->hw_params.ring_mask->tx[i] ||
647d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx[i] ||
648d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_err[i] ||
649d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_wbm_rel[i] ||
650d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->reo_status[i] ||
651d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rxdma2host[i] ||
652d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->host2rxdma[i] ||
653d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_mon_status[i]) {
654d4ecb90bSCarl Huang 			num_irq = 1;
655d4ecb90bSCarl Huang 		}
656d4ecb90bSCarl Huang 
657d4ecb90bSCarl Huang 		irq_grp->num_irq = num_irq;
658d4ecb90bSCarl Huang 		irq_grp->irqs[0] = base_vector + i;
659d4ecb90bSCarl Huang 
660d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
661d4ecb90bSCarl Huang 			int irq_idx = irq_grp->irqs[j];
662d4ecb90bSCarl Huang 			int vector = (i % num_vectors) + base_vector;
663d4ecb90bSCarl Huang 			int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
664d4ecb90bSCarl Huang 
665d4ecb90bSCarl Huang 			ab->irq_num[irq_idx] = irq;
666d4ecb90bSCarl Huang 
667d4ecb90bSCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
668d4ecb90bSCarl Huang 				   "irq:%d group:%d\n", irq, i);
669d4ecb90bSCarl Huang 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
670d4ecb90bSCarl Huang 					  IRQF_SHARED,
671d4ecb90bSCarl Huang 					  "DP_EXT_IRQ", irq_grp);
672d4ecb90bSCarl Huang 			if (ret) {
673d4ecb90bSCarl Huang 				ath11k_err(ab, "failed request irq %d: %d\n",
674d4ecb90bSCarl Huang 					   vector, ret);
675d4ecb90bSCarl Huang 				return ret;
676d4ecb90bSCarl Huang 			}
677d4ecb90bSCarl Huang 
678d4ecb90bSCarl Huang 			disable_irq_nosync(ab->irq_num[irq_idx]);
679d4ecb90bSCarl Huang 		}
680d4ecb90bSCarl Huang 	}
681d4ecb90bSCarl Huang 
682d4ecb90bSCarl Huang 	return 0;
683d4ecb90bSCarl Huang }
684d4ecb90bSCarl Huang 
6857f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab)
6867f4beda2SGovind Singh {
6877f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe;
6887f4beda2SGovind Singh 	u32 msi_data_start;
6897f4beda2SGovind Singh 	u32 msi_data_count;
6907f4beda2SGovind Singh 	u32 msi_irq_start;
6917f4beda2SGovind Singh 	unsigned int msi_data;
6927f4beda2SGovind Singh 	int irq, i, ret, irq_idx;
6937f4beda2SGovind Singh 
6947f4beda2SGovind Singh 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab),
6957f4beda2SGovind Singh 						 "CE", &msi_data_count,
6967f4beda2SGovind Singh 						 &msi_data_start, &msi_irq_start);
6977f4beda2SGovind Singh 	if (ret)
6987f4beda2SGovind Singh 		return ret;
6997f4beda2SGovind Singh 
7007f4beda2SGovind Singh 	/* Configure CE irqs */
701d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
7027f4beda2SGovind Singh 		msi_data = (i % msi_data_count) + msi_irq_start;
7037f4beda2SGovind Singh 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
7047f4beda2SGovind Singh 		ce_pipe = &ab->ce.ce_pipe[i];
7057f4beda2SGovind Singh 
706e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
7077f4beda2SGovind Singh 			continue;
7087f4beda2SGovind Singh 
7097f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
7107f4beda2SGovind Singh 
7110f01dcb8SAllen Pais 		tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
7122c3960c2SGovind Singh 
7137f4beda2SGovind Singh 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
7147f4beda2SGovind Singh 				  IRQF_SHARED, irq_name[irq_idx],
7157f4beda2SGovind Singh 				  ce_pipe);
7167f4beda2SGovind Singh 		if (ret) {
7177f4beda2SGovind Singh 			ath11k_err(ab, "failed to request irq %d: %d\n",
7187f4beda2SGovind Singh 				   irq_idx, ret);
7197f4beda2SGovind Singh 			return ret;
7207f4beda2SGovind Singh 		}
7217f4beda2SGovind Singh 
7227f4beda2SGovind Singh 		ab->irq_num[irq_idx] = irq;
723e5c860e1SCarl Huang 		ath11k_pci_ce_irq_disable(ab, i);
7247f4beda2SGovind Singh 	}
7257f4beda2SGovind Singh 
726d4ecb90bSCarl Huang 	ret = ath11k_pci_ext_irq_config(ab);
727d4ecb90bSCarl Huang 	if (ret)
728d4ecb90bSCarl Huang 		return ret;
729d4ecb90bSCarl Huang 
7307f4beda2SGovind Singh 	return 0;
7317f4beda2SGovind Singh }
7327f4beda2SGovind Singh 
7337f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
7347f4beda2SGovind Singh {
7357f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
7367f4beda2SGovind Singh 
737967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
738967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
7397f4beda2SGovind Singh 
740967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
741967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
742eb8de049SGovind Singh 	ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390;
743e838c14aSCarl Huang 
744e838c14aSCarl Huang 	ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
745e838c14aSCarl Huang 				    &cfg->shadow_reg_v2_len);
7467f4beda2SGovind Singh }
7477f4beda2SGovind Singh 
7487f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
7497f4beda2SGovind Singh {
7507f4beda2SGovind Singh 	int i;
7517f4beda2SGovind Singh 
752d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
753e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
7547f4beda2SGovind Singh 			continue;
7557f4beda2SGovind Singh 		ath11k_pci_ce_irq_enable(ab, i);
7567f4beda2SGovind Singh 	}
7577f4beda2SGovind Singh }
7587f4beda2SGovind Singh 
7595697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
7605697a564SGovind Singh {
7615697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
7625697a564SGovind Singh 	struct msi_desc *msi_desc;
7635697a564SGovind Singh 	int num_vectors;
7645697a564SGovind Singh 	int ret;
7655697a564SGovind Singh 
7665697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
7675697a564SGovind Singh 					    msi_config.total_vectors,
7685697a564SGovind Singh 					    msi_config.total_vectors,
7695697a564SGovind Singh 					    PCI_IRQ_MSI);
7705697a564SGovind Singh 	if (num_vectors != msi_config.total_vectors) {
7715697a564SGovind Singh 		ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
7725697a564SGovind Singh 			   msi_config.total_vectors, num_vectors);
7735697a564SGovind Singh 
7745697a564SGovind Singh 		if (num_vectors >= 0)
7755697a564SGovind Singh 			return -EINVAL;
7765697a564SGovind Singh 		else
7775697a564SGovind Singh 			return num_vectors;
7785697a564SGovind Singh 	}
7795697a564SGovind Singh 
7805697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
7815697a564SGovind Singh 	if (!msi_desc) {
7825697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
7835697a564SGovind Singh 		ret = -EINVAL;
7845697a564SGovind Singh 		goto free_msi_vector;
7855697a564SGovind Singh 	}
7865697a564SGovind Singh 
7875697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
788e8e55d89SAnilkumar Kolli 	if (msi_desc->msi_attrib.is_64)
789e8e55d89SAnilkumar Kolli 		set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags);
7905697a564SGovind Singh 
7915697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
7925697a564SGovind Singh 
7935697a564SGovind Singh 	return 0;
7945697a564SGovind Singh 
7955697a564SGovind Singh free_msi_vector:
7965697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
7975697a564SGovind Singh 
7985697a564SGovind Singh 	return ret;
7995697a564SGovind Singh }
8005697a564SGovind Singh 
8015697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci)
8025697a564SGovind Singh {
8035697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
8045697a564SGovind Singh }
8055697a564SGovind Singh 
8065762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
8075762613eSGovind Singh {
8085762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
8095762613eSGovind Singh 	u16 device_id;
8105762613eSGovind Singh 	int ret = 0;
8115762613eSGovind Singh 
8125762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
8135762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
8145762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
8155762613eSGovind Singh 			   device_id, ab_pci->dev_id);
8165762613eSGovind Singh 		ret = -EIO;
8175762613eSGovind Singh 		goto out;
8185762613eSGovind Singh 	}
8195762613eSGovind Singh 
8205762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
8215762613eSGovind Singh 	if (ret) {
8225762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
8235762613eSGovind Singh 		goto out;
8245762613eSGovind Singh 	}
8255762613eSGovind Singh 
8265762613eSGovind Singh 	ret = pci_enable_device(pdev);
8275762613eSGovind Singh 	if (ret) {
8285762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
8295762613eSGovind Singh 		goto out;
8305762613eSGovind Singh 	}
8315762613eSGovind Singh 
8325762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
8335762613eSGovind Singh 	if (ret) {
8345762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
8355762613eSGovind Singh 		goto disable_device;
8365762613eSGovind Singh 	}
8375762613eSGovind Singh 
8385762613eSGovind Singh 	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
8395762613eSGovind Singh 	if (ret) {
8405762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
8415762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
8425762613eSGovind Singh 		goto release_region;
8435762613eSGovind Singh 	}
8445762613eSGovind Singh 
8455762613eSGovind Singh 	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
8465762613eSGovind Singh 	if (ret) {
8475762613eSGovind Singh 		ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n",
8485762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
8495762613eSGovind Singh 		goto release_region;
8505762613eSGovind Singh 	}
8515762613eSGovind Singh 
8525762613eSGovind Singh 	pci_set_master(pdev);
8535762613eSGovind Singh 
8545762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
8555762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
8565762613eSGovind Singh 	if (!ab->mem) {
8575762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
8585762613eSGovind Singh 		ret = -EIO;
8595762613eSGovind Singh 		goto clear_master;
8605762613eSGovind Singh 	}
8615762613eSGovind Singh 
8625762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
8635762613eSGovind Singh 	return 0;
8645762613eSGovind Singh 
8655762613eSGovind Singh clear_master:
8665762613eSGovind Singh 	pci_clear_master(pdev);
8675762613eSGovind Singh release_region:
8685762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
8695762613eSGovind Singh disable_device:
8705762613eSGovind Singh 	pci_disable_device(pdev);
8715762613eSGovind Singh out:
8725762613eSGovind Singh 	return ret;
8735762613eSGovind Singh }
8745762613eSGovind Singh 
8755762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
8765762613eSGovind Singh {
8775762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
8785762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
8795762613eSGovind Singh 
8805762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
8815762613eSGovind Singh 	ab->mem = NULL;
8825762613eSGovind Singh 	pci_clear_master(pci_dev);
8835762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
8845762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
8855762613eSGovind Singh 		pci_disable_device(pci_dev);
8865762613eSGovind Singh }
8875762613eSGovind Singh 
8881399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
8891399fb87SGovind Singh {
8901399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
8911399fb87SGovind Singh 	int ret;
8921399fb87SGovind Singh 
893a05bd851SCarl Huang 	ab_pci->register_window = 0;
894a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
895babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, true);
896f3c603d4SCarl Huang 
8971399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
8981399fb87SGovind Singh 	if (ret) {
8991399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
9001399fb87SGovind Singh 		return ret;
9011399fb87SGovind Singh 	}
9021399fb87SGovind Singh 
9031399fb87SGovind Singh 	return 0;
9041399fb87SGovind Singh }
9051399fb87SGovind Singh 
9061399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
9071399fb87SGovind Singh {
9081399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
9091399fb87SGovind Singh 
910babb0cedSCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
9111399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
912a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
913babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, false);
9141399fb87SGovind Singh }
9151399fb87SGovind Singh 
9162c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
9172c3960c2SGovind Singh {
9182c3960c2SGovind Singh 	int i;
9192c3960c2SGovind Singh 
920d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
9212c3960c2SGovind Singh 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
9222c3960c2SGovind Singh 
923e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
9242c3960c2SGovind Singh 			continue;
9252c3960c2SGovind Singh 
9262c3960c2SGovind Singh 		tasklet_kill(&ce_pipe->intr_tq);
9272c3960c2SGovind Singh 	}
9282c3960c2SGovind Singh }
9292c3960c2SGovind Singh 
9307f4beda2SGovind Singh static void ath11k_pci_stop(struct ath11k_base *ab)
9317f4beda2SGovind Singh {
9322c3960c2SGovind Singh 	ath11k_pci_ce_irqs_disable(ab);
9332c3960c2SGovind Singh 	ath11k_pci_sync_ce_irqs(ab);
9342c3960c2SGovind Singh 	ath11k_pci_kill_tasklets(ab);
9357f4beda2SGovind Singh 	ath11k_ce_cleanup_pipes(ab);
9367f4beda2SGovind Singh }
9377f4beda2SGovind Singh 
9387f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab)
9397f4beda2SGovind Singh {
940a05bd851SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
941a05bd851SCarl Huang 
942a05bd851SCarl Huang 	set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
943a05bd851SCarl Huang 
9447f4beda2SGovind Singh 	ath11k_pci_ce_irqs_enable(ab);
9452c3960c2SGovind Singh 	ath11k_ce_rx_post_buf(ab);
9462c3960c2SGovind Singh 
9472c3960c2SGovind Singh 	return 0;
9482c3960c2SGovind Singh }
9492c3960c2SGovind Singh 
9502c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
9512c3960c2SGovind Singh 					  u8 *ul_pipe, u8 *dl_pipe)
9522c3960c2SGovind Singh {
9532c3960c2SGovind Singh 	const struct service_to_pipe *entry;
9542c3960c2SGovind Singh 	bool ul_set = false, dl_set = false;
9552c3960c2SGovind Singh 	int i;
9562c3960c2SGovind Singh 
957967c1d11SAnilkumar Kolli 	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
958967c1d11SAnilkumar Kolli 		entry = &ab->hw_params.svc_to_ce_map[i];
9592c3960c2SGovind Singh 
9602c3960c2SGovind Singh 		if (__le32_to_cpu(entry->service_id) != service_id)
9612c3960c2SGovind Singh 			continue;
9622c3960c2SGovind Singh 
9632c3960c2SGovind Singh 		switch (__le32_to_cpu(entry->pipedir)) {
9642c3960c2SGovind Singh 		case PIPEDIR_NONE:
9652c3960c2SGovind Singh 			break;
9662c3960c2SGovind Singh 		case PIPEDIR_IN:
9672c3960c2SGovind Singh 			WARN_ON(dl_set);
9682c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
9692c3960c2SGovind Singh 			dl_set = true;
9702c3960c2SGovind Singh 			break;
9712c3960c2SGovind Singh 		case PIPEDIR_OUT:
9722c3960c2SGovind Singh 			WARN_ON(ul_set);
9732c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
9742c3960c2SGovind Singh 			ul_set = true;
9752c3960c2SGovind Singh 			break;
9762c3960c2SGovind Singh 		case PIPEDIR_INOUT:
9772c3960c2SGovind Singh 			WARN_ON(dl_set);
9782c3960c2SGovind Singh 			WARN_ON(ul_set);
9792c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
9802c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
9812c3960c2SGovind Singh 			dl_set = true;
9822c3960c2SGovind Singh 			ul_set = true;
9832c3960c2SGovind Singh 			break;
9842c3960c2SGovind Singh 		}
9852c3960c2SGovind Singh 	}
9862c3960c2SGovind Singh 
9872c3960c2SGovind Singh 	if (WARN_ON(!ul_set || !dl_set))
9882c3960c2SGovind Singh 		return -ENOENT;
9897f4beda2SGovind Singh 
9907f4beda2SGovind Singh 	return 0;
9917f4beda2SGovind Singh }
9927f4beda2SGovind Singh 
9937f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
9947f4beda2SGovind Singh 	.start = ath11k_pci_start,
9957f4beda2SGovind Singh 	.stop = ath11k_pci_stop,
996654e959aSGovind Singh 	.read32 = ath11k_pci_read32,
997654e959aSGovind Singh 	.write32 = ath11k_pci_write32,
9981399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
9991399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
1000d4ecb90bSCarl Huang 	.irq_enable = ath11k_pci_ext_irq_enable,
1001d4ecb90bSCarl Huang 	.irq_disable = ath11k_pci_ext_irq_disable,
1002c4eacabeSGovind Singh 	.get_msi_address =  ath11k_pci_get_msi_address,
1003c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
10042c3960c2SGovind Singh 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
10051399fb87SGovind Singh };
10061399fb87SGovind Singh 
10076e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
10086e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
10096e0355afSGovind Singh {
10106e0355afSGovind Singh 	struct ath11k_base *ab;
10115762613eSGovind Singh 	struct ath11k_pci *ab_pci;
101218ac1665SKalle Valo 	u32 soc_hw_version, soc_hw_version_major, soc_hw_version_minor;
10135762613eSGovind Singh 	int ret;
10146e0355afSGovind Singh 
10156e0355afSGovind Singh 	dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n");
10166e0355afSGovind Singh 
10171ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
10181ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
10196e0355afSGovind Singh 	if (!ab) {
10206e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
10216e0355afSGovind Singh 		return -ENOMEM;
10226e0355afSGovind Singh 	}
10236e0355afSGovind Singh 
10246e0355afSGovind Singh 	ab->dev = &pdev->dev;
10256e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
10265762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
10275762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
10285762613eSGovind Singh 	ab_pci->ab = ab;
10295697a564SGovind Singh 	ab_pci->pdev = pdev;
10307f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
10315762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
1032654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
10335762613eSGovind Singh 
10345762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
10355762613eSGovind Singh 	if (ret) {
10365762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
10375762613eSGovind Singh 		goto err_free_core;
10385762613eSGovind Singh 	}
10396e0355afSGovind Singh 
104018ac1665SKalle Valo 	switch (pci_dev->device) {
104118ac1665SKalle Valo 	case QCA6390_DEVICE_ID:
104218ac1665SKalle Valo 		soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION);
104318ac1665SKalle Valo 		soc_hw_version_major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
104418ac1665SKalle Valo 						 soc_hw_version);
104518ac1665SKalle Valo 		soc_hw_version_minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
104618ac1665SKalle Valo 						 soc_hw_version);
104718ac1665SKalle Valo 
104818ac1665SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
104918ac1665SKalle Valo 			   soc_hw_version_major, soc_hw_version_minor);
105018ac1665SKalle Valo 
105118ac1665SKalle Valo 		switch (soc_hw_version_major) {
105218ac1665SKalle Valo 		case 2:
105318ac1665SKalle Valo 			ab->hw_rev = ATH11K_HW_QCA6390_HW20;
105418ac1665SKalle Valo 			break;
105518ac1665SKalle Valo 		default:
105618ac1665SKalle Valo 			dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n",
105718ac1665SKalle Valo 				soc_hw_version_major, soc_hw_version_minor);
105818ac1665SKalle Valo 			ret = -EOPNOTSUPP;
105918ac1665SKalle Valo 			goto err_pci_free_region;
106018ac1665SKalle Valo 		}
106118ac1665SKalle Valo 		break;
106218ac1665SKalle Valo 	default:
106318ac1665SKalle Valo 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
106418ac1665SKalle Valo 			pci_dev->device);
106518ac1665SKalle Valo 		ret = -EOPNOTSUPP;
106618ac1665SKalle Valo 		goto err_pci_free_region;
106718ac1665SKalle Valo 	}
106818ac1665SKalle Valo 
10695697a564SGovind Singh 	ret = ath11k_pci_enable_msi(ab_pci);
10705697a564SGovind Singh 	if (ret) {
10715697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
10725697a564SGovind Singh 		goto err_pci_free_region;
10735697a564SGovind Singh 	}
10745697a564SGovind Singh 
1075b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
1076b8246f88SKalle Valo 	if (ret)
1077b8246f88SKalle Valo 		goto err_pci_disable_msi;
1078b8246f88SKalle Valo 
10791399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
10801399fb87SGovind Singh 	if (ret) {
10811399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
10821399fb87SGovind Singh 		goto err_pci_disable_msi;
10831399fb87SGovind Singh 	}
10841399fb87SGovind Singh 
10857f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
10867f4beda2SGovind Singh 	if (ret)
10877f4beda2SGovind Singh 		goto err_mhi_unregister;
10887f4beda2SGovind Singh 
10897f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
10907f4beda2SGovind Singh 	if (ret) {
10917f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
10927f4beda2SGovind Singh 		goto err_hal_srng_deinit;
10937f4beda2SGovind Singh 	}
10947f4beda2SGovind Singh 
10957f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
10967f4beda2SGovind Singh 
10977f4beda2SGovind Singh 	ret = ath11k_pci_config_irq(ab);
10987f4beda2SGovind Singh 	if (ret) {
10997f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
11007f4beda2SGovind Singh 		goto err_ce_free;
11017f4beda2SGovind Singh 	}
11027f4beda2SGovind Singh 
11037f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
11047f4beda2SGovind Singh 	if (ret) {
11057f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
11067f4beda2SGovind Singh 		goto err_free_irq;
11077f4beda2SGovind Singh 	}
11086e0355afSGovind Singh 	return 0;
11095762613eSGovind Singh 
11107f4beda2SGovind Singh err_free_irq:
11117f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
11127f4beda2SGovind Singh 
11137f4beda2SGovind Singh err_ce_free:
11147f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
11157f4beda2SGovind Singh 
11167f4beda2SGovind Singh err_hal_srng_deinit:
11177f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
11187f4beda2SGovind Singh 
11197f4beda2SGovind Singh err_mhi_unregister:
11207f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
11217f4beda2SGovind Singh 
1122b8246f88SKalle Valo err_pci_disable_msi:
1123b8246f88SKalle Valo 	ath11k_pci_disable_msi(ab_pci);
1124b8246f88SKalle Valo 
11255697a564SGovind Singh err_pci_free_region:
11265697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
11275697a564SGovind Singh 
11285762613eSGovind Singh err_free_core:
11295762613eSGovind Singh 	ath11k_core_free(ab);
11305697a564SGovind Singh 
11315762613eSGovind Singh 	return ret;
11326e0355afSGovind Singh }
11336e0355afSGovind Singh 
11346e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
11356e0355afSGovind Singh {
11366e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
11375762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
11386e0355afSGovind Singh 
113961a57e51SAnilkumar Kolli 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
114061a57e51SAnilkumar Kolli 		ath11k_pci_power_down(ab);
114161a57e51SAnilkumar Kolli 		ath11k_debugfs_soc_destroy(ab);
114261a57e51SAnilkumar Kolli 		ath11k_qmi_deinit_service(ab);
114361a57e51SAnilkumar Kolli 		goto qmi_fail;
114461a57e51SAnilkumar Kolli 	}
114561a57e51SAnilkumar Kolli 
11466e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
11476fbd8898SCarl Huang 
11486fbd8898SCarl Huang 	ath11k_core_deinit(ab);
11496fbd8898SCarl Huang 
115061a57e51SAnilkumar Kolli qmi_fail:
11511399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
11526fbd8898SCarl Huang 
11536fbd8898SCarl Huang 	ath11k_pci_free_irq(ab);
11545697a564SGovind Singh 	ath11k_pci_disable_msi(ab_pci);
11555762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
11566fbd8898SCarl Huang 
11576fbd8898SCarl Huang 	ath11k_hal_srng_deinit(ab);
11586fbd8898SCarl Huang 	ath11k_ce_free_pipes(ab);
11596e0355afSGovind Singh 	ath11k_core_free(ab);
11606e0355afSGovind Singh }
11616e0355afSGovind Singh 
11621399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
11631399fb87SGovind Singh {
11641399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
11651399fb87SGovind Singh 
11661399fb87SGovind Singh 	ath11k_pci_power_down(ab);
11671399fb87SGovind Singh }
11681399fb87SGovind Singh 
11696e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
11706e0355afSGovind Singh 	.name = "ath11k_pci",
11716e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
11726e0355afSGovind Singh 	.probe = ath11k_pci_probe,
11736e0355afSGovind Singh 	.remove = ath11k_pci_remove,
11741399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
11756e0355afSGovind Singh };
11766e0355afSGovind Singh 
11776e0355afSGovind Singh static int ath11k_pci_init(void)
11786e0355afSGovind Singh {
11796e0355afSGovind Singh 	int ret;
11806e0355afSGovind Singh 
11816e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
11826e0355afSGovind Singh 	if (ret)
11836e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
11846e0355afSGovind Singh 		       ret);
11856e0355afSGovind Singh 
11866e0355afSGovind Singh 	return ret;
11876e0355afSGovind Singh }
11886e0355afSGovind Singh module_init(ath11k_pci_init);
11896e0355afSGovind Singh 
11906e0355afSGovind Singh static void ath11k_pci_exit(void)
11916e0355afSGovind Singh {
11926e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
11936e0355afSGovind Singh }
11946e0355afSGovind Singh 
11956e0355afSGovind Singh module_exit(ath11k_pci_exit);
11966e0355afSGovind Singh 
11976e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
11986e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
11993dbd7fe7SDevin Bayer 
12003dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */
12013dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE);
12023dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE);
12033dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE);
1204