xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision 0fbf19570099cf1c41e86b3b14a392d46131ed0d)
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
39*0fbf1957SBaochen 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) },
43*0fbf1957SBaochen Qiang 	{ PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) },
444e809461SAnilkumar Kolli 	/* TODO: add QCN9074_DEVICE_ID) once firmware issues are resolved */
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 	 */
185a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
186a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
187a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
188a05bd851SCarl Huang 
189654e959aSGovind Singh 	if (offset < WINDOW_START) {
190654e959aSGovind Singh 		iowrite32(value, ab->mem  + offset);
191654e959aSGovind Singh 	} else {
192480a7361SKarthikeyan Periyasamy 		if (ab->bus_params.static_window_map)
193480a7361SKarthikeyan Periyasamy 			window_start = ath11k_pci_get_window_start(ab, offset);
194480a7361SKarthikeyan Periyasamy 		else
195480a7361SKarthikeyan Periyasamy 			window_start = WINDOW_START;
196480a7361SKarthikeyan Periyasamy 
197480a7361SKarthikeyan Periyasamy 		if (window_start == WINDOW_START) {
198654e959aSGovind Singh 			spin_lock_bh(&ab_pci->window_lock);
199654e959aSGovind Singh 			ath11k_pci_select_window(ab_pci, offset);
200480a7361SKarthikeyan Periyasamy 			iowrite32(value, ab->mem + window_start +
201480a7361SKarthikeyan Periyasamy 				  (offset & WINDOW_RANGE_MASK));
202654e959aSGovind Singh 			spin_unlock_bh(&ab_pci->window_lock);
203480a7361SKarthikeyan Periyasamy 		} else {
204480a7361SKarthikeyan Periyasamy 			iowrite32(value, ab->mem + window_start +
205480a7361SKarthikeyan Periyasamy 				  (offset & WINDOW_RANGE_MASK));
206480a7361SKarthikeyan Periyasamy 		}
207654e959aSGovind Singh 	}
208a05bd851SCarl Huang 
209a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
210a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
211a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
212654e959aSGovind Singh }
213654e959aSGovind Singh 
214f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
215654e959aSGovind Singh {
216654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
217480a7361SKarthikeyan Periyasamy 	u32 val, window_start;
218654e959aSGovind Singh 
219a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
220a05bd851SCarl Huang 	 * need to wakeup MHI to access.
221a05bd851SCarl Huang 	 */
222a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
223a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
224a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
225a05bd851SCarl Huang 
226654e959aSGovind Singh 	if (offset < WINDOW_START) {
227654e959aSGovind Singh 		val = ioread32(ab->mem + offset);
228654e959aSGovind Singh 	} else {
229480a7361SKarthikeyan Periyasamy 		if (ab->bus_params.static_window_map)
230480a7361SKarthikeyan Periyasamy 			window_start = ath11k_pci_get_window_start(ab, offset);
231480a7361SKarthikeyan Periyasamy 		else
232480a7361SKarthikeyan Periyasamy 			window_start = WINDOW_START;
233480a7361SKarthikeyan Periyasamy 
234480a7361SKarthikeyan Periyasamy 		if (window_start == WINDOW_START) {
235654e959aSGovind Singh 			spin_lock_bh(&ab_pci->window_lock);
236654e959aSGovind Singh 			ath11k_pci_select_window(ab_pci, offset);
237480a7361SKarthikeyan Periyasamy 			val = ioread32(ab->mem + window_start +
238480a7361SKarthikeyan Periyasamy 				       (offset & WINDOW_RANGE_MASK));
239654e959aSGovind Singh 			spin_unlock_bh(&ab_pci->window_lock);
240480a7361SKarthikeyan Periyasamy 		} else {
241480a7361SKarthikeyan Periyasamy 			val = ioread32(ab->mem + window_start +
242480a7361SKarthikeyan Periyasamy 				       (offset & WINDOW_RANGE_MASK));
243480a7361SKarthikeyan Periyasamy 		}
244654e959aSGovind Singh 	}
245654e959aSGovind Singh 
246a05bd851SCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
247a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
248a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
249a05bd851SCarl Huang 
250654e959aSGovind Singh 	return val;
251654e959aSGovind Singh }
252654e959aSGovind Singh 
253f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
254f3c603d4SCarl Huang {
255f3c603d4SCarl Huang 	u32 val, delay;
256f3c603d4SCarl Huang 
257f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
258f3c603d4SCarl Huang 
259f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
260f3c603d4SCarl Huang 
261f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
262f3c603d4SCarl Huang 
263f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
264f3c603d4SCarl Huang 	delay = 10;
265f3c603d4SCarl Huang 	mdelay(delay);
266f3c603d4SCarl Huang 
267f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
268f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
269f3c603d4SCarl Huang 
270f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
271f3c603d4SCarl Huang 
272f3c603d4SCarl Huang 	mdelay(delay);
273f3c603d4SCarl Huang 
274f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
275f3c603d4SCarl Huang 	if (val == 0xffffffff)
276f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
277f3c603d4SCarl Huang }
278f3c603d4SCarl Huang 
279f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
280f3c603d4SCarl Huang {
281f3c603d4SCarl Huang 	u32 val;
282f3c603d4SCarl Huang 
283f3c603d4SCarl Huang 	/* read cookie */
284f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR);
285f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val);
286f3c603d4SCarl Huang 
287f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
288f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
289f3c603d4SCarl Huang 
290f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
291f3c603d4SCarl Huang 	mdelay(10);
292f3c603d4SCarl Huang 
293f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
294f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
295f3c603d4SCarl Huang 	 */
296f3c603d4SCarl Huang 	ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0);
297f3c603d4SCarl Huang 	mdelay(10);
298f3c603d4SCarl Huang 
299f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
300f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
301f3c603d4SCarl Huang 
302f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
303f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
304f3c603d4SCarl Huang 	 */
305f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
306f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
307f3c603d4SCarl Huang }
308f3c603d4SCarl Huang 
30906999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab,
31006999407SCarl Huang 				   u32 offset, u32 value, u32 mask)
31106999407SCarl Huang {
31206999407SCarl Huang 	u32 v;
31306999407SCarl Huang 	int i;
31406999407SCarl Huang 
31506999407SCarl Huang 	v = ath11k_pci_read32(ab, offset);
31606999407SCarl Huang 	if ((v & mask) == value)
31706999407SCarl Huang 		return 0;
31806999407SCarl Huang 
31906999407SCarl Huang 	for (i = 0; i < 10; i++) {
32006999407SCarl Huang 		ath11k_pci_write32(ab, offset, (v & ~mask) | value);
32106999407SCarl Huang 
32206999407SCarl Huang 		v = ath11k_pci_read32(ab, offset);
32306999407SCarl Huang 		if ((v & mask) == value)
32406999407SCarl Huang 			return 0;
32506999407SCarl Huang 
32606999407SCarl Huang 		mdelay(2);
32706999407SCarl Huang 	}
32806999407SCarl Huang 
32906999407SCarl Huang 	ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n",
33006999407SCarl Huang 		    offset, v & mask, value);
33106999407SCarl Huang 
33206999407SCarl Huang 	return -ETIMEDOUT;
33306999407SCarl Huang }
33406999407SCarl Huang 
33506999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
33606999407SCarl Huang {
33706999407SCarl Huang 	int ret;
33806999407SCarl Huang 
33906999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3406fe6f68fSKarthikeyan Periyasamy 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab),
34106999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL,
34206999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK);
34330d08503SDan Carpenter 	if (ret) {
34406999407SCarl Huang 		ath11k_warn(ab, "failed to set sysclk: %d\n", ret);
34506999407SCarl Huang 		return ret;
34606999407SCarl Huang 	}
34706999407SCarl Huang 
34806999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3496fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab),
3506fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_VAL,
3516fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
35230d08503SDan Carpenter 	if (ret) {
35306999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret);
35406999407SCarl Huang 		return ret;
35506999407SCarl Huang 	}
35606999407SCarl Huang 
35706999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3586fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab),
3596fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_VAL,
3606fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
36130d08503SDan Carpenter 	if (ret) {
36206999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config2: %d\n", ret);
36306999407SCarl Huang 		return ret;
36406999407SCarl Huang 	}
36506999407SCarl Huang 
36606999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3676fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab),
3686fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_VAL,
3696fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
37030d08503SDan Carpenter 	if (ret) {
37106999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config4: %d\n", ret);
37206999407SCarl Huang 		return ret;
37306999407SCarl Huang 	}
37406999407SCarl Huang 
37506999407SCarl Huang 	return 0;
37606999407SCarl Huang }
37706999407SCarl Huang 
378babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
379babb0cedSCarl Huang {
380babb0cedSCarl Huang 	u32 val;
381babb0cedSCarl Huang 	int i;
382babb0cedSCarl Huang 
383babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
384babb0cedSCarl Huang 
385babb0cedSCarl Huang 	/* PCIE link seems very unstable after the Hot Reset*/
386babb0cedSCarl Huang 	for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {
387babb0cedSCarl Huang 		if (val == 0xffffffff)
388babb0cedSCarl Huang 			mdelay(5);
389babb0cedSCarl Huang 
390babb0cedSCarl Huang 		ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
391babb0cedSCarl Huang 		val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
392babb0cedSCarl Huang 	}
393babb0cedSCarl Huang 
394babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val);
395babb0cedSCarl Huang 
396babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
397562934adSKalle Valo 	val |= GCC_GCC_PCIE_HOT_RST_VAL;
398babb0cedSCarl Huang 	ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
399babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
400babb0cedSCarl Huang 
401babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val);
402babb0cedSCarl Huang 
403babb0cedSCarl Huang 	mdelay(5);
404babb0cedSCarl Huang }
405babb0cedSCarl Huang 
406babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
407babb0cedSCarl Huang {
408babb0cedSCarl Huang 	/* This is a WAR for PCIE Hotreset.
409babb0cedSCarl Huang 	 * When target receive Hotreset, but will set the interrupt.
410babb0cedSCarl Huang 	 * So when download SBL again, SBL will open Interrupt and
411babb0cedSCarl Huang 	 * receive it, and crash immediately.
412babb0cedSCarl Huang 	 */
413babb0cedSCarl Huang 	ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
414babb0cedSCarl Huang }
415babb0cedSCarl Huang 
4160ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab)
4170ccdf439SCarl Huang {
4180ccdf439SCarl Huang 	u32 val;
4190ccdf439SCarl Huang 
4200ccdf439SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG);
4210ccdf439SCarl Huang 	val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK;
4220ccdf439SCarl Huang 	ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val);
4230ccdf439SCarl Huang }
4240ccdf439SCarl Huang 
425f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
426f3c603d4SCarl Huang {
427f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
428f3c603d4SCarl Huang 	mdelay(5);
429f3c603d4SCarl Huang }
430f3c603d4SCarl Huang 
431babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
432f3c603d4SCarl Huang {
433babb0cedSCarl Huang 	if (power_on) {
434babb0cedSCarl Huang 		ath11k_pci_enable_ltssm(ab);
435babb0cedSCarl Huang 		ath11k_pci_clear_all_intrs(ab);
4360ccdf439SCarl Huang 		ath11k_pci_set_wlaon_pwr_ctrl(ab);
43706999407SCarl Huang 		ath11k_pci_fix_l1ss(ab);
438babb0cedSCarl Huang 	}
439babb0cedSCarl Huang 
440f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
441f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
442f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
443f3c603d4SCarl Huang 	ath11k_pci_clear_dbg_registers(ab);
444f3c603d4SCarl Huang }
445f3c603d4SCarl Huang 
4461399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
4471399fb87SGovind Singh {
4481399fb87SGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(dev);
4491399fb87SGovind Singh 
4501399fb87SGovind Singh 	return pci_irq_vector(pci_dev, vector);
4511399fb87SGovind Singh }
4521399fb87SGovind Singh 
453c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
454c4eacabeSGovind Singh 				       u32 *msi_addr_hi)
455c4eacabeSGovind Singh {
456e8e55d89SAnilkumar Kolli 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
457c4eacabeSGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
458c4eacabeSGovind Singh 
459c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
460c4eacabeSGovind Singh 			      msi_addr_lo);
461c4eacabeSGovind Singh 
462e8e55d89SAnilkumar Kolli 	if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) {
463c4eacabeSGovind Singh 		pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
464c4eacabeSGovind Singh 				      msi_addr_hi);
465e8e55d89SAnilkumar Kolli 	} else {
466e8e55d89SAnilkumar Kolli 		*msi_addr_hi = 0;
467e8e55d89SAnilkumar Kolli 	}
468c4eacabeSGovind Singh }
469c4eacabeSGovind Singh 
4701399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
4711399fb87SGovind Singh 				       int *num_vectors, u32 *user_base_data,
4721399fb87SGovind Singh 				       u32 *base_vector)
4731399fb87SGovind Singh {
4741399fb87SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4757a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
4761399fb87SGovind Singh 	int idx;
4771399fb87SGovind Singh 
4787a3aed0cSAnilkumar Kolli 	for (idx = 0; idx < msi_config->total_users; idx++) {
4797a3aed0cSAnilkumar Kolli 		if (strcmp(user_name, msi_config->users[idx].name) == 0) {
4807a3aed0cSAnilkumar Kolli 			*num_vectors = msi_config->users[idx].num_vectors;
4817a3aed0cSAnilkumar Kolli 			*user_base_data = msi_config->users[idx].base_vector
4821399fb87SGovind Singh 				+ ab_pci->msi_ep_base_data;
4837a3aed0cSAnilkumar Kolli 			*base_vector = msi_config->users[idx].base_vector;
4841399fb87SGovind Singh 
4851399fb87SGovind Singh 			ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
4861399fb87SGovind Singh 				   user_name, *num_vectors, *user_base_data,
4871399fb87SGovind Singh 				   *base_vector);
4881399fb87SGovind Singh 
4891399fb87SGovind Singh 			return 0;
4901399fb87SGovind Singh 		}
4911399fb87SGovind Singh 	}
4921399fb87SGovind Singh 
4931399fb87SGovind Singh 	ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
4941399fb87SGovind Singh 
4951399fb87SGovind Singh 	return -EINVAL;
4961399fb87SGovind Singh }
4971399fb87SGovind Singh 
4986289ac2bSKarthikeyan Periyasamy static void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id,
4996289ac2bSKarthikeyan Periyasamy 				      u32 *msi_idx)
5006289ac2bSKarthikeyan Periyasamy {
5016289ac2bSKarthikeyan Periyasamy 	u32 i, msi_data_idx;
5026289ac2bSKarthikeyan Periyasamy 
5036289ac2bSKarthikeyan Periyasamy 	for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
5046289ac2bSKarthikeyan Periyasamy 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5056289ac2bSKarthikeyan Periyasamy 			continue;
5066289ac2bSKarthikeyan Periyasamy 
5076289ac2bSKarthikeyan Periyasamy 		if (ce_id == i)
5086289ac2bSKarthikeyan Periyasamy 			break;
5096289ac2bSKarthikeyan Periyasamy 
5106289ac2bSKarthikeyan Periyasamy 		msi_data_idx++;
5116289ac2bSKarthikeyan Periyasamy 	}
5126289ac2bSKarthikeyan Periyasamy 	*msi_idx = msi_data_idx;
5136289ac2bSKarthikeyan Periyasamy }
5146289ac2bSKarthikeyan Periyasamy 
515c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
516c4eacabeSGovind Singh 					  int *num_vectors, u32 *user_base_data,
517c4eacabeSGovind Singh 					  u32 *base_vector)
518c4eacabeSGovind Singh {
519c4eacabeSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
520c4eacabeSGovind Singh 
521c4eacabeSGovind Singh 	return ath11k_pci_get_user_msi_assignment(ab_pci, user_name,
522c4eacabeSGovind Singh 						  num_vectors, user_base_data,
523c4eacabeSGovind Singh 						  base_vector);
524c4eacabeSGovind Singh }
525c4eacabeSGovind Singh 
526d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
527d4ecb90bSCarl Huang {
528d4ecb90bSCarl Huang 	int i, j;
529d4ecb90bSCarl Huang 
530d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
531d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
532d4ecb90bSCarl Huang 
533d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++)
534d4ecb90bSCarl Huang 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
535d4ecb90bSCarl Huang 
536d4ecb90bSCarl Huang 		netif_napi_del(&irq_grp->napi);
537d4ecb90bSCarl Huang 	}
538d4ecb90bSCarl Huang }
539d4ecb90bSCarl Huang 
5407f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab)
5417f4beda2SGovind Singh {
5427f4beda2SGovind Singh 	int i, irq_idx;
5437f4beda2SGovind Singh 
544d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
545e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5467f4beda2SGovind Singh 			continue;
5477f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5487f4beda2SGovind Singh 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
5497f4beda2SGovind Singh 	}
550d4ecb90bSCarl Huang 
551d4ecb90bSCarl Huang 	ath11k_pci_free_ext_irq(ab);
5527f4beda2SGovind Singh }
5537f4beda2SGovind Singh 
5542c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
5552c3960c2SGovind Singh {
5562c3960c2SGovind Singh 	u32 irq_idx;
5572c3960c2SGovind Singh 
5582c3960c2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
5592c3960c2SGovind Singh 	enable_irq(ab->irq_num[irq_idx]);
5602c3960c2SGovind Singh }
5612c3960c2SGovind Singh 
5627f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
5637f4beda2SGovind Singh {
5647f4beda2SGovind Singh 	u32 irq_idx;
5657f4beda2SGovind Singh 
5667f4beda2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
5677f4beda2SGovind Singh 	disable_irq_nosync(ab->irq_num[irq_idx]);
5687f4beda2SGovind Singh }
5697f4beda2SGovind Singh 
5702c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
5712c3960c2SGovind Singh {
5722c3960c2SGovind Singh 	int i;
5732c3960c2SGovind Singh 
574d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
575e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5762c3960c2SGovind Singh 			continue;
5772c3960c2SGovind Singh 		ath11k_pci_ce_irq_disable(ab, i);
5782c3960c2SGovind Singh 	}
5792c3960c2SGovind Singh }
5802c3960c2SGovind Singh 
5812c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
5822c3960c2SGovind Singh {
5832c3960c2SGovind Singh 	int i;
5842c3960c2SGovind Singh 	int irq_idx;
5852c3960c2SGovind Singh 
586d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
587e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5882c3960c2SGovind Singh 			continue;
5892c3960c2SGovind Singh 
5902c3960c2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5912c3960c2SGovind Singh 		synchronize_irq(ab->irq_num[irq_idx]);
5922c3960c2SGovind Singh 	}
5932c3960c2SGovind Singh }
5942c3960c2SGovind Singh 
5950f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
5962c3960c2SGovind Singh {
5970f01dcb8SAllen Pais 	struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
5982c3960c2SGovind Singh 
5992c3960c2SGovind Singh 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
6002c3960c2SGovind Singh 
6012c3960c2SGovind Singh 	ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
6022c3960c2SGovind Singh }
6032c3960c2SGovind Singh 
6047f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
6057f4beda2SGovind Singh {
6067f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = arg;
6077f4beda2SGovind Singh 
6087dc67af0SKarthikeyan Periyasamy 	/* last interrupt received for this CE */
6097dc67af0SKarthikeyan Periyasamy 	ce_pipe->timestamp = jiffies;
6107dc67af0SKarthikeyan Periyasamy 
6117f4beda2SGovind Singh 	ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
6122c3960c2SGovind Singh 	tasklet_schedule(&ce_pipe->intr_tq);
6137f4beda2SGovind Singh 
6147f4beda2SGovind Singh 	return IRQ_HANDLED;
6157f4beda2SGovind Singh }
6167f4beda2SGovind Singh 
617d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
618d4ecb90bSCarl Huang {
619d4ecb90bSCarl Huang 	int i;
620d4ecb90bSCarl Huang 
621d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
622d4ecb90bSCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
623d4ecb90bSCarl Huang }
624d4ecb90bSCarl Huang 
625d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
626d4ecb90bSCarl Huang {
627d4ecb90bSCarl Huang 	int i;
628d4ecb90bSCarl Huang 
629d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
630d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
631d4ecb90bSCarl Huang 
632d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
633d4ecb90bSCarl Huang 
634d4ecb90bSCarl Huang 		napi_synchronize(&irq_grp->napi);
635d4ecb90bSCarl Huang 		napi_disable(&irq_grp->napi);
636d4ecb90bSCarl Huang 	}
637d4ecb90bSCarl Huang }
638d4ecb90bSCarl Huang 
639d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
640d4ecb90bSCarl Huang {
641d4ecb90bSCarl Huang 	int i;
642d4ecb90bSCarl Huang 
643d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
644d4ecb90bSCarl Huang 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
645d4ecb90bSCarl Huang }
646d4ecb90bSCarl Huang 
647d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
648d4ecb90bSCarl Huang {
649d4ecb90bSCarl Huang 	int i;
650d4ecb90bSCarl Huang 
651d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
652d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
653d4ecb90bSCarl Huang 
654d4ecb90bSCarl Huang 		napi_enable(&irq_grp->napi);
655d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
656d4ecb90bSCarl Huang 	}
657d4ecb90bSCarl Huang }
658d4ecb90bSCarl Huang 
659d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
660d4ecb90bSCarl Huang {
661d4ecb90bSCarl Huang 	int i, j, irq_idx;
662d4ecb90bSCarl Huang 
663d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
664d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
665d4ecb90bSCarl Huang 
666d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
667d4ecb90bSCarl Huang 			irq_idx = irq_grp->irqs[j];
668d4ecb90bSCarl Huang 			synchronize_irq(ab->irq_num[irq_idx]);
669d4ecb90bSCarl Huang 		}
670d4ecb90bSCarl Huang 	}
671d4ecb90bSCarl Huang }
672d4ecb90bSCarl Huang 
673d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
674d4ecb90bSCarl Huang {
675d4ecb90bSCarl Huang 	__ath11k_pci_ext_irq_disable(ab);
676d4ecb90bSCarl Huang 	ath11k_pci_sync_ext_irqs(ab);
677d4ecb90bSCarl Huang }
678d4ecb90bSCarl Huang 
679d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
680d4ecb90bSCarl Huang {
681d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
682d4ecb90bSCarl Huang 						struct ath11k_ext_irq_grp,
683d4ecb90bSCarl Huang 						napi);
684d4ecb90bSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
685d4ecb90bSCarl Huang 	int work_done;
686d4ecb90bSCarl Huang 
687d4ecb90bSCarl Huang 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
688d4ecb90bSCarl Huang 	if (work_done < budget) {
689d4ecb90bSCarl Huang 		napi_complete_done(napi, work_done);
690d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
691d4ecb90bSCarl Huang 	}
692d4ecb90bSCarl Huang 
693d4ecb90bSCarl Huang 	if (work_done > budget)
694d4ecb90bSCarl Huang 		work_done = budget;
695d4ecb90bSCarl Huang 
696d4ecb90bSCarl Huang 	return work_done;
697d4ecb90bSCarl Huang }
698d4ecb90bSCarl Huang 
699d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
700d4ecb90bSCarl Huang {
701d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = arg;
702d4ecb90bSCarl Huang 
703d4ecb90bSCarl Huang 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
704d4ecb90bSCarl Huang 
7057dc67af0SKarthikeyan Periyasamy 	/* last interrupt received for this group */
7067dc67af0SKarthikeyan Periyasamy 	irq_grp->timestamp = jiffies;
7077dc67af0SKarthikeyan Periyasamy 
708d4ecb90bSCarl Huang 	ath11k_pci_ext_grp_disable(irq_grp);
709d4ecb90bSCarl Huang 
710d4ecb90bSCarl Huang 	napi_schedule(&irq_grp->napi);
711d4ecb90bSCarl Huang 
712d4ecb90bSCarl Huang 	return IRQ_HANDLED;
713d4ecb90bSCarl Huang }
714d4ecb90bSCarl Huang 
715d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
716d4ecb90bSCarl Huang {
717d4ecb90bSCarl Huang 	int i, j, ret, num_vectors = 0;
7187dc67af0SKarthikeyan Periyasamy 	u32 user_base_data = 0, base_vector = 0, base_idx;
719d4ecb90bSCarl Huang 
7207dc67af0SKarthikeyan Periyasamy 	base_idx = ATH11K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX;
721b2c09458SColin Ian King 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
722b2c09458SColin Ian King 						 &num_vectors,
723b2c09458SColin Ian King 						 &user_base_data,
724d4ecb90bSCarl Huang 						 &base_vector);
725b2c09458SColin Ian King 	if (ret < 0)
726b2c09458SColin Ian King 		return ret;
727d4ecb90bSCarl Huang 
728d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
729d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
730d4ecb90bSCarl Huang 		u32 num_irq = 0;
731d4ecb90bSCarl Huang 
732d4ecb90bSCarl Huang 		irq_grp->ab = ab;
733d4ecb90bSCarl Huang 		irq_grp->grp_id = i;
734d4ecb90bSCarl Huang 		init_dummy_netdev(&irq_grp->napi_ndev);
735d4ecb90bSCarl Huang 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
736d4ecb90bSCarl Huang 			       ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
737d4ecb90bSCarl Huang 
738d4ecb90bSCarl Huang 		if (ab->hw_params.ring_mask->tx[i] ||
739d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx[i] ||
740d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_err[i] ||
741d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_wbm_rel[i] ||
742d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->reo_status[i] ||
743d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rxdma2host[i] ||
744d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->host2rxdma[i] ||
745d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_mon_status[i]) {
746d4ecb90bSCarl Huang 			num_irq = 1;
747d4ecb90bSCarl Huang 		}
748d4ecb90bSCarl Huang 
749d4ecb90bSCarl Huang 		irq_grp->num_irq = num_irq;
7507dc67af0SKarthikeyan Periyasamy 		irq_grp->irqs[0] = base_idx + i;
751d4ecb90bSCarl Huang 
752d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
753d4ecb90bSCarl Huang 			int irq_idx = irq_grp->irqs[j];
754d4ecb90bSCarl Huang 			int vector = (i % num_vectors) + base_vector;
755d4ecb90bSCarl Huang 			int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
756d4ecb90bSCarl Huang 
757d4ecb90bSCarl Huang 			ab->irq_num[irq_idx] = irq;
758d4ecb90bSCarl Huang 
759d4ecb90bSCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
760d4ecb90bSCarl Huang 				   "irq:%d group:%d\n", irq, i);
7617dc67af0SKarthikeyan Periyasamy 
7627dc67af0SKarthikeyan Periyasamy 			irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
763d4ecb90bSCarl Huang 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
764d4ecb90bSCarl Huang 					  IRQF_SHARED,
765d4ecb90bSCarl Huang 					  "DP_EXT_IRQ", irq_grp);
766d4ecb90bSCarl Huang 			if (ret) {
767d4ecb90bSCarl Huang 				ath11k_err(ab, "failed request irq %d: %d\n",
768d4ecb90bSCarl Huang 					   vector, ret);
769d4ecb90bSCarl Huang 				return ret;
770d4ecb90bSCarl Huang 			}
771d4ecb90bSCarl Huang 
772d4ecb90bSCarl Huang 			disable_irq_nosync(ab->irq_num[irq_idx]);
773d4ecb90bSCarl Huang 		}
774d4ecb90bSCarl Huang 	}
775d4ecb90bSCarl Huang 
776d4ecb90bSCarl Huang 	return 0;
777d4ecb90bSCarl Huang }
778d4ecb90bSCarl Huang 
7797f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab)
7807f4beda2SGovind Singh {
7817f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe;
7827f4beda2SGovind Singh 	u32 msi_data_start;
7836289ac2bSKarthikeyan Periyasamy 	u32 msi_data_count, msi_data_idx;
7847f4beda2SGovind Singh 	u32 msi_irq_start;
7857f4beda2SGovind Singh 	unsigned int msi_data;
7867f4beda2SGovind Singh 	int irq, i, ret, irq_idx;
7877f4beda2SGovind Singh 
7887f4beda2SGovind Singh 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab),
7897f4beda2SGovind Singh 						 "CE", &msi_data_count,
7907f4beda2SGovind Singh 						 &msi_data_start, &msi_irq_start);
7917f4beda2SGovind Singh 	if (ret)
7927f4beda2SGovind Singh 		return ret;
7937f4beda2SGovind Singh 
7947f4beda2SGovind Singh 	/* Configure CE irqs */
7956289ac2bSKarthikeyan Periyasamy 	for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
796e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
7977f4beda2SGovind Singh 			continue;
7987f4beda2SGovind Singh 
7996289ac2bSKarthikeyan Periyasamy 		msi_data = (msi_data_idx % msi_data_count) + msi_irq_start;
8006289ac2bSKarthikeyan Periyasamy 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
8016289ac2bSKarthikeyan Periyasamy 		ce_pipe = &ab->ce.ce_pipe[i];
8026289ac2bSKarthikeyan Periyasamy 
8037f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
8047f4beda2SGovind Singh 
8050f01dcb8SAllen Pais 		tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
8062c3960c2SGovind Singh 
8077f4beda2SGovind Singh 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
8087f4beda2SGovind Singh 				  IRQF_SHARED, irq_name[irq_idx],
8097f4beda2SGovind Singh 				  ce_pipe);
8107f4beda2SGovind Singh 		if (ret) {
8117f4beda2SGovind Singh 			ath11k_err(ab, "failed to request irq %d: %d\n",
8127f4beda2SGovind Singh 				   irq_idx, ret);
8137f4beda2SGovind Singh 			return ret;
8147f4beda2SGovind Singh 		}
8157f4beda2SGovind Singh 
8167f4beda2SGovind Singh 		ab->irq_num[irq_idx] = irq;
8176289ac2bSKarthikeyan Periyasamy 		msi_data_idx++;
818e678fbd4SKarthikeyan Periyasamy 
819e5c860e1SCarl Huang 		ath11k_pci_ce_irq_disable(ab, i);
8207f4beda2SGovind Singh 	}
8217f4beda2SGovind Singh 
822d4ecb90bSCarl Huang 	ret = ath11k_pci_ext_irq_config(ab);
823d4ecb90bSCarl Huang 	if (ret)
824d4ecb90bSCarl Huang 		return ret;
825d4ecb90bSCarl Huang 
8267f4beda2SGovind Singh 	return 0;
8277f4beda2SGovind Singh }
8287f4beda2SGovind Singh 
8297f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
8307f4beda2SGovind Singh {
8317f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
8327f4beda2SGovind Singh 
833967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
834967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
8357f4beda2SGovind Singh 
836967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
837967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
83816001e4bSAnilkumar Kolli 	ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
839e838c14aSCarl Huang 
840e838c14aSCarl Huang 	ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
841e838c14aSCarl Huang 				    &cfg->shadow_reg_v2_len);
8427f4beda2SGovind Singh }
8437f4beda2SGovind Singh 
8447f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
8457f4beda2SGovind Singh {
8467f4beda2SGovind Singh 	int i;
8477f4beda2SGovind Singh 
848d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
849e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
8507f4beda2SGovind Singh 			continue;
8517f4beda2SGovind Singh 		ath11k_pci_ce_irq_enable(ab, i);
8527f4beda2SGovind Singh 	}
8537f4beda2SGovind Singh }
8547f4beda2SGovind Singh 
8555697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
8565697a564SGovind Singh {
8575697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
8587a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
8595697a564SGovind Singh 	struct msi_desc *msi_desc;
8605697a564SGovind Singh 	int num_vectors;
8615697a564SGovind Singh 	int ret;
8625697a564SGovind Singh 
8635697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
8647a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
8657a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
8665697a564SGovind Singh 					    PCI_IRQ_MSI);
8677a3aed0cSAnilkumar Kolli 	if (num_vectors != msi_config->total_vectors) {
8685697a564SGovind Singh 		ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
8697a3aed0cSAnilkumar Kolli 			   msi_config->total_vectors, num_vectors);
8705697a564SGovind Singh 
8715697a564SGovind Singh 		if (num_vectors >= 0)
8725697a564SGovind Singh 			return -EINVAL;
8735697a564SGovind Singh 		else
8745697a564SGovind Singh 			return num_vectors;
8755697a564SGovind Singh 	}
8765697a564SGovind Singh 
8775697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
8785697a564SGovind Singh 	if (!msi_desc) {
8795697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
8805697a564SGovind Singh 		ret = -EINVAL;
8815697a564SGovind Singh 		goto free_msi_vector;
8825697a564SGovind Singh 	}
8835697a564SGovind Singh 
8845697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
885e8e55d89SAnilkumar Kolli 	if (msi_desc->msi_attrib.is_64)
886e8e55d89SAnilkumar Kolli 		set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags);
8875697a564SGovind Singh 
8885697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
8895697a564SGovind Singh 
8905697a564SGovind Singh 	return 0;
8915697a564SGovind Singh 
8925697a564SGovind Singh free_msi_vector:
8935697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
8945697a564SGovind Singh 
8955697a564SGovind Singh 	return ret;
8965697a564SGovind Singh }
8975697a564SGovind Singh 
8985697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci)
8995697a564SGovind Singh {
9005697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
9015697a564SGovind Singh }
9025697a564SGovind Singh 
9035762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
9045762613eSGovind Singh {
9055762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
9065762613eSGovind Singh 	u16 device_id;
9075762613eSGovind Singh 	int ret = 0;
9085762613eSGovind Singh 
9095762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
9105762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
9115762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
9125762613eSGovind Singh 			   device_id, ab_pci->dev_id);
9135762613eSGovind Singh 		ret = -EIO;
9145762613eSGovind Singh 		goto out;
9155762613eSGovind Singh 	}
9165762613eSGovind Singh 
9175762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
9185762613eSGovind Singh 	if (ret) {
9195762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
9205762613eSGovind Singh 		goto out;
9215762613eSGovind Singh 	}
9225762613eSGovind Singh 
9235762613eSGovind Singh 	ret = pci_enable_device(pdev);
9245762613eSGovind Singh 	if (ret) {
9255762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
9265762613eSGovind Singh 		goto out;
9275762613eSGovind Singh 	}
9285762613eSGovind Singh 
9295762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
9305762613eSGovind Singh 	if (ret) {
9315762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
9325762613eSGovind Singh 		goto disable_device;
9335762613eSGovind Singh 	}
9345762613eSGovind Singh 
9355762613eSGovind Singh 	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
9365762613eSGovind Singh 	if (ret) {
9375762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
9385762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
9395762613eSGovind Singh 		goto release_region;
9405762613eSGovind Singh 	}
9415762613eSGovind Singh 
9425762613eSGovind Singh 	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
9435762613eSGovind Singh 	if (ret) {
9445762613eSGovind Singh 		ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n",
9455762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
9465762613eSGovind Singh 		goto release_region;
9475762613eSGovind Singh 	}
9485762613eSGovind Singh 
9495762613eSGovind Singh 	pci_set_master(pdev);
9505762613eSGovind Singh 
9515762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
9525762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
9535762613eSGovind Singh 	if (!ab->mem) {
9545762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
9555762613eSGovind Singh 		ret = -EIO;
9565762613eSGovind Singh 		goto clear_master;
9575762613eSGovind Singh 	}
9585762613eSGovind Singh 
9595762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
9605762613eSGovind Singh 	return 0;
9615762613eSGovind Singh 
9625762613eSGovind Singh clear_master:
9635762613eSGovind Singh 	pci_clear_master(pdev);
9645762613eSGovind Singh release_region:
9655762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
9665762613eSGovind Singh disable_device:
9675762613eSGovind Singh 	pci_disable_device(pdev);
9685762613eSGovind Singh out:
9695762613eSGovind Singh 	return ret;
9705762613eSGovind Singh }
9715762613eSGovind Singh 
9725762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
9735762613eSGovind Singh {
9745762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
9755762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
9765762613eSGovind Singh 
9775762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
9785762613eSGovind Singh 	ab->mem = NULL;
9795762613eSGovind Singh 	pci_clear_master(pci_dev);
9805762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
9815762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
9825762613eSGovind Singh 		pci_disable_device(pci_dev);
9835762613eSGovind Singh }
9845762613eSGovind Singh 
985e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
986e9603f4bSCarl Huang {
987e9603f4bSCarl Huang 	struct ath11k_base *ab = ab_pci->ab;
988e9603f4bSCarl Huang 
989e9603f4bSCarl Huang 	pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL,
990e9603f4bSCarl Huang 				  &ab_pci->link_ctl);
991e9603f4bSCarl Huang 
992e9603f4bSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n",
993e9603f4bSCarl Huang 		   ab_pci->link_ctl,
994e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S),
995e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
996e9603f4bSCarl Huang 
997e9603f4bSCarl Huang 	/* disable L0s and L1 */
998e9603f4bSCarl Huang 	pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
999e9603f4bSCarl Huang 				   ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
1000e9603f4bSCarl Huang 
1001e9603f4bSCarl Huang 	set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags);
1002e9603f4bSCarl Huang }
1003e9603f4bSCarl Huang 
1004e9603f4bSCarl Huang static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci)
1005e9603f4bSCarl Huang {
1006e9603f4bSCarl Huang 	if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags))
1007e9603f4bSCarl Huang 		pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1008e9603f4bSCarl Huang 					   ab_pci->link_ctl);
1009e9603f4bSCarl Huang }
1010e9603f4bSCarl Huang 
10111399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
10121399fb87SGovind Singh {
10131399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
10141399fb87SGovind Singh 	int ret;
10151399fb87SGovind Singh 
1016a05bd851SCarl Huang 	ab_pci->register_window = 0;
1017a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1018babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, true);
1019f3c603d4SCarl Huang 
1020e9603f4bSCarl Huang 	/* Disable ASPM during firmware download due to problems switching
1021e9603f4bSCarl Huang 	 * to AMSS state.
1022e9603f4bSCarl Huang 	 */
1023e9603f4bSCarl Huang 	ath11k_pci_aspm_disable(ab_pci);
1024e9603f4bSCarl Huang 
10251399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
10261399fb87SGovind Singh 	if (ret) {
10271399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
10281399fb87SGovind Singh 		return ret;
10291399fb87SGovind Singh 	}
10301399fb87SGovind Singh 
1031480a7361SKarthikeyan Periyasamy 	if (ab->bus_params.static_window_map)
1032480a7361SKarthikeyan Periyasamy 		ath11k_pci_select_static_window(ab_pci);
1033480a7361SKarthikeyan Periyasamy 
10341399fb87SGovind Singh 	return 0;
10351399fb87SGovind Singh }
10361399fb87SGovind Singh 
10371399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
10381399fb87SGovind Singh {
10391399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
10401399fb87SGovind Singh 
1041e9603f4bSCarl Huang 	/* restore aspm in case firmware bootup fails */
1042e9603f4bSCarl Huang 	ath11k_pci_aspm_restore(ab_pci);
1043e9603f4bSCarl Huang 
1044babb0cedSCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
10451399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
1046a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1047babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, false);
10481399fb87SGovind Singh }
10491399fb87SGovind Singh 
1050fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab)
1051fa5917e4SCarl Huang {
1052fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
1053fa5917e4SCarl Huang 
1054fa5917e4SCarl Huang 	ath11k_mhi_suspend(ar_pci);
1055fa5917e4SCarl Huang 
1056fa5917e4SCarl Huang 	return 0;
1057fa5917e4SCarl Huang }
1058fa5917e4SCarl Huang 
1059fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab)
1060fa5917e4SCarl Huang {
1061fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
1062fa5917e4SCarl Huang 
1063fa5917e4SCarl Huang 	ath11k_mhi_resume(ar_pci);
1064fa5917e4SCarl Huang 
1065fa5917e4SCarl Huang 	return 0;
1066fa5917e4SCarl Huang }
1067fa5917e4SCarl Huang 
10682c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
10692c3960c2SGovind Singh {
10702c3960c2SGovind Singh 	int i;
10712c3960c2SGovind Singh 
1072d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
10732c3960c2SGovind Singh 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
10742c3960c2SGovind Singh 
1075e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
10762c3960c2SGovind Singh 			continue;
10772c3960c2SGovind Singh 
10782c3960c2SGovind Singh 		tasklet_kill(&ce_pipe->intr_tq);
10792c3960c2SGovind Singh 	}
10802c3960c2SGovind Singh }
10812c3960c2SGovind Singh 
1082d578ec2aSCarl Huang static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab)
10837f4beda2SGovind Singh {
10842c3960c2SGovind Singh 	ath11k_pci_ce_irqs_disable(ab);
10852c3960c2SGovind Singh 	ath11k_pci_sync_ce_irqs(ab);
10862c3960c2SGovind Singh 	ath11k_pci_kill_tasklets(ab);
1087d578ec2aSCarl Huang }
1088d578ec2aSCarl Huang 
1089d578ec2aSCarl Huang static void ath11k_pci_stop(struct ath11k_base *ab)
1090d578ec2aSCarl Huang {
1091d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
10927f4beda2SGovind Singh 	ath11k_ce_cleanup_pipes(ab);
10937f4beda2SGovind Singh }
10947f4beda2SGovind Singh 
10957f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab)
10967f4beda2SGovind Singh {
1097a05bd851SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
1098a05bd851SCarl Huang 
1099a05bd851SCarl Huang 	set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1100a05bd851SCarl Huang 
1101e9603f4bSCarl Huang 	ath11k_pci_aspm_restore(ab_pci);
1102e9603f4bSCarl Huang 
11037f4beda2SGovind Singh 	ath11k_pci_ce_irqs_enable(ab);
11042c3960c2SGovind Singh 	ath11k_ce_rx_post_buf(ab);
11052c3960c2SGovind Singh 
11062c3960c2SGovind Singh 	return 0;
11072c3960c2SGovind Singh }
11082c3960c2SGovind Singh 
1109d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab)
1110d578ec2aSCarl Huang {
1111d578ec2aSCarl Huang 	ath11k_pci_ce_irqs_enable(ab);
1112d578ec2aSCarl Huang }
1113d578ec2aSCarl Huang 
1114d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab)
1115d578ec2aSCarl Huang {
1116d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
1117d578ec2aSCarl Huang }
1118d578ec2aSCarl Huang 
11192c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
11202c3960c2SGovind Singh 					  u8 *ul_pipe, u8 *dl_pipe)
11212c3960c2SGovind Singh {
11222c3960c2SGovind Singh 	const struct service_to_pipe *entry;
11232c3960c2SGovind Singh 	bool ul_set = false, dl_set = false;
11242c3960c2SGovind Singh 	int i;
11252c3960c2SGovind Singh 
1126967c1d11SAnilkumar Kolli 	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
1127967c1d11SAnilkumar Kolli 		entry = &ab->hw_params.svc_to_ce_map[i];
11282c3960c2SGovind Singh 
11292c3960c2SGovind Singh 		if (__le32_to_cpu(entry->service_id) != service_id)
11302c3960c2SGovind Singh 			continue;
11312c3960c2SGovind Singh 
11322c3960c2SGovind Singh 		switch (__le32_to_cpu(entry->pipedir)) {
11332c3960c2SGovind Singh 		case PIPEDIR_NONE:
11342c3960c2SGovind Singh 			break;
11352c3960c2SGovind Singh 		case PIPEDIR_IN:
11362c3960c2SGovind Singh 			WARN_ON(dl_set);
11372c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
11382c3960c2SGovind Singh 			dl_set = true;
11392c3960c2SGovind Singh 			break;
11402c3960c2SGovind Singh 		case PIPEDIR_OUT:
11412c3960c2SGovind Singh 			WARN_ON(ul_set);
11422c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
11432c3960c2SGovind Singh 			ul_set = true;
11442c3960c2SGovind Singh 			break;
11452c3960c2SGovind Singh 		case PIPEDIR_INOUT:
11462c3960c2SGovind Singh 			WARN_ON(dl_set);
11472c3960c2SGovind Singh 			WARN_ON(ul_set);
11482c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
11492c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
11502c3960c2SGovind Singh 			dl_set = true;
11512c3960c2SGovind Singh 			ul_set = true;
11522c3960c2SGovind Singh 			break;
11532c3960c2SGovind Singh 		}
11542c3960c2SGovind Singh 	}
11552c3960c2SGovind Singh 
11562c3960c2SGovind Singh 	if (WARN_ON(!ul_set || !dl_set))
11572c3960c2SGovind Singh 		return -ENOENT;
11587f4beda2SGovind Singh 
11597f4beda2SGovind Singh 	return 0;
11607f4beda2SGovind Singh }
11617f4beda2SGovind Singh 
11627f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
11637f4beda2SGovind Singh 	.start = ath11k_pci_start,
11647f4beda2SGovind Singh 	.stop = ath11k_pci_stop,
1165654e959aSGovind Singh 	.read32 = ath11k_pci_read32,
1166654e959aSGovind Singh 	.write32 = ath11k_pci_write32,
11671399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
11681399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
1169fa5917e4SCarl Huang 	.suspend = ath11k_pci_hif_suspend,
1170fa5917e4SCarl Huang 	.resume = ath11k_pci_hif_resume,
1171d4ecb90bSCarl Huang 	.irq_enable = ath11k_pci_ext_irq_enable,
1172d4ecb90bSCarl Huang 	.irq_disable = ath11k_pci_ext_irq_disable,
1173c4eacabeSGovind Singh 	.get_msi_address =  ath11k_pci_get_msi_address,
1174c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
11752c3960c2SGovind Singh 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
1176d578ec2aSCarl Huang 	.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
1177d578ec2aSCarl Huang 	.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
11786289ac2bSKarthikeyan Periyasamy 	.get_ce_msi_idx = ath11k_pci_get_ce_msi_idx,
11791399fb87SGovind Singh };
11801399fb87SGovind Singh 
1181*0fbf1957SBaochen Qiang static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor)
1182*0fbf1957SBaochen Qiang {
1183*0fbf1957SBaochen Qiang 	u32 soc_hw_version;
1184*0fbf1957SBaochen Qiang 
1185*0fbf1957SBaochen Qiang 	soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION);
1186*0fbf1957SBaochen Qiang 	*major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
1187*0fbf1957SBaochen Qiang 			   soc_hw_version);
1188*0fbf1957SBaochen Qiang 	*minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
1189*0fbf1957SBaochen Qiang 			   soc_hw_version);
1190*0fbf1957SBaochen Qiang 
1191*0fbf1957SBaochen Qiang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
1192*0fbf1957SBaochen Qiang 		   *major, *minor);
1193*0fbf1957SBaochen Qiang }
1194*0fbf1957SBaochen Qiang 
11956e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
11966e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
11976e0355afSGovind Singh {
11986e0355afSGovind Singh 	struct ath11k_base *ab;
11995762613eSGovind Singh 	struct ath11k_pci *ab_pci;
1200*0fbf1957SBaochen Qiang 	u32 soc_hw_version_major, soc_hw_version_minor;
12015762613eSGovind Singh 	int ret;
12026e0355afSGovind Singh 
12031ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
12041ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
12056e0355afSGovind Singh 	if (!ab) {
12066e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
12076e0355afSGovind Singh 		return -ENOMEM;
12086e0355afSGovind Singh 	}
12096e0355afSGovind Singh 
12106e0355afSGovind Singh 	ab->dev = &pdev->dev;
12116e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
12125762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
12135762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
12145762613eSGovind Singh 	ab_pci->ab = ab;
12155697a564SGovind Singh 	ab_pci->pdev = pdev;
12167f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
12175762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
1218654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
12195762613eSGovind Singh 
12205762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
12215762613eSGovind Singh 	if (ret) {
12225762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
12235762613eSGovind Singh 		goto err_free_core;
12245762613eSGovind Singh 	}
12256e0355afSGovind Singh 
122618ac1665SKalle Valo 	switch (pci_dev->device) {
122718ac1665SKalle Valo 	case QCA6390_DEVICE_ID:
1228*0fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
1229*0fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
123018ac1665SKalle Valo 		switch (soc_hw_version_major) {
123118ac1665SKalle Valo 		case 2:
123218ac1665SKalle Valo 			ab->hw_rev = ATH11K_HW_QCA6390_HW20;
123318ac1665SKalle Valo 			break;
123418ac1665SKalle Valo 		default:
123518ac1665SKalle Valo 			dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n",
123618ac1665SKalle Valo 				soc_hw_version_major, soc_hw_version_minor);
123718ac1665SKalle Valo 			ret = -EOPNOTSUPP;
123818ac1665SKalle Valo 			goto err_pci_free_region;
123918ac1665SKalle Valo 		}
12404e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[0];
12414e809461SAnilkumar Kolli 		break;
12424e809461SAnilkumar Kolli 	case QCN9074_DEVICE_ID:
12434e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[1];
12444e809461SAnilkumar Kolli 		ab->bus_params.static_window_map = true;
12454e809461SAnilkumar Kolli 		ab->hw_rev = ATH11K_HW_QCN9074_HW10;
124618ac1665SKalle Valo 		break;
1247*0fbf1957SBaochen Qiang 	case WCN6855_DEVICE_ID:
1248*0fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
1249*0fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
1250*0fbf1957SBaochen Qiang 		switch (soc_hw_version_major) {
1251*0fbf1957SBaochen Qiang 		case 2:
1252*0fbf1957SBaochen Qiang 			ab->hw_rev = ATH11K_HW_WCN6855_HW20;
1253*0fbf1957SBaochen Qiang 			break;
1254*0fbf1957SBaochen Qiang 		default:
1255*0fbf1957SBaochen Qiang 			dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n",
1256*0fbf1957SBaochen Qiang 				soc_hw_version_major, soc_hw_version_minor);
1257*0fbf1957SBaochen Qiang 			ret = -EOPNOTSUPP;
1258*0fbf1957SBaochen Qiang 			goto err_pci_free_region;
1259*0fbf1957SBaochen Qiang 		}
1260*0fbf1957SBaochen Qiang 		ab_pci->msi_config = &ath11k_msi_config[0];
1261*0fbf1957SBaochen Qiang 		break;
126218ac1665SKalle Valo 	default:
126318ac1665SKalle Valo 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
126418ac1665SKalle Valo 			pci_dev->device);
126518ac1665SKalle Valo 		ret = -EOPNOTSUPP;
126618ac1665SKalle Valo 		goto err_pci_free_region;
126718ac1665SKalle Valo 	}
126818ac1665SKalle Valo 
12695697a564SGovind Singh 	ret = ath11k_pci_enable_msi(ab_pci);
12705697a564SGovind Singh 	if (ret) {
12715697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
12725697a564SGovind Singh 		goto err_pci_free_region;
12735697a564SGovind Singh 	}
12745697a564SGovind Singh 
1275b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
1276b8246f88SKalle Valo 	if (ret)
1277b8246f88SKalle Valo 		goto err_pci_disable_msi;
1278b8246f88SKalle Valo 
12791399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
12801399fb87SGovind Singh 	if (ret) {
12811399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
12821399fb87SGovind Singh 		goto err_pci_disable_msi;
12831399fb87SGovind Singh 	}
12841399fb87SGovind Singh 
12857f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
12867f4beda2SGovind Singh 	if (ret)
12877f4beda2SGovind Singh 		goto err_mhi_unregister;
12887f4beda2SGovind Singh 
12897f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
12907f4beda2SGovind Singh 	if (ret) {
12917f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
12927f4beda2SGovind Singh 		goto err_hal_srng_deinit;
12937f4beda2SGovind Singh 	}
12947f4beda2SGovind Singh 
12957f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
12967f4beda2SGovind Singh 
12977f4beda2SGovind Singh 	ret = ath11k_pci_config_irq(ab);
12987f4beda2SGovind Singh 	if (ret) {
12997f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
13007f4beda2SGovind Singh 		goto err_ce_free;
13017f4beda2SGovind Singh 	}
13027f4beda2SGovind Singh 
13037f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
13047f4beda2SGovind Singh 	if (ret) {
13057f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
13067f4beda2SGovind Singh 		goto err_free_irq;
13077f4beda2SGovind Singh 	}
13086e0355afSGovind Singh 	return 0;
13095762613eSGovind Singh 
13107f4beda2SGovind Singh err_free_irq:
13117f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
13127f4beda2SGovind Singh 
13137f4beda2SGovind Singh err_ce_free:
13147f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
13157f4beda2SGovind Singh 
13167f4beda2SGovind Singh err_hal_srng_deinit:
13177f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
13187f4beda2SGovind Singh 
13197f4beda2SGovind Singh err_mhi_unregister:
13207f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
13217f4beda2SGovind Singh 
1322b8246f88SKalle Valo err_pci_disable_msi:
1323b8246f88SKalle Valo 	ath11k_pci_disable_msi(ab_pci);
1324b8246f88SKalle Valo 
13255697a564SGovind Singh err_pci_free_region:
13265697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
13275697a564SGovind Singh 
13285762613eSGovind Singh err_free_core:
13295762613eSGovind Singh 	ath11k_core_free(ab);
13305697a564SGovind Singh 
13315762613eSGovind Singh 	return ret;
13326e0355afSGovind Singh }
13336e0355afSGovind Singh 
13346e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
13356e0355afSGovind Singh {
13366e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
13375762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
13386e0355afSGovind Singh 
133961a57e51SAnilkumar Kolli 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
134061a57e51SAnilkumar Kolli 		ath11k_pci_power_down(ab);
134161a57e51SAnilkumar Kolli 		ath11k_debugfs_soc_destroy(ab);
134261a57e51SAnilkumar Kolli 		ath11k_qmi_deinit_service(ab);
134361a57e51SAnilkumar Kolli 		goto qmi_fail;
134461a57e51SAnilkumar Kolli 	}
134561a57e51SAnilkumar Kolli 
13466e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
13476fbd8898SCarl Huang 
13486fbd8898SCarl Huang 	ath11k_core_deinit(ab);
13496fbd8898SCarl Huang 
135061a57e51SAnilkumar Kolli qmi_fail:
13511399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
13526fbd8898SCarl Huang 
13536fbd8898SCarl Huang 	ath11k_pci_free_irq(ab);
13545697a564SGovind Singh 	ath11k_pci_disable_msi(ab_pci);
13555762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
13566fbd8898SCarl Huang 
13576fbd8898SCarl Huang 	ath11k_hal_srng_deinit(ab);
13586fbd8898SCarl Huang 	ath11k_ce_free_pipes(ab);
13596e0355afSGovind Singh 	ath11k_core_free(ab);
13606e0355afSGovind Singh }
13616e0355afSGovind Singh 
13621399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
13631399fb87SGovind Singh {
13641399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
13651399fb87SGovind Singh 
13661399fb87SGovind Singh 	ath11k_pci_power_down(ab);
13671399fb87SGovind Singh }
13681399fb87SGovind Singh 
1369d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
1370d1b0c338SCarl Huang {
1371d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1372d1b0c338SCarl Huang 	int ret;
1373d1b0c338SCarl Huang 
1374d1b0c338SCarl Huang 	ret = ath11k_core_suspend(ab);
1375d1b0c338SCarl Huang 	if (ret)
1376d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to suspend core: %d\n", ret);
1377d1b0c338SCarl Huang 
1378d1b0c338SCarl Huang 	return ret;
1379d1b0c338SCarl Huang }
1380d1b0c338SCarl Huang 
1381d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
1382d1b0c338SCarl Huang {
1383d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1384d1b0c338SCarl Huang 	int ret;
1385d1b0c338SCarl Huang 
1386d1b0c338SCarl Huang 	ret = ath11k_core_resume(ab);
1387d1b0c338SCarl Huang 	if (ret)
1388d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to resume core: %d\n", ret);
1389d1b0c338SCarl Huang 
1390d1b0c338SCarl Huang 	return ret;
1391d1b0c338SCarl Huang }
1392d1b0c338SCarl Huang 
1393d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
1394d1b0c338SCarl Huang 			 ath11k_pci_pm_suspend,
1395d1b0c338SCarl Huang 			 ath11k_pci_pm_resume);
1396d1b0c338SCarl Huang 
13976e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
13986e0355afSGovind Singh 	.name = "ath11k_pci",
13996e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
14006e0355afSGovind Singh 	.probe = ath11k_pci_probe,
14016e0355afSGovind Singh 	.remove = ath11k_pci_remove,
14021399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
1403d1b0c338SCarl Huang #ifdef CONFIG_PM
1404d1b0c338SCarl Huang 	.driver.pm = &ath11k_pci_pm_ops,
1405d1b0c338SCarl Huang #endif
14066e0355afSGovind Singh };
14076e0355afSGovind Singh 
14086e0355afSGovind Singh static int ath11k_pci_init(void)
14096e0355afSGovind Singh {
14106e0355afSGovind Singh 	int ret;
14116e0355afSGovind Singh 
14126e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
14136e0355afSGovind Singh 	if (ret)
14146e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
14156e0355afSGovind Singh 		       ret);
14166e0355afSGovind Singh 
14176e0355afSGovind Singh 	return ret;
14186e0355afSGovind Singh }
14196e0355afSGovind Singh module_init(ath11k_pci_init);
14206e0355afSGovind Singh 
14216e0355afSGovind Singh static void ath11k_pci_exit(void)
14226e0355afSGovind Singh {
14236e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
14246e0355afSGovind Singh }
14256e0355afSGovind Singh 
14266e0355afSGovind Singh module_exit(ath11k_pci_exit);
14276e0355afSGovind Singh 
14286e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
14296e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
14303dbd7fe7SDevin Bayer 
14313dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */
14323dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE);
14333dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE);
14343dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE);
1435