xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision 081e2d6476e30399433b509684d5da4d1844e430)
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
384e809461SAnilkumar Kolli #define QCN9074_DEVICE_ID		0x1104
390fbf1957SBaochen Qiang #define WCN6855_DEVICE_ID		0x1103
406e0355afSGovind Singh 
416e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = {
426e0355afSGovind Singh 	{ PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) },
430fbf1957SBaochen Qiang 	{ PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) },
4449f5b114SAnilkumar Kolli 	{ PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) },
456e0355afSGovind Singh 	{0}
466e0355afSGovind Singh };
476e0355afSGovind Singh 
486e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table);
496e0355afSGovind Singh 
501ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = {
511ff8ed78SGovind Singh 	.mhi_support = true,
5256970454SGovind Singh 	.m3_fw_support = true,
536eb6ea51SGovind Singh 	.fixed_bdf_addr = false,
546eb6ea51SGovind Singh 	.fixed_mem_region = false,
551ff8ed78SGovind Singh };
561ff8ed78SGovind Singh 
577a3aed0cSAnilkumar Kolli static const struct ath11k_msi_config ath11k_msi_config[] = {
587a3aed0cSAnilkumar Kolli 	{
595697a564SGovind Singh 		.total_vectors = 32,
605697a564SGovind Singh 		.total_users = 4,
615697a564SGovind Singh 		.users = (struct ath11k_msi_user[]) {
625697a564SGovind Singh 			{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
635697a564SGovind Singh 			{ .name = "CE", .num_vectors = 10, .base_vector = 3 },
645697a564SGovind Singh 			{ .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
655697a564SGovind Singh 			{ .name = "DP", .num_vectors = 18, .base_vector = 14 },
665697a564SGovind Singh 		},
677a3aed0cSAnilkumar Kolli 	},
684e809461SAnilkumar Kolli 	{
694e809461SAnilkumar Kolli 		.total_vectors = 16,
704e809461SAnilkumar Kolli 		.total_users = 3,
714e809461SAnilkumar Kolli 		.users = (struct ath11k_msi_user[]) {
724e809461SAnilkumar Kolli 			{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
734e809461SAnilkumar Kolli 			{ .name = "CE", .num_vectors = 5, .base_vector = 3 },
744e809461SAnilkumar Kolli 			{ .name = "DP", .num_vectors = 8, .base_vector = 8 },
754e809461SAnilkumar Kolli 		},
764e809461SAnilkumar Kolli 	},
775697a564SGovind Singh };
785697a564SGovind Singh 
797f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
807f4beda2SGovind Singh 	"bhi",
817f4beda2SGovind Singh 	"mhi-er0",
827f4beda2SGovind Singh 	"mhi-er1",
837f4beda2SGovind Singh 	"ce0",
847f4beda2SGovind Singh 	"ce1",
857f4beda2SGovind Singh 	"ce2",
867f4beda2SGovind Singh 	"ce3",
877f4beda2SGovind Singh 	"ce4",
887f4beda2SGovind Singh 	"ce5",
897f4beda2SGovind Singh 	"ce6",
907f4beda2SGovind Singh 	"ce7",
917f4beda2SGovind Singh 	"ce8",
927f4beda2SGovind Singh 	"ce9",
937f4beda2SGovind Singh 	"ce10",
947f4beda2SGovind Singh 	"ce11",
957f4beda2SGovind Singh 	"host2wbm-desc-feed",
967f4beda2SGovind Singh 	"host2reo-re-injection",
977f4beda2SGovind Singh 	"host2reo-command",
987f4beda2SGovind Singh 	"host2rxdma-monitor-ring3",
997f4beda2SGovind Singh 	"host2rxdma-monitor-ring2",
1007f4beda2SGovind Singh 	"host2rxdma-monitor-ring1",
1017f4beda2SGovind Singh 	"reo2ost-exception",
1027f4beda2SGovind Singh 	"wbm2host-rx-release",
1037f4beda2SGovind Singh 	"reo2host-status",
1047f4beda2SGovind Singh 	"reo2host-destination-ring4",
1057f4beda2SGovind Singh 	"reo2host-destination-ring3",
1067f4beda2SGovind Singh 	"reo2host-destination-ring2",
1077f4beda2SGovind Singh 	"reo2host-destination-ring1",
1087f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac3",
1097f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac2",
1107f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac1",
1117f4beda2SGovind Singh 	"ppdu-end-interrupts-mac3",
1127f4beda2SGovind Singh 	"ppdu-end-interrupts-mac2",
1137f4beda2SGovind Singh 	"ppdu-end-interrupts-mac1",
1147f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac3",
1157f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac2",
1167f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac1",
1177f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac3",
1187f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac2",
1197f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac1",
1207f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac3",
1217f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac2",
1227f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac1",
1237f4beda2SGovind Singh 	"host2tcl-input-ring4",
1247f4beda2SGovind Singh 	"host2tcl-input-ring3",
1257f4beda2SGovind Singh 	"host2tcl-input-ring2",
1267f4beda2SGovind Singh 	"host2tcl-input-ring1",
1277f4beda2SGovind Singh 	"wbm2host-tx-completions-ring3",
1287f4beda2SGovind Singh 	"wbm2host-tx-completions-ring2",
1297f4beda2SGovind Singh 	"wbm2host-tx-completions-ring1",
1307f4beda2SGovind Singh 	"tcl2host-status-ring",
1317f4beda2SGovind Singh };
1327f4beda2SGovind Singh 
133654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset)
134654e959aSGovind Singh {
135654e959aSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
136654e959aSGovind Singh 
137654e959aSGovind Singh 	u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset);
138654e959aSGovind Singh 
139654e959aSGovind Singh 	lockdep_assert_held(&ab_pci->window_lock);
140654e959aSGovind Singh 
141654e959aSGovind Singh 	if (window != ab_pci->register_window) {
142654e959aSGovind Singh 		iowrite32(WINDOW_ENABLE_BIT | window,
143654e959aSGovind Singh 			  ab->mem + WINDOW_REG_ADDRESS);
144f6fa37a4SCarl Huang 		ioread32(ab->mem + WINDOW_REG_ADDRESS);
145654e959aSGovind Singh 		ab_pci->register_window = window;
146654e959aSGovind Singh 	}
147654e959aSGovind Singh }
148654e959aSGovind Singh 
149480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci)
150480a7361SKarthikeyan Periyasamy {
151480a7361SKarthikeyan Periyasamy 	u32 umac_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET);
152480a7361SKarthikeyan Periyasamy 	u32 ce_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE);
153480a7361SKarthikeyan Periyasamy 	u32 window;
154480a7361SKarthikeyan Periyasamy 
155480a7361SKarthikeyan Periyasamy 	window = (umac_window << 12) | (ce_window << 6);
156480a7361SKarthikeyan Periyasamy 
157480a7361SKarthikeyan Periyasamy 	iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + WINDOW_REG_ADDRESS);
158480a7361SKarthikeyan Periyasamy }
159480a7361SKarthikeyan Periyasamy 
160480a7361SKarthikeyan Periyasamy static inline u32 ath11k_pci_get_window_start(struct ath11k_base *ab,
161480a7361SKarthikeyan Periyasamy 					      u32 offset)
162480a7361SKarthikeyan Periyasamy {
163480a7361SKarthikeyan Periyasamy 	u32 window_start;
164480a7361SKarthikeyan Periyasamy 
165480a7361SKarthikeyan Periyasamy 	/* If offset lies within DP register range, use 3rd window */
166480a7361SKarthikeyan Periyasamy 	if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < WINDOW_RANGE_MASK)
167480a7361SKarthikeyan Periyasamy 		window_start = 3 * WINDOW_START;
168480a7361SKarthikeyan Periyasamy 	/* If offset lies within CE register range, use 2nd window */
169480a7361SKarthikeyan Periyasamy 	else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK)
170480a7361SKarthikeyan Periyasamy 		window_start = 2 * WINDOW_START;
171480a7361SKarthikeyan Periyasamy 	else
172480a7361SKarthikeyan Periyasamy 		window_start = WINDOW_START;
173480a7361SKarthikeyan Periyasamy 
174480a7361SKarthikeyan Periyasamy 	return window_start;
175480a7361SKarthikeyan Periyasamy }
176480a7361SKarthikeyan Periyasamy 
177f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
178654e959aSGovind Singh {
179654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
180480a7361SKarthikeyan Periyasamy 	u32 window_start;
181654e959aSGovind Singh 
182a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
183a05bd851SCarl Huang 	 * need to wakeup MHI to access.
184a05bd851SCarl Huang 	 */
185*081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
186*081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
187a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
188a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
189a05bd851SCarl Huang 
190654e959aSGovind Singh 	if (offset < WINDOW_START) {
191654e959aSGovind Singh 		iowrite32(value, ab->mem  + offset);
192654e959aSGovind Singh 	} else {
193480a7361SKarthikeyan Periyasamy 		if (ab->bus_params.static_window_map)
194480a7361SKarthikeyan Periyasamy 			window_start = ath11k_pci_get_window_start(ab, offset);
195480a7361SKarthikeyan Periyasamy 		else
196480a7361SKarthikeyan Periyasamy 			window_start = WINDOW_START;
197480a7361SKarthikeyan Periyasamy 
198480a7361SKarthikeyan Periyasamy 		if (window_start == WINDOW_START) {
199654e959aSGovind Singh 			spin_lock_bh(&ab_pci->window_lock);
200654e959aSGovind Singh 			ath11k_pci_select_window(ab_pci, offset);
201480a7361SKarthikeyan Periyasamy 			iowrite32(value, ab->mem + window_start +
202480a7361SKarthikeyan Periyasamy 				  (offset & WINDOW_RANGE_MASK));
203654e959aSGovind Singh 			spin_unlock_bh(&ab_pci->window_lock);
204480a7361SKarthikeyan Periyasamy 		} else {
205480a7361SKarthikeyan Periyasamy 			iowrite32(value, ab->mem + window_start +
206480a7361SKarthikeyan Periyasamy 				  (offset & WINDOW_RANGE_MASK));
207480a7361SKarthikeyan Periyasamy 		}
208654e959aSGovind Singh 	}
209a05bd851SCarl Huang 
210*081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
211*081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
212a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
213a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
214654e959aSGovind Singh }
215654e959aSGovind Singh 
216f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
217654e959aSGovind Singh {
218654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
219480a7361SKarthikeyan Periyasamy 	u32 val, window_start;
220654e959aSGovind Singh 
221a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
222a05bd851SCarl Huang 	 * need to wakeup MHI to access.
223a05bd851SCarl Huang 	 */
224*081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
225*081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
226a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
227a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
228a05bd851SCarl Huang 
229654e959aSGovind Singh 	if (offset < WINDOW_START) {
230654e959aSGovind Singh 		val = ioread32(ab->mem + offset);
231654e959aSGovind Singh 	} else {
232480a7361SKarthikeyan Periyasamy 		if (ab->bus_params.static_window_map)
233480a7361SKarthikeyan Periyasamy 			window_start = ath11k_pci_get_window_start(ab, offset);
234480a7361SKarthikeyan Periyasamy 		else
235480a7361SKarthikeyan Periyasamy 			window_start = WINDOW_START;
236480a7361SKarthikeyan Periyasamy 
237480a7361SKarthikeyan Periyasamy 		if (window_start == WINDOW_START) {
238654e959aSGovind Singh 			spin_lock_bh(&ab_pci->window_lock);
239654e959aSGovind Singh 			ath11k_pci_select_window(ab_pci, offset);
240480a7361SKarthikeyan Periyasamy 			val = ioread32(ab->mem + window_start +
241480a7361SKarthikeyan Periyasamy 				       (offset & WINDOW_RANGE_MASK));
242654e959aSGovind Singh 			spin_unlock_bh(&ab_pci->window_lock);
243480a7361SKarthikeyan Periyasamy 		} else {
244480a7361SKarthikeyan Periyasamy 			val = ioread32(ab->mem + window_start +
245480a7361SKarthikeyan Periyasamy 				       (offset & WINDOW_RANGE_MASK));
246480a7361SKarthikeyan Periyasamy 		}
247654e959aSGovind Singh 	}
248654e959aSGovind Singh 
249*081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
250*081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
251a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
252a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
253a05bd851SCarl Huang 
254654e959aSGovind Singh 	return val;
255654e959aSGovind Singh }
256654e959aSGovind Singh 
257f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
258f3c603d4SCarl Huang {
259f3c603d4SCarl Huang 	u32 val, delay;
260f3c603d4SCarl Huang 
261f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
262f3c603d4SCarl Huang 
263f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
264f3c603d4SCarl Huang 
265f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
266f3c603d4SCarl Huang 
267f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
268f3c603d4SCarl Huang 	delay = 10;
269f3c603d4SCarl Huang 	mdelay(delay);
270f3c603d4SCarl Huang 
271f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
272f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
273f3c603d4SCarl Huang 
274f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
275f3c603d4SCarl Huang 
276f3c603d4SCarl Huang 	mdelay(delay);
277f3c603d4SCarl Huang 
278f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
279f3c603d4SCarl Huang 	if (val == 0xffffffff)
280f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
281f3c603d4SCarl Huang }
282f3c603d4SCarl Huang 
283f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
284f3c603d4SCarl Huang {
285f3c603d4SCarl Huang 	u32 val;
286f3c603d4SCarl Huang 
287f3c603d4SCarl Huang 	/* read cookie */
288f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR);
289f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val);
290f3c603d4SCarl Huang 
291f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
292f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
293f3c603d4SCarl Huang 
294f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
295f3c603d4SCarl Huang 	mdelay(10);
296f3c603d4SCarl Huang 
297f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
298f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
299f3c603d4SCarl Huang 	 */
300f3c603d4SCarl Huang 	ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0);
301f3c603d4SCarl Huang 	mdelay(10);
302f3c603d4SCarl Huang 
303f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
304f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
305f3c603d4SCarl Huang 
306f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
307f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
308f3c603d4SCarl Huang 	 */
309f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
310f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
311f3c603d4SCarl Huang }
312f3c603d4SCarl Huang 
31306999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab,
31406999407SCarl Huang 				   u32 offset, u32 value, u32 mask)
31506999407SCarl Huang {
31606999407SCarl Huang 	u32 v;
31706999407SCarl Huang 	int i;
31806999407SCarl Huang 
31906999407SCarl Huang 	v = ath11k_pci_read32(ab, offset);
32006999407SCarl Huang 	if ((v & mask) == value)
32106999407SCarl Huang 		return 0;
32206999407SCarl Huang 
32306999407SCarl Huang 	for (i = 0; i < 10; i++) {
32406999407SCarl Huang 		ath11k_pci_write32(ab, offset, (v & ~mask) | value);
32506999407SCarl Huang 
32606999407SCarl Huang 		v = ath11k_pci_read32(ab, offset);
32706999407SCarl Huang 		if ((v & mask) == value)
32806999407SCarl Huang 			return 0;
32906999407SCarl Huang 
33006999407SCarl Huang 		mdelay(2);
33106999407SCarl Huang 	}
33206999407SCarl Huang 
33306999407SCarl Huang 	ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n",
33406999407SCarl Huang 		    offset, v & mask, value);
33506999407SCarl Huang 
33606999407SCarl Huang 	return -ETIMEDOUT;
33706999407SCarl Huang }
33806999407SCarl Huang 
33906999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
34006999407SCarl Huang {
34106999407SCarl Huang 	int ret;
34206999407SCarl Huang 
34306999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3446fe6f68fSKarthikeyan Periyasamy 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab),
34506999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL,
34606999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK);
34730d08503SDan Carpenter 	if (ret) {
34806999407SCarl Huang 		ath11k_warn(ab, "failed to set sysclk: %d\n", ret);
34906999407SCarl Huang 		return ret;
35006999407SCarl Huang 	}
35106999407SCarl Huang 
35206999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3536fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab),
3546fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_VAL,
3556fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
35630d08503SDan Carpenter 	if (ret) {
35706999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret);
35806999407SCarl Huang 		return ret;
35906999407SCarl Huang 	}
36006999407SCarl Huang 
36106999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3626fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab),
3636fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_VAL,
3646fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
36530d08503SDan Carpenter 	if (ret) {
36606999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config2: %d\n", ret);
36706999407SCarl Huang 		return ret;
36806999407SCarl Huang 	}
36906999407SCarl Huang 
37006999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3716fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab),
3726fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_VAL,
3736fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
37430d08503SDan Carpenter 	if (ret) {
37506999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config4: %d\n", ret);
37606999407SCarl Huang 		return ret;
37706999407SCarl Huang 	}
37806999407SCarl Huang 
37906999407SCarl Huang 	return 0;
38006999407SCarl Huang }
38106999407SCarl Huang 
382babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
383babb0cedSCarl Huang {
384babb0cedSCarl Huang 	u32 val;
385babb0cedSCarl Huang 	int i;
386babb0cedSCarl Huang 
387babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
388babb0cedSCarl Huang 
389babb0cedSCarl Huang 	/* PCIE link seems very unstable after the Hot Reset*/
390babb0cedSCarl Huang 	for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {
391babb0cedSCarl Huang 		if (val == 0xffffffff)
392babb0cedSCarl Huang 			mdelay(5);
393babb0cedSCarl Huang 
394babb0cedSCarl Huang 		ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
395babb0cedSCarl Huang 		val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
396babb0cedSCarl Huang 	}
397babb0cedSCarl Huang 
398babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val);
399babb0cedSCarl Huang 
400babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
401562934adSKalle Valo 	val |= GCC_GCC_PCIE_HOT_RST_VAL;
402babb0cedSCarl Huang 	ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
403babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
404babb0cedSCarl Huang 
405babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val);
406babb0cedSCarl Huang 
407babb0cedSCarl Huang 	mdelay(5);
408babb0cedSCarl Huang }
409babb0cedSCarl Huang 
410babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
411babb0cedSCarl Huang {
412babb0cedSCarl Huang 	/* This is a WAR for PCIE Hotreset.
413babb0cedSCarl Huang 	 * When target receive Hotreset, but will set the interrupt.
414babb0cedSCarl Huang 	 * So when download SBL again, SBL will open Interrupt and
415babb0cedSCarl Huang 	 * receive it, and crash immediately.
416babb0cedSCarl Huang 	 */
417babb0cedSCarl Huang 	ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
418babb0cedSCarl Huang }
419babb0cedSCarl Huang 
4200ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab)
4210ccdf439SCarl Huang {
4220ccdf439SCarl Huang 	u32 val;
4230ccdf439SCarl Huang 
4240ccdf439SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG);
4250ccdf439SCarl Huang 	val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK;
4260ccdf439SCarl Huang 	ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val);
4270ccdf439SCarl Huang }
4280ccdf439SCarl Huang 
429f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
430f3c603d4SCarl Huang {
431f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
432f3c603d4SCarl Huang 	mdelay(5);
433f3c603d4SCarl Huang }
434f3c603d4SCarl Huang 
435babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
436f3c603d4SCarl Huang {
4378a0b899fSBaochen Qiang 	mdelay(100);
4388a0b899fSBaochen Qiang 
439babb0cedSCarl Huang 	if (power_on) {
440babb0cedSCarl Huang 		ath11k_pci_enable_ltssm(ab);
441babb0cedSCarl Huang 		ath11k_pci_clear_all_intrs(ab);
4420ccdf439SCarl Huang 		ath11k_pci_set_wlaon_pwr_ctrl(ab);
4435088df05SBaochen Qiang 		if (ab->hw_params.fix_l1ss)
44406999407SCarl Huang 			ath11k_pci_fix_l1ss(ab);
445babb0cedSCarl Huang 	}
446babb0cedSCarl Huang 
447f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
4488a0b899fSBaochen Qiang 	ath11k_pci_clear_dbg_registers(ab);
449f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
450f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
451f3c603d4SCarl Huang }
452f3c603d4SCarl Huang 
4531399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
4541399fb87SGovind Singh {
4551399fb87SGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(dev);
4561399fb87SGovind Singh 
4571399fb87SGovind Singh 	return pci_irq_vector(pci_dev, vector);
4581399fb87SGovind Singh }
4591399fb87SGovind Singh 
460c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
461c4eacabeSGovind Singh 				       u32 *msi_addr_hi)
462c4eacabeSGovind Singh {
463e8e55d89SAnilkumar Kolli 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
464c4eacabeSGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
465c4eacabeSGovind Singh 
466c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
467c4eacabeSGovind Singh 			      msi_addr_lo);
468c4eacabeSGovind Singh 
469e8e55d89SAnilkumar Kolli 	if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) {
470c4eacabeSGovind Singh 		pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
471c4eacabeSGovind Singh 				      msi_addr_hi);
472e8e55d89SAnilkumar Kolli 	} else {
473e8e55d89SAnilkumar Kolli 		*msi_addr_hi = 0;
474e8e55d89SAnilkumar Kolli 	}
475c4eacabeSGovind Singh }
476c4eacabeSGovind Singh 
4771399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
4781399fb87SGovind Singh 				       int *num_vectors, u32 *user_base_data,
4791399fb87SGovind Singh 				       u32 *base_vector)
4801399fb87SGovind Singh {
4811399fb87SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4827a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
4831399fb87SGovind Singh 	int idx;
4841399fb87SGovind Singh 
4857a3aed0cSAnilkumar Kolli 	for (idx = 0; idx < msi_config->total_users; idx++) {
4867a3aed0cSAnilkumar Kolli 		if (strcmp(user_name, msi_config->users[idx].name) == 0) {
4877a3aed0cSAnilkumar Kolli 			*num_vectors = msi_config->users[idx].num_vectors;
4887a3aed0cSAnilkumar Kolli 			*user_base_data = msi_config->users[idx].base_vector
4891399fb87SGovind Singh 				+ ab_pci->msi_ep_base_data;
4907a3aed0cSAnilkumar Kolli 			*base_vector = msi_config->users[idx].base_vector;
4911399fb87SGovind Singh 
4921399fb87SGovind Singh 			ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
4931399fb87SGovind Singh 				   user_name, *num_vectors, *user_base_data,
4941399fb87SGovind Singh 				   *base_vector);
4951399fb87SGovind Singh 
4961399fb87SGovind Singh 			return 0;
4971399fb87SGovind Singh 		}
4981399fb87SGovind Singh 	}
4991399fb87SGovind Singh 
5001399fb87SGovind Singh 	ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
5011399fb87SGovind Singh 
5021399fb87SGovind Singh 	return -EINVAL;
5031399fb87SGovind Singh }
5041399fb87SGovind Singh 
5056289ac2bSKarthikeyan Periyasamy static void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id,
5066289ac2bSKarthikeyan Periyasamy 				      u32 *msi_idx)
5076289ac2bSKarthikeyan Periyasamy {
5086289ac2bSKarthikeyan Periyasamy 	u32 i, msi_data_idx;
5096289ac2bSKarthikeyan Periyasamy 
5106289ac2bSKarthikeyan Periyasamy 	for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
5116289ac2bSKarthikeyan Periyasamy 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5126289ac2bSKarthikeyan Periyasamy 			continue;
5136289ac2bSKarthikeyan Periyasamy 
5146289ac2bSKarthikeyan Periyasamy 		if (ce_id == i)
5156289ac2bSKarthikeyan Periyasamy 			break;
5166289ac2bSKarthikeyan Periyasamy 
5176289ac2bSKarthikeyan Periyasamy 		msi_data_idx++;
5186289ac2bSKarthikeyan Periyasamy 	}
5196289ac2bSKarthikeyan Periyasamy 	*msi_idx = msi_data_idx;
5206289ac2bSKarthikeyan Periyasamy }
5216289ac2bSKarthikeyan Periyasamy 
522c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
523c4eacabeSGovind Singh 					  int *num_vectors, u32 *user_base_data,
524c4eacabeSGovind Singh 					  u32 *base_vector)
525c4eacabeSGovind Singh {
526c4eacabeSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
527c4eacabeSGovind Singh 
528c4eacabeSGovind Singh 	return ath11k_pci_get_user_msi_assignment(ab_pci, user_name,
529c4eacabeSGovind Singh 						  num_vectors, user_base_data,
530c4eacabeSGovind Singh 						  base_vector);
531c4eacabeSGovind Singh }
532c4eacabeSGovind Singh 
533d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
534d4ecb90bSCarl Huang {
535d4ecb90bSCarl Huang 	int i, j;
536d4ecb90bSCarl Huang 
537d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
538d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
539d4ecb90bSCarl Huang 
540d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++)
541d4ecb90bSCarl Huang 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
542d4ecb90bSCarl Huang 
543d4ecb90bSCarl Huang 		netif_napi_del(&irq_grp->napi);
544d4ecb90bSCarl Huang 	}
545d4ecb90bSCarl Huang }
546d4ecb90bSCarl Huang 
5477f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab)
5487f4beda2SGovind Singh {
5497f4beda2SGovind Singh 	int i, irq_idx;
5507f4beda2SGovind Singh 
551d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
552e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5537f4beda2SGovind Singh 			continue;
5547f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5557f4beda2SGovind Singh 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
5567f4beda2SGovind Singh 	}
557d4ecb90bSCarl Huang 
558d4ecb90bSCarl Huang 	ath11k_pci_free_ext_irq(ab);
5597f4beda2SGovind Singh }
5607f4beda2SGovind Singh 
5612c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
5622c3960c2SGovind Singh {
5632c3960c2SGovind Singh 	u32 irq_idx;
5642c3960c2SGovind Singh 
5652c3960c2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
5662c3960c2SGovind Singh 	enable_irq(ab->irq_num[irq_idx]);
5672c3960c2SGovind Singh }
5682c3960c2SGovind Singh 
5697f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
5707f4beda2SGovind Singh {
5717f4beda2SGovind Singh 	u32 irq_idx;
5727f4beda2SGovind Singh 
5737f4beda2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
5747f4beda2SGovind Singh 	disable_irq_nosync(ab->irq_num[irq_idx]);
5757f4beda2SGovind Singh }
5767f4beda2SGovind Singh 
5772c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
5782c3960c2SGovind Singh {
5792c3960c2SGovind Singh 	int i;
5802c3960c2SGovind Singh 
581d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
582e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5832c3960c2SGovind Singh 			continue;
5842c3960c2SGovind Singh 		ath11k_pci_ce_irq_disable(ab, i);
5852c3960c2SGovind Singh 	}
5862c3960c2SGovind Singh }
5872c3960c2SGovind Singh 
5882c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
5892c3960c2SGovind Singh {
5902c3960c2SGovind Singh 	int i;
5912c3960c2SGovind Singh 	int irq_idx;
5922c3960c2SGovind Singh 
593d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
594e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5952c3960c2SGovind Singh 			continue;
5962c3960c2SGovind Singh 
5972c3960c2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5982c3960c2SGovind Singh 		synchronize_irq(ab->irq_num[irq_idx]);
5992c3960c2SGovind Singh 	}
6002c3960c2SGovind Singh }
6012c3960c2SGovind Singh 
6020f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
6032c3960c2SGovind Singh {
6040f01dcb8SAllen Pais 	struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
6052c3960c2SGovind Singh 
6062c3960c2SGovind Singh 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
6072c3960c2SGovind Singh 
6082c3960c2SGovind Singh 	ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
6092c3960c2SGovind Singh }
6102c3960c2SGovind Singh 
6117f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
6127f4beda2SGovind Singh {
6137f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = arg;
6147f4beda2SGovind Singh 
6157dc67af0SKarthikeyan Periyasamy 	/* last interrupt received for this CE */
6167dc67af0SKarthikeyan Periyasamy 	ce_pipe->timestamp = jiffies;
6177dc67af0SKarthikeyan Periyasamy 
6187f4beda2SGovind Singh 	ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
6192c3960c2SGovind Singh 	tasklet_schedule(&ce_pipe->intr_tq);
6207f4beda2SGovind Singh 
6217f4beda2SGovind Singh 	return IRQ_HANDLED;
6227f4beda2SGovind Singh }
6237f4beda2SGovind Singh 
624d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
625d4ecb90bSCarl Huang {
626d4ecb90bSCarl Huang 	int i;
627d4ecb90bSCarl Huang 
628d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
629d4ecb90bSCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
630d4ecb90bSCarl Huang }
631d4ecb90bSCarl Huang 
632d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
633d4ecb90bSCarl Huang {
634d4ecb90bSCarl Huang 	int i;
635d4ecb90bSCarl Huang 
636d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
637d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
638d4ecb90bSCarl Huang 
639d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
640d4ecb90bSCarl Huang 
641d4ecb90bSCarl Huang 		napi_synchronize(&irq_grp->napi);
642d4ecb90bSCarl Huang 		napi_disable(&irq_grp->napi);
643d4ecb90bSCarl Huang 	}
644d4ecb90bSCarl Huang }
645d4ecb90bSCarl Huang 
646d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
647d4ecb90bSCarl Huang {
648d4ecb90bSCarl Huang 	int i;
649d4ecb90bSCarl Huang 
650d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
651d4ecb90bSCarl Huang 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
652d4ecb90bSCarl Huang }
653d4ecb90bSCarl Huang 
654d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
655d4ecb90bSCarl Huang {
656d4ecb90bSCarl Huang 	int i;
657d4ecb90bSCarl Huang 
658d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
659d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
660d4ecb90bSCarl Huang 
661d4ecb90bSCarl Huang 		napi_enable(&irq_grp->napi);
662d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
663d4ecb90bSCarl Huang 	}
664d4ecb90bSCarl Huang }
665d4ecb90bSCarl Huang 
666d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
667d4ecb90bSCarl Huang {
668d4ecb90bSCarl Huang 	int i, j, irq_idx;
669d4ecb90bSCarl Huang 
670d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
671d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
672d4ecb90bSCarl Huang 
673d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
674d4ecb90bSCarl Huang 			irq_idx = irq_grp->irqs[j];
675d4ecb90bSCarl Huang 			synchronize_irq(ab->irq_num[irq_idx]);
676d4ecb90bSCarl Huang 		}
677d4ecb90bSCarl Huang 	}
678d4ecb90bSCarl Huang }
679d4ecb90bSCarl Huang 
680d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
681d4ecb90bSCarl Huang {
682d4ecb90bSCarl Huang 	__ath11k_pci_ext_irq_disable(ab);
683d4ecb90bSCarl Huang 	ath11k_pci_sync_ext_irqs(ab);
684d4ecb90bSCarl Huang }
685d4ecb90bSCarl Huang 
686d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
687d4ecb90bSCarl Huang {
688d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
689d4ecb90bSCarl Huang 						struct ath11k_ext_irq_grp,
690d4ecb90bSCarl Huang 						napi);
691d4ecb90bSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
692d4ecb90bSCarl Huang 	int work_done;
693d4ecb90bSCarl Huang 
694d4ecb90bSCarl Huang 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
695d4ecb90bSCarl Huang 	if (work_done < budget) {
696d4ecb90bSCarl Huang 		napi_complete_done(napi, work_done);
697d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
698d4ecb90bSCarl Huang 	}
699d4ecb90bSCarl Huang 
700d4ecb90bSCarl Huang 	if (work_done > budget)
701d4ecb90bSCarl Huang 		work_done = budget;
702d4ecb90bSCarl Huang 
703d4ecb90bSCarl Huang 	return work_done;
704d4ecb90bSCarl Huang }
705d4ecb90bSCarl Huang 
706d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
707d4ecb90bSCarl Huang {
708d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = arg;
709d4ecb90bSCarl Huang 
710d4ecb90bSCarl Huang 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
711d4ecb90bSCarl Huang 
7127dc67af0SKarthikeyan Periyasamy 	/* last interrupt received for this group */
7137dc67af0SKarthikeyan Periyasamy 	irq_grp->timestamp = jiffies;
7147dc67af0SKarthikeyan Periyasamy 
715d4ecb90bSCarl Huang 	ath11k_pci_ext_grp_disable(irq_grp);
716d4ecb90bSCarl Huang 
717d4ecb90bSCarl Huang 	napi_schedule(&irq_grp->napi);
718d4ecb90bSCarl Huang 
719d4ecb90bSCarl Huang 	return IRQ_HANDLED;
720d4ecb90bSCarl Huang }
721d4ecb90bSCarl Huang 
722d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
723d4ecb90bSCarl Huang {
724d4ecb90bSCarl Huang 	int i, j, ret, num_vectors = 0;
7257dc67af0SKarthikeyan Periyasamy 	u32 user_base_data = 0, base_vector = 0, base_idx;
726d4ecb90bSCarl Huang 
7277dc67af0SKarthikeyan Periyasamy 	base_idx = ATH11K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX;
728b2c09458SColin Ian King 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
729b2c09458SColin Ian King 						 &num_vectors,
730b2c09458SColin Ian King 						 &user_base_data,
731d4ecb90bSCarl Huang 						 &base_vector);
732b2c09458SColin Ian King 	if (ret < 0)
733b2c09458SColin Ian King 		return ret;
734d4ecb90bSCarl Huang 
735d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
736d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
737d4ecb90bSCarl Huang 		u32 num_irq = 0;
738d4ecb90bSCarl Huang 
739d4ecb90bSCarl Huang 		irq_grp->ab = ab;
740d4ecb90bSCarl Huang 		irq_grp->grp_id = i;
741d4ecb90bSCarl Huang 		init_dummy_netdev(&irq_grp->napi_ndev);
742d4ecb90bSCarl Huang 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
743d4ecb90bSCarl Huang 			       ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
744d4ecb90bSCarl Huang 
745d4ecb90bSCarl Huang 		if (ab->hw_params.ring_mask->tx[i] ||
746d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx[i] ||
747d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_err[i] ||
748d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_wbm_rel[i] ||
749d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->reo_status[i] ||
750d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rxdma2host[i] ||
751d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->host2rxdma[i] ||
752d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_mon_status[i]) {
753d4ecb90bSCarl Huang 			num_irq = 1;
754d4ecb90bSCarl Huang 		}
755d4ecb90bSCarl Huang 
756d4ecb90bSCarl Huang 		irq_grp->num_irq = num_irq;
7577dc67af0SKarthikeyan Periyasamy 		irq_grp->irqs[0] = base_idx + i;
758d4ecb90bSCarl Huang 
759d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
760d4ecb90bSCarl Huang 			int irq_idx = irq_grp->irqs[j];
761d4ecb90bSCarl Huang 			int vector = (i % num_vectors) + base_vector;
762d4ecb90bSCarl Huang 			int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
763d4ecb90bSCarl Huang 
764d4ecb90bSCarl Huang 			ab->irq_num[irq_idx] = irq;
765d4ecb90bSCarl Huang 
766d4ecb90bSCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
767d4ecb90bSCarl Huang 				   "irq:%d group:%d\n", irq, i);
7687dc67af0SKarthikeyan Periyasamy 
7697dc67af0SKarthikeyan Periyasamy 			irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
770d4ecb90bSCarl Huang 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
771d4ecb90bSCarl Huang 					  IRQF_SHARED,
772d4ecb90bSCarl Huang 					  "DP_EXT_IRQ", irq_grp);
773d4ecb90bSCarl Huang 			if (ret) {
774d4ecb90bSCarl Huang 				ath11k_err(ab, "failed request irq %d: %d\n",
775d4ecb90bSCarl Huang 					   vector, ret);
776d4ecb90bSCarl Huang 				return ret;
777d4ecb90bSCarl Huang 			}
778d4ecb90bSCarl Huang 
779d4ecb90bSCarl Huang 			disable_irq_nosync(ab->irq_num[irq_idx]);
780d4ecb90bSCarl Huang 		}
781d4ecb90bSCarl Huang 	}
782d4ecb90bSCarl Huang 
783d4ecb90bSCarl Huang 	return 0;
784d4ecb90bSCarl Huang }
785d4ecb90bSCarl Huang 
7867f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab)
7877f4beda2SGovind Singh {
7887f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe;
7897f4beda2SGovind Singh 	u32 msi_data_start;
7906289ac2bSKarthikeyan Periyasamy 	u32 msi_data_count, msi_data_idx;
7917f4beda2SGovind Singh 	u32 msi_irq_start;
7927f4beda2SGovind Singh 	unsigned int msi_data;
7937f4beda2SGovind Singh 	int irq, i, ret, irq_idx;
7947f4beda2SGovind Singh 
7957f4beda2SGovind Singh 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab),
7967f4beda2SGovind Singh 						 "CE", &msi_data_count,
7977f4beda2SGovind Singh 						 &msi_data_start, &msi_irq_start);
7987f4beda2SGovind Singh 	if (ret)
7997f4beda2SGovind Singh 		return ret;
8007f4beda2SGovind Singh 
8017f4beda2SGovind Singh 	/* Configure CE irqs */
8026289ac2bSKarthikeyan Periyasamy 	for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
803e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
8047f4beda2SGovind Singh 			continue;
8057f4beda2SGovind Singh 
8066289ac2bSKarthikeyan Periyasamy 		msi_data = (msi_data_idx % msi_data_count) + msi_irq_start;
8076289ac2bSKarthikeyan Periyasamy 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
8086289ac2bSKarthikeyan Periyasamy 		ce_pipe = &ab->ce.ce_pipe[i];
8096289ac2bSKarthikeyan Periyasamy 
8107f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
8117f4beda2SGovind Singh 
8120f01dcb8SAllen Pais 		tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
8132c3960c2SGovind Singh 
8147f4beda2SGovind Singh 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
8157f4beda2SGovind Singh 				  IRQF_SHARED, irq_name[irq_idx],
8167f4beda2SGovind Singh 				  ce_pipe);
8177f4beda2SGovind Singh 		if (ret) {
8187f4beda2SGovind Singh 			ath11k_err(ab, "failed to request irq %d: %d\n",
8197f4beda2SGovind Singh 				   irq_idx, ret);
8207f4beda2SGovind Singh 			return ret;
8217f4beda2SGovind Singh 		}
8227f4beda2SGovind Singh 
8237f4beda2SGovind Singh 		ab->irq_num[irq_idx] = irq;
8246289ac2bSKarthikeyan Periyasamy 		msi_data_idx++;
825e678fbd4SKarthikeyan Periyasamy 
826e5c860e1SCarl Huang 		ath11k_pci_ce_irq_disable(ab, i);
8277f4beda2SGovind Singh 	}
8287f4beda2SGovind Singh 
829d4ecb90bSCarl Huang 	ret = ath11k_pci_ext_irq_config(ab);
830d4ecb90bSCarl Huang 	if (ret)
831d4ecb90bSCarl Huang 		return ret;
832d4ecb90bSCarl Huang 
8337f4beda2SGovind Singh 	return 0;
8347f4beda2SGovind Singh }
8357f4beda2SGovind Singh 
8367f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
8377f4beda2SGovind Singh {
8387f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
8397f4beda2SGovind Singh 
840967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
841967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
8427f4beda2SGovind Singh 
843967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
844967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
84516001e4bSAnilkumar Kolli 	ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
846e838c14aSCarl Huang 
847e838c14aSCarl Huang 	ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
848e838c14aSCarl Huang 				    &cfg->shadow_reg_v2_len);
8497f4beda2SGovind Singh }
8507f4beda2SGovind Singh 
8517f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
8527f4beda2SGovind Singh {
8537f4beda2SGovind Singh 	int i;
8547f4beda2SGovind Singh 
855d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
856e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
8577f4beda2SGovind Singh 			continue;
8587f4beda2SGovind Singh 		ath11k_pci_ce_irq_enable(ab, i);
8597f4beda2SGovind Singh 	}
8607f4beda2SGovind Singh }
8617f4beda2SGovind Singh 
86296527d52SBaochen Qiang static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable)
86396527d52SBaochen Qiang {
86496527d52SBaochen Qiang 	struct pci_dev *dev = ab_pci->pdev;
86596527d52SBaochen Qiang 	u16 control;
86696527d52SBaochen Qiang 
86796527d52SBaochen Qiang 	pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
86896527d52SBaochen Qiang 
86996527d52SBaochen Qiang 	if (enable)
87096527d52SBaochen Qiang 		control |= PCI_MSI_FLAGS_ENABLE;
87196527d52SBaochen Qiang 	else
87296527d52SBaochen Qiang 		control &= ~PCI_MSI_FLAGS_ENABLE;
87396527d52SBaochen Qiang 
87496527d52SBaochen Qiang 	pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
87596527d52SBaochen Qiang }
87696527d52SBaochen Qiang 
87796527d52SBaochen Qiang static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci)
87896527d52SBaochen Qiang {
87996527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, true);
88096527d52SBaochen Qiang }
88196527d52SBaochen Qiang 
88296527d52SBaochen Qiang static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci)
88396527d52SBaochen Qiang {
88496527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, false);
88596527d52SBaochen Qiang }
88696527d52SBaochen Qiang 
88796527d52SBaochen Qiang static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
8885697a564SGovind Singh {
8895697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
8907a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
8915697a564SGovind Singh 	struct msi_desc *msi_desc;
8925697a564SGovind Singh 	int num_vectors;
8935697a564SGovind Singh 	int ret;
8945697a564SGovind Singh 
8955697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
8967a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
8977a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
8985697a564SGovind Singh 					    PCI_IRQ_MSI);
8997a3aed0cSAnilkumar Kolli 	if (num_vectors != msi_config->total_vectors) {
9005697a564SGovind Singh 		ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
9017a3aed0cSAnilkumar Kolli 			   msi_config->total_vectors, num_vectors);
9025697a564SGovind Singh 
9035697a564SGovind Singh 		if (num_vectors >= 0)
9045697a564SGovind Singh 			return -EINVAL;
9055697a564SGovind Singh 		else
9065697a564SGovind Singh 			return num_vectors;
9075697a564SGovind Singh 	}
90896527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
9095697a564SGovind Singh 
9105697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
9115697a564SGovind Singh 	if (!msi_desc) {
9125697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
9135697a564SGovind Singh 		ret = -EINVAL;
9145697a564SGovind Singh 		goto free_msi_vector;
9155697a564SGovind Singh 	}
9165697a564SGovind Singh 
9175697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
918e8e55d89SAnilkumar Kolli 	if (msi_desc->msi_attrib.is_64)
919e8e55d89SAnilkumar Kolli 		set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags);
9205697a564SGovind Singh 
9215697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
9225697a564SGovind Singh 
9235697a564SGovind Singh 	return 0;
9245697a564SGovind Singh 
9255697a564SGovind Singh free_msi_vector:
9265697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
9275697a564SGovind Singh 
9285697a564SGovind Singh 	return ret;
9295697a564SGovind Singh }
9305697a564SGovind Singh 
93196527d52SBaochen Qiang static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci)
9325697a564SGovind Singh {
9335697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
9345697a564SGovind Singh }
9355697a564SGovind Singh 
9365762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
9375762613eSGovind Singh {
9385762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
9395762613eSGovind Singh 	u16 device_id;
9405762613eSGovind Singh 	int ret = 0;
9415762613eSGovind Singh 
9425762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
9435762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
9445762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
9455762613eSGovind Singh 			   device_id, ab_pci->dev_id);
9465762613eSGovind Singh 		ret = -EIO;
9475762613eSGovind Singh 		goto out;
9485762613eSGovind Singh 	}
9495762613eSGovind Singh 
9505762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
9515762613eSGovind Singh 	if (ret) {
9525762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
9535762613eSGovind Singh 		goto out;
9545762613eSGovind Singh 	}
9555762613eSGovind Singh 
9565762613eSGovind Singh 	ret = pci_enable_device(pdev);
9575762613eSGovind Singh 	if (ret) {
9585762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
9595762613eSGovind Singh 		goto out;
9605762613eSGovind Singh 	}
9615762613eSGovind Singh 
9625762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
9635762613eSGovind Singh 	if (ret) {
9645762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
9655762613eSGovind Singh 		goto disable_device;
9665762613eSGovind Singh 	}
9675762613eSGovind Singh 
968923a1346SChristophe JAILLET 	ret = dma_set_mask_and_coherent(&pdev->dev,
969923a1346SChristophe JAILLET 					DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
9705762613eSGovind Singh 	if (ret) {
9715762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
9725762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
9735762613eSGovind Singh 		goto release_region;
9745762613eSGovind Singh 	}
9755762613eSGovind Singh 
9765762613eSGovind Singh 	pci_set_master(pdev);
9775762613eSGovind Singh 
9785762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
9795762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
9805762613eSGovind Singh 	if (!ab->mem) {
9815762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
9825762613eSGovind Singh 		ret = -EIO;
9835762613eSGovind Singh 		goto clear_master;
9845762613eSGovind Singh 	}
9855762613eSGovind Singh 
9865762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
9875762613eSGovind Singh 	return 0;
9885762613eSGovind Singh 
9895762613eSGovind Singh clear_master:
9905762613eSGovind Singh 	pci_clear_master(pdev);
9915762613eSGovind Singh release_region:
9925762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
9935762613eSGovind Singh disable_device:
9945762613eSGovind Singh 	pci_disable_device(pdev);
9955762613eSGovind Singh out:
9965762613eSGovind Singh 	return ret;
9975762613eSGovind Singh }
9985762613eSGovind Singh 
9995762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
10005762613eSGovind Singh {
10015762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
10025762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
10035762613eSGovind Singh 
10045762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
10055762613eSGovind Singh 	ab->mem = NULL;
10065762613eSGovind Singh 	pci_clear_master(pci_dev);
10075762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
10085762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
10095762613eSGovind Singh 		pci_disable_device(pci_dev);
10105762613eSGovind Singh }
10115762613eSGovind Singh 
1012e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
1013e9603f4bSCarl Huang {
1014e9603f4bSCarl Huang 	struct ath11k_base *ab = ab_pci->ab;
1015e9603f4bSCarl Huang 
1016e9603f4bSCarl Huang 	pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1017e9603f4bSCarl Huang 				  &ab_pci->link_ctl);
1018e9603f4bSCarl Huang 
1019e9603f4bSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n",
1020e9603f4bSCarl Huang 		   ab_pci->link_ctl,
1021e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S),
1022e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
1023e9603f4bSCarl Huang 
1024e9603f4bSCarl Huang 	/* disable L0s and L1 */
1025e9603f4bSCarl Huang 	pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1026e9603f4bSCarl Huang 				   ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
1027e9603f4bSCarl Huang 
1028e9603f4bSCarl Huang 	set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags);
1029e9603f4bSCarl Huang }
1030e9603f4bSCarl Huang 
1031e9603f4bSCarl Huang static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci)
1032e9603f4bSCarl Huang {
1033e9603f4bSCarl Huang 	if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags))
1034e9603f4bSCarl Huang 		pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1035e9603f4bSCarl Huang 					   ab_pci->link_ctl);
1036e9603f4bSCarl Huang }
1037e9603f4bSCarl Huang 
10381399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
10391399fb87SGovind Singh {
10401399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
10411399fb87SGovind Singh 	int ret;
10421399fb87SGovind Singh 
1043a05bd851SCarl Huang 	ab_pci->register_window = 0;
1044a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1045babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, true);
1046f3c603d4SCarl Huang 
1047e9603f4bSCarl Huang 	/* Disable ASPM during firmware download due to problems switching
1048e9603f4bSCarl Huang 	 * to AMSS state.
1049e9603f4bSCarl Huang 	 */
1050e9603f4bSCarl Huang 	ath11k_pci_aspm_disable(ab_pci);
1051e9603f4bSCarl Huang 
105296527d52SBaochen Qiang 	ath11k_pci_msi_enable(ab_pci);
105396527d52SBaochen Qiang 
10541399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
10551399fb87SGovind Singh 	if (ret) {
10561399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
10571399fb87SGovind Singh 		return ret;
10581399fb87SGovind Singh 	}
10591399fb87SGovind Singh 
1060480a7361SKarthikeyan Periyasamy 	if (ab->bus_params.static_window_map)
1061480a7361SKarthikeyan Periyasamy 		ath11k_pci_select_static_window(ab_pci);
1062480a7361SKarthikeyan Periyasamy 
10631399fb87SGovind Singh 	return 0;
10641399fb87SGovind Singh }
10651399fb87SGovind Singh 
10661399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
10671399fb87SGovind Singh {
10681399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
10691399fb87SGovind Singh 
1070e9603f4bSCarl Huang 	/* restore aspm in case firmware bootup fails */
1071e9603f4bSCarl Huang 	ath11k_pci_aspm_restore(ab_pci);
1072e9603f4bSCarl Huang 
1073babb0cedSCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
107496527d52SBaochen Qiang 
107596527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
107696527d52SBaochen Qiang 
10771399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
1078a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1079babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, false);
10801399fb87SGovind Singh }
10811399fb87SGovind Singh 
1082fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab)
1083fa5917e4SCarl Huang {
1084fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
1085fa5917e4SCarl Huang 
1086fa5917e4SCarl Huang 	ath11k_mhi_suspend(ar_pci);
1087fa5917e4SCarl Huang 
1088fa5917e4SCarl Huang 	return 0;
1089fa5917e4SCarl Huang }
1090fa5917e4SCarl Huang 
1091fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab)
1092fa5917e4SCarl Huang {
1093fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
1094fa5917e4SCarl Huang 
1095fa5917e4SCarl Huang 	ath11k_mhi_resume(ar_pci);
1096fa5917e4SCarl Huang 
1097fa5917e4SCarl Huang 	return 0;
1098fa5917e4SCarl Huang }
1099fa5917e4SCarl Huang 
11002c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
11012c3960c2SGovind Singh {
11022c3960c2SGovind Singh 	int i;
11032c3960c2SGovind Singh 
1104d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
11052c3960c2SGovind Singh 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
11062c3960c2SGovind Singh 
1107e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
11082c3960c2SGovind Singh 			continue;
11092c3960c2SGovind Singh 
11102c3960c2SGovind Singh 		tasklet_kill(&ce_pipe->intr_tq);
11112c3960c2SGovind Singh 	}
11122c3960c2SGovind Singh }
11132c3960c2SGovind Singh 
1114d578ec2aSCarl Huang static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab)
11157f4beda2SGovind Singh {
11162c3960c2SGovind Singh 	ath11k_pci_ce_irqs_disable(ab);
11172c3960c2SGovind Singh 	ath11k_pci_sync_ce_irqs(ab);
11182c3960c2SGovind Singh 	ath11k_pci_kill_tasklets(ab);
1119d578ec2aSCarl Huang }
1120d578ec2aSCarl Huang 
1121d578ec2aSCarl Huang static void ath11k_pci_stop(struct ath11k_base *ab)
1122d578ec2aSCarl Huang {
1123d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
11247f4beda2SGovind Singh 	ath11k_ce_cleanup_pipes(ab);
11257f4beda2SGovind Singh }
11267f4beda2SGovind Singh 
11277f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab)
11287f4beda2SGovind Singh {
1129a05bd851SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
1130a05bd851SCarl Huang 
1131a05bd851SCarl Huang 	set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1132a05bd851SCarl Huang 
1133e9603f4bSCarl Huang 	ath11k_pci_aspm_restore(ab_pci);
1134e9603f4bSCarl Huang 
11357f4beda2SGovind Singh 	ath11k_pci_ce_irqs_enable(ab);
11362c3960c2SGovind Singh 	ath11k_ce_rx_post_buf(ab);
11372c3960c2SGovind Singh 
11382c3960c2SGovind Singh 	return 0;
11392c3960c2SGovind Singh }
11402c3960c2SGovind Singh 
1141d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab)
1142d578ec2aSCarl Huang {
1143d578ec2aSCarl Huang 	ath11k_pci_ce_irqs_enable(ab);
1144d578ec2aSCarl Huang }
1145d578ec2aSCarl Huang 
1146d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab)
1147d578ec2aSCarl Huang {
1148d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
1149d578ec2aSCarl Huang }
1150d578ec2aSCarl Huang 
11512c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
11522c3960c2SGovind Singh 					  u8 *ul_pipe, u8 *dl_pipe)
11532c3960c2SGovind Singh {
11542c3960c2SGovind Singh 	const struct service_to_pipe *entry;
11552c3960c2SGovind Singh 	bool ul_set = false, dl_set = false;
11562c3960c2SGovind Singh 	int i;
11572c3960c2SGovind Singh 
1158967c1d11SAnilkumar Kolli 	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
1159967c1d11SAnilkumar Kolli 		entry = &ab->hw_params.svc_to_ce_map[i];
11602c3960c2SGovind Singh 
11612c3960c2SGovind Singh 		if (__le32_to_cpu(entry->service_id) != service_id)
11622c3960c2SGovind Singh 			continue;
11632c3960c2SGovind Singh 
11642c3960c2SGovind Singh 		switch (__le32_to_cpu(entry->pipedir)) {
11652c3960c2SGovind Singh 		case PIPEDIR_NONE:
11662c3960c2SGovind Singh 			break;
11672c3960c2SGovind Singh 		case PIPEDIR_IN:
11682c3960c2SGovind Singh 			WARN_ON(dl_set);
11692c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
11702c3960c2SGovind Singh 			dl_set = true;
11712c3960c2SGovind Singh 			break;
11722c3960c2SGovind Singh 		case PIPEDIR_OUT:
11732c3960c2SGovind Singh 			WARN_ON(ul_set);
11742c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
11752c3960c2SGovind Singh 			ul_set = true;
11762c3960c2SGovind Singh 			break;
11772c3960c2SGovind Singh 		case PIPEDIR_INOUT:
11782c3960c2SGovind Singh 			WARN_ON(dl_set);
11792c3960c2SGovind Singh 			WARN_ON(ul_set);
11802c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
11812c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
11822c3960c2SGovind Singh 			dl_set = true;
11832c3960c2SGovind Singh 			ul_set = true;
11842c3960c2SGovind Singh 			break;
11852c3960c2SGovind Singh 		}
11862c3960c2SGovind Singh 	}
11872c3960c2SGovind Singh 
11882c3960c2SGovind Singh 	if (WARN_ON(!ul_set || !dl_set))
11892c3960c2SGovind Singh 		return -ENOENT;
11907f4beda2SGovind Singh 
11917f4beda2SGovind Singh 	return 0;
11927f4beda2SGovind Singh }
11937f4beda2SGovind Singh 
11947f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
11957f4beda2SGovind Singh 	.start = ath11k_pci_start,
11967f4beda2SGovind Singh 	.stop = ath11k_pci_stop,
1197654e959aSGovind Singh 	.read32 = ath11k_pci_read32,
1198654e959aSGovind Singh 	.write32 = ath11k_pci_write32,
11991399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
12001399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
1201fa5917e4SCarl Huang 	.suspend = ath11k_pci_hif_suspend,
1202fa5917e4SCarl Huang 	.resume = ath11k_pci_hif_resume,
1203d4ecb90bSCarl Huang 	.irq_enable = ath11k_pci_ext_irq_enable,
1204d4ecb90bSCarl Huang 	.irq_disable = ath11k_pci_ext_irq_disable,
1205c4eacabeSGovind Singh 	.get_msi_address =  ath11k_pci_get_msi_address,
1206c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
12072c3960c2SGovind Singh 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
1208d578ec2aSCarl Huang 	.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
1209d578ec2aSCarl Huang 	.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
12106289ac2bSKarthikeyan Periyasamy 	.get_ce_msi_idx = ath11k_pci_get_ce_msi_idx,
12111399fb87SGovind Singh };
12121399fb87SGovind Singh 
12130fbf1957SBaochen Qiang static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor)
12140fbf1957SBaochen Qiang {
12150fbf1957SBaochen Qiang 	u32 soc_hw_version;
12160fbf1957SBaochen Qiang 
12170fbf1957SBaochen Qiang 	soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION);
12180fbf1957SBaochen Qiang 	*major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
12190fbf1957SBaochen Qiang 			   soc_hw_version);
12200fbf1957SBaochen Qiang 	*minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
12210fbf1957SBaochen Qiang 			   soc_hw_version);
12220fbf1957SBaochen Qiang 
12230fbf1957SBaochen Qiang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
12240fbf1957SBaochen Qiang 		   *major, *minor);
12250fbf1957SBaochen Qiang }
12260fbf1957SBaochen Qiang 
12276e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
12286e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
12296e0355afSGovind Singh {
12306e0355afSGovind Singh 	struct ath11k_base *ab;
12315762613eSGovind Singh 	struct ath11k_pci *ab_pci;
12320fbf1957SBaochen Qiang 	u32 soc_hw_version_major, soc_hw_version_minor;
12335762613eSGovind Singh 	int ret;
12346e0355afSGovind Singh 
12351ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
12361ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
12376e0355afSGovind Singh 	if (!ab) {
12386e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
12396e0355afSGovind Singh 		return -ENOMEM;
12406e0355afSGovind Singh 	}
12416e0355afSGovind Singh 
12426e0355afSGovind Singh 	ab->dev = &pdev->dev;
12436e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
12445762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
12455762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
12465762613eSGovind Singh 	ab_pci->ab = ab;
12475697a564SGovind Singh 	ab_pci->pdev = pdev;
12487f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
12495762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
1250654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
12515762613eSGovind Singh 
12525762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
12535762613eSGovind Singh 	if (ret) {
12545762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
12555762613eSGovind Singh 		goto err_free_core;
12565762613eSGovind Singh 	}
12576e0355afSGovind Singh 
1258fc95d10aSWen Gong 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n",
1259fc95d10aSWen Gong 		   pdev->vendor, pdev->device,
1260fc95d10aSWen Gong 		   pdev->subsystem_vendor, pdev->subsystem_device);
1261fc95d10aSWen Gong 
1262fc95d10aSWen Gong 	ab->id.vendor = pdev->vendor;
1263fc95d10aSWen Gong 	ab->id.device = pdev->device;
1264fc95d10aSWen Gong 	ab->id.subsystem_vendor = pdev->subsystem_vendor;
1265fc95d10aSWen Gong 	ab->id.subsystem_device = pdev->subsystem_device;
1266fc95d10aSWen Gong 
126718ac1665SKalle Valo 	switch (pci_dev->device) {
126818ac1665SKalle Valo 	case QCA6390_DEVICE_ID:
12690fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
12700fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
127118ac1665SKalle Valo 		switch (soc_hw_version_major) {
127218ac1665SKalle Valo 		case 2:
127318ac1665SKalle Valo 			ab->hw_rev = ATH11K_HW_QCA6390_HW20;
127418ac1665SKalle Valo 			break;
127518ac1665SKalle Valo 		default:
127618ac1665SKalle Valo 			dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n",
127718ac1665SKalle Valo 				soc_hw_version_major, soc_hw_version_minor);
127818ac1665SKalle Valo 			ret = -EOPNOTSUPP;
127918ac1665SKalle Valo 			goto err_pci_free_region;
128018ac1665SKalle Valo 		}
12814e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[0];
12824e809461SAnilkumar Kolli 		break;
12834e809461SAnilkumar Kolli 	case QCN9074_DEVICE_ID:
12844e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[1];
12854e809461SAnilkumar Kolli 		ab->bus_params.static_window_map = true;
12864e809461SAnilkumar Kolli 		ab->hw_rev = ATH11K_HW_QCN9074_HW10;
128718ac1665SKalle Valo 		break;
12880fbf1957SBaochen Qiang 	case WCN6855_DEVICE_ID:
1289fc95d10aSWen Gong 		ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD;
12900fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
12910fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
12920fbf1957SBaochen Qiang 		switch (soc_hw_version_major) {
12930fbf1957SBaochen Qiang 		case 2:
12940fbf1957SBaochen Qiang 			ab->hw_rev = ATH11K_HW_WCN6855_HW20;
12950fbf1957SBaochen Qiang 			break;
12960fbf1957SBaochen Qiang 		default:
12970fbf1957SBaochen Qiang 			dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n",
12980fbf1957SBaochen Qiang 				soc_hw_version_major, soc_hw_version_minor);
12990fbf1957SBaochen Qiang 			ret = -EOPNOTSUPP;
13000fbf1957SBaochen Qiang 			goto err_pci_free_region;
13010fbf1957SBaochen Qiang 		}
13020fbf1957SBaochen Qiang 		ab_pci->msi_config = &ath11k_msi_config[0];
13030fbf1957SBaochen Qiang 		break;
130418ac1665SKalle Valo 	default:
130518ac1665SKalle Valo 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
130618ac1665SKalle Valo 			pci_dev->device);
130718ac1665SKalle Valo 		ret = -EOPNOTSUPP;
130818ac1665SKalle Valo 		goto err_pci_free_region;
130918ac1665SKalle Valo 	}
131018ac1665SKalle Valo 
131196527d52SBaochen Qiang 	ret = ath11k_pci_alloc_msi(ab_pci);
13125697a564SGovind Singh 	if (ret) {
13135697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
13145697a564SGovind Singh 		goto err_pci_free_region;
13155697a564SGovind Singh 	}
13165697a564SGovind Singh 
1317b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
1318b8246f88SKalle Valo 	if (ret)
1319b8246f88SKalle Valo 		goto err_pci_disable_msi;
1320b8246f88SKalle Valo 
13211399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
13221399fb87SGovind Singh 	if (ret) {
13231399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
13241399fb87SGovind Singh 		goto err_pci_disable_msi;
13251399fb87SGovind Singh 	}
13261399fb87SGovind Singh 
13277f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
13287f4beda2SGovind Singh 	if (ret)
13297f4beda2SGovind Singh 		goto err_mhi_unregister;
13307f4beda2SGovind Singh 
13317f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
13327f4beda2SGovind Singh 	if (ret) {
13337f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
13347f4beda2SGovind Singh 		goto err_hal_srng_deinit;
13357f4beda2SGovind Singh 	}
13367f4beda2SGovind Singh 
13377f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
13387f4beda2SGovind Singh 
13397f4beda2SGovind Singh 	ret = ath11k_pci_config_irq(ab);
13407f4beda2SGovind Singh 	if (ret) {
13417f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
13427f4beda2SGovind Singh 		goto err_ce_free;
13437f4beda2SGovind Singh 	}
13447f4beda2SGovind Singh 
13457f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
13467f4beda2SGovind Singh 	if (ret) {
13477f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
13487f4beda2SGovind Singh 		goto err_free_irq;
13497f4beda2SGovind Singh 	}
13506e0355afSGovind Singh 	return 0;
13515762613eSGovind Singh 
13527f4beda2SGovind Singh err_free_irq:
13537f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
13547f4beda2SGovind Singh 
13557f4beda2SGovind Singh err_ce_free:
13567f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
13577f4beda2SGovind Singh 
13587f4beda2SGovind Singh err_hal_srng_deinit:
13597f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
13607f4beda2SGovind Singh 
13617f4beda2SGovind Singh err_mhi_unregister:
13627f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
13637f4beda2SGovind Singh 
1364b8246f88SKalle Valo err_pci_disable_msi:
136596527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
1366b8246f88SKalle Valo 
13675697a564SGovind Singh err_pci_free_region:
13685697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
13695697a564SGovind Singh 
13705762613eSGovind Singh err_free_core:
13715762613eSGovind Singh 	ath11k_core_free(ab);
13725697a564SGovind Singh 
13735762613eSGovind Singh 	return ret;
13746e0355afSGovind Singh }
13756e0355afSGovind Singh 
13766e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
13776e0355afSGovind Singh {
13786e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
13795762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
13806e0355afSGovind Singh 
138161a57e51SAnilkumar Kolli 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
138261a57e51SAnilkumar Kolli 		ath11k_pci_power_down(ab);
138361a57e51SAnilkumar Kolli 		ath11k_debugfs_soc_destroy(ab);
138461a57e51SAnilkumar Kolli 		ath11k_qmi_deinit_service(ab);
138561a57e51SAnilkumar Kolli 		goto qmi_fail;
138661a57e51SAnilkumar Kolli 	}
138761a57e51SAnilkumar Kolli 
13886e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
13896fbd8898SCarl Huang 
13906fbd8898SCarl Huang 	ath11k_core_deinit(ab);
13916fbd8898SCarl Huang 
139261a57e51SAnilkumar Kolli qmi_fail:
13931399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
13946fbd8898SCarl Huang 
13956fbd8898SCarl Huang 	ath11k_pci_free_irq(ab);
139696527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
13975762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
13986fbd8898SCarl Huang 
13996fbd8898SCarl Huang 	ath11k_hal_srng_deinit(ab);
14006fbd8898SCarl Huang 	ath11k_ce_free_pipes(ab);
14016e0355afSGovind Singh 	ath11k_core_free(ab);
14026e0355afSGovind Singh }
14036e0355afSGovind Singh 
14041399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
14051399fb87SGovind Singh {
14061399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
14071399fb87SGovind Singh 
14081399fb87SGovind Singh 	ath11k_pci_power_down(ab);
14091399fb87SGovind Singh }
14101399fb87SGovind Singh 
1411d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
1412d1b0c338SCarl Huang {
1413d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1414d1b0c338SCarl Huang 	int ret;
1415d1b0c338SCarl Huang 
1416d1b0c338SCarl Huang 	ret = ath11k_core_suspend(ab);
1417d1b0c338SCarl Huang 	if (ret)
1418d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to suspend core: %d\n", ret);
1419d1b0c338SCarl Huang 
1420d1b0c338SCarl Huang 	return ret;
1421d1b0c338SCarl Huang }
1422d1b0c338SCarl Huang 
1423d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
1424d1b0c338SCarl Huang {
1425d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1426d1b0c338SCarl Huang 	int ret;
1427d1b0c338SCarl Huang 
1428d1b0c338SCarl Huang 	ret = ath11k_core_resume(ab);
1429d1b0c338SCarl Huang 	if (ret)
1430d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to resume core: %d\n", ret);
1431d1b0c338SCarl Huang 
1432d1b0c338SCarl Huang 	return ret;
1433d1b0c338SCarl Huang }
1434d1b0c338SCarl Huang 
1435d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
1436d1b0c338SCarl Huang 			 ath11k_pci_pm_suspend,
1437d1b0c338SCarl Huang 			 ath11k_pci_pm_resume);
1438d1b0c338SCarl Huang 
14396e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
14406e0355afSGovind Singh 	.name = "ath11k_pci",
14416e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
14426e0355afSGovind Singh 	.probe = ath11k_pci_probe,
14436e0355afSGovind Singh 	.remove = ath11k_pci_remove,
14441399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
1445d1b0c338SCarl Huang #ifdef CONFIG_PM
1446d1b0c338SCarl Huang 	.driver.pm = &ath11k_pci_pm_ops,
1447d1b0c338SCarl Huang #endif
14486e0355afSGovind Singh };
14496e0355afSGovind Singh 
14506e0355afSGovind Singh static int ath11k_pci_init(void)
14516e0355afSGovind Singh {
14526e0355afSGovind Singh 	int ret;
14536e0355afSGovind Singh 
14546e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
14556e0355afSGovind Singh 	if (ret)
14566e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
14576e0355afSGovind Singh 		       ret);
14586e0355afSGovind Singh 
14596e0355afSGovind Singh 	return ret;
14606e0355afSGovind Singh }
14616e0355afSGovind Singh module_init(ath11k_pci_init);
14626e0355afSGovind Singh 
14636e0355afSGovind Singh static void ath11k_pci_exit(void)
14646e0355afSGovind Singh {
14656e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
14666e0355afSGovind Singh }
14676e0355afSGovind Singh 
14686e0355afSGovind Singh module_exit(ath11k_pci_exit);
14696e0355afSGovind Singh 
14706e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
14716e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
14723dbd7fe7SDevin Bayer 
14733dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */
14743dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE);
14753dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE);
14763dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE);
1477