xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision e9603f4bdcc04417f1c7b3585e63654819dc11f6)
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);
129f6fa37a4SCarl Huang 		ioread32(ab->mem + WINDOW_REG_ADDRESS);
130654e959aSGovind Singh 		ab_pci->register_window = window;
131654e959aSGovind Singh 	}
132654e959aSGovind Singh }
133654e959aSGovind Singh 
134f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
135654e959aSGovind Singh {
136654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
137654e959aSGovind Singh 
138a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
139a05bd851SCarl Huang 	 * need to wakeup MHI to access.
140a05bd851SCarl Huang 	 */
141a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
142a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
143a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
144a05bd851SCarl Huang 
145654e959aSGovind Singh 	if (offset < WINDOW_START) {
146654e959aSGovind Singh 		iowrite32(value, ab->mem  + offset);
147654e959aSGovind Singh 	} else {
148654e959aSGovind Singh 		spin_lock_bh(&ab_pci->window_lock);
149654e959aSGovind Singh 		ath11k_pci_select_window(ab_pci, offset);
150654e959aSGovind Singh 		iowrite32(value, ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK));
151654e959aSGovind Singh 		spin_unlock_bh(&ab_pci->window_lock);
152654e959aSGovind Singh 	}
153a05bd851SCarl Huang 
154a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
155a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
156a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
157654e959aSGovind Singh }
158654e959aSGovind Singh 
159f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
160654e959aSGovind Singh {
161654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
162654e959aSGovind Singh 	u32 val;
163654e959aSGovind Singh 
164a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
165a05bd851SCarl Huang 	 * need to wakeup MHI to access.
166a05bd851SCarl Huang 	 */
167a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
168a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
169a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
170a05bd851SCarl Huang 
171654e959aSGovind Singh 	if (offset < WINDOW_START) {
172654e959aSGovind Singh 		val = ioread32(ab->mem + offset);
173654e959aSGovind Singh 	} else {
174654e959aSGovind Singh 		spin_lock_bh(&ab_pci->window_lock);
175654e959aSGovind Singh 		ath11k_pci_select_window(ab_pci, offset);
176654e959aSGovind Singh 		val = ioread32(ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK));
177654e959aSGovind Singh 		spin_unlock_bh(&ab_pci->window_lock);
178654e959aSGovind Singh 	}
179654e959aSGovind Singh 
180a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
181a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
182a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
183a05bd851SCarl Huang 
184654e959aSGovind Singh 	return val;
185654e959aSGovind Singh }
186654e959aSGovind Singh 
187f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
188f3c603d4SCarl Huang {
189f3c603d4SCarl Huang 	u32 val, delay;
190f3c603d4SCarl Huang 
191f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
192f3c603d4SCarl Huang 
193f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
194f3c603d4SCarl Huang 
195f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
196f3c603d4SCarl Huang 
197f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
198f3c603d4SCarl Huang 	delay = 10;
199f3c603d4SCarl Huang 	mdelay(delay);
200f3c603d4SCarl Huang 
201f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
202f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
203f3c603d4SCarl Huang 
204f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
205f3c603d4SCarl Huang 
206f3c603d4SCarl Huang 	mdelay(delay);
207f3c603d4SCarl Huang 
208f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
209f3c603d4SCarl Huang 	if (val == 0xffffffff)
210f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
211f3c603d4SCarl Huang }
212f3c603d4SCarl Huang 
213f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
214f3c603d4SCarl Huang {
215f3c603d4SCarl Huang 	u32 val;
216f3c603d4SCarl Huang 
217f3c603d4SCarl Huang 	/* read cookie */
218f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR);
219f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val);
220f3c603d4SCarl Huang 
221f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
222f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
223f3c603d4SCarl Huang 
224f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
225f3c603d4SCarl Huang 	mdelay(10);
226f3c603d4SCarl Huang 
227f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
228f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
229f3c603d4SCarl Huang 	 */
230f3c603d4SCarl Huang 	ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0);
231f3c603d4SCarl Huang 	mdelay(10);
232f3c603d4SCarl Huang 
233f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
234f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
235f3c603d4SCarl Huang 
236f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
237f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
238f3c603d4SCarl Huang 	 */
239f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
240f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
241f3c603d4SCarl Huang }
242f3c603d4SCarl Huang 
24306999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab,
24406999407SCarl Huang 				   u32 offset, u32 value, u32 mask)
24506999407SCarl Huang {
24606999407SCarl Huang 	u32 v;
24706999407SCarl Huang 	int i;
24806999407SCarl Huang 
24906999407SCarl Huang 	v = ath11k_pci_read32(ab, offset);
25006999407SCarl Huang 	if ((v & mask) == value)
25106999407SCarl Huang 		return 0;
25206999407SCarl Huang 
25306999407SCarl Huang 	for (i = 0; i < 10; i++) {
25406999407SCarl Huang 		ath11k_pci_write32(ab, offset, (v & ~mask) | value);
25506999407SCarl Huang 
25606999407SCarl Huang 		v = ath11k_pci_read32(ab, offset);
25706999407SCarl Huang 		if ((v & mask) == value)
25806999407SCarl Huang 			return 0;
25906999407SCarl Huang 
26006999407SCarl Huang 		mdelay(2);
26106999407SCarl Huang 	}
26206999407SCarl Huang 
26306999407SCarl Huang 	ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n",
26406999407SCarl Huang 		    offset, v & mask, value);
26506999407SCarl Huang 
26606999407SCarl Huang 	return -ETIMEDOUT;
26706999407SCarl Huang }
26806999407SCarl Huang 
26906999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
27006999407SCarl Huang {
27106999407SCarl Huang 	int ret;
27206999407SCarl Huang 
27306999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
27406999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG,
27506999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL,
27606999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK);
27730d08503SDan Carpenter 	if (ret) {
27806999407SCarl Huang 		ath11k_warn(ab, "failed to set sysclk: %d\n", ret);
27906999407SCarl Huang 		return ret;
28006999407SCarl Huang 	}
28106999407SCarl Huang 
28206999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
28306999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_REG,
28406999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_VAL,
28506999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK);
28630d08503SDan Carpenter 	if (ret) {
28706999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret);
28806999407SCarl Huang 		return ret;
28906999407SCarl Huang 	}
29006999407SCarl Huang 
29106999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
29206999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_REG,
29306999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_VAL,
29406999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK);
29530d08503SDan Carpenter 	if (ret) {
29606999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config2: %d\n", ret);
29706999407SCarl Huang 		return ret;
29806999407SCarl Huang 	}
29906999407SCarl Huang 
30006999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
30106999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_REG,
30206999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_VAL,
30306999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK);
30430d08503SDan Carpenter 	if (ret) {
30506999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config4: %d\n", ret);
30606999407SCarl Huang 		return ret;
30706999407SCarl Huang 	}
30806999407SCarl Huang 
30906999407SCarl Huang 	return 0;
31006999407SCarl Huang }
31106999407SCarl Huang 
312babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
313babb0cedSCarl Huang {
314babb0cedSCarl Huang 	u32 val;
315babb0cedSCarl Huang 	int i;
316babb0cedSCarl Huang 
317babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
318babb0cedSCarl Huang 
319babb0cedSCarl Huang 	/* PCIE link seems very unstable after the Hot Reset*/
320babb0cedSCarl Huang 	for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {
321babb0cedSCarl Huang 		if (val == 0xffffffff)
322babb0cedSCarl Huang 			mdelay(5);
323babb0cedSCarl Huang 
324babb0cedSCarl Huang 		ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
325babb0cedSCarl Huang 		val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
326babb0cedSCarl Huang 	}
327babb0cedSCarl Huang 
328babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val);
329babb0cedSCarl Huang 
330babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
331babb0cedSCarl Huang 	val |= GCC_GCC_PCIE_HOT_RST_VAL | 0x10;
332babb0cedSCarl Huang 	ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
333babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
334babb0cedSCarl Huang 
335babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val);
336babb0cedSCarl Huang 
337babb0cedSCarl Huang 	mdelay(5);
338babb0cedSCarl Huang }
339babb0cedSCarl Huang 
340babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
341babb0cedSCarl Huang {
342babb0cedSCarl Huang 	/* This is a WAR for PCIE Hotreset.
343babb0cedSCarl Huang 	 * When target receive Hotreset, but will set the interrupt.
344babb0cedSCarl Huang 	 * So when download SBL again, SBL will open Interrupt and
345babb0cedSCarl Huang 	 * receive it, and crash immediately.
346babb0cedSCarl Huang 	 */
347babb0cedSCarl Huang 	ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
348babb0cedSCarl Huang }
349babb0cedSCarl Huang 
3500ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab)
3510ccdf439SCarl Huang {
3520ccdf439SCarl Huang 	u32 val;
3530ccdf439SCarl Huang 
3540ccdf439SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG);
3550ccdf439SCarl Huang 	val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK;
3560ccdf439SCarl Huang 	ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val);
3570ccdf439SCarl Huang }
3580ccdf439SCarl Huang 
359f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
360f3c603d4SCarl Huang {
361f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
362f3c603d4SCarl Huang 	mdelay(5);
363f3c603d4SCarl Huang }
364f3c603d4SCarl Huang 
365babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
366f3c603d4SCarl Huang {
367babb0cedSCarl Huang 	if (power_on) {
368babb0cedSCarl Huang 		ath11k_pci_enable_ltssm(ab);
369babb0cedSCarl Huang 		ath11k_pci_clear_all_intrs(ab);
3700ccdf439SCarl Huang 		ath11k_pci_set_wlaon_pwr_ctrl(ab);
37106999407SCarl Huang 		ath11k_pci_fix_l1ss(ab);
372babb0cedSCarl Huang 	}
373babb0cedSCarl Huang 
374f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
375f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
376f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
377f3c603d4SCarl Huang 	ath11k_pci_clear_dbg_registers(ab);
378f3c603d4SCarl Huang }
379f3c603d4SCarl Huang 
3801399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
3811399fb87SGovind Singh {
3821399fb87SGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(dev);
3831399fb87SGovind Singh 
3841399fb87SGovind Singh 	return pci_irq_vector(pci_dev, vector);
3851399fb87SGovind Singh }
3861399fb87SGovind Singh 
387c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
388c4eacabeSGovind Singh 				       u32 *msi_addr_hi)
389c4eacabeSGovind Singh {
390e8e55d89SAnilkumar Kolli 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
391c4eacabeSGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
392c4eacabeSGovind Singh 
393c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
394c4eacabeSGovind Singh 			      msi_addr_lo);
395c4eacabeSGovind Singh 
396e8e55d89SAnilkumar Kolli 	if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) {
397c4eacabeSGovind Singh 		pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
398c4eacabeSGovind Singh 				      msi_addr_hi);
399e8e55d89SAnilkumar Kolli 	} else {
400e8e55d89SAnilkumar Kolli 		*msi_addr_hi = 0;
401e8e55d89SAnilkumar Kolli 	}
402c4eacabeSGovind Singh }
403c4eacabeSGovind Singh 
4041399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
4051399fb87SGovind Singh 				       int *num_vectors, u32 *user_base_data,
4061399fb87SGovind Singh 				       u32 *base_vector)
4071399fb87SGovind Singh {
4081399fb87SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4091399fb87SGovind Singh 	int idx;
4101399fb87SGovind Singh 
4111399fb87SGovind Singh 	for (idx = 0; idx < msi_config.total_users; idx++) {
4121399fb87SGovind Singh 		if (strcmp(user_name, msi_config.users[idx].name) == 0) {
4131399fb87SGovind Singh 			*num_vectors = msi_config.users[idx].num_vectors;
4141399fb87SGovind Singh 			*user_base_data = msi_config.users[idx].base_vector
4151399fb87SGovind Singh 				+ ab_pci->msi_ep_base_data;
4161399fb87SGovind Singh 			*base_vector = msi_config.users[idx].base_vector;
4171399fb87SGovind Singh 
4181399fb87SGovind Singh 			ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
4191399fb87SGovind Singh 				   user_name, *num_vectors, *user_base_data,
4201399fb87SGovind Singh 				   *base_vector);
4211399fb87SGovind Singh 
4221399fb87SGovind Singh 			return 0;
4231399fb87SGovind Singh 		}
4241399fb87SGovind Singh 	}
4251399fb87SGovind Singh 
4261399fb87SGovind Singh 	ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
4271399fb87SGovind Singh 
4281399fb87SGovind Singh 	return -EINVAL;
4291399fb87SGovind Singh }
4301399fb87SGovind Singh 
431c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
432c4eacabeSGovind Singh 					  int *num_vectors, u32 *user_base_data,
433c4eacabeSGovind Singh 					  u32 *base_vector)
434c4eacabeSGovind Singh {
435c4eacabeSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
436c4eacabeSGovind Singh 
437c4eacabeSGovind Singh 	return ath11k_pci_get_user_msi_assignment(ab_pci, user_name,
438c4eacabeSGovind Singh 						  num_vectors, user_base_data,
439c4eacabeSGovind Singh 						  base_vector);
440c4eacabeSGovind Singh }
441c4eacabeSGovind Singh 
442d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
443d4ecb90bSCarl Huang {
444d4ecb90bSCarl Huang 	int i, j;
445d4ecb90bSCarl Huang 
446d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
447d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
448d4ecb90bSCarl Huang 
449d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++)
450d4ecb90bSCarl Huang 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
451d4ecb90bSCarl Huang 
452d4ecb90bSCarl Huang 		netif_napi_del(&irq_grp->napi);
453d4ecb90bSCarl Huang 	}
454d4ecb90bSCarl Huang }
455d4ecb90bSCarl Huang 
4567f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab)
4577f4beda2SGovind Singh {
4587f4beda2SGovind Singh 	int i, irq_idx;
4597f4beda2SGovind Singh 
460d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
461e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
4627f4beda2SGovind Singh 			continue;
4637f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
4647f4beda2SGovind Singh 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
4657f4beda2SGovind Singh 	}
466d4ecb90bSCarl Huang 
467d4ecb90bSCarl Huang 	ath11k_pci_free_ext_irq(ab);
4687f4beda2SGovind Singh }
4697f4beda2SGovind Singh 
4702c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
4712c3960c2SGovind Singh {
4722c3960c2SGovind Singh 	u32 irq_idx;
4732c3960c2SGovind Singh 
4742c3960c2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
4752c3960c2SGovind Singh 	enable_irq(ab->irq_num[irq_idx]);
4762c3960c2SGovind Singh }
4772c3960c2SGovind Singh 
4787f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
4797f4beda2SGovind Singh {
4807f4beda2SGovind Singh 	u32 irq_idx;
4817f4beda2SGovind Singh 
4827f4beda2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
4837f4beda2SGovind Singh 	disable_irq_nosync(ab->irq_num[irq_idx]);
4847f4beda2SGovind Singh }
4857f4beda2SGovind Singh 
4862c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
4872c3960c2SGovind Singh {
4882c3960c2SGovind Singh 	int i;
4892c3960c2SGovind Singh 
490d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
491e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
4922c3960c2SGovind Singh 			continue;
4932c3960c2SGovind Singh 		ath11k_pci_ce_irq_disable(ab, i);
4942c3960c2SGovind Singh 	}
4952c3960c2SGovind Singh }
4962c3960c2SGovind Singh 
4972c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
4982c3960c2SGovind Singh {
4992c3960c2SGovind Singh 	int i;
5002c3960c2SGovind Singh 	int irq_idx;
5012c3960c2SGovind Singh 
502d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
503e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5042c3960c2SGovind Singh 			continue;
5052c3960c2SGovind Singh 
5062c3960c2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5072c3960c2SGovind Singh 		synchronize_irq(ab->irq_num[irq_idx]);
5082c3960c2SGovind Singh 	}
5092c3960c2SGovind Singh }
5102c3960c2SGovind Singh 
5110f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
5122c3960c2SGovind Singh {
5130f01dcb8SAllen Pais 	struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
5142c3960c2SGovind Singh 
5152c3960c2SGovind Singh 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
5162c3960c2SGovind Singh 
5172c3960c2SGovind Singh 	ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
5182c3960c2SGovind Singh }
5192c3960c2SGovind Singh 
5207f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
5217f4beda2SGovind Singh {
5227f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = arg;
5237f4beda2SGovind Singh 
5247f4beda2SGovind Singh 	ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
5252c3960c2SGovind Singh 	tasklet_schedule(&ce_pipe->intr_tq);
5267f4beda2SGovind Singh 
5277f4beda2SGovind Singh 	return IRQ_HANDLED;
5287f4beda2SGovind Singh }
5297f4beda2SGovind Singh 
530d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
531d4ecb90bSCarl Huang {
532d4ecb90bSCarl Huang 	int i;
533d4ecb90bSCarl Huang 
534d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
535d4ecb90bSCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
536d4ecb90bSCarl Huang }
537d4ecb90bSCarl Huang 
538d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
539d4ecb90bSCarl Huang {
540d4ecb90bSCarl Huang 	int i;
541d4ecb90bSCarl Huang 
542d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
543d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
544d4ecb90bSCarl Huang 
545d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
546d4ecb90bSCarl Huang 
547d4ecb90bSCarl Huang 		napi_synchronize(&irq_grp->napi);
548d4ecb90bSCarl Huang 		napi_disable(&irq_grp->napi);
549d4ecb90bSCarl Huang 	}
550d4ecb90bSCarl Huang }
551d4ecb90bSCarl Huang 
552d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
553d4ecb90bSCarl Huang {
554d4ecb90bSCarl Huang 	int i;
555d4ecb90bSCarl Huang 
556d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
557d4ecb90bSCarl Huang 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
558d4ecb90bSCarl Huang }
559d4ecb90bSCarl Huang 
560d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
561d4ecb90bSCarl Huang {
562d4ecb90bSCarl Huang 	int i;
563d4ecb90bSCarl Huang 
564d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
565d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
566d4ecb90bSCarl Huang 
567d4ecb90bSCarl Huang 		napi_enable(&irq_grp->napi);
568d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
569d4ecb90bSCarl Huang 	}
570d4ecb90bSCarl Huang }
571d4ecb90bSCarl Huang 
572d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
573d4ecb90bSCarl Huang {
574d4ecb90bSCarl Huang 	int i, j, irq_idx;
575d4ecb90bSCarl Huang 
576d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
577d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
578d4ecb90bSCarl Huang 
579d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
580d4ecb90bSCarl Huang 			irq_idx = irq_grp->irqs[j];
581d4ecb90bSCarl Huang 			synchronize_irq(ab->irq_num[irq_idx]);
582d4ecb90bSCarl Huang 		}
583d4ecb90bSCarl Huang 	}
584d4ecb90bSCarl Huang }
585d4ecb90bSCarl Huang 
586d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
587d4ecb90bSCarl Huang {
588d4ecb90bSCarl Huang 	__ath11k_pci_ext_irq_disable(ab);
589d4ecb90bSCarl Huang 	ath11k_pci_sync_ext_irqs(ab);
590d4ecb90bSCarl Huang }
591d4ecb90bSCarl Huang 
592d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
593d4ecb90bSCarl Huang {
594d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
595d4ecb90bSCarl Huang 						struct ath11k_ext_irq_grp,
596d4ecb90bSCarl Huang 						napi);
597d4ecb90bSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
598d4ecb90bSCarl Huang 	int work_done;
599d4ecb90bSCarl Huang 
600d4ecb90bSCarl Huang 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
601d4ecb90bSCarl Huang 	if (work_done < budget) {
602d4ecb90bSCarl Huang 		napi_complete_done(napi, work_done);
603d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
604d4ecb90bSCarl Huang 	}
605d4ecb90bSCarl Huang 
606d4ecb90bSCarl Huang 	if (work_done > budget)
607d4ecb90bSCarl Huang 		work_done = budget;
608d4ecb90bSCarl Huang 
609d4ecb90bSCarl Huang 	return work_done;
610d4ecb90bSCarl Huang }
611d4ecb90bSCarl Huang 
612d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
613d4ecb90bSCarl Huang {
614d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = arg;
615d4ecb90bSCarl Huang 
616d4ecb90bSCarl Huang 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
617d4ecb90bSCarl Huang 
618d4ecb90bSCarl Huang 	ath11k_pci_ext_grp_disable(irq_grp);
619d4ecb90bSCarl Huang 
620d4ecb90bSCarl Huang 	napi_schedule(&irq_grp->napi);
621d4ecb90bSCarl Huang 
622d4ecb90bSCarl Huang 	return IRQ_HANDLED;
623d4ecb90bSCarl Huang }
624d4ecb90bSCarl Huang 
625d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
626d4ecb90bSCarl Huang {
627d4ecb90bSCarl Huang 	int i, j, ret, num_vectors = 0;
628d4ecb90bSCarl Huang 	u32 user_base_data = 0, base_vector = 0;
629d4ecb90bSCarl Huang 
630b2c09458SColin Ian King 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
631b2c09458SColin Ian King 						 &num_vectors,
632b2c09458SColin Ian King 						 &user_base_data,
633d4ecb90bSCarl Huang 						 &base_vector);
634b2c09458SColin Ian King 	if (ret < 0)
635b2c09458SColin Ian King 		return ret;
636d4ecb90bSCarl Huang 
637d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
638d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
639d4ecb90bSCarl Huang 		u32 num_irq = 0;
640d4ecb90bSCarl Huang 
641d4ecb90bSCarl Huang 		irq_grp->ab = ab;
642d4ecb90bSCarl Huang 		irq_grp->grp_id = i;
643d4ecb90bSCarl Huang 		init_dummy_netdev(&irq_grp->napi_ndev);
644d4ecb90bSCarl Huang 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
645d4ecb90bSCarl Huang 			       ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
646d4ecb90bSCarl Huang 
647d4ecb90bSCarl Huang 		if (ab->hw_params.ring_mask->tx[i] ||
648d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx[i] ||
649d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_err[i] ||
650d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_wbm_rel[i] ||
651d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->reo_status[i] ||
652d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rxdma2host[i] ||
653d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->host2rxdma[i] ||
654d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_mon_status[i]) {
655d4ecb90bSCarl Huang 			num_irq = 1;
656d4ecb90bSCarl Huang 		}
657d4ecb90bSCarl Huang 
658d4ecb90bSCarl Huang 		irq_grp->num_irq = num_irq;
659d4ecb90bSCarl Huang 		irq_grp->irqs[0] = base_vector + i;
660d4ecb90bSCarl Huang 
661d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
662d4ecb90bSCarl Huang 			int irq_idx = irq_grp->irqs[j];
663d4ecb90bSCarl Huang 			int vector = (i % num_vectors) + base_vector;
664d4ecb90bSCarl Huang 			int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
665d4ecb90bSCarl Huang 
666d4ecb90bSCarl Huang 			ab->irq_num[irq_idx] = irq;
667d4ecb90bSCarl Huang 
668d4ecb90bSCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
669d4ecb90bSCarl Huang 				   "irq:%d group:%d\n", irq, i);
670d4ecb90bSCarl Huang 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
671d4ecb90bSCarl Huang 					  IRQF_SHARED,
672d4ecb90bSCarl Huang 					  "DP_EXT_IRQ", irq_grp);
673d4ecb90bSCarl Huang 			if (ret) {
674d4ecb90bSCarl Huang 				ath11k_err(ab, "failed request irq %d: %d\n",
675d4ecb90bSCarl Huang 					   vector, ret);
676d4ecb90bSCarl Huang 				return ret;
677d4ecb90bSCarl Huang 			}
678d4ecb90bSCarl Huang 
679d4ecb90bSCarl Huang 			disable_irq_nosync(ab->irq_num[irq_idx]);
680d4ecb90bSCarl Huang 		}
681d4ecb90bSCarl Huang 	}
682d4ecb90bSCarl Huang 
683d4ecb90bSCarl Huang 	return 0;
684d4ecb90bSCarl Huang }
685d4ecb90bSCarl Huang 
6867f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab)
6877f4beda2SGovind Singh {
6887f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe;
6897f4beda2SGovind Singh 	u32 msi_data_start;
6907f4beda2SGovind Singh 	u32 msi_data_count;
6917f4beda2SGovind Singh 	u32 msi_irq_start;
6927f4beda2SGovind Singh 	unsigned int msi_data;
6937f4beda2SGovind Singh 	int irq, i, ret, irq_idx;
6947f4beda2SGovind Singh 
6957f4beda2SGovind Singh 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab),
6967f4beda2SGovind Singh 						 "CE", &msi_data_count,
6977f4beda2SGovind Singh 						 &msi_data_start, &msi_irq_start);
6987f4beda2SGovind Singh 	if (ret)
6997f4beda2SGovind Singh 		return ret;
7007f4beda2SGovind Singh 
7017f4beda2SGovind Singh 	/* Configure CE irqs */
702d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
7037f4beda2SGovind Singh 		msi_data = (i % msi_data_count) + msi_irq_start;
7047f4beda2SGovind Singh 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
7057f4beda2SGovind Singh 		ce_pipe = &ab->ce.ce_pipe[i];
7067f4beda2SGovind Singh 
707e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
7087f4beda2SGovind Singh 			continue;
7097f4beda2SGovind Singh 
7107f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
7117f4beda2SGovind Singh 
7120f01dcb8SAllen Pais 		tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
7132c3960c2SGovind Singh 
7147f4beda2SGovind Singh 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
7157f4beda2SGovind Singh 				  IRQF_SHARED, irq_name[irq_idx],
7167f4beda2SGovind Singh 				  ce_pipe);
7177f4beda2SGovind Singh 		if (ret) {
7187f4beda2SGovind Singh 			ath11k_err(ab, "failed to request irq %d: %d\n",
7197f4beda2SGovind Singh 				   irq_idx, ret);
7207f4beda2SGovind Singh 			return ret;
7217f4beda2SGovind Singh 		}
7227f4beda2SGovind Singh 
7237f4beda2SGovind Singh 		ab->irq_num[irq_idx] = irq;
724e5c860e1SCarl Huang 		ath11k_pci_ce_irq_disable(ab, i);
7257f4beda2SGovind Singh 	}
7267f4beda2SGovind Singh 
727d4ecb90bSCarl Huang 	ret = ath11k_pci_ext_irq_config(ab);
728d4ecb90bSCarl Huang 	if (ret)
729d4ecb90bSCarl Huang 		return ret;
730d4ecb90bSCarl Huang 
7317f4beda2SGovind Singh 	return 0;
7327f4beda2SGovind Singh }
7337f4beda2SGovind Singh 
7347f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
7357f4beda2SGovind Singh {
7367f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
7377f4beda2SGovind Singh 
738967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
739967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
7407f4beda2SGovind Singh 
741967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
742967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
743eb8de049SGovind Singh 	ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390;
744e838c14aSCarl Huang 
745e838c14aSCarl Huang 	ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
746e838c14aSCarl Huang 				    &cfg->shadow_reg_v2_len);
7477f4beda2SGovind Singh }
7487f4beda2SGovind Singh 
7497f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
7507f4beda2SGovind Singh {
7517f4beda2SGovind Singh 	int i;
7527f4beda2SGovind Singh 
753d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
754e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
7557f4beda2SGovind Singh 			continue;
7567f4beda2SGovind Singh 		ath11k_pci_ce_irq_enable(ab, i);
7577f4beda2SGovind Singh 	}
7587f4beda2SGovind Singh }
7597f4beda2SGovind Singh 
7605697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
7615697a564SGovind Singh {
7625697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
7635697a564SGovind Singh 	struct msi_desc *msi_desc;
7645697a564SGovind Singh 	int num_vectors;
7655697a564SGovind Singh 	int ret;
7665697a564SGovind Singh 
7675697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
7685697a564SGovind Singh 					    msi_config.total_vectors,
7695697a564SGovind Singh 					    msi_config.total_vectors,
7705697a564SGovind Singh 					    PCI_IRQ_MSI);
7715697a564SGovind Singh 	if (num_vectors != msi_config.total_vectors) {
7725697a564SGovind Singh 		ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
7735697a564SGovind Singh 			   msi_config.total_vectors, num_vectors);
7745697a564SGovind Singh 
7755697a564SGovind Singh 		if (num_vectors >= 0)
7765697a564SGovind Singh 			return -EINVAL;
7775697a564SGovind Singh 		else
7785697a564SGovind Singh 			return num_vectors;
7795697a564SGovind Singh 	}
7805697a564SGovind Singh 
7815697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
7825697a564SGovind Singh 	if (!msi_desc) {
7835697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
7845697a564SGovind Singh 		ret = -EINVAL;
7855697a564SGovind Singh 		goto free_msi_vector;
7865697a564SGovind Singh 	}
7875697a564SGovind Singh 
7885697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
789e8e55d89SAnilkumar Kolli 	if (msi_desc->msi_attrib.is_64)
790e8e55d89SAnilkumar Kolli 		set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags);
7915697a564SGovind Singh 
7925697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
7935697a564SGovind Singh 
7945697a564SGovind Singh 	return 0;
7955697a564SGovind Singh 
7965697a564SGovind Singh free_msi_vector:
7975697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
7985697a564SGovind Singh 
7995697a564SGovind Singh 	return ret;
8005697a564SGovind Singh }
8015697a564SGovind Singh 
8025697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci)
8035697a564SGovind Singh {
8045697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
8055697a564SGovind Singh }
8065697a564SGovind Singh 
8075762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
8085762613eSGovind Singh {
8095762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
8105762613eSGovind Singh 	u16 device_id;
8115762613eSGovind Singh 	int ret = 0;
8125762613eSGovind Singh 
8135762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
8145762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
8155762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
8165762613eSGovind Singh 			   device_id, ab_pci->dev_id);
8175762613eSGovind Singh 		ret = -EIO;
8185762613eSGovind Singh 		goto out;
8195762613eSGovind Singh 	}
8205762613eSGovind Singh 
8215762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
8225762613eSGovind Singh 	if (ret) {
8235762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
8245762613eSGovind Singh 		goto out;
8255762613eSGovind Singh 	}
8265762613eSGovind Singh 
8275762613eSGovind Singh 	ret = pci_enable_device(pdev);
8285762613eSGovind Singh 	if (ret) {
8295762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
8305762613eSGovind Singh 		goto out;
8315762613eSGovind Singh 	}
8325762613eSGovind Singh 
8335762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
8345762613eSGovind Singh 	if (ret) {
8355762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
8365762613eSGovind Singh 		goto disable_device;
8375762613eSGovind Singh 	}
8385762613eSGovind Singh 
8395762613eSGovind Singh 	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
8405762613eSGovind Singh 	if (ret) {
8415762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
8425762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
8435762613eSGovind Singh 		goto release_region;
8445762613eSGovind Singh 	}
8455762613eSGovind Singh 
8465762613eSGovind Singh 	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
8475762613eSGovind Singh 	if (ret) {
8485762613eSGovind Singh 		ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n",
8495762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
8505762613eSGovind Singh 		goto release_region;
8515762613eSGovind Singh 	}
8525762613eSGovind Singh 
8535762613eSGovind Singh 	pci_set_master(pdev);
8545762613eSGovind Singh 
8555762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
8565762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
8575762613eSGovind Singh 	if (!ab->mem) {
8585762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
8595762613eSGovind Singh 		ret = -EIO;
8605762613eSGovind Singh 		goto clear_master;
8615762613eSGovind Singh 	}
8625762613eSGovind Singh 
8635762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
8645762613eSGovind Singh 	return 0;
8655762613eSGovind Singh 
8665762613eSGovind Singh clear_master:
8675762613eSGovind Singh 	pci_clear_master(pdev);
8685762613eSGovind Singh release_region:
8695762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
8705762613eSGovind Singh disable_device:
8715762613eSGovind Singh 	pci_disable_device(pdev);
8725762613eSGovind Singh out:
8735762613eSGovind Singh 	return ret;
8745762613eSGovind Singh }
8755762613eSGovind Singh 
8765762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
8775762613eSGovind Singh {
8785762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
8795762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
8805762613eSGovind Singh 
8815762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
8825762613eSGovind Singh 	ab->mem = NULL;
8835762613eSGovind Singh 	pci_clear_master(pci_dev);
8845762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
8855762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
8865762613eSGovind Singh 		pci_disable_device(pci_dev);
8875762613eSGovind Singh }
8885762613eSGovind Singh 
889*e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
890*e9603f4bSCarl Huang {
891*e9603f4bSCarl Huang 	struct ath11k_base *ab = ab_pci->ab;
892*e9603f4bSCarl Huang 
893*e9603f4bSCarl Huang 	pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL,
894*e9603f4bSCarl Huang 				  &ab_pci->link_ctl);
895*e9603f4bSCarl Huang 
896*e9603f4bSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n",
897*e9603f4bSCarl Huang 		   ab_pci->link_ctl,
898*e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S),
899*e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
900*e9603f4bSCarl Huang 
901*e9603f4bSCarl Huang 	/* disable L0s and L1 */
902*e9603f4bSCarl Huang 	pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
903*e9603f4bSCarl Huang 				   ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
904*e9603f4bSCarl Huang 
905*e9603f4bSCarl Huang 	set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags);
906*e9603f4bSCarl Huang }
907*e9603f4bSCarl Huang 
908*e9603f4bSCarl Huang static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci)
909*e9603f4bSCarl Huang {
910*e9603f4bSCarl Huang 	if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags))
911*e9603f4bSCarl Huang 		pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
912*e9603f4bSCarl Huang 					   ab_pci->link_ctl);
913*e9603f4bSCarl Huang }
914*e9603f4bSCarl Huang 
9151399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
9161399fb87SGovind Singh {
9171399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
9181399fb87SGovind Singh 	int ret;
9191399fb87SGovind Singh 
920a05bd851SCarl Huang 	ab_pci->register_window = 0;
921a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
922babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, true);
923f3c603d4SCarl Huang 
924*e9603f4bSCarl Huang 	/* Disable ASPM during firmware download due to problems switching
925*e9603f4bSCarl Huang 	 * to AMSS state.
926*e9603f4bSCarl Huang 	 */
927*e9603f4bSCarl Huang 	ath11k_pci_aspm_disable(ab_pci);
928*e9603f4bSCarl Huang 
9291399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
9301399fb87SGovind Singh 	if (ret) {
9311399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
9321399fb87SGovind Singh 		return ret;
9331399fb87SGovind Singh 	}
9341399fb87SGovind Singh 
9351399fb87SGovind Singh 	return 0;
9361399fb87SGovind Singh }
9371399fb87SGovind Singh 
9381399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
9391399fb87SGovind Singh {
9401399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
9411399fb87SGovind Singh 
942*e9603f4bSCarl Huang 	/* restore aspm in case firmware bootup fails */
943*e9603f4bSCarl Huang 	ath11k_pci_aspm_restore(ab_pci);
944*e9603f4bSCarl Huang 
945babb0cedSCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
9461399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
947a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
948babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, false);
9491399fb87SGovind Singh }
9501399fb87SGovind Singh 
951fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab)
952fa5917e4SCarl Huang {
953fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
954fa5917e4SCarl Huang 
955fa5917e4SCarl Huang 	ath11k_mhi_suspend(ar_pci);
956fa5917e4SCarl Huang 
957fa5917e4SCarl Huang 	return 0;
958fa5917e4SCarl Huang }
959fa5917e4SCarl Huang 
960fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab)
961fa5917e4SCarl Huang {
962fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
963fa5917e4SCarl Huang 
964fa5917e4SCarl Huang 	ath11k_mhi_resume(ar_pci);
965fa5917e4SCarl Huang 
966fa5917e4SCarl Huang 	return 0;
967fa5917e4SCarl Huang }
968fa5917e4SCarl Huang 
9692c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
9702c3960c2SGovind Singh {
9712c3960c2SGovind Singh 	int i;
9722c3960c2SGovind Singh 
973d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
9742c3960c2SGovind Singh 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
9752c3960c2SGovind Singh 
976e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
9772c3960c2SGovind Singh 			continue;
9782c3960c2SGovind Singh 
9792c3960c2SGovind Singh 		tasklet_kill(&ce_pipe->intr_tq);
9802c3960c2SGovind Singh 	}
9812c3960c2SGovind Singh }
9822c3960c2SGovind Singh 
983d578ec2aSCarl Huang static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab)
9847f4beda2SGovind Singh {
9852c3960c2SGovind Singh 	ath11k_pci_ce_irqs_disable(ab);
9862c3960c2SGovind Singh 	ath11k_pci_sync_ce_irqs(ab);
9872c3960c2SGovind Singh 	ath11k_pci_kill_tasklets(ab);
988d578ec2aSCarl Huang }
989d578ec2aSCarl Huang 
990d578ec2aSCarl Huang static void ath11k_pci_stop(struct ath11k_base *ab)
991d578ec2aSCarl Huang {
992d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
9937f4beda2SGovind Singh 	ath11k_ce_cleanup_pipes(ab);
9947f4beda2SGovind Singh }
9957f4beda2SGovind Singh 
9967f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab)
9977f4beda2SGovind Singh {
998a05bd851SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
999a05bd851SCarl Huang 
1000a05bd851SCarl Huang 	set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1001a05bd851SCarl Huang 
1002*e9603f4bSCarl Huang 	ath11k_pci_aspm_restore(ab_pci);
1003*e9603f4bSCarl Huang 
10047f4beda2SGovind Singh 	ath11k_pci_ce_irqs_enable(ab);
10052c3960c2SGovind Singh 	ath11k_ce_rx_post_buf(ab);
10062c3960c2SGovind Singh 
10072c3960c2SGovind Singh 	return 0;
10082c3960c2SGovind Singh }
10092c3960c2SGovind Singh 
1010d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab)
1011d578ec2aSCarl Huang {
1012d578ec2aSCarl Huang 	ath11k_pci_ce_irqs_enable(ab);
1013d578ec2aSCarl Huang }
1014d578ec2aSCarl Huang 
1015d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab)
1016d578ec2aSCarl Huang {
1017d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
1018d578ec2aSCarl Huang }
1019d578ec2aSCarl Huang 
10202c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
10212c3960c2SGovind Singh 					  u8 *ul_pipe, u8 *dl_pipe)
10222c3960c2SGovind Singh {
10232c3960c2SGovind Singh 	const struct service_to_pipe *entry;
10242c3960c2SGovind Singh 	bool ul_set = false, dl_set = false;
10252c3960c2SGovind Singh 	int i;
10262c3960c2SGovind Singh 
1027967c1d11SAnilkumar Kolli 	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
1028967c1d11SAnilkumar Kolli 		entry = &ab->hw_params.svc_to_ce_map[i];
10292c3960c2SGovind Singh 
10302c3960c2SGovind Singh 		if (__le32_to_cpu(entry->service_id) != service_id)
10312c3960c2SGovind Singh 			continue;
10322c3960c2SGovind Singh 
10332c3960c2SGovind Singh 		switch (__le32_to_cpu(entry->pipedir)) {
10342c3960c2SGovind Singh 		case PIPEDIR_NONE:
10352c3960c2SGovind Singh 			break;
10362c3960c2SGovind Singh 		case PIPEDIR_IN:
10372c3960c2SGovind Singh 			WARN_ON(dl_set);
10382c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
10392c3960c2SGovind Singh 			dl_set = true;
10402c3960c2SGovind Singh 			break;
10412c3960c2SGovind Singh 		case PIPEDIR_OUT:
10422c3960c2SGovind Singh 			WARN_ON(ul_set);
10432c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
10442c3960c2SGovind Singh 			ul_set = true;
10452c3960c2SGovind Singh 			break;
10462c3960c2SGovind Singh 		case PIPEDIR_INOUT:
10472c3960c2SGovind Singh 			WARN_ON(dl_set);
10482c3960c2SGovind Singh 			WARN_ON(ul_set);
10492c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
10502c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
10512c3960c2SGovind Singh 			dl_set = true;
10522c3960c2SGovind Singh 			ul_set = true;
10532c3960c2SGovind Singh 			break;
10542c3960c2SGovind Singh 		}
10552c3960c2SGovind Singh 	}
10562c3960c2SGovind Singh 
10572c3960c2SGovind Singh 	if (WARN_ON(!ul_set || !dl_set))
10582c3960c2SGovind Singh 		return -ENOENT;
10597f4beda2SGovind Singh 
10607f4beda2SGovind Singh 	return 0;
10617f4beda2SGovind Singh }
10627f4beda2SGovind Singh 
10637f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
10647f4beda2SGovind Singh 	.start = ath11k_pci_start,
10657f4beda2SGovind Singh 	.stop = ath11k_pci_stop,
1066654e959aSGovind Singh 	.read32 = ath11k_pci_read32,
1067654e959aSGovind Singh 	.write32 = ath11k_pci_write32,
10681399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
10691399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
1070fa5917e4SCarl Huang 	.suspend = ath11k_pci_hif_suspend,
1071fa5917e4SCarl Huang 	.resume = ath11k_pci_hif_resume,
1072d4ecb90bSCarl Huang 	.irq_enable = ath11k_pci_ext_irq_enable,
1073d4ecb90bSCarl Huang 	.irq_disable = ath11k_pci_ext_irq_disable,
1074c4eacabeSGovind Singh 	.get_msi_address =  ath11k_pci_get_msi_address,
1075c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
10762c3960c2SGovind Singh 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
1077d578ec2aSCarl Huang 	.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
1078d578ec2aSCarl Huang 	.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
10791399fb87SGovind Singh };
10801399fb87SGovind Singh 
10816e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
10826e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
10836e0355afSGovind Singh {
10846e0355afSGovind Singh 	struct ath11k_base *ab;
10855762613eSGovind Singh 	struct ath11k_pci *ab_pci;
108618ac1665SKalle Valo 	u32 soc_hw_version, soc_hw_version_major, soc_hw_version_minor;
10875762613eSGovind Singh 	int ret;
10886e0355afSGovind Singh 
10896e0355afSGovind Singh 	dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n");
10906e0355afSGovind Singh 
10911ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
10921ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
10936e0355afSGovind Singh 	if (!ab) {
10946e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
10956e0355afSGovind Singh 		return -ENOMEM;
10966e0355afSGovind Singh 	}
10976e0355afSGovind Singh 
10986e0355afSGovind Singh 	ab->dev = &pdev->dev;
10996e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
11005762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
11015762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
11025762613eSGovind Singh 	ab_pci->ab = ab;
11035697a564SGovind Singh 	ab_pci->pdev = pdev;
11047f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
11055762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
1106654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
11075762613eSGovind Singh 
11085762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
11095762613eSGovind Singh 	if (ret) {
11105762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
11115762613eSGovind Singh 		goto err_free_core;
11125762613eSGovind Singh 	}
11136e0355afSGovind Singh 
111418ac1665SKalle Valo 	switch (pci_dev->device) {
111518ac1665SKalle Valo 	case QCA6390_DEVICE_ID:
111618ac1665SKalle Valo 		soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION);
111718ac1665SKalle Valo 		soc_hw_version_major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
111818ac1665SKalle Valo 						 soc_hw_version);
111918ac1665SKalle Valo 		soc_hw_version_minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
112018ac1665SKalle Valo 						 soc_hw_version);
112118ac1665SKalle Valo 
112218ac1665SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
112318ac1665SKalle Valo 			   soc_hw_version_major, soc_hw_version_minor);
112418ac1665SKalle Valo 
112518ac1665SKalle Valo 		switch (soc_hw_version_major) {
112618ac1665SKalle Valo 		case 2:
112718ac1665SKalle Valo 			ab->hw_rev = ATH11K_HW_QCA6390_HW20;
112818ac1665SKalle Valo 			break;
112918ac1665SKalle Valo 		default:
113018ac1665SKalle Valo 			dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n",
113118ac1665SKalle Valo 				soc_hw_version_major, soc_hw_version_minor);
113218ac1665SKalle Valo 			ret = -EOPNOTSUPP;
113318ac1665SKalle Valo 			goto err_pci_free_region;
113418ac1665SKalle Valo 		}
113518ac1665SKalle Valo 		break;
113618ac1665SKalle Valo 	default:
113718ac1665SKalle Valo 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
113818ac1665SKalle Valo 			pci_dev->device);
113918ac1665SKalle Valo 		ret = -EOPNOTSUPP;
114018ac1665SKalle Valo 		goto err_pci_free_region;
114118ac1665SKalle Valo 	}
114218ac1665SKalle Valo 
11435697a564SGovind Singh 	ret = ath11k_pci_enable_msi(ab_pci);
11445697a564SGovind Singh 	if (ret) {
11455697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
11465697a564SGovind Singh 		goto err_pci_free_region;
11475697a564SGovind Singh 	}
11485697a564SGovind Singh 
1149b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
1150b8246f88SKalle Valo 	if (ret)
1151b8246f88SKalle Valo 		goto err_pci_disable_msi;
1152b8246f88SKalle Valo 
11531399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
11541399fb87SGovind Singh 	if (ret) {
11551399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
11561399fb87SGovind Singh 		goto err_pci_disable_msi;
11571399fb87SGovind Singh 	}
11581399fb87SGovind Singh 
11597f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
11607f4beda2SGovind Singh 	if (ret)
11617f4beda2SGovind Singh 		goto err_mhi_unregister;
11627f4beda2SGovind Singh 
11637f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
11647f4beda2SGovind Singh 	if (ret) {
11657f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
11667f4beda2SGovind Singh 		goto err_hal_srng_deinit;
11677f4beda2SGovind Singh 	}
11687f4beda2SGovind Singh 
11697f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
11707f4beda2SGovind Singh 
11717f4beda2SGovind Singh 	ret = ath11k_pci_config_irq(ab);
11727f4beda2SGovind Singh 	if (ret) {
11737f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
11747f4beda2SGovind Singh 		goto err_ce_free;
11757f4beda2SGovind Singh 	}
11767f4beda2SGovind Singh 
11777f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
11787f4beda2SGovind Singh 	if (ret) {
11797f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
11807f4beda2SGovind Singh 		goto err_free_irq;
11817f4beda2SGovind Singh 	}
11826e0355afSGovind Singh 	return 0;
11835762613eSGovind Singh 
11847f4beda2SGovind Singh err_free_irq:
11857f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
11867f4beda2SGovind Singh 
11877f4beda2SGovind Singh err_ce_free:
11887f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
11897f4beda2SGovind Singh 
11907f4beda2SGovind Singh err_hal_srng_deinit:
11917f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
11927f4beda2SGovind Singh 
11937f4beda2SGovind Singh err_mhi_unregister:
11947f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
11957f4beda2SGovind Singh 
1196b8246f88SKalle Valo err_pci_disable_msi:
1197b8246f88SKalle Valo 	ath11k_pci_disable_msi(ab_pci);
1198b8246f88SKalle Valo 
11995697a564SGovind Singh err_pci_free_region:
12005697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
12015697a564SGovind Singh 
12025762613eSGovind Singh err_free_core:
12035762613eSGovind Singh 	ath11k_core_free(ab);
12045697a564SGovind Singh 
12055762613eSGovind Singh 	return ret;
12066e0355afSGovind Singh }
12076e0355afSGovind Singh 
12086e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
12096e0355afSGovind Singh {
12106e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
12115762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
12126e0355afSGovind Singh 
121361a57e51SAnilkumar Kolli 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
121461a57e51SAnilkumar Kolli 		ath11k_pci_power_down(ab);
121561a57e51SAnilkumar Kolli 		ath11k_debugfs_soc_destroy(ab);
121661a57e51SAnilkumar Kolli 		ath11k_qmi_deinit_service(ab);
121761a57e51SAnilkumar Kolli 		goto qmi_fail;
121861a57e51SAnilkumar Kolli 	}
121961a57e51SAnilkumar Kolli 
12206e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
12216fbd8898SCarl Huang 
12226fbd8898SCarl Huang 	ath11k_core_deinit(ab);
12236fbd8898SCarl Huang 
122461a57e51SAnilkumar Kolli qmi_fail:
12251399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
12266fbd8898SCarl Huang 
12276fbd8898SCarl Huang 	ath11k_pci_free_irq(ab);
12285697a564SGovind Singh 	ath11k_pci_disable_msi(ab_pci);
12295762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
12306fbd8898SCarl Huang 
12316fbd8898SCarl Huang 	ath11k_hal_srng_deinit(ab);
12326fbd8898SCarl Huang 	ath11k_ce_free_pipes(ab);
12336e0355afSGovind Singh 	ath11k_core_free(ab);
12346e0355afSGovind Singh }
12356e0355afSGovind Singh 
12361399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
12371399fb87SGovind Singh {
12381399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
12391399fb87SGovind Singh 
12401399fb87SGovind Singh 	ath11k_pci_power_down(ab);
12411399fb87SGovind Singh }
12421399fb87SGovind Singh 
1243d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
1244d1b0c338SCarl Huang {
1245d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1246d1b0c338SCarl Huang 	int ret;
1247d1b0c338SCarl Huang 
1248d1b0c338SCarl Huang 	ret = ath11k_core_suspend(ab);
1249d1b0c338SCarl Huang 	if (ret)
1250d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to suspend core: %d\n", ret);
1251d1b0c338SCarl Huang 
1252d1b0c338SCarl Huang 	return ret;
1253d1b0c338SCarl Huang }
1254d1b0c338SCarl Huang 
1255d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
1256d1b0c338SCarl Huang {
1257d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1258d1b0c338SCarl Huang 	int ret;
1259d1b0c338SCarl Huang 
1260d1b0c338SCarl Huang 	ret = ath11k_core_resume(ab);
1261d1b0c338SCarl Huang 	if (ret)
1262d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to resume core: %d\n", ret);
1263d1b0c338SCarl Huang 
1264d1b0c338SCarl Huang 	return ret;
1265d1b0c338SCarl Huang }
1266d1b0c338SCarl Huang 
1267d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
1268d1b0c338SCarl Huang 			 ath11k_pci_pm_suspend,
1269d1b0c338SCarl Huang 			 ath11k_pci_pm_resume);
1270d1b0c338SCarl Huang 
12716e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
12726e0355afSGovind Singh 	.name = "ath11k_pci",
12736e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
12746e0355afSGovind Singh 	.probe = ath11k_pci_probe,
12756e0355afSGovind Singh 	.remove = ath11k_pci_remove,
12761399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
1277d1b0c338SCarl Huang #ifdef CONFIG_PM
1278d1b0c338SCarl Huang 	.driver.pm = &ath11k_pci_pm_ops,
1279d1b0c338SCarl Huang #endif
12806e0355afSGovind Singh };
12816e0355afSGovind Singh 
12826e0355afSGovind Singh static int ath11k_pci_init(void)
12836e0355afSGovind Singh {
12846e0355afSGovind Singh 	int ret;
12856e0355afSGovind Singh 
12866e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
12876e0355afSGovind Singh 	if (ret)
12886e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
12896e0355afSGovind Singh 		       ret);
12906e0355afSGovind Singh 
12916e0355afSGovind Singh 	return ret;
12926e0355afSGovind Singh }
12936e0355afSGovind Singh module_init(ath11k_pci_init);
12946e0355afSGovind Singh 
12956e0355afSGovind Singh static void ath11k_pci_exit(void)
12966e0355afSGovind Singh {
12976e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
12986e0355afSGovind Singh }
12996e0355afSGovind Singh 
13006e0355afSGovind Singh module_exit(ath11k_pci_exit);
13016e0355afSGovind Singh 
13026e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
13036e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
13043dbd7fe7SDevin Bayer 
13053dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */
13063dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE);
13073dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE);
13083dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE);
1309