xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision 16001e4b2e681b8fb5e7bc50db5522081d46347a)
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 
537a3aed0cSAnilkumar Kolli static const struct ath11k_msi_config ath11k_msi_config[] = {
547a3aed0cSAnilkumar Kolli 	{
555697a564SGovind Singh 		.total_vectors = 32,
565697a564SGovind Singh 		.total_users = 4,
575697a564SGovind Singh 		.users = (struct ath11k_msi_user[]) {
585697a564SGovind Singh 			{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
595697a564SGovind Singh 			{ .name = "CE", .num_vectors = 10, .base_vector = 3 },
605697a564SGovind Singh 			{ .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
615697a564SGovind Singh 			{ .name = "DP", .num_vectors = 18, .base_vector = 14 },
625697a564SGovind Singh 		},
637a3aed0cSAnilkumar Kolli 	},
645697a564SGovind Singh };
655697a564SGovind Singh 
667f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
677f4beda2SGovind Singh 	"bhi",
687f4beda2SGovind Singh 	"mhi-er0",
697f4beda2SGovind Singh 	"mhi-er1",
707f4beda2SGovind Singh 	"ce0",
717f4beda2SGovind Singh 	"ce1",
727f4beda2SGovind Singh 	"ce2",
737f4beda2SGovind Singh 	"ce3",
747f4beda2SGovind Singh 	"ce4",
757f4beda2SGovind Singh 	"ce5",
767f4beda2SGovind Singh 	"ce6",
777f4beda2SGovind Singh 	"ce7",
787f4beda2SGovind Singh 	"ce8",
797f4beda2SGovind Singh 	"ce9",
807f4beda2SGovind Singh 	"ce10",
817f4beda2SGovind Singh 	"ce11",
827f4beda2SGovind Singh 	"host2wbm-desc-feed",
837f4beda2SGovind Singh 	"host2reo-re-injection",
847f4beda2SGovind Singh 	"host2reo-command",
857f4beda2SGovind Singh 	"host2rxdma-monitor-ring3",
867f4beda2SGovind Singh 	"host2rxdma-monitor-ring2",
877f4beda2SGovind Singh 	"host2rxdma-monitor-ring1",
887f4beda2SGovind Singh 	"reo2ost-exception",
897f4beda2SGovind Singh 	"wbm2host-rx-release",
907f4beda2SGovind Singh 	"reo2host-status",
917f4beda2SGovind Singh 	"reo2host-destination-ring4",
927f4beda2SGovind Singh 	"reo2host-destination-ring3",
937f4beda2SGovind Singh 	"reo2host-destination-ring2",
947f4beda2SGovind Singh 	"reo2host-destination-ring1",
957f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac3",
967f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac2",
977f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac1",
987f4beda2SGovind Singh 	"ppdu-end-interrupts-mac3",
997f4beda2SGovind Singh 	"ppdu-end-interrupts-mac2",
1007f4beda2SGovind Singh 	"ppdu-end-interrupts-mac1",
1017f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac3",
1027f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac2",
1037f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac1",
1047f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac3",
1057f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac2",
1067f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac1",
1077f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac3",
1087f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac2",
1097f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac1",
1107f4beda2SGovind Singh 	"host2tcl-input-ring4",
1117f4beda2SGovind Singh 	"host2tcl-input-ring3",
1127f4beda2SGovind Singh 	"host2tcl-input-ring2",
1137f4beda2SGovind Singh 	"host2tcl-input-ring1",
1147f4beda2SGovind Singh 	"wbm2host-tx-completions-ring3",
1157f4beda2SGovind Singh 	"wbm2host-tx-completions-ring2",
1167f4beda2SGovind Singh 	"wbm2host-tx-completions-ring1",
1177f4beda2SGovind Singh 	"tcl2host-status-ring",
1187f4beda2SGovind Singh };
1197f4beda2SGovind Singh 
120654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset)
121654e959aSGovind Singh {
122654e959aSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
123654e959aSGovind Singh 
124654e959aSGovind Singh 	u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset);
125654e959aSGovind Singh 
126654e959aSGovind Singh 	lockdep_assert_held(&ab_pci->window_lock);
127654e959aSGovind Singh 
128654e959aSGovind Singh 	if (window != ab_pci->register_window) {
129654e959aSGovind Singh 		iowrite32(WINDOW_ENABLE_BIT | window,
130654e959aSGovind Singh 			  ab->mem + WINDOW_REG_ADDRESS);
131f6fa37a4SCarl Huang 		ioread32(ab->mem + WINDOW_REG_ADDRESS);
132654e959aSGovind Singh 		ab_pci->register_window = window;
133654e959aSGovind Singh 	}
134654e959aSGovind Singh }
135654e959aSGovind Singh 
136f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
137654e959aSGovind Singh {
138654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
139654e959aSGovind Singh 
140a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
141a05bd851SCarl Huang 	 * need to wakeup MHI to access.
142a05bd851SCarl Huang 	 */
143a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
144a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
145a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
146a05bd851SCarl Huang 
147654e959aSGovind Singh 	if (offset < WINDOW_START) {
148654e959aSGovind Singh 		iowrite32(value, ab->mem  + offset);
149654e959aSGovind Singh 	} else {
150654e959aSGovind Singh 		spin_lock_bh(&ab_pci->window_lock);
151654e959aSGovind Singh 		ath11k_pci_select_window(ab_pci, offset);
152654e959aSGovind Singh 		iowrite32(value, ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK));
153654e959aSGovind Singh 		spin_unlock_bh(&ab_pci->window_lock);
154654e959aSGovind Singh 	}
155a05bd851SCarl Huang 
156a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
157a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
158a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
159654e959aSGovind Singh }
160654e959aSGovind Singh 
161f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
162654e959aSGovind Singh {
163654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
164654e959aSGovind Singh 	u32 val;
165654e959aSGovind Singh 
166a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
167a05bd851SCarl Huang 	 * need to wakeup MHI to access.
168a05bd851SCarl Huang 	 */
169a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
170a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
171a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
172a05bd851SCarl Huang 
173654e959aSGovind Singh 	if (offset < WINDOW_START) {
174654e959aSGovind Singh 		val = ioread32(ab->mem + offset);
175654e959aSGovind Singh 	} else {
176654e959aSGovind Singh 		spin_lock_bh(&ab_pci->window_lock);
177654e959aSGovind Singh 		ath11k_pci_select_window(ab_pci, offset);
178654e959aSGovind Singh 		val = ioread32(ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK));
179654e959aSGovind Singh 		spin_unlock_bh(&ab_pci->window_lock);
180654e959aSGovind Singh 	}
181654e959aSGovind Singh 
182a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
183a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
184a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
185a05bd851SCarl Huang 
186654e959aSGovind Singh 	return val;
187654e959aSGovind Singh }
188654e959aSGovind Singh 
189f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
190f3c603d4SCarl Huang {
191f3c603d4SCarl Huang 	u32 val, delay;
192f3c603d4SCarl Huang 
193f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
194f3c603d4SCarl Huang 
195f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
196f3c603d4SCarl Huang 
197f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
198f3c603d4SCarl Huang 
199f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
200f3c603d4SCarl Huang 	delay = 10;
201f3c603d4SCarl Huang 	mdelay(delay);
202f3c603d4SCarl Huang 
203f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
204f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
205f3c603d4SCarl Huang 
206f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
207f3c603d4SCarl Huang 
208f3c603d4SCarl Huang 	mdelay(delay);
209f3c603d4SCarl Huang 
210f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
211f3c603d4SCarl Huang 	if (val == 0xffffffff)
212f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
213f3c603d4SCarl Huang }
214f3c603d4SCarl Huang 
215f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
216f3c603d4SCarl Huang {
217f3c603d4SCarl Huang 	u32 val;
218f3c603d4SCarl Huang 
219f3c603d4SCarl Huang 	/* read cookie */
220f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR);
221f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val);
222f3c603d4SCarl Huang 
223f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
224f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
225f3c603d4SCarl Huang 
226f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
227f3c603d4SCarl Huang 	mdelay(10);
228f3c603d4SCarl Huang 
229f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
230f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
231f3c603d4SCarl Huang 	 */
232f3c603d4SCarl Huang 	ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0);
233f3c603d4SCarl Huang 	mdelay(10);
234f3c603d4SCarl Huang 
235f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
236f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
237f3c603d4SCarl Huang 
238f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
239f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
240f3c603d4SCarl Huang 	 */
241f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
242f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
243f3c603d4SCarl Huang }
244f3c603d4SCarl Huang 
24506999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab,
24606999407SCarl Huang 				   u32 offset, u32 value, u32 mask)
24706999407SCarl Huang {
24806999407SCarl Huang 	u32 v;
24906999407SCarl Huang 	int i;
25006999407SCarl Huang 
25106999407SCarl Huang 	v = ath11k_pci_read32(ab, offset);
25206999407SCarl Huang 	if ((v & mask) == value)
25306999407SCarl Huang 		return 0;
25406999407SCarl Huang 
25506999407SCarl Huang 	for (i = 0; i < 10; i++) {
25606999407SCarl Huang 		ath11k_pci_write32(ab, offset, (v & ~mask) | value);
25706999407SCarl Huang 
25806999407SCarl Huang 		v = ath11k_pci_read32(ab, offset);
25906999407SCarl Huang 		if ((v & mask) == value)
26006999407SCarl Huang 			return 0;
26106999407SCarl Huang 
26206999407SCarl Huang 		mdelay(2);
26306999407SCarl Huang 	}
26406999407SCarl Huang 
26506999407SCarl Huang 	ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n",
26606999407SCarl Huang 		    offset, v & mask, value);
26706999407SCarl Huang 
26806999407SCarl Huang 	return -ETIMEDOUT;
26906999407SCarl Huang }
27006999407SCarl Huang 
27106999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
27206999407SCarl Huang {
27306999407SCarl Huang 	int ret;
27406999407SCarl Huang 
27506999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
27606999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG,
27706999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL,
27806999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK);
27930d08503SDan Carpenter 	if (ret) {
28006999407SCarl Huang 		ath11k_warn(ab, "failed to set sysclk: %d\n", ret);
28106999407SCarl Huang 		return ret;
28206999407SCarl Huang 	}
28306999407SCarl Huang 
28406999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
28506999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_REG,
28606999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_VAL,
28706999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK);
28830d08503SDan Carpenter 	if (ret) {
28906999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret);
29006999407SCarl Huang 		return ret;
29106999407SCarl Huang 	}
29206999407SCarl Huang 
29306999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
29406999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_REG,
29506999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_VAL,
29606999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK);
29730d08503SDan Carpenter 	if (ret) {
29806999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config2: %d\n", ret);
29906999407SCarl Huang 		return ret;
30006999407SCarl Huang 	}
30106999407SCarl Huang 
30206999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
30306999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_REG,
30406999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_VAL,
30506999407SCarl Huang 				      PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK);
30630d08503SDan Carpenter 	if (ret) {
30706999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config4: %d\n", ret);
30806999407SCarl Huang 		return ret;
30906999407SCarl Huang 	}
31006999407SCarl Huang 
31106999407SCarl Huang 	return 0;
31206999407SCarl Huang }
31306999407SCarl Huang 
314babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
315babb0cedSCarl Huang {
316babb0cedSCarl Huang 	u32 val;
317babb0cedSCarl Huang 	int i;
318babb0cedSCarl Huang 
319babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
320babb0cedSCarl Huang 
321babb0cedSCarl Huang 	/* PCIE link seems very unstable after the Hot Reset*/
322babb0cedSCarl Huang 	for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {
323babb0cedSCarl Huang 		if (val == 0xffffffff)
324babb0cedSCarl Huang 			mdelay(5);
325babb0cedSCarl Huang 
326babb0cedSCarl Huang 		ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
327babb0cedSCarl Huang 		val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
328babb0cedSCarl Huang 	}
329babb0cedSCarl Huang 
330babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val);
331babb0cedSCarl Huang 
332babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
333562934adSKalle Valo 	val |= GCC_GCC_PCIE_HOT_RST_VAL;
334babb0cedSCarl Huang 	ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
335babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
336babb0cedSCarl Huang 
337babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val);
338babb0cedSCarl Huang 
339babb0cedSCarl Huang 	mdelay(5);
340babb0cedSCarl Huang }
341babb0cedSCarl Huang 
342babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
343babb0cedSCarl Huang {
344babb0cedSCarl Huang 	/* This is a WAR for PCIE Hotreset.
345babb0cedSCarl Huang 	 * When target receive Hotreset, but will set the interrupt.
346babb0cedSCarl Huang 	 * So when download SBL again, SBL will open Interrupt and
347babb0cedSCarl Huang 	 * receive it, and crash immediately.
348babb0cedSCarl Huang 	 */
349babb0cedSCarl Huang 	ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
350babb0cedSCarl Huang }
351babb0cedSCarl Huang 
3520ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab)
3530ccdf439SCarl Huang {
3540ccdf439SCarl Huang 	u32 val;
3550ccdf439SCarl Huang 
3560ccdf439SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG);
3570ccdf439SCarl Huang 	val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK;
3580ccdf439SCarl Huang 	ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val);
3590ccdf439SCarl Huang }
3600ccdf439SCarl Huang 
361f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
362f3c603d4SCarl Huang {
363f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
364f3c603d4SCarl Huang 	mdelay(5);
365f3c603d4SCarl Huang }
366f3c603d4SCarl Huang 
367babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
368f3c603d4SCarl Huang {
369babb0cedSCarl Huang 	if (power_on) {
370babb0cedSCarl Huang 		ath11k_pci_enable_ltssm(ab);
371babb0cedSCarl Huang 		ath11k_pci_clear_all_intrs(ab);
3720ccdf439SCarl Huang 		ath11k_pci_set_wlaon_pwr_ctrl(ab);
37306999407SCarl Huang 		ath11k_pci_fix_l1ss(ab);
374babb0cedSCarl Huang 	}
375babb0cedSCarl Huang 
376f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
377f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
378f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
379f3c603d4SCarl Huang 	ath11k_pci_clear_dbg_registers(ab);
380f3c603d4SCarl Huang }
381f3c603d4SCarl Huang 
3821399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
3831399fb87SGovind Singh {
3841399fb87SGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(dev);
3851399fb87SGovind Singh 
3861399fb87SGovind Singh 	return pci_irq_vector(pci_dev, vector);
3871399fb87SGovind Singh }
3881399fb87SGovind Singh 
389c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
390c4eacabeSGovind Singh 				       u32 *msi_addr_hi)
391c4eacabeSGovind Singh {
392e8e55d89SAnilkumar Kolli 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
393c4eacabeSGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
394c4eacabeSGovind Singh 
395c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
396c4eacabeSGovind Singh 			      msi_addr_lo);
397c4eacabeSGovind Singh 
398e8e55d89SAnilkumar Kolli 	if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) {
399c4eacabeSGovind Singh 		pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
400c4eacabeSGovind Singh 				      msi_addr_hi);
401e8e55d89SAnilkumar Kolli 	} else {
402e8e55d89SAnilkumar Kolli 		*msi_addr_hi = 0;
403e8e55d89SAnilkumar Kolli 	}
404c4eacabeSGovind Singh }
405c4eacabeSGovind Singh 
4061399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
4071399fb87SGovind Singh 				       int *num_vectors, u32 *user_base_data,
4081399fb87SGovind Singh 				       u32 *base_vector)
4091399fb87SGovind Singh {
4101399fb87SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4117a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
4121399fb87SGovind Singh 	int idx;
4131399fb87SGovind Singh 
4147a3aed0cSAnilkumar Kolli 	for (idx = 0; idx < msi_config->total_users; idx++) {
4157a3aed0cSAnilkumar Kolli 		if (strcmp(user_name, msi_config->users[idx].name) == 0) {
4167a3aed0cSAnilkumar Kolli 			*num_vectors = msi_config->users[idx].num_vectors;
4177a3aed0cSAnilkumar Kolli 			*user_base_data = msi_config->users[idx].base_vector
4181399fb87SGovind Singh 				+ ab_pci->msi_ep_base_data;
4197a3aed0cSAnilkumar Kolli 			*base_vector = msi_config->users[idx].base_vector;
4201399fb87SGovind Singh 
4211399fb87SGovind Singh 			ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
4221399fb87SGovind Singh 				   user_name, *num_vectors, *user_base_data,
4231399fb87SGovind Singh 				   *base_vector);
4241399fb87SGovind Singh 
4251399fb87SGovind Singh 			return 0;
4261399fb87SGovind Singh 		}
4271399fb87SGovind Singh 	}
4281399fb87SGovind Singh 
4291399fb87SGovind Singh 	ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
4301399fb87SGovind Singh 
4311399fb87SGovind Singh 	return -EINVAL;
4321399fb87SGovind Singh }
4331399fb87SGovind Singh 
434c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
435c4eacabeSGovind Singh 					  int *num_vectors, u32 *user_base_data,
436c4eacabeSGovind Singh 					  u32 *base_vector)
437c4eacabeSGovind Singh {
438c4eacabeSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
439c4eacabeSGovind Singh 
440c4eacabeSGovind Singh 	return ath11k_pci_get_user_msi_assignment(ab_pci, user_name,
441c4eacabeSGovind Singh 						  num_vectors, user_base_data,
442c4eacabeSGovind Singh 						  base_vector);
443c4eacabeSGovind Singh }
444c4eacabeSGovind Singh 
445d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
446d4ecb90bSCarl Huang {
447d4ecb90bSCarl Huang 	int i, j;
448d4ecb90bSCarl Huang 
449d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
450d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
451d4ecb90bSCarl Huang 
452d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++)
453d4ecb90bSCarl Huang 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
454d4ecb90bSCarl Huang 
455d4ecb90bSCarl Huang 		netif_napi_del(&irq_grp->napi);
456d4ecb90bSCarl Huang 	}
457d4ecb90bSCarl Huang }
458d4ecb90bSCarl Huang 
4597f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab)
4607f4beda2SGovind Singh {
4617f4beda2SGovind Singh 	int i, irq_idx;
4627f4beda2SGovind Singh 
463d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
464e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
4657f4beda2SGovind Singh 			continue;
4667f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
4677f4beda2SGovind Singh 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
4687f4beda2SGovind Singh 	}
469d4ecb90bSCarl Huang 
470d4ecb90bSCarl Huang 	ath11k_pci_free_ext_irq(ab);
4717f4beda2SGovind Singh }
4727f4beda2SGovind Singh 
4732c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
4742c3960c2SGovind Singh {
4752c3960c2SGovind Singh 	u32 irq_idx;
4762c3960c2SGovind Singh 
4772c3960c2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
4782c3960c2SGovind Singh 	enable_irq(ab->irq_num[irq_idx]);
4792c3960c2SGovind Singh }
4802c3960c2SGovind Singh 
4817f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
4827f4beda2SGovind Singh {
4837f4beda2SGovind Singh 	u32 irq_idx;
4847f4beda2SGovind Singh 
4857f4beda2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
4867f4beda2SGovind Singh 	disable_irq_nosync(ab->irq_num[irq_idx]);
4877f4beda2SGovind Singh }
4887f4beda2SGovind Singh 
4892c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
4902c3960c2SGovind Singh {
4912c3960c2SGovind Singh 	int i;
4922c3960c2SGovind Singh 
493d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
494e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
4952c3960c2SGovind Singh 			continue;
4962c3960c2SGovind Singh 		ath11k_pci_ce_irq_disable(ab, i);
4972c3960c2SGovind Singh 	}
4982c3960c2SGovind Singh }
4992c3960c2SGovind Singh 
5002c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
5012c3960c2SGovind Singh {
5022c3960c2SGovind Singh 	int i;
5032c3960c2SGovind Singh 	int irq_idx;
5042c3960c2SGovind Singh 
505d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
506e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5072c3960c2SGovind Singh 			continue;
5082c3960c2SGovind Singh 
5092c3960c2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5102c3960c2SGovind Singh 		synchronize_irq(ab->irq_num[irq_idx]);
5112c3960c2SGovind Singh 	}
5122c3960c2SGovind Singh }
5132c3960c2SGovind Singh 
5140f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
5152c3960c2SGovind Singh {
5160f01dcb8SAllen Pais 	struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
5172c3960c2SGovind Singh 
5182c3960c2SGovind Singh 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
5192c3960c2SGovind Singh 
5202c3960c2SGovind Singh 	ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
5212c3960c2SGovind Singh }
5222c3960c2SGovind Singh 
5237f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
5247f4beda2SGovind Singh {
5257f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = arg;
5267f4beda2SGovind Singh 
5277f4beda2SGovind Singh 	ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
5282c3960c2SGovind Singh 	tasklet_schedule(&ce_pipe->intr_tq);
5297f4beda2SGovind Singh 
5307f4beda2SGovind Singh 	return IRQ_HANDLED;
5317f4beda2SGovind Singh }
5327f4beda2SGovind Singh 
533d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
534d4ecb90bSCarl Huang {
535d4ecb90bSCarl Huang 	int i;
536d4ecb90bSCarl Huang 
537d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
538d4ecb90bSCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
539d4ecb90bSCarl Huang }
540d4ecb90bSCarl Huang 
541d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
542d4ecb90bSCarl Huang {
543d4ecb90bSCarl Huang 	int i;
544d4ecb90bSCarl Huang 
545d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
546d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
547d4ecb90bSCarl Huang 
548d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
549d4ecb90bSCarl Huang 
550d4ecb90bSCarl Huang 		napi_synchronize(&irq_grp->napi);
551d4ecb90bSCarl Huang 		napi_disable(&irq_grp->napi);
552d4ecb90bSCarl Huang 	}
553d4ecb90bSCarl Huang }
554d4ecb90bSCarl Huang 
555d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
556d4ecb90bSCarl Huang {
557d4ecb90bSCarl Huang 	int i;
558d4ecb90bSCarl Huang 
559d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
560d4ecb90bSCarl Huang 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
561d4ecb90bSCarl Huang }
562d4ecb90bSCarl Huang 
563d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
564d4ecb90bSCarl Huang {
565d4ecb90bSCarl Huang 	int i;
566d4ecb90bSCarl Huang 
567d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
568d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
569d4ecb90bSCarl Huang 
570d4ecb90bSCarl Huang 		napi_enable(&irq_grp->napi);
571d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
572d4ecb90bSCarl Huang 	}
573d4ecb90bSCarl Huang }
574d4ecb90bSCarl Huang 
575d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
576d4ecb90bSCarl Huang {
577d4ecb90bSCarl Huang 	int i, j, irq_idx;
578d4ecb90bSCarl Huang 
579d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
580d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
581d4ecb90bSCarl Huang 
582d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
583d4ecb90bSCarl Huang 			irq_idx = irq_grp->irqs[j];
584d4ecb90bSCarl Huang 			synchronize_irq(ab->irq_num[irq_idx]);
585d4ecb90bSCarl Huang 		}
586d4ecb90bSCarl Huang 	}
587d4ecb90bSCarl Huang }
588d4ecb90bSCarl Huang 
589d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
590d4ecb90bSCarl Huang {
591d4ecb90bSCarl Huang 	__ath11k_pci_ext_irq_disable(ab);
592d4ecb90bSCarl Huang 	ath11k_pci_sync_ext_irqs(ab);
593d4ecb90bSCarl Huang }
594d4ecb90bSCarl Huang 
595d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
596d4ecb90bSCarl Huang {
597d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
598d4ecb90bSCarl Huang 						struct ath11k_ext_irq_grp,
599d4ecb90bSCarl Huang 						napi);
600d4ecb90bSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
601d4ecb90bSCarl Huang 	int work_done;
602d4ecb90bSCarl Huang 
603d4ecb90bSCarl Huang 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
604d4ecb90bSCarl Huang 	if (work_done < budget) {
605d4ecb90bSCarl Huang 		napi_complete_done(napi, work_done);
606d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
607d4ecb90bSCarl Huang 	}
608d4ecb90bSCarl Huang 
609d4ecb90bSCarl Huang 	if (work_done > budget)
610d4ecb90bSCarl Huang 		work_done = budget;
611d4ecb90bSCarl Huang 
612d4ecb90bSCarl Huang 	return work_done;
613d4ecb90bSCarl Huang }
614d4ecb90bSCarl Huang 
615d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
616d4ecb90bSCarl Huang {
617d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = arg;
618d4ecb90bSCarl Huang 
619d4ecb90bSCarl Huang 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
620d4ecb90bSCarl Huang 
621d4ecb90bSCarl Huang 	ath11k_pci_ext_grp_disable(irq_grp);
622d4ecb90bSCarl Huang 
623d4ecb90bSCarl Huang 	napi_schedule(&irq_grp->napi);
624d4ecb90bSCarl Huang 
625d4ecb90bSCarl Huang 	return IRQ_HANDLED;
626d4ecb90bSCarl Huang }
627d4ecb90bSCarl Huang 
628d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
629d4ecb90bSCarl Huang {
630d4ecb90bSCarl Huang 	int i, j, ret, num_vectors = 0;
631d4ecb90bSCarl Huang 	u32 user_base_data = 0, base_vector = 0;
632d4ecb90bSCarl Huang 
633b2c09458SColin Ian King 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
634b2c09458SColin Ian King 						 &num_vectors,
635b2c09458SColin Ian King 						 &user_base_data,
636d4ecb90bSCarl Huang 						 &base_vector);
637b2c09458SColin Ian King 	if (ret < 0)
638b2c09458SColin Ian King 		return ret;
639d4ecb90bSCarl Huang 
640d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
641d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
642d4ecb90bSCarl Huang 		u32 num_irq = 0;
643d4ecb90bSCarl Huang 
644d4ecb90bSCarl Huang 		irq_grp->ab = ab;
645d4ecb90bSCarl Huang 		irq_grp->grp_id = i;
646d4ecb90bSCarl Huang 		init_dummy_netdev(&irq_grp->napi_ndev);
647d4ecb90bSCarl Huang 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
648d4ecb90bSCarl Huang 			       ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
649d4ecb90bSCarl Huang 
650d4ecb90bSCarl Huang 		if (ab->hw_params.ring_mask->tx[i] ||
651d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx[i] ||
652d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_err[i] ||
653d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_wbm_rel[i] ||
654d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->reo_status[i] ||
655d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rxdma2host[i] ||
656d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->host2rxdma[i] ||
657d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_mon_status[i]) {
658d4ecb90bSCarl Huang 			num_irq = 1;
659d4ecb90bSCarl Huang 		}
660d4ecb90bSCarl Huang 
661d4ecb90bSCarl Huang 		irq_grp->num_irq = num_irq;
662d4ecb90bSCarl Huang 		irq_grp->irqs[0] = base_vector + i;
663d4ecb90bSCarl Huang 
664d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
665d4ecb90bSCarl Huang 			int irq_idx = irq_grp->irqs[j];
666d4ecb90bSCarl Huang 			int vector = (i % num_vectors) + base_vector;
667d4ecb90bSCarl Huang 			int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
668d4ecb90bSCarl Huang 
669d4ecb90bSCarl Huang 			ab->irq_num[irq_idx] = irq;
670d4ecb90bSCarl Huang 
671d4ecb90bSCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
672d4ecb90bSCarl Huang 				   "irq:%d group:%d\n", irq, i);
673d4ecb90bSCarl Huang 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
674d4ecb90bSCarl Huang 					  IRQF_SHARED,
675d4ecb90bSCarl Huang 					  "DP_EXT_IRQ", irq_grp);
676d4ecb90bSCarl Huang 			if (ret) {
677d4ecb90bSCarl Huang 				ath11k_err(ab, "failed request irq %d: %d\n",
678d4ecb90bSCarl Huang 					   vector, ret);
679d4ecb90bSCarl Huang 				return ret;
680d4ecb90bSCarl Huang 			}
681d4ecb90bSCarl Huang 
682d4ecb90bSCarl Huang 			disable_irq_nosync(ab->irq_num[irq_idx]);
683d4ecb90bSCarl Huang 		}
684d4ecb90bSCarl Huang 	}
685d4ecb90bSCarl Huang 
686d4ecb90bSCarl Huang 	return 0;
687d4ecb90bSCarl Huang }
688d4ecb90bSCarl Huang 
6897f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab)
6907f4beda2SGovind Singh {
6917f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe;
6927f4beda2SGovind Singh 	u32 msi_data_start;
6937f4beda2SGovind Singh 	u32 msi_data_count;
6947f4beda2SGovind Singh 	u32 msi_irq_start;
6957f4beda2SGovind Singh 	unsigned int msi_data;
6967f4beda2SGovind Singh 	int irq, i, ret, irq_idx;
6977f4beda2SGovind Singh 
6987f4beda2SGovind Singh 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab),
6997f4beda2SGovind Singh 						 "CE", &msi_data_count,
7007f4beda2SGovind Singh 						 &msi_data_start, &msi_irq_start);
7017f4beda2SGovind Singh 	if (ret)
7027f4beda2SGovind Singh 		return ret;
7037f4beda2SGovind Singh 
7047f4beda2SGovind Singh 	/* Configure CE irqs */
705d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
7067f4beda2SGovind Singh 		msi_data = (i % msi_data_count) + msi_irq_start;
7077f4beda2SGovind Singh 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
7087f4beda2SGovind Singh 		ce_pipe = &ab->ce.ce_pipe[i];
7097f4beda2SGovind Singh 
710e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
7117f4beda2SGovind Singh 			continue;
7127f4beda2SGovind Singh 
7137f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
7147f4beda2SGovind Singh 
7150f01dcb8SAllen Pais 		tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
7162c3960c2SGovind Singh 
7177f4beda2SGovind Singh 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
7187f4beda2SGovind Singh 				  IRQF_SHARED, irq_name[irq_idx],
7197f4beda2SGovind Singh 				  ce_pipe);
7207f4beda2SGovind Singh 		if (ret) {
7217f4beda2SGovind Singh 			ath11k_err(ab, "failed to request irq %d: %d\n",
7227f4beda2SGovind Singh 				   irq_idx, ret);
7237f4beda2SGovind Singh 			return ret;
7247f4beda2SGovind Singh 		}
7257f4beda2SGovind Singh 
7267f4beda2SGovind Singh 		ab->irq_num[irq_idx] = irq;
727e5c860e1SCarl Huang 		ath11k_pci_ce_irq_disable(ab, i);
7287f4beda2SGovind Singh 	}
7297f4beda2SGovind Singh 
730d4ecb90bSCarl Huang 	ret = ath11k_pci_ext_irq_config(ab);
731d4ecb90bSCarl Huang 	if (ret)
732d4ecb90bSCarl Huang 		return ret;
733d4ecb90bSCarl Huang 
7347f4beda2SGovind Singh 	return 0;
7357f4beda2SGovind Singh }
7367f4beda2SGovind Singh 
7377f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
7387f4beda2SGovind Singh {
7397f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
7407f4beda2SGovind Singh 
741967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
742967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
7437f4beda2SGovind Singh 
744967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
745967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
746*16001e4bSAnilkumar Kolli 	ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
747e838c14aSCarl Huang 
748e838c14aSCarl Huang 	ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
749e838c14aSCarl Huang 				    &cfg->shadow_reg_v2_len);
7507f4beda2SGovind Singh }
7517f4beda2SGovind Singh 
7527f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
7537f4beda2SGovind Singh {
7547f4beda2SGovind Singh 	int i;
7557f4beda2SGovind Singh 
756d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
757e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
7587f4beda2SGovind Singh 			continue;
7597f4beda2SGovind Singh 		ath11k_pci_ce_irq_enable(ab, i);
7607f4beda2SGovind Singh 	}
7617f4beda2SGovind Singh }
7627f4beda2SGovind Singh 
7635697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
7645697a564SGovind Singh {
7655697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
7667a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
7675697a564SGovind Singh 	struct msi_desc *msi_desc;
7685697a564SGovind Singh 	int num_vectors;
7695697a564SGovind Singh 	int ret;
7705697a564SGovind Singh 
7715697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
7727a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
7737a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
7745697a564SGovind Singh 					    PCI_IRQ_MSI);
7757a3aed0cSAnilkumar Kolli 	if (num_vectors != msi_config->total_vectors) {
7765697a564SGovind Singh 		ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
7777a3aed0cSAnilkumar Kolli 			   msi_config->total_vectors, num_vectors);
7785697a564SGovind Singh 
7795697a564SGovind Singh 		if (num_vectors >= 0)
7805697a564SGovind Singh 			return -EINVAL;
7815697a564SGovind Singh 		else
7825697a564SGovind Singh 			return num_vectors;
7835697a564SGovind Singh 	}
7845697a564SGovind Singh 
7855697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
7865697a564SGovind Singh 	if (!msi_desc) {
7875697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
7885697a564SGovind Singh 		ret = -EINVAL;
7895697a564SGovind Singh 		goto free_msi_vector;
7905697a564SGovind Singh 	}
7915697a564SGovind Singh 
7925697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
793e8e55d89SAnilkumar Kolli 	if (msi_desc->msi_attrib.is_64)
794e8e55d89SAnilkumar Kolli 		set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags);
7955697a564SGovind Singh 
7965697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
7975697a564SGovind Singh 
7985697a564SGovind Singh 	return 0;
7995697a564SGovind Singh 
8005697a564SGovind Singh free_msi_vector:
8015697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
8025697a564SGovind Singh 
8035697a564SGovind Singh 	return ret;
8045697a564SGovind Singh }
8055697a564SGovind Singh 
8065697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci)
8075697a564SGovind Singh {
8085697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
8095697a564SGovind Singh }
8105697a564SGovind Singh 
8115762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
8125762613eSGovind Singh {
8135762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
8145762613eSGovind Singh 	u16 device_id;
8155762613eSGovind Singh 	int ret = 0;
8165762613eSGovind Singh 
8175762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
8185762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
8195762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
8205762613eSGovind Singh 			   device_id, ab_pci->dev_id);
8215762613eSGovind Singh 		ret = -EIO;
8225762613eSGovind Singh 		goto out;
8235762613eSGovind Singh 	}
8245762613eSGovind Singh 
8255762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
8265762613eSGovind Singh 	if (ret) {
8275762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
8285762613eSGovind Singh 		goto out;
8295762613eSGovind Singh 	}
8305762613eSGovind Singh 
8315762613eSGovind Singh 	ret = pci_enable_device(pdev);
8325762613eSGovind Singh 	if (ret) {
8335762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
8345762613eSGovind Singh 		goto out;
8355762613eSGovind Singh 	}
8365762613eSGovind Singh 
8375762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
8385762613eSGovind Singh 	if (ret) {
8395762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
8405762613eSGovind Singh 		goto disable_device;
8415762613eSGovind Singh 	}
8425762613eSGovind Singh 
8435762613eSGovind Singh 	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
8445762613eSGovind Singh 	if (ret) {
8455762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
8465762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
8475762613eSGovind Singh 		goto release_region;
8485762613eSGovind Singh 	}
8495762613eSGovind Singh 
8505762613eSGovind Singh 	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
8515762613eSGovind Singh 	if (ret) {
8525762613eSGovind Singh 		ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n",
8535762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
8545762613eSGovind Singh 		goto release_region;
8555762613eSGovind Singh 	}
8565762613eSGovind Singh 
8575762613eSGovind Singh 	pci_set_master(pdev);
8585762613eSGovind Singh 
8595762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
8605762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
8615762613eSGovind Singh 	if (!ab->mem) {
8625762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
8635762613eSGovind Singh 		ret = -EIO;
8645762613eSGovind Singh 		goto clear_master;
8655762613eSGovind Singh 	}
8665762613eSGovind Singh 
8675762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
8685762613eSGovind Singh 	return 0;
8695762613eSGovind Singh 
8705762613eSGovind Singh clear_master:
8715762613eSGovind Singh 	pci_clear_master(pdev);
8725762613eSGovind Singh release_region:
8735762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
8745762613eSGovind Singh disable_device:
8755762613eSGovind Singh 	pci_disable_device(pdev);
8765762613eSGovind Singh out:
8775762613eSGovind Singh 	return ret;
8785762613eSGovind Singh }
8795762613eSGovind Singh 
8805762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
8815762613eSGovind Singh {
8825762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
8835762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
8845762613eSGovind Singh 
8855762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
8865762613eSGovind Singh 	ab->mem = NULL;
8875762613eSGovind Singh 	pci_clear_master(pci_dev);
8885762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
8895762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
8905762613eSGovind Singh 		pci_disable_device(pci_dev);
8915762613eSGovind Singh }
8925762613eSGovind Singh 
893e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
894e9603f4bSCarl Huang {
895e9603f4bSCarl Huang 	struct ath11k_base *ab = ab_pci->ab;
896e9603f4bSCarl Huang 
897e9603f4bSCarl Huang 	pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL,
898e9603f4bSCarl Huang 				  &ab_pci->link_ctl);
899e9603f4bSCarl Huang 
900e9603f4bSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n",
901e9603f4bSCarl Huang 		   ab_pci->link_ctl,
902e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S),
903e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
904e9603f4bSCarl Huang 
905e9603f4bSCarl Huang 	/* disable L0s and L1 */
906e9603f4bSCarl Huang 	pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
907e9603f4bSCarl Huang 				   ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
908e9603f4bSCarl Huang 
909e9603f4bSCarl Huang 	set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags);
910e9603f4bSCarl Huang }
911e9603f4bSCarl Huang 
912e9603f4bSCarl Huang static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci)
913e9603f4bSCarl Huang {
914e9603f4bSCarl Huang 	if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags))
915e9603f4bSCarl Huang 		pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
916e9603f4bSCarl Huang 					   ab_pci->link_ctl);
917e9603f4bSCarl Huang }
918e9603f4bSCarl Huang 
9191399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
9201399fb87SGovind Singh {
9211399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
9221399fb87SGovind Singh 	int ret;
9231399fb87SGovind Singh 
924a05bd851SCarl Huang 	ab_pci->register_window = 0;
925a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
926babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, true);
927f3c603d4SCarl Huang 
928e9603f4bSCarl Huang 	/* Disable ASPM during firmware download due to problems switching
929e9603f4bSCarl Huang 	 * to AMSS state.
930e9603f4bSCarl Huang 	 */
931e9603f4bSCarl Huang 	ath11k_pci_aspm_disable(ab_pci);
932e9603f4bSCarl Huang 
9331399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
9341399fb87SGovind Singh 	if (ret) {
9351399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
9361399fb87SGovind Singh 		return ret;
9371399fb87SGovind Singh 	}
9381399fb87SGovind Singh 
9391399fb87SGovind Singh 	return 0;
9401399fb87SGovind Singh }
9411399fb87SGovind Singh 
9421399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
9431399fb87SGovind Singh {
9441399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
9451399fb87SGovind Singh 
946e9603f4bSCarl Huang 	/* restore aspm in case firmware bootup fails */
947e9603f4bSCarl Huang 	ath11k_pci_aspm_restore(ab_pci);
948e9603f4bSCarl Huang 
949babb0cedSCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
9501399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
951a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
952babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, false);
9531399fb87SGovind Singh }
9541399fb87SGovind Singh 
955fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab)
956fa5917e4SCarl Huang {
957fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
958fa5917e4SCarl Huang 
959fa5917e4SCarl Huang 	ath11k_mhi_suspend(ar_pci);
960fa5917e4SCarl Huang 
961fa5917e4SCarl Huang 	return 0;
962fa5917e4SCarl Huang }
963fa5917e4SCarl Huang 
964fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab)
965fa5917e4SCarl Huang {
966fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
967fa5917e4SCarl Huang 
968fa5917e4SCarl Huang 	ath11k_mhi_resume(ar_pci);
969fa5917e4SCarl Huang 
970fa5917e4SCarl Huang 	return 0;
971fa5917e4SCarl Huang }
972fa5917e4SCarl Huang 
9732c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
9742c3960c2SGovind Singh {
9752c3960c2SGovind Singh 	int i;
9762c3960c2SGovind Singh 
977d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
9782c3960c2SGovind Singh 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
9792c3960c2SGovind Singh 
980e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
9812c3960c2SGovind Singh 			continue;
9822c3960c2SGovind Singh 
9832c3960c2SGovind Singh 		tasklet_kill(&ce_pipe->intr_tq);
9842c3960c2SGovind Singh 	}
9852c3960c2SGovind Singh }
9862c3960c2SGovind Singh 
987d578ec2aSCarl Huang static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab)
9887f4beda2SGovind Singh {
9892c3960c2SGovind Singh 	ath11k_pci_ce_irqs_disable(ab);
9902c3960c2SGovind Singh 	ath11k_pci_sync_ce_irqs(ab);
9912c3960c2SGovind Singh 	ath11k_pci_kill_tasklets(ab);
992d578ec2aSCarl Huang }
993d578ec2aSCarl Huang 
994d578ec2aSCarl Huang static void ath11k_pci_stop(struct ath11k_base *ab)
995d578ec2aSCarl Huang {
996d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
9977f4beda2SGovind Singh 	ath11k_ce_cleanup_pipes(ab);
9987f4beda2SGovind Singh }
9997f4beda2SGovind Singh 
10007f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab)
10017f4beda2SGovind Singh {
1002a05bd851SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
1003a05bd851SCarl Huang 
1004a05bd851SCarl Huang 	set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1005a05bd851SCarl Huang 
1006e9603f4bSCarl Huang 	ath11k_pci_aspm_restore(ab_pci);
1007e9603f4bSCarl Huang 
10087f4beda2SGovind Singh 	ath11k_pci_ce_irqs_enable(ab);
10092c3960c2SGovind Singh 	ath11k_ce_rx_post_buf(ab);
10102c3960c2SGovind Singh 
10112c3960c2SGovind Singh 	return 0;
10122c3960c2SGovind Singh }
10132c3960c2SGovind Singh 
1014d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab)
1015d578ec2aSCarl Huang {
1016d578ec2aSCarl Huang 	ath11k_pci_ce_irqs_enable(ab);
1017d578ec2aSCarl Huang }
1018d578ec2aSCarl Huang 
1019d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab)
1020d578ec2aSCarl Huang {
1021d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
1022d578ec2aSCarl Huang }
1023d578ec2aSCarl Huang 
10242c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
10252c3960c2SGovind Singh 					  u8 *ul_pipe, u8 *dl_pipe)
10262c3960c2SGovind Singh {
10272c3960c2SGovind Singh 	const struct service_to_pipe *entry;
10282c3960c2SGovind Singh 	bool ul_set = false, dl_set = false;
10292c3960c2SGovind Singh 	int i;
10302c3960c2SGovind Singh 
1031967c1d11SAnilkumar Kolli 	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
1032967c1d11SAnilkumar Kolli 		entry = &ab->hw_params.svc_to_ce_map[i];
10332c3960c2SGovind Singh 
10342c3960c2SGovind Singh 		if (__le32_to_cpu(entry->service_id) != service_id)
10352c3960c2SGovind Singh 			continue;
10362c3960c2SGovind Singh 
10372c3960c2SGovind Singh 		switch (__le32_to_cpu(entry->pipedir)) {
10382c3960c2SGovind Singh 		case PIPEDIR_NONE:
10392c3960c2SGovind Singh 			break;
10402c3960c2SGovind Singh 		case PIPEDIR_IN:
10412c3960c2SGovind Singh 			WARN_ON(dl_set);
10422c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
10432c3960c2SGovind Singh 			dl_set = true;
10442c3960c2SGovind Singh 			break;
10452c3960c2SGovind Singh 		case PIPEDIR_OUT:
10462c3960c2SGovind Singh 			WARN_ON(ul_set);
10472c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
10482c3960c2SGovind Singh 			ul_set = true;
10492c3960c2SGovind Singh 			break;
10502c3960c2SGovind Singh 		case PIPEDIR_INOUT:
10512c3960c2SGovind Singh 			WARN_ON(dl_set);
10522c3960c2SGovind Singh 			WARN_ON(ul_set);
10532c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
10542c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
10552c3960c2SGovind Singh 			dl_set = true;
10562c3960c2SGovind Singh 			ul_set = true;
10572c3960c2SGovind Singh 			break;
10582c3960c2SGovind Singh 		}
10592c3960c2SGovind Singh 	}
10602c3960c2SGovind Singh 
10612c3960c2SGovind Singh 	if (WARN_ON(!ul_set || !dl_set))
10622c3960c2SGovind Singh 		return -ENOENT;
10637f4beda2SGovind Singh 
10647f4beda2SGovind Singh 	return 0;
10657f4beda2SGovind Singh }
10667f4beda2SGovind Singh 
10677f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
10687f4beda2SGovind Singh 	.start = ath11k_pci_start,
10697f4beda2SGovind Singh 	.stop = ath11k_pci_stop,
1070654e959aSGovind Singh 	.read32 = ath11k_pci_read32,
1071654e959aSGovind Singh 	.write32 = ath11k_pci_write32,
10721399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
10731399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
1074fa5917e4SCarl Huang 	.suspend = ath11k_pci_hif_suspend,
1075fa5917e4SCarl Huang 	.resume = ath11k_pci_hif_resume,
1076d4ecb90bSCarl Huang 	.irq_enable = ath11k_pci_ext_irq_enable,
1077d4ecb90bSCarl Huang 	.irq_disable = ath11k_pci_ext_irq_disable,
1078c4eacabeSGovind Singh 	.get_msi_address =  ath11k_pci_get_msi_address,
1079c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
10802c3960c2SGovind Singh 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
1081d578ec2aSCarl Huang 	.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
1082d578ec2aSCarl Huang 	.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
10831399fb87SGovind Singh };
10841399fb87SGovind Singh 
10856e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
10866e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
10876e0355afSGovind Singh {
10886e0355afSGovind Singh 	struct ath11k_base *ab;
10895762613eSGovind Singh 	struct ath11k_pci *ab_pci;
109018ac1665SKalle Valo 	u32 soc_hw_version, soc_hw_version_major, soc_hw_version_minor;
10915762613eSGovind Singh 	int ret;
10926e0355afSGovind Singh 
10931ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
10941ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
10956e0355afSGovind Singh 	if (!ab) {
10966e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
10976e0355afSGovind Singh 		return -ENOMEM;
10986e0355afSGovind Singh 	}
10996e0355afSGovind Singh 
11006e0355afSGovind Singh 	ab->dev = &pdev->dev;
11016e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
11025762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
11035762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
11045762613eSGovind Singh 	ab_pci->ab = ab;
11055697a564SGovind Singh 	ab_pci->pdev = pdev;
11067f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
11075762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
1108654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
11095762613eSGovind Singh 
11105762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
11115762613eSGovind Singh 	if (ret) {
11125762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
11135762613eSGovind Singh 		goto err_free_core;
11145762613eSGovind Singh 	}
11156e0355afSGovind Singh 
111618ac1665SKalle Valo 	switch (pci_dev->device) {
111718ac1665SKalle Valo 	case QCA6390_DEVICE_ID:
111818ac1665SKalle Valo 		soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION);
111918ac1665SKalle Valo 		soc_hw_version_major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
112018ac1665SKalle Valo 						 soc_hw_version);
112118ac1665SKalle Valo 		soc_hw_version_minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
112218ac1665SKalle Valo 						 soc_hw_version);
112318ac1665SKalle Valo 
112418ac1665SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
112518ac1665SKalle Valo 			   soc_hw_version_major, soc_hw_version_minor);
112618ac1665SKalle Valo 
112718ac1665SKalle Valo 		switch (soc_hw_version_major) {
112818ac1665SKalle Valo 		case 2:
112918ac1665SKalle Valo 			ab->hw_rev = ATH11K_HW_QCA6390_HW20;
113018ac1665SKalle Valo 			break;
113118ac1665SKalle Valo 		default:
113218ac1665SKalle Valo 			dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n",
113318ac1665SKalle Valo 				soc_hw_version_major, soc_hw_version_minor);
113418ac1665SKalle Valo 			ret = -EOPNOTSUPP;
113518ac1665SKalle Valo 			goto err_pci_free_region;
113618ac1665SKalle Valo 		}
113718ac1665SKalle Valo 		break;
113818ac1665SKalle Valo 	default:
113918ac1665SKalle Valo 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
114018ac1665SKalle Valo 			pci_dev->device);
114118ac1665SKalle Valo 		ret = -EOPNOTSUPP;
114218ac1665SKalle Valo 		goto err_pci_free_region;
114318ac1665SKalle Valo 	}
114418ac1665SKalle Valo 
11457a3aed0cSAnilkumar Kolli 	ab_pci->msi_config = &ath11k_msi_config[0];
11465697a564SGovind Singh 	ret = ath11k_pci_enable_msi(ab_pci);
11475697a564SGovind Singh 	if (ret) {
11485697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
11495697a564SGovind Singh 		goto err_pci_free_region;
11505697a564SGovind Singh 	}
11515697a564SGovind Singh 
1152b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
1153b8246f88SKalle Valo 	if (ret)
1154b8246f88SKalle Valo 		goto err_pci_disable_msi;
1155b8246f88SKalle Valo 
11561399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
11571399fb87SGovind Singh 	if (ret) {
11581399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
11591399fb87SGovind Singh 		goto err_pci_disable_msi;
11601399fb87SGovind Singh 	}
11611399fb87SGovind Singh 
11627f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
11637f4beda2SGovind Singh 	if (ret)
11647f4beda2SGovind Singh 		goto err_mhi_unregister;
11657f4beda2SGovind Singh 
11667f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
11677f4beda2SGovind Singh 	if (ret) {
11687f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
11697f4beda2SGovind Singh 		goto err_hal_srng_deinit;
11707f4beda2SGovind Singh 	}
11717f4beda2SGovind Singh 
11727f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
11737f4beda2SGovind Singh 
11747f4beda2SGovind Singh 	ret = ath11k_pci_config_irq(ab);
11757f4beda2SGovind Singh 	if (ret) {
11767f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
11777f4beda2SGovind Singh 		goto err_ce_free;
11787f4beda2SGovind Singh 	}
11797f4beda2SGovind Singh 
11807f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
11817f4beda2SGovind Singh 	if (ret) {
11827f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
11837f4beda2SGovind Singh 		goto err_free_irq;
11847f4beda2SGovind Singh 	}
11856e0355afSGovind Singh 	return 0;
11865762613eSGovind Singh 
11877f4beda2SGovind Singh err_free_irq:
11887f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
11897f4beda2SGovind Singh 
11907f4beda2SGovind Singh err_ce_free:
11917f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
11927f4beda2SGovind Singh 
11937f4beda2SGovind Singh err_hal_srng_deinit:
11947f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
11957f4beda2SGovind Singh 
11967f4beda2SGovind Singh err_mhi_unregister:
11977f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
11987f4beda2SGovind Singh 
1199b8246f88SKalle Valo err_pci_disable_msi:
1200b8246f88SKalle Valo 	ath11k_pci_disable_msi(ab_pci);
1201b8246f88SKalle Valo 
12025697a564SGovind Singh err_pci_free_region:
12035697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
12045697a564SGovind Singh 
12055762613eSGovind Singh err_free_core:
12065762613eSGovind Singh 	ath11k_core_free(ab);
12075697a564SGovind Singh 
12085762613eSGovind Singh 	return ret;
12096e0355afSGovind Singh }
12106e0355afSGovind Singh 
12116e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
12126e0355afSGovind Singh {
12136e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
12145762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
12156e0355afSGovind Singh 
121661a57e51SAnilkumar Kolli 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
121761a57e51SAnilkumar Kolli 		ath11k_pci_power_down(ab);
121861a57e51SAnilkumar Kolli 		ath11k_debugfs_soc_destroy(ab);
121961a57e51SAnilkumar Kolli 		ath11k_qmi_deinit_service(ab);
122061a57e51SAnilkumar Kolli 		goto qmi_fail;
122161a57e51SAnilkumar Kolli 	}
122261a57e51SAnilkumar Kolli 
12236e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
12246fbd8898SCarl Huang 
12256fbd8898SCarl Huang 	ath11k_core_deinit(ab);
12266fbd8898SCarl Huang 
122761a57e51SAnilkumar Kolli qmi_fail:
12281399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
12296fbd8898SCarl Huang 
12306fbd8898SCarl Huang 	ath11k_pci_free_irq(ab);
12315697a564SGovind Singh 	ath11k_pci_disable_msi(ab_pci);
12325762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
12336fbd8898SCarl Huang 
12346fbd8898SCarl Huang 	ath11k_hal_srng_deinit(ab);
12356fbd8898SCarl Huang 	ath11k_ce_free_pipes(ab);
12366e0355afSGovind Singh 	ath11k_core_free(ab);
12376e0355afSGovind Singh }
12386e0355afSGovind Singh 
12391399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
12401399fb87SGovind Singh {
12411399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
12421399fb87SGovind Singh 
12431399fb87SGovind Singh 	ath11k_pci_power_down(ab);
12441399fb87SGovind Singh }
12451399fb87SGovind Singh 
1246d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
1247d1b0c338SCarl Huang {
1248d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1249d1b0c338SCarl Huang 	int ret;
1250d1b0c338SCarl Huang 
1251d1b0c338SCarl Huang 	ret = ath11k_core_suspend(ab);
1252d1b0c338SCarl Huang 	if (ret)
1253d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to suspend core: %d\n", ret);
1254d1b0c338SCarl Huang 
1255d1b0c338SCarl Huang 	return ret;
1256d1b0c338SCarl Huang }
1257d1b0c338SCarl Huang 
1258d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
1259d1b0c338SCarl Huang {
1260d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1261d1b0c338SCarl Huang 	int ret;
1262d1b0c338SCarl Huang 
1263d1b0c338SCarl Huang 	ret = ath11k_core_resume(ab);
1264d1b0c338SCarl Huang 	if (ret)
1265d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to resume core: %d\n", ret);
1266d1b0c338SCarl Huang 
1267d1b0c338SCarl Huang 	return ret;
1268d1b0c338SCarl Huang }
1269d1b0c338SCarl Huang 
1270d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
1271d1b0c338SCarl Huang 			 ath11k_pci_pm_suspend,
1272d1b0c338SCarl Huang 			 ath11k_pci_pm_resume);
1273d1b0c338SCarl Huang 
12746e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
12756e0355afSGovind Singh 	.name = "ath11k_pci",
12766e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
12776e0355afSGovind Singh 	.probe = ath11k_pci_probe,
12786e0355afSGovind Singh 	.remove = ath11k_pci_remove,
12791399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
1280d1b0c338SCarl Huang #ifdef CONFIG_PM
1281d1b0c338SCarl Huang 	.driver.pm = &ath11k_pci_pm_ops,
1282d1b0c338SCarl Huang #endif
12836e0355afSGovind Singh };
12846e0355afSGovind Singh 
12856e0355afSGovind Singh static int ath11k_pci_init(void)
12866e0355afSGovind Singh {
12876e0355afSGovind Singh 	int ret;
12886e0355afSGovind Singh 
12896e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
12906e0355afSGovind Singh 	if (ret)
12916e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
12926e0355afSGovind Singh 		       ret);
12936e0355afSGovind Singh 
12946e0355afSGovind Singh 	return ret;
12956e0355afSGovind Singh }
12966e0355afSGovind Singh module_init(ath11k_pci_init);
12976e0355afSGovind Singh 
12986e0355afSGovind Singh static void ath11k_pci_exit(void)
12996e0355afSGovind Singh {
13006e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
13016e0355afSGovind Singh }
13026e0355afSGovind Singh 
13036e0355afSGovind Singh module_exit(ath11k_pci_exit);
13046e0355afSGovind Singh 
13056e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
13066e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
13073dbd7fe7SDevin Bayer 
13083dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */
13093dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE);
13103dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE);
13113dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE);
1312