xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision 4e80946197a83a6115e308334618449b77696d6a)
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
38*4e809461SAnilkumar Kolli #define QCN9074_DEVICE_ID		0x1104
396e0355afSGovind Singh 
406e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = {
416e0355afSGovind Singh 	{ PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) },
42*4e809461SAnilkumar Kolli 	/* TODO: add QCN9074_DEVICE_ID) once firmware issues are resolved */
436e0355afSGovind Singh 	{0}
446e0355afSGovind Singh };
456e0355afSGovind Singh 
466e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table);
476e0355afSGovind Singh 
481ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = {
491ff8ed78SGovind Singh 	.mhi_support = true,
5056970454SGovind Singh 	.m3_fw_support = true,
516eb6ea51SGovind Singh 	.fixed_bdf_addr = false,
526eb6ea51SGovind Singh 	.fixed_mem_region = false,
531ff8ed78SGovind Singh };
541ff8ed78SGovind Singh 
557a3aed0cSAnilkumar Kolli static const struct ath11k_msi_config ath11k_msi_config[] = {
567a3aed0cSAnilkumar Kolli 	{
575697a564SGovind Singh 		.total_vectors = 32,
585697a564SGovind Singh 		.total_users = 4,
595697a564SGovind Singh 		.users = (struct ath11k_msi_user[]) {
605697a564SGovind Singh 			{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
615697a564SGovind Singh 			{ .name = "CE", .num_vectors = 10, .base_vector = 3 },
625697a564SGovind Singh 			{ .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
635697a564SGovind Singh 			{ .name = "DP", .num_vectors = 18, .base_vector = 14 },
645697a564SGovind Singh 		},
657a3aed0cSAnilkumar Kolli 	},
66*4e809461SAnilkumar Kolli 	{
67*4e809461SAnilkumar Kolli 		.total_vectors = 16,
68*4e809461SAnilkumar Kolli 		.total_users = 3,
69*4e809461SAnilkumar Kolli 		.users = (struct ath11k_msi_user[]) {
70*4e809461SAnilkumar Kolli 			{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
71*4e809461SAnilkumar Kolli 			{ .name = "CE", .num_vectors = 5, .base_vector = 3 },
72*4e809461SAnilkumar Kolli 			{ .name = "DP", .num_vectors = 8, .base_vector = 8 },
73*4e809461SAnilkumar Kolli 		},
74*4e809461SAnilkumar Kolli 	},
755697a564SGovind Singh };
765697a564SGovind Singh 
777f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
787f4beda2SGovind Singh 	"bhi",
797f4beda2SGovind Singh 	"mhi-er0",
807f4beda2SGovind Singh 	"mhi-er1",
817f4beda2SGovind Singh 	"ce0",
827f4beda2SGovind Singh 	"ce1",
837f4beda2SGovind Singh 	"ce2",
847f4beda2SGovind Singh 	"ce3",
857f4beda2SGovind Singh 	"ce4",
867f4beda2SGovind Singh 	"ce5",
877f4beda2SGovind Singh 	"ce6",
887f4beda2SGovind Singh 	"ce7",
897f4beda2SGovind Singh 	"ce8",
907f4beda2SGovind Singh 	"ce9",
917f4beda2SGovind Singh 	"ce10",
927f4beda2SGovind Singh 	"ce11",
937f4beda2SGovind Singh 	"host2wbm-desc-feed",
947f4beda2SGovind Singh 	"host2reo-re-injection",
957f4beda2SGovind Singh 	"host2reo-command",
967f4beda2SGovind Singh 	"host2rxdma-monitor-ring3",
977f4beda2SGovind Singh 	"host2rxdma-monitor-ring2",
987f4beda2SGovind Singh 	"host2rxdma-monitor-ring1",
997f4beda2SGovind Singh 	"reo2ost-exception",
1007f4beda2SGovind Singh 	"wbm2host-rx-release",
1017f4beda2SGovind Singh 	"reo2host-status",
1027f4beda2SGovind Singh 	"reo2host-destination-ring4",
1037f4beda2SGovind Singh 	"reo2host-destination-ring3",
1047f4beda2SGovind Singh 	"reo2host-destination-ring2",
1057f4beda2SGovind Singh 	"reo2host-destination-ring1",
1067f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac3",
1077f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac2",
1087f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac1",
1097f4beda2SGovind Singh 	"ppdu-end-interrupts-mac3",
1107f4beda2SGovind Singh 	"ppdu-end-interrupts-mac2",
1117f4beda2SGovind Singh 	"ppdu-end-interrupts-mac1",
1127f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac3",
1137f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac2",
1147f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac1",
1157f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac3",
1167f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac2",
1177f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac1",
1187f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac3",
1197f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac2",
1207f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac1",
1217f4beda2SGovind Singh 	"host2tcl-input-ring4",
1227f4beda2SGovind Singh 	"host2tcl-input-ring3",
1237f4beda2SGovind Singh 	"host2tcl-input-ring2",
1247f4beda2SGovind Singh 	"host2tcl-input-ring1",
1257f4beda2SGovind Singh 	"wbm2host-tx-completions-ring3",
1267f4beda2SGovind Singh 	"wbm2host-tx-completions-ring2",
1277f4beda2SGovind Singh 	"wbm2host-tx-completions-ring1",
1287f4beda2SGovind Singh 	"tcl2host-status-ring",
1297f4beda2SGovind Singh };
1307f4beda2SGovind Singh 
131654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset)
132654e959aSGovind Singh {
133654e959aSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
134654e959aSGovind Singh 
135654e959aSGovind Singh 	u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset);
136654e959aSGovind Singh 
137654e959aSGovind Singh 	lockdep_assert_held(&ab_pci->window_lock);
138654e959aSGovind Singh 
139654e959aSGovind Singh 	if (window != ab_pci->register_window) {
140654e959aSGovind Singh 		iowrite32(WINDOW_ENABLE_BIT | window,
141654e959aSGovind Singh 			  ab->mem + WINDOW_REG_ADDRESS);
142f6fa37a4SCarl Huang 		ioread32(ab->mem + WINDOW_REG_ADDRESS);
143654e959aSGovind Singh 		ab_pci->register_window = window;
144654e959aSGovind Singh 	}
145654e959aSGovind Singh }
146654e959aSGovind Singh 
147480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci)
148480a7361SKarthikeyan Periyasamy {
149480a7361SKarthikeyan Periyasamy 	u32 umac_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET);
150480a7361SKarthikeyan Periyasamy 	u32 ce_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE);
151480a7361SKarthikeyan Periyasamy 	u32 window;
152480a7361SKarthikeyan Periyasamy 
153480a7361SKarthikeyan Periyasamy 	window = (umac_window << 12) | (ce_window << 6);
154480a7361SKarthikeyan Periyasamy 
155480a7361SKarthikeyan Periyasamy 	iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + WINDOW_REG_ADDRESS);
156480a7361SKarthikeyan Periyasamy }
157480a7361SKarthikeyan Periyasamy 
158480a7361SKarthikeyan Periyasamy static inline u32 ath11k_pci_get_window_start(struct ath11k_base *ab,
159480a7361SKarthikeyan Periyasamy 					      u32 offset)
160480a7361SKarthikeyan Periyasamy {
161480a7361SKarthikeyan Periyasamy 	u32 window_start;
162480a7361SKarthikeyan Periyasamy 
163480a7361SKarthikeyan Periyasamy 	/* If offset lies within DP register range, use 3rd window */
164480a7361SKarthikeyan Periyasamy 	if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < WINDOW_RANGE_MASK)
165480a7361SKarthikeyan Periyasamy 		window_start = 3 * WINDOW_START;
166480a7361SKarthikeyan Periyasamy 	/* If offset lies within CE register range, use 2nd window */
167480a7361SKarthikeyan Periyasamy 	else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK)
168480a7361SKarthikeyan Periyasamy 		window_start = 2 * WINDOW_START;
169480a7361SKarthikeyan Periyasamy 	else
170480a7361SKarthikeyan Periyasamy 		window_start = WINDOW_START;
171480a7361SKarthikeyan Periyasamy 
172480a7361SKarthikeyan Periyasamy 	return window_start;
173480a7361SKarthikeyan Periyasamy }
174480a7361SKarthikeyan Periyasamy 
175f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
176654e959aSGovind Singh {
177654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
178480a7361SKarthikeyan Periyasamy 	u32 window_start;
179654e959aSGovind Singh 
180a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
181a05bd851SCarl Huang 	 * need to wakeup MHI to access.
182a05bd851SCarl Huang 	 */
183a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
184a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
185a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
186a05bd851SCarl Huang 
187654e959aSGovind Singh 	if (offset < WINDOW_START) {
188654e959aSGovind Singh 		iowrite32(value, ab->mem  + offset);
189654e959aSGovind Singh 	} else {
190480a7361SKarthikeyan Periyasamy 		if (ab->bus_params.static_window_map)
191480a7361SKarthikeyan Periyasamy 			window_start = ath11k_pci_get_window_start(ab, offset);
192480a7361SKarthikeyan Periyasamy 		else
193480a7361SKarthikeyan Periyasamy 			window_start = WINDOW_START;
194480a7361SKarthikeyan Periyasamy 
195480a7361SKarthikeyan Periyasamy 		if (window_start == WINDOW_START) {
196654e959aSGovind Singh 			spin_lock_bh(&ab_pci->window_lock);
197654e959aSGovind Singh 			ath11k_pci_select_window(ab_pci, offset);
198480a7361SKarthikeyan Periyasamy 			iowrite32(value, ab->mem + window_start +
199480a7361SKarthikeyan Periyasamy 				  (offset & WINDOW_RANGE_MASK));
200654e959aSGovind Singh 			spin_unlock_bh(&ab_pci->window_lock);
201480a7361SKarthikeyan Periyasamy 		} else {
202480a7361SKarthikeyan Periyasamy 			iowrite32(value, ab->mem + window_start +
203480a7361SKarthikeyan Periyasamy 				  (offset & WINDOW_RANGE_MASK));
204480a7361SKarthikeyan Periyasamy 		}
205654e959aSGovind Singh 	}
206a05bd851SCarl Huang 
207a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
208a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
209a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
210654e959aSGovind Singh }
211654e959aSGovind Singh 
212f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
213654e959aSGovind Singh {
214654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
215480a7361SKarthikeyan Periyasamy 	u32 val, window_start;
216654e959aSGovind Singh 
217a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
218a05bd851SCarl Huang 	 * need to wakeup MHI to access.
219a05bd851SCarl Huang 	 */
220a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
221a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
222a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
223a05bd851SCarl Huang 
224654e959aSGovind Singh 	if (offset < WINDOW_START) {
225654e959aSGovind Singh 		val = ioread32(ab->mem + offset);
226654e959aSGovind Singh 	} else {
227480a7361SKarthikeyan Periyasamy 		if (ab->bus_params.static_window_map)
228480a7361SKarthikeyan Periyasamy 			window_start = ath11k_pci_get_window_start(ab, offset);
229480a7361SKarthikeyan Periyasamy 		else
230480a7361SKarthikeyan Periyasamy 			window_start = WINDOW_START;
231480a7361SKarthikeyan Periyasamy 
232480a7361SKarthikeyan Periyasamy 		if (window_start == WINDOW_START) {
233654e959aSGovind Singh 			spin_lock_bh(&ab_pci->window_lock);
234654e959aSGovind Singh 			ath11k_pci_select_window(ab_pci, offset);
235480a7361SKarthikeyan Periyasamy 			val = ioread32(ab->mem + window_start +
236480a7361SKarthikeyan Periyasamy 				       (offset & WINDOW_RANGE_MASK));
237654e959aSGovind Singh 			spin_unlock_bh(&ab_pci->window_lock);
238480a7361SKarthikeyan Periyasamy 		} else {
239480a7361SKarthikeyan Periyasamy 			val = ioread32(ab->mem + window_start +
240480a7361SKarthikeyan Periyasamy 				       (offset & WINDOW_RANGE_MASK));
241480a7361SKarthikeyan Periyasamy 		}
242654e959aSGovind Singh 	}
243654e959aSGovind Singh 
244a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
245a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
246a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
247a05bd851SCarl Huang 
248654e959aSGovind Singh 	return val;
249654e959aSGovind Singh }
250654e959aSGovind Singh 
251f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
252f3c603d4SCarl Huang {
253f3c603d4SCarl Huang 	u32 val, delay;
254f3c603d4SCarl Huang 
255f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
256f3c603d4SCarl Huang 
257f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
258f3c603d4SCarl Huang 
259f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
260f3c603d4SCarl Huang 
261f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
262f3c603d4SCarl Huang 	delay = 10;
263f3c603d4SCarl Huang 	mdelay(delay);
264f3c603d4SCarl Huang 
265f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
266f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
267f3c603d4SCarl Huang 
268f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
269f3c603d4SCarl Huang 
270f3c603d4SCarl Huang 	mdelay(delay);
271f3c603d4SCarl Huang 
272f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
273f3c603d4SCarl Huang 	if (val == 0xffffffff)
274f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
275f3c603d4SCarl Huang }
276f3c603d4SCarl Huang 
277f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
278f3c603d4SCarl Huang {
279f3c603d4SCarl Huang 	u32 val;
280f3c603d4SCarl Huang 
281f3c603d4SCarl Huang 	/* read cookie */
282f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR);
283f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val);
284f3c603d4SCarl Huang 
285f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
286f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
287f3c603d4SCarl Huang 
288f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
289f3c603d4SCarl Huang 	mdelay(10);
290f3c603d4SCarl Huang 
291f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
292f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
293f3c603d4SCarl Huang 	 */
294f3c603d4SCarl Huang 	ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0);
295f3c603d4SCarl Huang 	mdelay(10);
296f3c603d4SCarl Huang 
297f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
298f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
299f3c603d4SCarl Huang 
300f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
301f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
302f3c603d4SCarl Huang 	 */
303f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
304f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
305f3c603d4SCarl Huang }
306f3c603d4SCarl Huang 
30706999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab,
30806999407SCarl Huang 				   u32 offset, u32 value, u32 mask)
30906999407SCarl Huang {
31006999407SCarl Huang 	u32 v;
31106999407SCarl Huang 	int i;
31206999407SCarl Huang 
31306999407SCarl Huang 	v = ath11k_pci_read32(ab, offset);
31406999407SCarl Huang 	if ((v & mask) == value)
31506999407SCarl Huang 		return 0;
31606999407SCarl Huang 
31706999407SCarl Huang 	for (i = 0; i < 10; i++) {
31806999407SCarl Huang 		ath11k_pci_write32(ab, offset, (v & ~mask) | value);
31906999407SCarl Huang 
32006999407SCarl Huang 		v = ath11k_pci_read32(ab, offset);
32106999407SCarl Huang 		if ((v & mask) == value)
32206999407SCarl Huang 			return 0;
32306999407SCarl Huang 
32406999407SCarl Huang 		mdelay(2);
32506999407SCarl Huang 	}
32606999407SCarl Huang 
32706999407SCarl Huang 	ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n",
32806999407SCarl Huang 		    offset, v & mask, value);
32906999407SCarl Huang 
33006999407SCarl Huang 	return -ETIMEDOUT;
33106999407SCarl Huang }
33206999407SCarl Huang 
33306999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
33406999407SCarl Huang {
33506999407SCarl Huang 	int ret;
33606999407SCarl Huang 
33706999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3386fe6f68fSKarthikeyan Periyasamy 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab),
33906999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL,
34006999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK);
34130d08503SDan Carpenter 	if (ret) {
34206999407SCarl Huang 		ath11k_warn(ab, "failed to set sysclk: %d\n", ret);
34306999407SCarl Huang 		return ret;
34406999407SCarl Huang 	}
34506999407SCarl Huang 
34606999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3476fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab),
3486fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_VAL,
3496fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
35030d08503SDan Carpenter 	if (ret) {
35106999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret);
35206999407SCarl Huang 		return ret;
35306999407SCarl Huang 	}
35406999407SCarl Huang 
35506999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3566fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab),
3576fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_VAL,
3586fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
35930d08503SDan Carpenter 	if (ret) {
36006999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config2: %d\n", ret);
36106999407SCarl Huang 		return ret;
36206999407SCarl Huang 	}
36306999407SCarl Huang 
36406999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3656fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab),
3666fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_VAL,
3676fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
36830d08503SDan Carpenter 	if (ret) {
36906999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config4: %d\n", ret);
37006999407SCarl Huang 		return ret;
37106999407SCarl Huang 	}
37206999407SCarl Huang 
37306999407SCarl Huang 	return 0;
37406999407SCarl Huang }
37506999407SCarl Huang 
376babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
377babb0cedSCarl Huang {
378babb0cedSCarl Huang 	u32 val;
379babb0cedSCarl Huang 	int i;
380babb0cedSCarl Huang 
381babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
382babb0cedSCarl Huang 
383babb0cedSCarl Huang 	/* PCIE link seems very unstable after the Hot Reset*/
384babb0cedSCarl Huang 	for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {
385babb0cedSCarl Huang 		if (val == 0xffffffff)
386babb0cedSCarl Huang 			mdelay(5);
387babb0cedSCarl Huang 
388babb0cedSCarl Huang 		ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
389babb0cedSCarl Huang 		val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
390babb0cedSCarl Huang 	}
391babb0cedSCarl Huang 
392babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val);
393babb0cedSCarl Huang 
394babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
395562934adSKalle Valo 	val |= GCC_GCC_PCIE_HOT_RST_VAL;
396babb0cedSCarl Huang 	ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
397babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
398babb0cedSCarl Huang 
399babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val);
400babb0cedSCarl Huang 
401babb0cedSCarl Huang 	mdelay(5);
402babb0cedSCarl Huang }
403babb0cedSCarl Huang 
404babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
405babb0cedSCarl Huang {
406babb0cedSCarl Huang 	/* This is a WAR for PCIE Hotreset.
407babb0cedSCarl Huang 	 * When target receive Hotreset, but will set the interrupt.
408babb0cedSCarl Huang 	 * So when download SBL again, SBL will open Interrupt and
409babb0cedSCarl Huang 	 * receive it, and crash immediately.
410babb0cedSCarl Huang 	 */
411babb0cedSCarl Huang 	ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
412babb0cedSCarl Huang }
413babb0cedSCarl Huang 
4140ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab)
4150ccdf439SCarl Huang {
4160ccdf439SCarl Huang 	u32 val;
4170ccdf439SCarl Huang 
4180ccdf439SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG);
4190ccdf439SCarl Huang 	val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK;
4200ccdf439SCarl Huang 	ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val);
4210ccdf439SCarl Huang }
4220ccdf439SCarl Huang 
423f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
424f3c603d4SCarl Huang {
425f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
426f3c603d4SCarl Huang 	mdelay(5);
427f3c603d4SCarl Huang }
428f3c603d4SCarl Huang 
429babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
430f3c603d4SCarl Huang {
431babb0cedSCarl Huang 	if (power_on) {
432babb0cedSCarl Huang 		ath11k_pci_enable_ltssm(ab);
433babb0cedSCarl Huang 		ath11k_pci_clear_all_intrs(ab);
4340ccdf439SCarl Huang 		ath11k_pci_set_wlaon_pwr_ctrl(ab);
43506999407SCarl Huang 		ath11k_pci_fix_l1ss(ab);
436babb0cedSCarl Huang 	}
437babb0cedSCarl Huang 
438f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
439f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
440f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
441f3c603d4SCarl Huang 	ath11k_pci_clear_dbg_registers(ab);
442f3c603d4SCarl Huang }
443f3c603d4SCarl Huang 
4441399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
4451399fb87SGovind Singh {
4461399fb87SGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(dev);
4471399fb87SGovind Singh 
4481399fb87SGovind Singh 	return pci_irq_vector(pci_dev, vector);
4491399fb87SGovind Singh }
4501399fb87SGovind Singh 
451c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
452c4eacabeSGovind Singh 				       u32 *msi_addr_hi)
453c4eacabeSGovind Singh {
454e8e55d89SAnilkumar Kolli 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
455c4eacabeSGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
456c4eacabeSGovind Singh 
457c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
458c4eacabeSGovind Singh 			      msi_addr_lo);
459c4eacabeSGovind Singh 
460e8e55d89SAnilkumar Kolli 	if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) {
461c4eacabeSGovind Singh 		pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
462c4eacabeSGovind Singh 				      msi_addr_hi);
463e8e55d89SAnilkumar Kolli 	} else {
464e8e55d89SAnilkumar Kolli 		*msi_addr_hi = 0;
465e8e55d89SAnilkumar Kolli 	}
466c4eacabeSGovind Singh }
467c4eacabeSGovind Singh 
4681399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
4691399fb87SGovind Singh 				       int *num_vectors, u32 *user_base_data,
4701399fb87SGovind Singh 				       u32 *base_vector)
4711399fb87SGovind Singh {
4721399fb87SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4737a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
4741399fb87SGovind Singh 	int idx;
4751399fb87SGovind Singh 
4767a3aed0cSAnilkumar Kolli 	for (idx = 0; idx < msi_config->total_users; idx++) {
4777a3aed0cSAnilkumar Kolli 		if (strcmp(user_name, msi_config->users[idx].name) == 0) {
4787a3aed0cSAnilkumar Kolli 			*num_vectors = msi_config->users[idx].num_vectors;
4797a3aed0cSAnilkumar Kolli 			*user_base_data = msi_config->users[idx].base_vector
4801399fb87SGovind Singh 				+ ab_pci->msi_ep_base_data;
4817a3aed0cSAnilkumar Kolli 			*base_vector = msi_config->users[idx].base_vector;
4821399fb87SGovind Singh 
4831399fb87SGovind Singh 			ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
4841399fb87SGovind Singh 				   user_name, *num_vectors, *user_base_data,
4851399fb87SGovind Singh 				   *base_vector);
4861399fb87SGovind Singh 
4871399fb87SGovind Singh 			return 0;
4881399fb87SGovind Singh 		}
4891399fb87SGovind Singh 	}
4901399fb87SGovind Singh 
4911399fb87SGovind Singh 	ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
4921399fb87SGovind Singh 
4931399fb87SGovind Singh 	return -EINVAL;
4941399fb87SGovind Singh }
4951399fb87SGovind Singh 
4966289ac2bSKarthikeyan Periyasamy static void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id,
4976289ac2bSKarthikeyan Periyasamy 				      u32 *msi_idx)
4986289ac2bSKarthikeyan Periyasamy {
4996289ac2bSKarthikeyan Periyasamy 	u32 i, msi_data_idx;
5006289ac2bSKarthikeyan Periyasamy 
5016289ac2bSKarthikeyan Periyasamy 	for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
5026289ac2bSKarthikeyan Periyasamy 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5036289ac2bSKarthikeyan Periyasamy 			continue;
5046289ac2bSKarthikeyan Periyasamy 
5056289ac2bSKarthikeyan Periyasamy 		if (ce_id == i)
5066289ac2bSKarthikeyan Periyasamy 			break;
5076289ac2bSKarthikeyan Periyasamy 
5086289ac2bSKarthikeyan Periyasamy 		msi_data_idx++;
5096289ac2bSKarthikeyan Periyasamy 	}
5106289ac2bSKarthikeyan Periyasamy 	*msi_idx = msi_data_idx;
5116289ac2bSKarthikeyan Periyasamy }
5126289ac2bSKarthikeyan Periyasamy 
513c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
514c4eacabeSGovind Singh 					  int *num_vectors, u32 *user_base_data,
515c4eacabeSGovind Singh 					  u32 *base_vector)
516c4eacabeSGovind Singh {
517c4eacabeSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
518c4eacabeSGovind Singh 
519c4eacabeSGovind Singh 	return ath11k_pci_get_user_msi_assignment(ab_pci, user_name,
520c4eacabeSGovind Singh 						  num_vectors, user_base_data,
521c4eacabeSGovind Singh 						  base_vector);
522c4eacabeSGovind Singh }
523c4eacabeSGovind Singh 
524d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
525d4ecb90bSCarl Huang {
526d4ecb90bSCarl Huang 	int i, j;
527d4ecb90bSCarl Huang 
528d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
529d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
530d4ecb90bSCarl Huang 
531d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++)
532d4ecb90bSCarl Huang 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
533d4ecb90bSCarl Huang 
534d4ecb90bSCarl Huang 		netif_napi_del(&irq_grp->napi);
535d4ecb90bSCarl Huang 	}
536d4ecb90bSCarl Huang }
537d4ecb90bSCarl Huang 
5387f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab)
5397f4beda2SGovind Singh {
5407f4beda2SGovind Singh 	int i, irq_idx;
5417f4beda2SGovind Singh 
542d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
543e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5447f4beda2SGovind Singh 			continue;
5457f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5467f4beda2SGovind Singh 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
5477f4beda2SGovind Singh 	}
548d4ecb90bSCarl Huang 
549d4ecb90bSCarl Huang 	ath11k_pci_free_ext_irq(ab);
5507f4beda2SGovind Singh }
5517f4beda2SGovind Singh 
5522c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
5532c3960c2SGovind Singh {
5542c3960c2SGovind Singh 	u32 irq_idx;
5552c3960c2SGovind Singh 
5562c3960c2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
5572c3960c2SGovind Singh 	enable_irq(ab->irq_num[irq_idx]);
5582c3960c2SGovind Singh }
5592c3960c2SGovind Singh 
5607f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
5617f4beda2SGovind Singh {
5627f4beda2SGovind Singh 	u32 irq_idx;
5637f4beda2SGovind Singh 
5647f4beda2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
5657f4beda2SGovind Singh 	disable_irq_nosync(ab->irq_num[irq_idx]);
5667f4beda2SGovind Singh }
5677f4beda2SGovind Singh 
5682c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
5692c3960c2SGovind Singh {
5702c3960c2SGovind Singh 	int i;
5712c3960c2SGovind Singh 
572d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
573e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5742c3960c2SGovind Singh 			continue;
5752c3960c2SGovind Singh 		ath11k_pci_ce_irq_disable(ab, i);
5762c3960c2SGovind Singh 	}
5772c3960c2SGovind Singh }
5782c3960c2SGovind Singh 
5792c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
5802c3960c2SGovind Singh {
5812c3960c2SGovind Singh 	int i;
5822c3960c2SGovind Singh 	int irq_idx;
5832c3960c2SGovind Singh 
584d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
585e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5862c3960c2SGovind Singh 			continue;
5872c3960c2SGovind Singh 
5882c3960c2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5892c3960c2SGovind Singh 		synchronize_irq(ab->irq_num[irq_idx]);
5902c3960c2SGovind Singh 	}
5912c3960c2SGovind Singh }
5922c3960c2SGovind Singh 
5930f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
5942c3960c2SGovind Singh {
5950f01dcb8SAllen Pais 	struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
5962c3960c2SGovind Singh 
5972c3960c2SGovind Singh 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
5982c3960c2SGovind Singh 
5992c3960c2SGovind Singh 	ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
6002c3960c2SGovind Singh }
6012c3960c2SGovind Singh 
6027f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
6037f4beda2SGovind Singh {
6047f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = arg;
6057f4beda2SGovind Singh 
6067dc67af0SKarthikeyan Periyasamy 	/* last interrupt received for this CE */
6077dc67af0SKarthikeyan Periyasamy 	ce_pipe->timestamp = jiffies;
6087dc67af0SKarthikeyan Periyasamy 
6097f4beda2SGovind Singh 	ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
6102c3960c2SGovind Singh 	tasklet_schedule(&ce_pipe->intr_tq);
6117f4beda2SGovind Singh 
6127f4beda2SGovind Singh 	return IRQ_HANDLED;
6137f4beda2SGovind Singh }
6147f4beda2SGovind Singh 
615d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
616d4ecb90bSCarl Huang {
617d4ecb90bSCarl Huang 	int i;
618d4ecb90bSCarl Huang 
619d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
620d4ecb90bSCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
621d4ecb90bSCarl Huang }
622d4ecb90bSCarl Huang 
623d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
624d4ecb90bSCarl Huang {
625d4ecb90bSCarl Huang 	int i;
626d4ecb90bSCarl Huang 
627d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
628d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
629d4ecb90bSCarl Huang 
630d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
631d4ecb90bSCarl Huang 
632d4ecb90bSCarl Huang 		napi_synchronize(&irq_grp->napi);
633d4ecb90bSCarl Huang 		napi_disable(&irq_grp->napi);
634d4ecb90bSCarl Huang 	}
635d4ecb90bSCarl Huang }
636d4ecb90bSCarl Huang 
637d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
638d4ecb90bSCarl Huang {
639d4ecb90bSCarl Huang 	int i;
640d4ecb90bSCarl Huang 
641d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
642d4ecb90bSCarl Huang 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
643d4ecb90bSCarl Huang }
644d4ecb90bSCarl Huang 
645d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
646d4ecb90bSCarl Huang {
647d4ecb90bSCarl Huang 	int i;
648d4ecb90bSCarl Huang 
649d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
650d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
651d4ecb90bSCarl Huang 
652d4ecb90bSCarl Huang 		napi_enable(&irq_grp->napi);
653d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
654d4ecb90bSCarl Huang 	}
655d4ecb90bSCarl Huang }
656d4ecb90bSCarl Huang 
657d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
658d4ecb90bSCarl Huang {
659d4ecb90bSCarl Huang 	int i, j, irq_idx;
660d4ecb90bSCarl Huang 
661d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
662d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
663d4ecb90bSCarl Huang 
664d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
665d4ecb90bSCarl Huang 			irq_idx = irq_grp->irqs[j];
666d4ecb90bSCarl Huang 			synchronize_irq(ab->irq_num[irq_idx]);
667d4ecb90bSCarl Huang 		}
668d4ecb90bSCarl Huang 	}
669d4ecb90bSCarl Huang }
670d4ecb90bSCarl Huang 
671d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
672d4ecb90bSCarl Huang {
673d4ecb90bSCarl Huang 	__ath11k_pci_ext_irq_disable(ab);
674d4ecb90bSCarl Huang 	ath11k_pci_sync_ext_irqs(ab);
675d4ecb90bSCarl Huang }
676d4ecb90bSCarl Huang 
677d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
678d4ecb90bSCarl Huang {
679d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
680d4ecb90bSCarl Huang 						struct ath11k_ext_irq_grp,
681d4ecb90bSCarl Huang 						napi);
682d4ecb90bSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
683d4ecb90bSCarl Huang 	int work_done;
684d4ecb90bSCarl Huang 
685d4ecb90bSCarl Huang 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
686d4ecb90bSCarl Huang 	if (work_done < budget) {
687d4ecb90bSCarl Huang 		napi_complete_done(napi, work_done);
688d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
689d4ecb90bSCarl Huang 	}
690d4ecb90bSCarl Huang 
691d4ecb90bSCarl Huang 	if (work_done > budget)
692d4ecb90bSCarl Huang 		work_done = budget;
693d4ecb90bSCarl Huang 
694d4ecb90bSCarl Huang 	return work_done;
695d4ecb90bSCarl Huang }
696d4ecb90bSCarl Huang 
697d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
698d4ecb90bSCarl Huang {
699d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = arg;
700d4ecb90bSCarl Huang 
701d4ecb90bSCarl Huang 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
702d4ecb90bSCarl Huang 
7037dc67af0SKarthikeyan Periyasamy 	/* last interrupt received for this group */
7047dc67af0SKarthikeyan Periyasamy 	irq_grp->timestamp = jiffies;
7057dc67af0SKarthikeyan Periyasamy 
706d4ecb90bSCarl Huang 	ath11k_pci_ext_grp_disable(irq_grp);
707d4ecb90bSCarl Huang 
708d4ecb90bSCarl Huang 	napi_schedule(&irq_grp->napi);
709d4ecb90bSCarl Huang 
710d4ecb90bSCarl Huang 	return IRQ_HANDLED;
711d4ecb90bSCarl Huang }
712d4ecb90bSCarl Huang 
713d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
714d4ecb90bSCarl Huang {
715d4ecb90bSCarl Huang 	int i, j, ret, num_vectors = 0;
7167dc67af0SKarthikeyan Periyasamy 	u32 user_base_data = 0, base_vector = 0, base_idx;
717d4ecb90bSCarl Huang 
7187dc67af0SKarthikeyan Periyasamy 	base_idx = ATH11K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX;
719b2c09458SColin Ian King 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
720b2c09458SColin Ian King 						 &num_vectors,
721b2c09458SColin Ian King 						 &user_base_data,
722d4ecb90bSCarl Huang 						 &base_vector);
723b2c09458SColin Ian King 	if (ret < 0)
724b2c09458SColin Ian King 		return ret;
725d4ecb90bSCarl Huang 
726d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
727d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
728d4ecb90bSCarl Huang 		u32 num_irq = 0;
729d4ecb90bSCarl Huang 
730d4ecb90bSCarl Huang 		irq_grp->ab = ab;
731d4ecb90bSCarl Huang 		irq_grp->grp_id = i;
732d4ecb90bSCarl Huang 		init_dummy_netdev(&irq_grp->napi_ndev);
733d4ecb90bSCarl Huang 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
734d4ecb90bSCarl Huang 			       ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
735d4ecb90bSCarl Huang 
736d4ecb90bSCarl Huang 		if (ab->hw_params.ring_mask->tx[i] ||
737d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx[i] ||
738d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_err[i] ||
739d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_wbm_rel[i] ||
740d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->reo_status[i] ||
741d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rxdma2host[i] ||
742d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->host2rxdma[i] ||
743d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_mon_status[i]) {
744d4ecb90bSCarl Huang 			num_irq = 1;
745d4ecb90bSCarl Huang 		}
746d4ecb90bSCarl Huang 
747d4ecb90bSCarl Huang 		irq_grp->num_irq = num_irq;
7487dc67af0SKarthikeyan Periyasamy 		irq_grp->irqs[0] = base_idx + i;
749d4ecb90bSCarl Huang 
750d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
751d4ecb90bSCarl Huang 			int irq_idx = irq_grp->irqs[j];
752d4ecb90bSCarl Huang 			int vector = (i % num_vectors) + base_vector;
753d4ecb90bSCarl Huang 			int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
754d4ecb90bSCarl Huang 
755d4ecb90bSCarl Huang 			ab->irq_num[irq_idx] = irq;
756d4ecb90bSCarl Huang 
757d4ecb90bSCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
758d4ecb90bSCarl Huang 				   "irq:%d group:%d\n", irq, i);
7597dc67af0SKarthikeyan Periyasamy 
7607dc67af0SKarthikeyan Periyasamy 			irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
761d4ecb90bSCarl Huang 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
762d4ecb90bSCarl Huang 					  IRQF_SHARED,
763d4ecb90bSCarl Huang 					  "DP_EXT_IRQ", irq_grp);
764d4ecb90bSCarl Huang 			if (ret) {
765d4ecb90bSCarl Huang 				ath11k_err(ab, "failed request irq %d: %d\n",
766d4ecb90bSCarl Huang 					   vector, ret);
767d4ecb90bSCarl Huang 				return ret;
768d4ecb90bSCarl Huang 			}
769d4ecb90bSCarl Huang 
770d4ecb90bSCarl Huang 			disable_irq_nosync(ab->irq_num[irq_idx]);
771d4ecb90bSCarl Huang 		}
772d4ecb90bSCarl Huang 	}
773d4ecb90bSCarl Huang 
774d4ecb90bSCarl Huang 	return 0;
775d4ecb90bSCarl Huang }
776d4ecb90bSCarl Huang 
7777f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab)
7787f4beda2SGovind Singh {
7797f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe;
7807f4beda2SGovind Singh 	u32 msi_data_start;
7816289ac2bSKarthikeyan Periyasamy 	u32 msi_data_count, msi_data_idx;
7827f4beda2SGovind Singh 	u32 msi_irq_start;
7837f4beda2SGovind Singh 	unsigned int msi_data;
7847f4beda2SGovind Singh 	int irq, i, ret, irq_idx;
7857f4beda2SGovind Singh 
7867f4beda2SGovind Singh 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab),
7877f4beda2SGovind Singh 						 "CE", &msi_data_count,
7887f4beda2SGovind Singh 						 &msi_data_start, &msi_irq_start);
7897f4beda2SGovind Singh 	if (ret)
7907f4beda2SGovind Singh 		return ret;
7917f4beda2SGovind Singh 
7927f4beda2SGovind Singh 	/* Configure CE irqs */
7936289ac2bSKarthikeyan Periyasamy 	for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
794e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
7957f4beda2SGovind Singh 			continue;
7967f4beda2SGovind Singh 
7976289ac2bSKarthikeyan Periyasamy 		msi_data = (msi_data_idx % msi_data_count) + msi_irq_start;
7986289ac2bSKarthikeyan Periyasamy 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
7996289ac2bSKarthikeyan Periyasamy 		ce_pipe = &ab->ce.ce_pipe[i];
8006289ac2bSKarthikeyan Periyasamy 
8017f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
8027f4beda2SGovind Singh 
8030f01dcb8SAllen Pais 		tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
8042c3960c2SGovind Singh 
8057f4beda2SGovind Singh 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
8067f4beda2SGovind Singh 				  IRQF_SHARED, irq_name[irq_idx],
8077f4beda2SGovind Singh 				  ce_pipe);
8087f4beda2SGovind Singh 		if (ret) {
8097f4beda2SGovind Singh 			ath11k_err(ab, "failed to request irq %d: %d\n",
8107f4beda2SGovind Singh 				   irq_idx, ret);
8117f4beda2SGovind Singh 			return ret;
8127f4beda2SGovind Singh 		}
8137f4beda2SGovind Singh 
8147f4beda2SGovind Singh 		ab->irq_num[irq_idx] = irq;
8156289ac2bSKarthikeyan Periyasamy 		msi_data_idx++;
816e678fbd4SKarthikeyan Periyasamy 
817e5c860e1SCarl Huang 		ath11k_pci_ce_irq_disable(ab, i);
8187f4beda2SGovind Singh 	}
8197f4beda2SGovind Singh 
820d4ecb90bSCarl Huang 	ret = ath11k_pci_ext_irq_config(ab);
821d4ecb90bSCarl Huang 	if (ret)
822d4ecb90bSCarl Huang 		return ret;
823d4ecb90bSCarl Huang 
8247f4beda2SGovind Singh 	return 0;
8257f4beda2SGovind Singh }
8267f4beda2SGovind Singh 
8277f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
8287f4beda2SGovind Singh {
8297f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
8307f4beda2SGovind Singh 
831967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
832967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
8337f4beda2SGovind Singh 
834967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
835967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
83616001e4bSAnilkumar Kolli 	ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
837e838c14aSCarl Huang 
838e838c14aSCarl Huang 	ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
839e838c14aSCarl Huang 				    &cfg->shadow_reg_v2_len);
8407f4beda2SGovind Singh }
8417f4beda2SGovind Singh 
8427f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
8437f4beda2SGovind Singh {
8447f4beda2SGovind Singh 	int i;
8457f4beda2SGovind Singh 
846d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
847e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
8487f4beda2SGovind Singh 			continue;
8497f4beda2SGovind Singh 		ath11k_pci_ce_irq_enable(ab, i);
8507f4beda2SGovind Singh 	}
8517f4beda2SGovind Singh }
8527f4beda2SGovind Singh 
8535697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
8545697a564SGovind Singh {
8555697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
8567a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
8575697a564SGovind Singh 	struct msi_desc *msi_desc;
8585697a564SGovind Singh 	int num_vectors;
8595697a564SGovind Singh 	int ret;
8605697a564SGovind Singh 
8615697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
8627a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
8637a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
8645697a564SGovind Singh 					    PCI_IRQ_MSI);
8657a3aed0cSAnilkumar Kolli 	if (num_vectors != msi_config->total_vectors) {
8665697a564SGovind Singh 		ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
8677a3aed0cSAnilkumar Kolli 			   msi_config->total_vectors, num_vectors);
8685697a564SGovind Singh 
8695697a564SGovind Singh 		if (num_vectors >= 0)
8705697a564SGovind Singh 			return -EINVAL;
8715697a564SGovind Singh 		else
8725697a564SGovind Singh 			return num_vectors;
8735697a564SGovind Singh 	}
8745697a564SGovind Singh 
8755697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
8765697a564SGovind Singh 	if (!msi_desc) {
8775697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
8785697a564SGovind Singh 		ret = -EINVAL;
8795697a564SGovind Singh 		goto free_msi_vector;
8805697a564SGovind Singh 	}
8815697a564SGovind Singh 
8825697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
883e8e55d89SAnilkumar Kolli 	if (msi_desc->msi_attrib.is_64)
884e8e55d89SAnilkumar Kolli 		set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags);
8855697a564SGovind Singh 
8865697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
8875697a564SGovind Singh 
8885697a564SGovind Singh 	return 0;
8895697a564SGovind Singh 
8905697a564SGovind Singh free_msi_vector:
8915697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
8925697a564SGovind Singh 
8935697a564SGovind Singh 	return ret;
8945697a564SGovind Singh }
8955697a564SGovind Singh 
8965697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci)
8975697a564SGovind Singh {
8985697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
8995697a564SGovind Singh }
9005697a564SGovind Singh 
9015762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
9025762613eSGovind Singh {
9035762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
9045762613eSGovind Singh 	u16 device_id;
9055762613eSGovind Singh 	int ret = 0;
9065762613eSGovind Singh 
9075762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
9085762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
9095762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
9105762613eSGovind Singh 			   device_id, ab_pci->dev_id);
9115762613eSGovind Singh 		ret = -EIO;
9125762613eSGovind Singh 		goto out;
9135762613eSGovind Singh 	}
9145762613eSGovind Singh 
9155762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
9165762613eSGovind Singh 	if (ret) {
9175762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
9185762613eSGovind Singh 		goto out;
9195762613eSGovind Singh 	}
9205762613eSGovind Singh 
9215762613eSGovind Singh 	ret = pci_enable_device(pdev);
9225762613eSGovind Singh 	if (ret) {
9235762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
9245762613eSGovind Singh 		goto out;
9255762613eSGovind Singh 	}
9265762613eSGovind Singh 
9275762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
9285762613eSGovind Singh 	if (ret) {
9295762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
9305762613eSGovind Singh 		goto disable_device;
9315762613eSGovind Singh 	}
9325762613eSGovind Singh 
9335762613eSGovind Singh 	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
9345762613eSGovind Singh 	if (ret) {
9355762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
9365762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
9375762613eSGovind Singh 		goto release_region;
9385762613eSGovind Singh 	}
9395762613eSGovind Singh 
9405762613eSGovind Singh 	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
9415762613eSGovind Singh 	if (ret) {
9425762613eSGovind Singh 		ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n",
9435762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
9445762613eSGovind Singh 		goto release_region;
9455762613eSGovind Singh 	}
9465762613eSGovind Singh 
9475762613eSGovind Singh 	pci_set_master(pdev);
9485762613eSGovind Singh 
9495762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
9505762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
9515762613eSGovind Singh 	if (!ab->mem) {
9525762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
9535762613eSGovind Singh 		ret = -EIO;
9545762613eSGovind Singh 		goto clear_master;
9555762613eSGovind Singh 	}
9565762613eSGovind Singh 
9575762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
9585762613eSGovind Singh 	return 0;
9595762613eSGovind Singh 
9605762613eSGovind Singh clear_master:
9615762613eSGovind Singh 	pci_clear_master(pdev);
9625762613eSGovind Singh release_region:
9635762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
9645762613eSGovind Singh disable_device:
9655762613eSGovind Singh 	pci_disable_device(pdev);
9665762613eSGovind Singh out:
9675762613eSGovind Singh 	return ret;
9685762613eSGovind Singh }
9695762613eSGovind Singh 
9705762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
9715762613eSGovind Singh {
9725762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
9735762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
9745762613eSGovind Singh 
9755762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
9765762613eSGovind Singh 	ab->mem = NULL;
9775762613eSGovind Singh 	pci_clear_master(pci_dev);
9785762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
9795762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
9805762613eSGovind Singh 		pci_disable_device(pci_dev);
9815762613eSGovind Singh }
9825762613eSGovind Singh 
983e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
984e9603f4bSCarl Huang {
985e9603f4bSCarl Huang 	struct ath11k_base *ab = ab_pci->ab;
986e9603f4bSCarl Huang 
987e9603f4bSCarl Huang 	pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL,
988e9603f4bSCarl Huang 				  &ab_pci->link_ctl);
989e9603f4bSCarl Huang 
990e9603f4bSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n",
991e9603f4bSCarl Huang 		   ab_pci->link_ctl,
992e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S),
993e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
994e9603f4bSCarl Huang 
995e9603f4bSCarl Huang 	/* disable L0s and L1 */
996e9603f4bSCarl Huang 	pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
997e9603f4bSCarl Huang 				   ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
998e9603f4bSCarl Huang 
999e9603f4bSCarl Huang 	set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags);
1000e9603f4bSCarl Huang }
1001e9603f4bSCarl Huang 
1002e9603f4bSCarl Huang static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci)
1003e9603f4bSCarl Huang {
1004e9603f4bSCarl Huang 	if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags))
1005e9603f4bSCarl Huang 		pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1006e9603f4bSCarl Huang 					   ab_pci->link_ctl);
1007e9603f4bSCarl Huang }
1008e9603f4bSCarl Huang 
10091399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
10101399fb87SGovind Singh {
10111399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
10121399fb87SGovind Singh 	int ret;
10131399fb87SGovind Singh 
1014a05bd851SCarl Huang 	ab_pci->register_window = 0;
1015a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1016babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, true);
1017f3c603d4SCarl Huang 
1018e9603f4bSCarl Huang 	/* Disable ASPM during firmware download due to problems switching
1019e9603f4bSCarl Huang 	 * to AMSS state.
1020e9603f4bSCarl Huang 	 */
1021e9603f4bSCarl Huang 	ath11k_pci_aspm_disable(ab_pci);
1022e9603f4bSCarl Huang 
10231399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
10241399fb87SGovind Singh 	if (ret) {
10251399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
10261399fb87SGovind Singh 		return ret;
10271399fb87SGovind Singh 	}
10281399fb87SGovind Singh 
1029480a7361SKarthikeyan Periyasamy 	if (ab->bus_params.static_window_map)
1030480a7361SKarthikeyan Periyasamy 		ath11k_pci_select_static_window(ab_pci);
1031480a7361SKarthikeyan Periyasamy 
10321399fb87SGovind Singh 	return 0;
10331399fb87SGovind Singh }
10341399fb87SGovind Singh 
10351399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
10361399fb87SGovind Singh {
10371399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
10381399fb87SGovind Singh 
1039e9603f4bSCarl Huang 	/* restore aspm in case firmware bootup fails */
1040e9603f4bSCarl Huang 	ath11k_pci_aspm_restore(ab_pci);
1041e9603f4bSCarl Huang 
1042babb0cedSCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
10431399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
1044a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1045babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, false);
10461399fb87SGovind Singh }
10471399fb87SGovind Singh 
1048fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab)
1049fa5917e4SCarl Huang {
1050fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
1051fa5917e4SCarl Huang 
1052fa5917e4SCarl Huang 	ath11k_mhi_suspend(ar_pci);
1053fa5917e4SCarl Huang 
1054fa5917e4SCarl Huang 	return 0;
1055fa5917e4SCarl Huang }
1056fa5917e4SCarl Huang 
1057fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab)
1058fa5917e4SCarl Huang {
1059fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
1060fa5917e4SCarl Huang 
1061fa5917e4SCarl Huang 	ath11k_mhi_resume(ar_pci);
1062fa5917e4SCarl Huang 
1063fa5917e4SCarl Huang 	return 0;
1064fa5917e4SCarl Huang }
1065fa5917e4SCarl Huang 
10662c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
10672c3960c2SGovind Singh {
10682c3960c2SGovind Singh 	int i;
10692c3960c2SGovind Singh 
1070d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
10712c3960c2SGovind Singh 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
10722c3960c2SGovind Singh 
1073e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
10742c3960c2SGovind Singh 			continue;
10752c3960c2SGovind Singh 
10762c3960c2SGovind Singh 		tasklet_kill(&ce_pipe->intr_tq);
10772c3960c2SGovind Singh 	}
10782c3960c2SGovind Singh }
10792c3960c2SGovind Singh 
1080d578ec2aSCarl Huang static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab)
10817f4beda2SGovind Singh {
10822c3960c2SGovind Singh 	ath11k_pci_ce_irqs_disable(ab);
10832c3960c2SGovind Singh 	ath11k_pci_sync_ce_irqs(ab);
10842c3960c2SGovind Singh 	ath11k_pci_kill_tasklets(ab);
1085d578ec2aSCarl Huang }
1086d578ec2aSCarl Huang 
1087d578ec2aSCarl Huang static void ath11k_pci_stop(struct ath11k_base *ab)
1088d578ec2aSCarl Huang {
1089d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
10907f4beda2SGovind Singh 	ath11k_ce_cleanup_pipes(ab);
10917f4beda2SGovind Singh }
10927f4beda2SGovind Singh 
10937f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab)
10947f4beda2SGovind Singh {
1095a05bd851SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
1096a05bd851SCarl Huang 
1097a05bd851SCarl Huang 	set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1098a05bd851SCarl Huang 
1099e9603f4bSCarl Huang 	ath11k_pci_aspm_restore(ab_pci);
1100e9603f4bSCarl Huang 
11017f4beda2SGovind Singh 	ath11k_pci_ce_irqs_enable(ab);
11022c3960c2SGovind Singh 	ath11k_ce_rx_post_buf(ab);
11032c3960c2SGovind Singh 
11042c3960c2SGovind Singh 	return 0;
11052c3960c2SGovind Singh }
11062c3960c2SGovind Singh 
1107d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab)
1108d578ec2aSCarl Huang {
1109d578ec2aSCarl Huang 	ath11k_pci_ce_irqs_enable(ab);
1110d578ec2aSCarl Huang }
1111d578ec2aSCarl Huang 
1112d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab)
1113d578ec2aSCarl Huang {
1114d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
1115d578ec2aSCarl Huang }
1116d578ec2aSCarl Huang 
11172c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
11182c3960c2SGovind Singh 					  u8 *ul_pipe, u8 *dl_pipe)
11192c3960c2SGovind Singh {
11202c3960c2SGovind Singh 	const struct service_to_pipe *entry;
11212c3960c2SGovind Singh 	bool ul_set = false, dl_set = false;
11222c3960c2SGovind Singh 	int i;
11232c3960c2SGovind Singh 
1124967c1d11SAnilkumar Kolli 	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
1125967c1d11SAnilkumar Kolli 		entry = &ab->hw_params.svc_to_ce_map[i];
11262c3960c2SGovind Singh 
11272c3960c2SGovind Singh 		if (__le32_to_cpu(entry->service_id) != service_id)
11282c3960c2SGovind Singh 			continue;
11292c3960c2SGovind Singh 
11302c3960c2SGovind Singh 		switch (__le32_to_cpu(entry->pipedir)) {
11312c3960c2SGovind Singh 		case PIPEDIR_NONE:
11322c3960c2SGovind Singh 			break;
11332c3960c2SGovind Singh 		case PIPEDIR_IN:
11342c3960c2SGovind Singh 			WARN_ON(dl_set);
11352c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
11362c3960c2SGovind Singh 			dl_set = true;
11372c3960c2SGovind Singh 			break;
11382c3960c2SGovind Singh 		case PIPEDIR_OUT:
11392c3960c2SGovind Singh 			WARN_ON(ul_set);
11402c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
11412c3960c2SGovind Singh 			ul_set = true;
11422c3960c2SGovind Singh 			break;
11432c3960c2SGovind Singh 		case PIPEDIR_INOUT:
11442c3960c2SGovind Singh 			WARN_ON(dl_set);
11452c3960c2SGovind Singh 			WARN_ON(ul_set);
11462c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
11472c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
11482c3960c2SGovind Singh 			dl_set = true;
11492c3960c2SGovind Singh 			ul_set = true;
11502c3960c2SGovind Singh 			break;
11512c3960c2SGovind Singh 		}
11522c3960c2SGovind Singh 	}
11532c3960c2SGovind Singh 
11542c3960c2SGovind Singh 	if (WARN_ON(!ul_set || !dl_set))
11552c3960c2SGovind Singh 		return -ENOENT;
11567f4beda2SGovind Singh 
11577f4beda2SGovind Singh 	return 0;
11587f4beda2SGovind Singh }
11597f4beda2SGovind Singh 
11607f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
11617f4beda2SGovind Singh 	.start = ath11k_pci_start,
11627f4beda2SGovind Singh 	.stop = ath11k_pci_stop,
1163654e959aSGovind Singh 	.read32 = ath11k_pci_read32,
1164654e959aSGovind Singh 	.write32 = ath11k_pci_write32,
11651399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
11661399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
1167fa5917e4SCarl Huang 	.suspend = ath11k_pci_hif_suspend,
1168fa5917e4SCarl Huang 	.resume = ath11k_pci_hif_resume,
1169d4ecb90bSCarl Huang 	.irq_enable = ath11k_pci_ext_irq_enable,
1170d4ecb90bSCarl Huang 	.irq_disable = ath11k_pci_ext_irq_disable,
1171c4eacabeSGovind Singh 	.get_msi_address =  ath11k_pci_get_msi_address,
1172c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
11732c3960c2SGovind Singh 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
1174d578ec2aSCarl Huang 	.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
1175d578ec2aSCarl Huang 	.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
11766289ac2bSKarthikeyan Periyasamy 	.get_ce_msi_idx = ath11k_pci_get_ce_msi_idx,
11771399fb87SGovind Singh };
11781399fb87SGovind Singh 
11796e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
11806e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
11816e0355afSGovind Singh {
11826e0355afSGovind Singh 	struct ath11k_base *ab;
11835762613eSGovind Singh 	struct ath11k_pci *ab_pci;
118418ac1665SKalle Valo 	u32 soc_hw_version, soc_hw_version_major, soc_hw_version_minor;
11855762613eSGovind Singh 	int ret;
11866e0355afSGovind Singh 
11871ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
11881ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
11896e0355afSGovind Singh 	if (!ab) {
11906e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
11916e0355afSGovind Singh 		return -ENOMEM;
11926e0355afSGovind Singh 	}
11936e0355afSGovind Singh 
11946e0355afSGovind Singh 	ab->dev = &pdev->dev;
11956e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
11965762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
11975762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
11985762613eSGovind Singh 	ab_pci->ab = ab;
11995697a564SGovind Singh 	ab_pci->pdev = pdev;
12007f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
12015762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
1202654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
12035762613eSGovind Singh 
12045762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
12055762613eSGovind Singh 	if (ret) {
12065762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
12075762613eSGovind Singh 		goto err_free_core;
12085762613eSGovind Singh 	}
12096e0355afSGovind Singh 
121018ac1665SKalle Valo 	switch (pci_dev->device) {
121118ac1665SKalle Valo 	case QCA6390_DEVICE_ID:
121218ac1665SKalle Valo 		soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION);
121318ac1665SKalle Valo 		soc_hw_version_major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
121418ac1665SKalle Valo 						 soc_hw_version);
121518ac1665SKalle Valo 		soc_hw_version_minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
121618ac1665SKalle Valo 						 soc_hw_version);
121718ac1665SKalle Valo 
121818ac1665SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
121918ac1665SKalle Valo 			   soc_hw_version_major, soc_hw_version_minor);
122018ac1665SKalle Valo 
122118ac1665SKalle Valo 		switch (soc_hw_version_major) {
122218ac1665SKalle Valo 		case 2:
122318ac1665SKalle Valo 			ab->hw_rev = ATH11K_HW_QCA6390_HW20;
122418ac1665SKalle Valo 			break;
122518ac1665SKalle Valo 		default:
122618ac1665SKalle Valo 			dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n",
122718ac1665SKalle Valo 				soc_hw_version_major, soc_hw_version_minor);
122818ac1665SKalle Valo 			ret = -EOPNOTSUPP;
122918ac1665SKalle Valo 			goto err_pci_free_region;
123018ac1665SKalle Valo 		}
1231*4e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[0];
1232*4e809461SAnilkumar Kolli 		break;
1233*4e809461SAnilkumar Kolli 	case QCN9074_DEVICE_ID:
1234*4e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[1];
1235*4e809461SAnilkumar Kolli 		ab->bus_params.static_window_map = true;
1236*4e809461SAnilkumar Kolli 		ab->hw_rev = ATH11K_HW_QCN9074_HW10;
123718ac1665SKalle Valo 		break;
123818ac1665SKalle Valo 	default:
123918ac1665SKalle Valo 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
124018ac1665SKalle Valo 			pci_dev->device);
124118ac1665SKalle Valo 		ret = -EOPNOTSUPP;
124218ac1665SKalle Valo 		goto err_pci_free_region;
124318ac1665SKalle Valo 	}
124418ac1665SKalle Valo 
12455697a564SGovind Singh 	ret = ath11k_pci_enable_msi(ab_pci);
12465697a564SGovind Singh 	if (ret) {
12475697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
12485697a564SGovind Singh 		goto err_pci_free_region;
12495697a564SGovind Singh 	}
12505697a564SGovind Singh 
1251b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
1252b8246f88SKalle Valo 	if (ret)
1253b8246f88SKalle Valo 		goto err_pci_disable_msi;
1254b8246f88SKalle Valo 
12551399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
12561399fb87SGovind Singh 	if (ret) {
12571399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
12581399fb87SGovind Singh 		goto err_pci_disable_msi;
12591399fb87SGovind Singh 	}
12601399fb87SGovind Singh 
12617f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
12627f4beda2SGovind Singh 	if (ret)
12637f4beda2SGovind Singh 		goto err_mhi_unregister;
12647f4beda2SGovind Singh 
12657f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
12667f4beda2SGovind Singh 	if (ret) {
12677f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
12687f4beda2SGovind Singh 		goto err_hal_srng_deinit;
12697f4beda2SGovind Singh 	}
12707f4beda2SGovind Singh 
12717f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
12727f4beda2SGovind Singh 
12737f4beda2SGovind Singh 	ret = ath11k_pci_config_irq(ab);
12747f4beda2SGovind Singh 	if (ret) {
12757f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
12767f4beda2SGovind Singh 		goto err_ce_free;
12777f4beda2SGovind Singh 	}
12787f4beda2SGovind Singh 
12797f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
12807f4beda2SGovind Singh 	if (ret) {
12817f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
12827f4beda2SGovind Singh 		goto err_free_irq;
12837f4beda2SGovind Singh 	}
12846e0355afSGovind Singh 	return 0;
12855762613eSGovind Singh 
12867f4beda2SGovind Singh err_free_irq:
12877f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
12887f4beda2SGovind Singh 
12897f4beda2SGovind Singh err_ce_free:
12907f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
12917f4beda2SGovind Singh 
12927f4beda2SGovind Singh err_hal_srng_deinit:
12937f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
12947f4beda2SGovind Singh 
12957f4beda2SGovind Singh err_mhi_unregister:
12967f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
12977f4beda2SGovind Singh 
1298b8246f88SKalle Valo err_pci_disable_msi:
1299b8246f88SKalle Valo 	ath11k_pci_disable_msi(ab_pci);
1300b8246f88SKalle Valo 
13015697a564SGovind Singh err_pci_free_region:
13025697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
13035697a564SGovind Singh 
13045762613eSGovind Singh err_free_core:
13055762613eSGovind Singh 	ath11k_core_free(ab);
13065697a564SGovind Singh 
13075762613eSGovind Singh 	return ret;
13086e0355afSGovind Singh }
13096e0355afSGovind Singh 
13106e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
13116e0355afSGovind Singh {
13126e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
13135762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
13146e0355afSGovind Singh 
131561a57e51SAnilkumar Kolli 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
131661a57e51SAnilkumar Kolli 		ath11k_pci_power_down(ab);
131761a57e51SAnilkumar Kolli 		ath11k_debugfs_soc_destroy(ab);
131861a57e51SAnilkumar Kolli 		ath11k_qmi_deinit_service(ab);
131961a57e51SAnilkumar Kolli 		goto qmi_fail;
132061a57e51SAnilkumar Kolli 	}
132161a57e51SAnilkumar Kolli 
13226e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
13236fbd8898SCarl Huang 
13246fbd8898SCarl Huang 	ath11k_core_deinit(ab);
13256fbd8898SCarl Huang 
132661a57e51SAnilkumar Kolli qmi_fail:
13271399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
13286fbd8898SCarl Huang 
13296fbd8898SCarl Huang 	ath11k_pci_free_irq(ab);
13305697a564SGovind Singh 	ath11k_pci_disable_msi(ab_pci);
13315762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
13326fbd8898SCarl Huang 
13336fbd8898SCarl Huang 	ath11k_hal_srng_deinit(ab);
13346fbd8898SCarl Huang 	ath11k_ce_free_pipes(ab);
13356e0355afSGovind Singh 	ath11k_core_free(ab);
13366e0355afSGovind Singh }
13376e0355afSGovind Singh 
13381399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
13391399fb87SGovind Singh {
13401399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
13411399fb87SGovind Singh 
13421399fb87SGovind Singh 	ath11k_pci_power_down(ab);
13431399fb87SGovind Singh }
13441399fb87SGovind Singh 
1345d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
1346d1b0c338SCarl Huang {
1347d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1348d1b0c338SCarl Huang 	int ret;
1349d1b0c338SCarl Huang 
1350d1b0c338SCarl Huang 	ret = ath11k_core_suspend(ab);
1351d1b0c338SCarl Huang 	if (ret)
1352d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to suspend core: %d\n", ret);
1353d1b0c338SCarl Huang 
1354d1b0c338SCarl Huang 	return ret;
1355d1b0c338SCarl Huang }
1356d1b0c338SCarl Huang 
1357d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
1358d1b0c338SCarl Huang {
1359d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1360d1b0c338SCarl Huang 	int ret;
1361d1b0c338SCarl Huang 
1362d1b0c338SCarl Huang 	ret = ath11k_core_resume(ab);
1363d1b0c338SCarl Huang 	if (ret)
1364d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to resume core: %d\n", ret);
1365d1b0c338SCarl Huang 
1366d1b0c338SCarl Huang 	return ret;
1367d1b0c338SCarl Huang }
1368d1b0c338SCarl Huang 
1369d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
1370d1b0c338SCarl Huang 			 ath11k_pci_pm_suspend,
1371d1b0c338SCarl Huang 			 ath11k_pci_pm_resume);
1372d1b0c338SCarl Huang 
13736e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
13746e0355afSGovind Singh 	.name = "ath11k_pci",
13756e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
13766e0355afSGovind Singh 	.probe = ath11k_pci_probe,
13776e0355afSGovind Singh 	.remove = ath11k_pci_remove,
13781399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
1379d1b0c338SCarl Huang #ifdef CONFIG_PM
1380d1b0c338SCarl Huang 	.driver.pm = &ath11k_pci_pm_ops,
1381d1b0c338SCarl Huang #endif
13826e0355afSGovind Singh };
13836e0355afSGovind Singh 
13846e0355afSGovind Singh static int ath11k_pci_init(void)
13856e0355afSGovind Singh {
13866e0355afSGovind Singh 	int ret;
13876e0355afSGovind Singh 
13886e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
13896e0355afSGovind Singh 	if (ret)
13906e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
13916e0355afSGovind Singh 		       ret);
13926e0355afSGovind Singh 
13936e0355afSGovind Singh 	return ret;
13946e0355afSGovind Singh }
13956e0355afSGovind Singh module_init(ath11k_pci_init);
13966e0355afSGovind Singh 
13976e0355afSGovind Singh static void ath11k_pci_exit(void)
13986e0355afSGovind Singh {
13996e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
14006e0355afSGovind Singh }
14016e0355afSGovind Singh 
14026e0355afSGovind Singh module_exit(ath11k_pci_exit);
14036e0355afSGovind Singh 
14046e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
14056e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
14063dbd7fe7SDevin Bayer 
14073dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */
14083dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE);
14093dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE);
14103dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE);
1411