xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision 4ab4693f327ad015c4637ae42dc53c8471aed9c8)
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
20*4ab4693fSCarl Huang #define ATH11K_PCI_IRQ_DP_OFFSET	14
217f4beda2SGovind Singh 
22654e959aSGovind Singh #define WINDOW_ENABLE_BIT		0x40000000
23654e959aSGovind Singh #define WINDOW_REG_ADDRESS		0x310c
24654e959aSGovind Singh #define WINDOW_VALUE_MASK		GENMASK(24, 19)
25654e959aSGovind Singh #define WINDOW_START			0x80000
26654e959aSGovind Singh #define WINDOW_RANGE_MASK		GENMASK(18, 0)
27654e959aSGovind Singh 
2818ac1665SKalle Valo #define TCSR_SOC_HW_VERSION		0x0224
2918ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MAJOR_MASK	GENMASK(16, 8)
3018ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MINOR_MASK	GENMASK(7, 0)
3118ac1665SKalle Valo 
32a05bd851SCarl Huang /* BAR0 + 4k is always accessible, and no
33a05bd851SCarl Huang  * need to force wakeup.
34a05bd851SCarl Huang  * 4K - 32 = 0xFE0
35a05bd851SCarl Huang  */
36a05bd851SCarl Huang #define ACCESS_ALWAYS_OFF 0xFE0
37a05bd851SCarl Huang 
386e0355afSGovind Singh #define QCA6390_DEVICE_ID		0x1101
394e809461SAnilkumar Kolli #define QCN9074_DEVICE_ID		0x1104
400fbf1957SBaochen Qiang #define WCN6855_DEVICE_ID		0x1103
416e0355afSGovind Singh 
426e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = {
436e0355afSGovind Singh 	{ PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) },
440fbf1957SBaochen Qiang 	{ PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) },
4549f5b114SAnilkumar Kolli 	{ PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) },
466e0355afSGovind Singh 	{0}
476e0355afSGovind Singh };
486e0355afSGovind Singh 
496e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table);
506e0355afSGovind Singh 
511ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = {
521ff8ed78SGovind Singh 	.mhi_support = true,
5356970454SGovind Singh 	.m3_fw_support = true,
546eb6ea51SGovind Singh 	.fixed_bdf_addr = false,
556eb6ea51SGovind Singh 	.fixed_mem_region = false,
561ff8ed78SGovind Singh };
571ff8ed78SGovind Singh 
587a3aed0cSAnilkumar Kolli static const struct ath11k_msi_config ath11k_msi_config[] = {
597a3aed0cSAnilkumar Kolli 	{
605697a564SGovind Singh 		.total_vectors = 32,
615697a564SGovind Singh 		.total_users = 4,
625697a564SGovind Singh 		.users = (struct ath11k_msi_user[]) {
635697a564SGovind Singh 			{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
645697a564SGovind Singh 			{ .name = "CE", .num_vectors = 10, .base_vector = 3 },
655697a564SGovind Singh 			{ .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
665697a564SGovind Singh 			{ .name = "DP", .num_vectors = 18, .base_vector = 14 },
675697a564SGovind Singh 		},
687a3aed0cSAnilkumar Kolli 	},
694e809461SAnilkumar Kolli 	{
704e809461SAnilkumar Kolli 		.total_vectors = 16,
714e809461SAnilkumar Kolli 		.total_users = 3,
724e809461SAnilkumar Kolli 		.users = (struct ath11k_msi_user[]) {
734e809461SAnilkumar Kolli 			{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
744e809461SAnilkumar Kolli 			{ .name = "CE", .num_vectors = 5, .base_vector = 3 },
754e809461SAnilkumar Kolli 			{ .name = "DP", .num_vectors = 8, .base_vector = 8 },
764e809461SAnilkumar Kolli 		},
774e809461SAnilkumar Kolli 	},
785697a564SGovind Singh };
795697a564SGovind Singh 
807f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
817f4beda2SGovind Singh 	"bhi",
827f4beda2SGovind Singh 	"mhi-er0",
837f4beda2SGovind Singh 	"mhi-er1",
847f4beda2SGovind Singh 	"ce0",
857f4beda2SGovind Singh 	"ce1",
867f4beda2SGovind Singh 	"ce2",
877f4beda2SGovind Singh 	"ce3",
887f4beda2SGovind Singh 	"ce4",
897f4beda2SGovind Singh 	"ce5",
907f4beda2SGovind Singh 	"ce6",
917f4beda2SGovind Singh 	"ce7",
927f4beda2SGovind Singh 	"ce8",
937f4beda2SGovind Singh 	"ce9",
947f4beda2SGovind Singh 	"ce10",
957f4beda2SGovind Singh 	"ce11",
967f4beda2SGovind Singh 	"host2wbm-desc-feed",
977f4beda2SGovind Singh 	"host2reo-re-injection",
987f4beda2SGovind Singh 	"host2reo-command",
997f4beda2SGovind Singh 	"host2rxdma-monitor-ring3",
1007f4beda2SGovind Singh 	"host2rxdma-monitor-ring2",
1017f4beda2SGovind Singh 	"host2rxdma-monitor-ring1",
1027f4beda2SGovind Singh 	"reo2ost-exception",
1037f4beda2SGovind Singh 	"wbm2host-rx-release",
1047f4beda2SGovind Singh 	"reo2host-status",
1057f4beda2SGovind Singh 	"reo2host-destination-ring4",
1067f4beda2SGovind Singh 	"reo2host-destination-ring3",
1077f4beda2SGovind Singh 	"reo2host-destination-ring2",
1087f4beda2SGovind Singh 	"reo2host-destination-ring1",
1097f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac3",
1107f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac2",
1117f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac1",
1127f4beda2SGovind Singh 	"ppdu-end-interrupts-mac3",
1137f4beda2SGovind Singh 	"ppdu-end-interrupts-mac2",
1147f4beda2SGovind Singh 	"ppdu-end-interrupts-mac1",
1157f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac3",
1167f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac2",
1177f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac1",
1187f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac3",
1197f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac2",
1207f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac1",
1217f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac3",
1227f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac2",
1237f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac1",
1247f4beda2SGovind Singh 	"host2tcl-input-ring4",
1257f4beda2SGovind Singh 	"host2tcl-input-ring3",
1267f4beda2SGovind Singh 	"host2tcl-input-ring2",
1277f4beda2SGovind Singh 	"host2tcl-input-ring1",
1287f4beda2SGovind Singh 	"wbm2host-tx-completions-ring3",
1297f4beda2SGovind Singh 	"wbm2host-tx-completions-ring2",
1307f4beda2SGovind Singh 	"wbm2host-tx-completions-ring1",
1317f4beda2SGovind Singh 	"tcl2host-status-ring",
1327f4beda2SGovind Singh };
1337f4beda2SGovind Singh 
134654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset)
135654e959aSGovind Singh {
136654e959aSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
137654e959aSGovind Singh 
138654e959aSGovind Singh 	u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset);
139654e959aSGovind Singh 
140654e959aSGovind Singh 	lockdep_assert_held(&ab_pci->window_lock);
141654e959aSGovind Singh 
142654e959aSGovind Singh 	if (window != ab_pci->register_window) {
143654e959aSGovind Singh 		iowrite32(WINDOW_ENABLE_BIT | window,
144654e959aSGovind Singh 			  ab->mem + WINDOW_REG_ADDRESS);
145f6fa37a4SCarl Huang 		ioread32(ab->mem + WINDOW_REG_ADDRESS);
146654e959aSGovind Singh 		ab_pci->register_window = window;
147654e959aSGovind Singh 	}
148654e959aSGovind Singh }
149654e959aSGovind Singh 
150480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci)
151480a7361SKarthikeyan Periyasamy {
152480a7361SKarthikeyan Periyasamy 	u32 umac_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET);
153480a7361SKarthikeyan Periyasamy 	u32 ce_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE);
154480a7361SKarthikeyan Periyasamy 	u32 window;
155480a7361SKarthikeyan Periyasamy 
156480a7361SKarthikeyan Periyasamy 	window = (umac_window << 12) | (ce_window << 6);
157480a7361SKarthikeyan Periyasamy 
158480a7361SKarthikeyan Periyasamy 	iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + WINDOW_REG_ADDRESS);
159480a7361SKarthikeyan Periyasamy }
160480a7361SKarthikeyan Periyasamy 
161480a7361SKarthikeyan Periyasamy static inline u32 ath11k_pci_get_window_start(struct ath11k_base *ab,
162480a7361SKarthikeyan Periyasamy 					      u32 offset)
163480a7361SKarthikeyan Periyasamy {
164480a7361SKarthikeyan Periyasamy 	u32 window_start;
165480a7361SKarthikeyan Periyasamy 
166480a7361SKarthikeyan Periyasamy 	/* If offset lies within DP register range, use 3rd window */
167480a7361SKarthikeyan Periyasamy 	if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < WINDOW_RANGE_MASK)
168480a7361SKarthikeyan Periyasamy 		window_start = 3 * WINDOW_START;
169480a7361SKarthikeyan Periyasamy 	/* If offset lies within CE register range, use 2nd window */
170480a7361SKarthikeyan Periyasamy 	else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK)
171480a7361SKarthikeyan Periyasamy 		window_start = 2 * WINDOW_START;
172480a7361SKarthikeyan Periyasamy 	else
173480a7361SKarthikeyan Periyasamy 		window_start = WINDOW_START;
174480a7361SKarthikeyan Periyasamy 
175480a7361SKarthikeyan Periyasamy 	return window_start;
176480a7361SKarthikeyan Periyasamy }
177480a7361SKarthikeyan Periyasamy 
178f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
179654e959aSGovind Singh {
180654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
181480a7361SKarthikeyan Periyasamy 	u32 window_start;
182654e959aSGovind Singh 
183a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
184a05bd851SCarl Huang 	 * need to wakeup MHI to access.
185a05bd851SCarl Huang 	 */
186081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
187081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
188a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
189a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
190a05bd851SCarl Huang 
191654e959aSGovind Singh 	if (offset < WINDOW_START) {
192654e959aSGovind Singh 		iowrite32(value, ab->mem  + offset);
193654e959aSGovind Singh 	} else {
194480a7361SKarthikeyan Periyasamy 		if (ab->bus_params.static_window_map)
195480a7361SKarthikeyan Periyasamy 			window_start = ath11k_pci_get_window_start(ab, offset);
196480a7361SKarthikeyan Periyasamy 		else
197480a7361SKarthikeyan Periyasamy 			window_start = WINDOW_START;
198480a7361SKarthikeyan Periyasamy 
199480a7361SKarthikeyan Periyasamy 		if (window_start == WINDOW_START) {
200654e959aSGovind Singh 			spin_lock_bh(&ab_pci->window_lock);
201654e959aSGovind Singh 			ath11k_pci_select_window(ab_pci, offset);
202480a7361SKarthikeyan Periyasamy 			iowrite32(value, ab->mem + window_start +
203480a7361SKarthikeyan Periyasamy 				  (offset & WINDOW_RANGE_MASK));
204654e959aSGovind Singh 			spin_unlock_bh(&ab_pci->window_lock);
205480a7361SKarthikeyan Periyasamy 		} else {
206480a7361SKarthikeyan Periyasamy 			iowrite32(value, ab->mem + window_start +
207480a7361SKarthikeyan Periyasamy 				  (offset & WINDOW_RANGE_MASK));
208480a7361SKarthikeyan Periyasamy 		}
209654e959aSGovind Singh 	}
210a05bd851SCarl Huang 
211081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
212081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
213a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
214a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
215654e959aSGovind Singh }
216654e959aSGovind Singh 
217f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
218654e959aSGovind Singh {
219654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
220480a7361SKarthikeyan Periyasamy 	u32 val, window_start;
221654e959aSGovind Singh 
222a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
223a05bd851SCarl Huang 	 * need to wakeup MHI to access.
224a05bd851SCarl Huang 	 */
225081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
226081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
227a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
228a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
229a05bd851SCarl Huang 
230654e959aSGovind Singh 	if (offset < WINDOW_START) {
231654e959aSGovind Singh 		val = ioread32(ab->mem + offset);
232654e959aSGovind Singh 	} else {
233480a7361SKarthikeyan Periyasamy 		if (ab->bus_params.static_window_map)
234480a7361SKarthikeyan Periyasamy 			window_start = ath11k_pci_get_window_start(ab, offset);
235480a7361SKarthikeyan Periyasamy 		else
236480a7361SKarthikeyan Periyasamy 			window_start = WINDOW_START;
237480a7361SKarthikeyan Periyasamy 
238480a7361SKarthikeyan Periyasamy 		if (window_start == WINDOW_START) {
239654e959aSGovind Singh 			spin_lock_bh(&ab_pci->window_lock);
240654e959aSGovind Singh 			ath11k_pci_select_window(ab_pci, offset);
241480a7361SKarthikeyan Periyasamy 			val = ioread32(ab->mem + window_start +
242480a7361SKarthikeyan Periyasamy 				       (offset & WINDOW_RANGE_MASK));
243654e959aSGovind Singh 			spin_unlock_bh(&ab_pci->window_lock);
244480a7361SKarthikeyan Periyasamy 		} else {
245480a7361SKarthikeyan Periyasamy 			val = ioread32(ab->mem + window_start +
246480a7361SKarthikeyan Periyasamy 				       (offset & WINDOW_RANGE_MASK));
247480a7361SKarthikeyan Periyasamy 		}
248654e959aSGovind Singh 	}
249654e959aSGovind Singh 
250081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
251081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
252a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
253a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
254a05bd851SCarl Huang 
255654e959aSGovind Singh 	return val;
256654e959aSGovind Singh }
257654e959aSGovind Singh 
258f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
259f3c603d4SCarl Huang {
260f3c603d4SCarl Huang 	u32 val, delay;
261f3c603d4SCarl Huang 
262f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
263f3c603d4SCarl Huang 
264f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
265f3c603d4SCarl Huang 
266f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
267f3c603d4SCarl Huang 
268f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
269f3c603d4SCarl Huang 	delay = 10;
270f3c603d4SCarl Huang 	mdelay(delay);
271f3c603d4SCarl Huang 
272f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
273f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
274f3c603d4SCarl Huang 
275f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
276f3c603d4SCarl Huang 
277f3c603d4SCarl Huang 	mdelay(delay);
278f3c603d4SCarl Huang 
279f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
280f3c603d4SCarl Huang 	if (val == 0xffffffff)
281f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
282f3c603d4SCarl Huang }
283f3c603d4SCarl Huang 
284f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
285f3c603d4SCarl Huang {
286f3c603d4SCarl Huang 	u32 val;
287f3c603d4SCarl Huang 
288f3c603d4SCarl Huang 	/* read cookie */
289f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR);
290f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val);
291f3c603d4SCarl Huang 
292f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
293f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
294f3c603d4SCarl Huang 
295f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
296f3c603d4SCarl Huang 	mdelay(10);
297f3c603d4SCarl Huang 
298f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
299f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
300f3c603d4SCarl Huang 	 */
301f3c603d4SCarl Huang 	ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0);
302f3c603d4SCarl Huang 	mdelay(10);
303f3c603d4SCarl Huang 
304f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
305f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
306f3c603d4SCarl Huang 
307f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
308f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
309f3c603d4SCarl Huang 	 */
310f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
311f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
312f3c603d4SCarl Huang }
313f3c603d4SCarl Huang 
31406999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab,
31506999407SCarl Huang 				   u32 offset, u32 value, u32 mask)
31606999407SCarl Huang {
31706999407SCarl Huang 	u32 v;
31806999407SCarl Huang 	int i;
31906999407SCarl Huang 
32006999407SCarl Huang 	v = ath11k_pci_read32(ab, offset);
32106999407SCarl Huang 	if ((v & mask) == value)
32206999407SCarl Huang 		return 0;
32306999407SCarl Huang 
32406999407SCarl Huang 	for (i = 0; i < 10; i++) {
32506999407SCarl Huang 		ath11k_pci_write32(ab, offset, (v & ~mask) | value);
32606999407SCarl Huang 
32706999407SCarl Huang 		v = ath11k_pci_read32(ab, offset);
32806999407SCarl Huang 		if ((v & mask) == value)
32906999407SCarl Huang 			return 0;
33006999407SCarl Huang 
33106999407SCarl Huang 		mdelay(2);
33206999407SCarl Huang 	}
33306999407SCarl Huang 
33406999407SCarl Huang 	ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n",
33506999407SCarl Huang 		    offset, v & mask, value);
33606999407SCarl Huang 
33706999407SCarl Huang 	return -ETIMEDOUT;
33806999407SCarl Huang }
33906999407SCarl Huang 
34006999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
34106999407SCarl Huang {
34206999407SCarl Huang 	int ret;
34306999407SCarl Huang 
34406999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3456fe6f68fSKarthikeyan Periyasamy 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab),
34606999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL,
34706999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK);
34830d08503SDan Carpenter 	if (ret) {
34906999407SCarl Huang 		ath11k_warn(ab, "failed to set sysclk: %d\n", ret);
35006999407SCarl Huang 		return ret;
35106999407SCarl Huang 	}
35206999407SCarl Huang 
35306999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3546fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab),
3556fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_VAL,
3566fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
35730d08503SDan Carpenter 	if (ret) {
35806999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret);
35906999407SCarl Huang 		return ret;
36006999407SCarl Huang 	}
36106999407SCarl Huang 
36206999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3636fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab),
3646fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_VAL,
3656fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
36630d08503SDan Carpenter 	if (ret) {
36706999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config2: %d\n", ret);
36806999407SCarl Huang 		return ret;
36906999407SCarl Huang 	}
37006999407SCarl Huang 
37106999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3726fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab),
3736fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_VAL,
3746fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
37530d08503SDan Carpenter 	if (ret) {
37606999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config4: %d\n", ret);
37706999407SCarl Huang 		return ret;
37806999407SCarl Huang 	}
37906999407SCarl Huang 
38006999407SCarl Huang 	return 0;
38106999407SCarl Huang }
38206999407SCarl Huang 
383babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
384babb0cedSCarl Huang {
385babb0cedSCarl Huang 	u32 val;
386babb0cedSCarl Huang 	int i;
387babb0cedSCarl Huang 
388babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
389babb0cedSCarl Huang 
390babb0cedSCarl Huang 	/* PCIE link seems very unstable after the Hot Reset*/
391babb0cedSCarl Huang 	for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {
392babb0cedSCarl Huang 		if (val == 0xffffffff)
393babb0cedSCarl Huang 			mdelay(5);
394babb0cedSCarl Huang 
395babb0cedSCarl Huang 		ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
396babb0cedSCarl Huang 		val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
397babb0cedSCarl Huang 	}
398babb0cedSCarl Huang 
399babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val);
400babb0cedSCarl Huang 
401babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
402562934adSKalle Valo 	val |= GCC_GCC_PCIE_HOT_RST_VAL;
403babb0cedSCarl Huang 	ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
404babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
405babb0cedSCarl Huang 
406babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val);
407babb0cedSCarl Huang 
408babb0cedSCarl Huang 	mdelay(5);
409babb0cedSCarl Huang }
410babb0cedSCarl Huang 
411babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
412babb0cedSCarl Huang {
413babb0cedSCarl Huang 	/* This is a WAR for PCIE Hotreset.
414babb0cedSCarl Huang 	 * When target receive Hotreset, but will set the interrupt.
415babb0cedSCarl Huang 	 * So when download SBL again, SBL will open Interrupt and
416babb0cedSCarl Huang 	 * receive it, and crash immediately.
417babb0cedSCarl Huang 	 */
418babb0cedSCarl Huang 	ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
419babb0cedSCarl Huang }
420babb0cedSCarl Huang 
4210ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab)
4220ccdf439SCarl Huang {
4230ccdf439SCarl Huang 	u32 val;
4240ccdf439SCarl Huang 
4250ccdf439SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG);
4260ccdf439SCarl Huang 	val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK;
4270ccdf439SCarl Huang 	ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val);
4280ccdf439SCarl Huang }
4290ccdf439SCarl Huang 
430f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
431f3c603d4SCarl Huang {
432f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
433f3c603d4SCarl Huang 	mdelay(5);
434f3c603d4SCarl Huang }
435f3c603d4SCarl Huang 
436babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
437f3c603d4SCarl Huang {
4388a0b899fSBaochen Qiang 	mdelay(100);
4398a0b899fSBaochen Qiang 
440babb0cedSCarl Huang 	if (power_on) {
441babb0cedSCarl Huang 		ath11k_pci_enable_ltssm(ab);
442babb0cedSCarl Huang 		ath11k_pci_clear_all_intrs(ab);
4430ccdf439SCarl Huang 		ath11k_pci_set_wlaon_pwr_ctrl(ab);
4445088df05SBaochen Qiang 		if (ab->hw_params.fix_l1ss)
44506999407SCarl Huang 			ath11k_pci_fix_l1ss(ab);
446babb0cedSCarl Huang 	}
447babb0cedSCarl Huang 
448f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
4498a0b899fSBaochen Qiang 	ath11k_pci_clear_dbg_registers(ab);
450f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
451f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
452f3c603d4SCarl Huang }
453f3c603d4SCarl Huang 
4541399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
4551399fb87SGovind Singh {
4561399fb87SGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(dev);
4571399fb87SGovind Singh 
4581399fb87SGovind Singh 	return pci_irq_vector(pci_dev, vector);
4591399fb87SGovind Singh }
4601399fb87SGovind Singh 
461c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
462c4eacabeSGovind Singh 				       u32 *msi_addr_hi)
463c4eacabeSGovind Singh {
464e8e55d89SAnilkumar Kolli 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
465c4eacabeSGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
466c4eacabeSGovind Singh 
467c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
468c4eacabeSGovind Singh 			      msi_addr_lo);
469c4eacabeSGovind Singh 
470e8e55d89SAnilkumar Kolli 	if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) {
471c4eacabeSGovind Singh 		pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
472c4eacabeSGovind Singh 				      msi_addr_hi);
473e8e55d89SAnilkumar Kolli 	} else {
474e8e55d89SAnilkumar Kolli 		*msi_addr_hi = 0;
475e8e55d89SAnilkumar Kolli 	}
476c4eacabeSGovind Singh }
477c4eacabeSGovind Singh 
4781399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
4791399fb87SGovind Singh 				       int *num_vectors, u32 *user_base_data,
4801399fb87SGovind Singh 				       u32 *base_vector)
4811399fb87SGovind Singh {
4821399fb87SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4837a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
4841399fb87SGovind Singh 	int idx;
4851399fb87SGovind Singh 
4867a3aed0cSAnilkumar Kolli 	for (idx = 0; idx < msi_config->total_users; idx++) {
4877a3aed0cSAnilkumar Kolli 		if (strcmp(user_name, msi_config->users[idx].name) == 0) {
4887a3aed0cSAnilkumar Kolli 			*num_vectors = msi_config->users[idx].num_vectors;
4897a3aed0cSAnilkumar Kolli 			*user_base_data = msi_config->users[idx].base_vector
4901399fb87SGovind Singh 				+ ab_pci->msi_ep_base_data;
4917a3aed0cSAnilkumar Kolli 			*base_vector = msi_config->users[idx].base_vector;
4921399fb87SGovind Singh 
4931399fb87SGovind Singh 			ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
4941399fb87SGovind Singh 				   user_name, *num_vectors, *user_base_data,
4951399fb87SGovind Singh 				   *base_vector);
4961399fb87SGovind Singh 
4971399fb87SGovind Singh 			return 0;
4981399fb87SGovind Singh 		}
4991399fb87SGovind Singh 	}
5001399fb87SGovind Singh 
5011399fb87SGovind Singh 	ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
5021399fb87SGovind Singh 
5031399fb87SGovind Singh 	return -EINVAL;
5041399fb87SGovind Singh }
5051399fb87SGovind Singh 
5066289ac2bSKarthikeyan Periyasamy static void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id,
5076289ac2bSKarthikeyan Periyasamy 				      u32 *msi_idx)
5086289ac2bSKarthikeyan Periyasamy {
5096289ac2bSKarthikeyan Periyasamy 	u32 i, msi_data_idx;
5106289ac2bSKarthikeyan Periyasamy 
5116289ac2bSKarthikeyan Periyasamy 	for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
5126289ac2bSKarthikeyan Periyasamy 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5136289ac2bSKarthikeyan Periyasamy 			continue;
5146289ac2bSKarthikeyan Periyasamy 
5156289ac2bSKarthikeyan Periyasamy 		if (ce_id == i)
5166289ac2bSKarthikeyan Periyasamy 			break;
5176289ac2bSKarthikeyan Periyasamy 
5186289ac2bSKarthikeyan Periyasamy 		msi_data_idx++;
5196289ac2bSKarthikeyan Periyasamy 	}
5206289ac2bSKarthikeyan Periyasamy 	*msi_idx = msi_data_idx;
5216289ac2bSKarthikeyan Periyasamy }
5226289ac2bSKarthikeyan Periyasamy 
523c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
524c4eacabeSGovind Singh 					  int *num_vectors, u32 *user_base_data,
525c4eacabeSGovind Singh 					  u32 *base_vector)
526c4eacabeSGovind Singh {
527c4eacabeSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
528c4eacabeSGovind Singh 
529c4eacabeSGovind Singh 	return ath11k_pci_get_user_msi_assignment(ab_pci, user_name,
530c4eacabeSGovind Singh 						  num_vectors, user_base_data,
531c4eacabeSGovind Singh 						  base_vector);
532c4eacabeSGovind Singh }
533c4eacabeSGovind Singh 
534d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
535d4ecb90bSCarl Huang {
536d4ecb90bSCarl Huang 	int i, j;
537d4ecb90bSCarl Huang 
538d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
539d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
540d4ecb90bSCarl Huang 
541d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++)
542d4ecb90bSCarl Huang 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
543d4ecb90bSCarl Huang 
544d4ecb90bSCarl Huang 		netif_napi_del(&irq_grp->napi);
545d4ecb90bSCarl Huang 	}
546d4ecb90bSCarl Huang }
547d4ecb90bSCarl Huang 
5487f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab)
5497f4beda2SGovind Singh {
5507f4beda2SGovind Singh 	int i, irq_idx;
5517f4beda2SGovind Singh 
552d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
553e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5547f4beda2SGovind Singh 			continue;
5557f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5567f4beda2SGovind Singh 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
5577f4beda2SGovind Singh 	}
558d4ecb90bSCarl Huang 
559d4ecb90bSCarl Huang 	ath11k_pci_free_ext_irq(ab);
5607f4beda2SGovind Singh }
5617f4beda2SGovind Singh 
5622c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
5632c3960c2SGovind Singh {
5642c3960c2SGovind Singh 	u32 irq_idx;
5652c3960c2SGovind Singh 
5662c3960c2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
5672c3960c2SGovind Singh 	enable_irq(ab->irq_num[irq_idx]);
5682c3960c2SGovind Singh }
5692c3960c2SGovind Singh 
5707f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
5717f4beda2SGovind Singh {
5727f4beda2SGovind Singh 	u32 irq_idx;
5737f4beda2SGovind Singh 
5747f4beda2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
5757f4beda2SGovind Singh 	disable_irq_nosync(ab->irq_num[irq_idx]);
5767f4beda2SGovind Singh }
5777f4beda2SGovind Singh 
5782c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
5792c3960c2SGovind Singh {
5802c3960c2SGovind Singh 	int i;
5812c3960c2SGovind Singh 
58201279bcdSCarl Huang 	clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
58301279bcdSCarl Huang 
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 		ath11k_pci_ce_irq_disable(ab, i);
5882c3960c2SGovind Singh 	}
5892c3960c2SGovind Singh }
5902c3960c2SGovind Singh 
5912c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
5922c3960c2SGovind Singh {
5932c3960c2SGovind Singh 	int i;
5942c3960c2SGovind Singh 	int irq_idx;
5952c3960c2SGovind Singh 
596d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
597e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5982c3960c2SGovind Singh 			continue;
5992c3960c2SGovind Singh 
6002c3960c2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
6012c3960c2SGovind Singh 		synchronize_irq(ab->irq_num[irq_idx]);
6022c3960c2SGovind Singh 	}
6032c3960c2SGovind Singh }
6042c3960c2SGovind Singh 
6050f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
6062c3960c2SGovind Singh {
6070f01dcb8SAllen Pais 	struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
6082c3960c2SGovind Singh 
6092c3960c2SGovind Singh 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
6102c3960c2SGovind Singh 
6112c3960c2SGovind Singh 	ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
6122c3960c2SGovind Singh }
6132c3960c2SGovind Singh 
6147f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
6157f4beda2SGovind Singh {
6167f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = arg;
61701279bcdSCarl Huang 	struct ath11k_base *ab = ce_pipe->ab;
61801279bcdSCarl Huang 
61901279bcdSCarl Huang 	if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags))
62001279bcdSCarl Huang 		return IRQ_HANDLED;
6217f4beda2SGovind Singh 
6227dc67af0SKarthikeyan Periyasamy 	/* last interrupt received for this CE */
6237dc67af0SKarthikeyan Periyasamy 	ce_pipe->timestamp = jiffies;
6247dc67af0SKarthikeyan Periyasamy 
6257f4beda2SGovind Singh 	ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
6262c3960c2SGovind Singh 	tasklet_schedule(&ce_pipe->intr_tq);
6277f4beda2SGovind Singh 
6287f4beda2SGovind Singh 	return IRQ_HANDLED;
6297f4beda2SGovind Singh }
6307f4beda2SGovind Singh 
631d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
632d4ecb90bSCarl Huang {
633d4ecb90bSCarl Huang 	int i;
634d4ecb90bSCarl Huang 
635d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
636d4ecb90bSCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
637d4ecb90bSCarl Huang }
638d4ecb90bSCarl Huang 
639d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
640d4ecb90bSCarl Huang {
641d4ecb90bSCarl Huang 	int i;
642d4ecb90bSCarl Huang 
64301279bcdSCarl Huang 	clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags);
64401279bcdSCarl Huang 
645d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
646d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
647d4ecb90bSCarl Huang 
648d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
649d4ecb90bSCarl Huang 
650d4ecb90bSCarl Huang 		napi_synchronize(&irq_grp->napi);
651d4ecb90bSCarl Huang 		napi_disable(&irq_grp->napi);
652d4ecb90bSCarl Huang 	}
653d4ecb90bSCarl Huang }
654d4ecb90bSCarl Huang 
655d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
656d4ecb90bSCarl Huang {
657d4ecb90bSCarl Huang 	int i;
658d4ecb90bSCarl Huang 
659d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
660d4ecb90bSCarl Huang 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
661d4ecb90bSCarl Huang }
662d4ecb90bSCarl Huang 
663d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
664d4ecb90bSCarl Huang {
665d4ecb90bSCarl Huang 	int i;
666d4ecb90bSCarl Huang 
66701279bcdSCarl Huang 	set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags);
66801279bcdSCarl Huang 
669d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
670d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
671d4ecb90bSCarl Huang 
672d4ecb90bSCarl Huang 		napi_enable(&irq_grp->napi);
673d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
674d4ecb90bSCarl Huang 	}
675d4ecb90bSCarl Huang }
676d4ecb90bSCarl Huang 
677d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
678d4ecb90bSCarl Huang {
679d4ecb90bSCarl Huang 	int i, j, irq_idx;
680d4ecb90bSCarl Huang 
681d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
682d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
683d4ecb90bSCarl Huang 
684d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
685d4ecb90bSCarl Huang 			irq_idx = irq_grp->irqs[j];
686d4ecb90bSCarl Huang 			synchronize_irq(ab->irq_num[irq_idx]);
687d4ecb90bSCarl Huang 		}
688d4ecb90bSCarl Huang 	}
689d4ecb90bSCarl Huang }
690d4ecb90bSCarl Huang 
691d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
692d4ecb90bSCarl Huang {
693d4ecb90bSCarl Huang 	__ath11k_pci_ext_irq_disable(ab);
694d4ecb90bSCarl Huang 	ath11k_pci_sync_ext_irqs(ab);
695d4ecb90bSCarl Huang }
696d4ecb90bSCarl Huang 
697d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
698d4ecb90bSCarl Huang {
699d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
700d4ecb90bSCarl Huang 						struct ath11k_ext_irq_grp,
701d4ecb90bSCarl Huang 						napi);
702d4ecb90bSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
703d4ecb90bSCarl Huang 	int work_done;
704d4ecb90bSCarl Huang 
705d4ecb90bSCarl Huang 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
706d4ecb90bSCarl Huang 	if (work_done < budget) {
707d4ecb90bSCarl Huang 		napi_complete_done(napi, work_done);
708d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
709d4ecb90bSCarl Huang 	}
710d4ecb90bSCarl Huang 
711d4ecb90bSCarl Huang 	if (work_done > budget)
712d4ecb90bSCarl Huang 		work_done = budget;
713d4ecb90bSCarl Huang 
714d4ecb90bSCarl Huang 	return work_done;
715d4ecb90bSCarl Huang }
716d4ecb90bSCarl Huang 
717d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
718d4ecb90bSCarl Huang {
719d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = arg;
72001279bcdSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
72101279bcdSCarl Huang 
72201279bcdSCarl Huang 	if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags))
72301279bcdSCarl Huang 		return IRQ_HANDLED;
724d4ecb90bSCarl Huang 
725d4ecb90bSCarl Huang 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
726d4ecb90bSCarl Huang 
7277dc67af0SKarthikeyan Periyasamy 	/* last interrupt received for this group */
7287dc67af0SKarthikeyan Periyasamy 	irq_grp->timestamp = jiffies;
7297dc67af0SKarthikeyan Periyasamy 
730d4ecb90bSCarl Huang 	ath11k_pci_ext_grp_disable(irq_grp);
731d4ecb90bSCarl Huang 
732d4ecb90bSCarl Huang 	napi_schedule(&irq_grp->napi);
733d4ecb90bSCarl Huang 
734d4ecb90bSCarl Huang 	return IRQ_HANDLED;
735d4ecb90bSCarl Huang }
736d4ecb90bSCarl Huang 
737d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
738d4ecb90bSCarl Huang {
739d4ecb90bSCarl Huang 	int i, j, ret, num_vectors = 0;
740*4ab4693fSCarl Huang 	u32 user_base_data = 0, base_vector = 0;
741d4ecb90bSCarl Huang 
742b2c09458SColin Ian King 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
743b2c09458SColin Ian King 						 &num_vectors,
744b2c09458SColin Ian King 						 &user_base_data,
745d4ecb90bSCarl Huang 						 &base_vector);
746b2c09458SColin Ian King 	if (ret < 0)
747b2c09458SColin Ian King 		return ret;
748d4ecb90bSCarl Huang 
749d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
750d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
751d4ecb90bSCarl Huang 		u32 num_irq = 0;
752d4ecb90bSCarl Huang 
753d4ecb90bSCarl Huang 		irq_grp->ab = ab;
754d4ecb90bSCarl Huang 		irq_grp->grp_id = i;
755d4ecb90bSCarl Huang 		init_dummy_netdev(&irq_grp->napi_ndev);
756d4ecb90bSCarl Huang 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
757d4ecb90bSCarl Huang 			       ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
758d4ecb90bSCarl Huang 
759d4ecb90bSCarl Huang 		if (ab->hw_params.ring_mask->tx[i] ||
760d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx[i] ||
761d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_err[i] ||
762d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_wbm_rel[i] ||
763d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->reo_status[i] ||
764d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rxdma2host[i] ||
765d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->host2rxdma[i] ||
766d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_mon_status[i]) {
767d4ecb90bSCarl Huang 			num_irq = 1;
768d4ecb90bSCarl Huang 		}
769d4ecb90bSCarl Huang 
770d4ecb90bSCarl Huang 		irq_grp->num_irq = num_irq;
771*4ab4693fSCarl Huang 		irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i;
772d4ecb90bSCarl Huang 
773d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
774d4ecb90bSCarl Huang 			int irq_idx = irq_grp->irqs[j];
775d4ecb90bSCarl Huang 			int vector = (i % num_vectors) + base_vector;
776d4ecb90bSCarl Huang 			int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
777d4ecb90bSCarl Huang 
778d4ecb90bSCarl Huang 			ab->irq_num[irq_idx] = irq;
779d4ecb90bSCarl Huang 
780d4ecb90bSCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
781d4ecb90bSCarl Huang 				   "irq:%d group:%d\n", irq, i);
7827dc67af0SKarthikeyan Periyasamy 
7837dc67af0SKarthikeyan Periyasamy 			irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
784d4ecb90bSCarl Huang 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
785d4ecb90bSCarl Huang 					  IRQF_SHARED,
786d4ecb90bSCarl Huang 					  "DP_EXT_IRQ", irq_grp);
787d4ecb90bSCarl Huang 			if (ret) {
788d4ecb90bSCarl Huang 				ath11k_err(ab, "failed request irq %d: %d\n",
789d4ecb90bSCarl Huang 					   vector, ret);
790d4ecb90bSCarl Huang 				return ret;
791d4ecb90bSCarl Huang 			}
792d4ecb90bSCarl Huang 
793d4ecb90bSCarl Huang 			disable_irq_nosync(ab->irq_num[irq_idx]);
794d4ecb90bSCarl Huang 		}
795d4ecb90bSCarl Huang 	}
796d4ecb90bSCarl Huang 
797d4ecb90bSCarl Huang 	return 0;
798d4ecb90bSCarl Huang }
799d4ecb90bSCarl Huang 
8007f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab)
8017f4beda2SGovind Singh {
8027f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe;
8037f4beda2SGovind Singh 	u32 msi_data_start;
8046289ac2bSKarthikeyan Periyasamy 	u32 msi_data_count, msi_data_idx;
8057f4beda2SGovind Singh 	u32 msi_irq_start;
8067f4beda2SGovind Singh 	unsigned int msi_data;
8077f4beda2SGovind Singh 	int irq, i, ret, irq_idx;
8087f4beda2SGovind Singh 
8097f4beda2SGovind Singh 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab),
8107f4beda2SGovind Singh 						 "CE", &msi_data_count,
8117f4beda2SGovind Singh 						 &msi_data_start, &msi_irq_start);
8127f4beda2SGovind Singh 	if (ret)
8137f4beda2SGovind Singh 		return ret;
8147f4beda2SGovind Singh 
8157f4beda2SGovind Singh 	/* Configure CE irqs */
8166289ac2bSKarthikeyan Periyasamy 	for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
817e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
8187f4beda2SGovind Singh 			continue;
8197f4beda2SGovind Singh 
8206289ac2bSKarthikeyan Periyasamy 		msi_data = (msi_data_idx % msi_data_count) + msi_irq_start;
8216289ac2bSKarthikeyan Periyasamy 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
8226289ac2bSKarthikeyan Periyasamy 		ce_pipe = &ab->ce.ce_pipe[i];
8236289ac2bSKarthikeyan Periyasamy 
8247f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
8257f4beda2SGovind Singh 
8260f01dcb8SAllen Pais 		tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
8272c3960c2SGovind Singh 
8287f4beda2SGovind Singh 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
8297f4beda2SGovind Singh 				  IRQF_SHARED, irq_name[irq_idx],
8307f4beda2SGovind Singh 				  ce_pipe);
8317f4beda2SGovind Singh 		if (ret) {
8327f4beda2SGovind Singh 			ath11k_err(ab, "failed to request irq %d: %d\n",
8337f4beda2SGovind Singh 				   irq_idx, ret);
8347f4beda2SGovind Singh 			return ret;
8357f4beda2SGovind Singh 		}
8367f4beda2SGovind Singh 
8377f4beda2SGovind Singh 		ab->irq_num[irq_idx] = irq;
8386289ac2bSKarthikeyan Periyasamy 		msi_data_idx++;
839e678fbd4SKarthikeyan Periyasamy 
840e5c860e1SCarl Huang 		ath11k_pci_ce_irq_disable(ab, i);
8417f4beda2SGovind Singh 	}
8427f4beda2SGovind Singh 
843d4ecb90bSCarl Huang 	ret = ath11k_pci_ext_irq_config(ab);
844d4ecb90bSCarl Huang 	if (ret)
845d4ecb90bSCarl Huang 		return ret;
846d4ecb90bSCarl Huang 
8477f4beda2SGovind Singh 	return 0;
8487f4beda2SGovind Singh }
8497f4beda2SGovind Singh 
8507f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
8517f4beda2SGovind Singh {
8527f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
8537f4beda2SGovind Singh 
854967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
855967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
8567f4beda2SGovind Singh 
857967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
858967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
85916001e4bSAnilkumar Kolli 	ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
860e838c14aSCarl Huang 
861e838c14aSCarl Huang 	ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
862e838c14aSCarl Huang 				    &cfg->shadow_reg_v2_len);
8637f4beda2SGovind Singh }
8647f4beda2SGovind Singh 
8657f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
8667f4beda2SGovind Singh {
8677f4beda2SGovind Singh 	int i;
8687f4beda2SGovind Singh 
86901279bcdSCarl Huang 	set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
87001279bcdSCarl Huang 
871d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
872e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
8737f4beda2SGovind Singh 			continue;
8747f4beda2SGovind Singh 		ath11k_pci_ce_irq_enable(ab, i);
8757f4beda2SGovind Singh 	}
8767f4beda2SGovind Singh }
8777f4beda2SGovind Singh 
87896527d52SBaochen Qiang static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable)
87996527d52SBaochen Qiang {
88096527d52SBaochen Qiang 	struct pci_dev *dev = ab_pci->pdev;
88196527d52SBaochen Qiang 	u16 control;
88296527d52SBaochen Qiang 
88396527d52SBaochen Qiang 	pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
88496527d52SBaochen Qiang 
88596527d52SBaochen Qiang 	if (enable)
88696527d52SBaochen Qiang 		control |= PCI_MSI_FLAGS_ENABLE;
88796527d52SBaochen Qiang 	else
88896527d52SBaochen Qiang 		control &= ~PCI_MSI_FLAGS_ENABLE;
88996527d52SBaochen Qiang 
89096527d52SBaochen Qiang 	pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
89196527d52SBaochen Qiang }
89296527d52SBaochen Qiang 
89396527d52SBaochen Qiang static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci)
89496527d52SBaochen Qiang {
89596527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, true);
89696527d52SBaochen Qiang }
89796527d52SBaochen Qiang 
89896527d52SBaochen Qiang static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci)
89996527d52SBaochen Qiang {
90096527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, false);
90196527d52SBaochen Qiang }
90296527d52SBaochen Qiang 
90396527d52SBaochen Qiang static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
9045697a564SGovind Singh {
9055697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
9067a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
9075697a564SGovind Singh 	struct msi_desc *msi_desc;
9085697a564SGovind Singh 	int num_vectors;
9095697a564SGovind Singh 	int ret;
9105697a564SGovind Singh 
9115697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
9127a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
9137a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
9145697a564SGovind Singh 					    PCI_IRQ_MSI);
9157a3aed0cSAnilkumar Kolli 	if (num_vectors != msi_config->total_vectors) {
9165697a564SGovind Singh 		ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
9177a3aed0cSAnilkumar Kolli 			   msi_config->total_vectors, num_vectors);
9185697a564SGovind Singh 
9195697a564SGovind Singh 		if (num_vectors >= 0)
9205697a564SGovind Singh 			return -EINVAL;
9215697a564SGovind Singh 		else
9225697a564SGovind Singh 			return num_vectors;
9235697a564SGovind Singh 	}
92496527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
9255697a564SGovind Singh 
9265697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
9275697a564SGovind Singh 	if (!msi_desc) {
9285697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
9295697a564SGovind Singh 		ret = -EINVAL;
9305697a564SGovind Singh 		goto free_msi_vector;
9315697a564SGovind Singh 	}
9325697a564SGovind Singh 
9335697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
934e8e55d89SAnilkumar Kolli 	if (msi_desc->msi_attrib.is_64)
935e8e55d89SAnilkumar Kolli 		set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags);
9365697a564SGovind Singh 
9375697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
9385697a564SGovind Singh 
9395697a564SGovind Singh 	return 0;
9405697a564SGovind Singh 
9415697a564SGovind Singh free_msi_vector:
9425697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
9435697a564SGovind Singh 
9445697a564SGovind Singh 	return ret;
9455697a564SGovind Singh }
9465697a564SGovind Singh 
94796527d52SBaochen Qiang static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci)
9485697a564SGovind Singh {
9495697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
9505697a564SGovind Singh }
9515697a564SGovind Singh 
95287b4072dSCarl Huang static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci)
95387b4072dSCarl Huang {
95487b4072dSCarl Huang 	struct msi_desc *msi_desc;
95587b4072dSCarl Huang 
95687b4072dSCarl Huang 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
95787b4072dSCarl Huang 	if (!msi_desc) {
95887b4072dSCarl Huang 		ath11k_err(ab_pci->ab, "msi_desc is NULL!\n");
95987b4072dSCarl Huang 		pci_free_irq_vectors(ab_pci->pdev);
96087b4072dSCarl Huang 		return -EINVAL;
96187b4072dSCarl Huang 	}
96287b4072dSCarl Huang 
96387b4072dSCarl Huang 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
96487b4072dSCarl Huang 
96587b4072dSCarl Huang 	ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n",
96687b4072dSCarl Huang 		   ab_pci->msi_ep_base_data);
96787b4072dSCarl Huang 
96887b4072dSCarl Huang 	return 0;
96987b4072dSCarl Huang }
97087b4072dSCarl Huang 
9715762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
9725762613eSGovind Singh {
9735762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
9745762613eSGovind Singh 	u16 device_id;
9755762613eSGovind Singh 	int ret = 0;
9765762613eSGovind Singh 
9775762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
9785762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
9795762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
9805762613eSGovind Singh 			   device_id, ab_pci->dev_id);
9815762613eSGovind Singh 		ret = -EIO;
9825762613eSGovind Singh 		goto out;
9835762613eSGovind Singh 	}
9845762613eSGovind Singh 
9855762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
9865762613eSGovind Singh 	if (ret) {
9875762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
9885762613eSGovind Singh 		goto out;
9895762613eSGovind Singh 	}
9905762613eSGovind Singh 
9915762613eSGovind Singh 	ret = pci_enable_device(pdev);
9925762613eSGovind Singh 	if (ret) {
9935762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
9945762613eSGovind Singh 		goto out;
9955762613eSGovind Singh 	}
9965762613eSGovind Singh 
9975762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
9985762613eSGovind Singh 	if (ret) {
9995762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
10005762613eSGovind Singh 		goto disable_device;
10015762613eSGovind Singh 	}
10025762613eSGovind Singh 
1003923a1346SChristophe JAILLET 	ret = dma_set_mask_and_coherent(&pdev->dev,
1004923a1346SChristophe JAILLET 					DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
10055762613eSGovind Singh 	if (ret) {
10065762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
10075762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
10085762613eSGovind Singh 		goto release_region;
10095762613eSGovind Singh 	}
10105762613eSGovind Singh 
10115762613eSGovind Singh 	pci_set_master(pdev);
10125762613eSGovind Singh 
10135762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
10145762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
10155762613eSGovind Singh 	if (!ab->mem) {
10165762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
10175762613eSGovind Singh 		ret = -EIO;
10185762613eSGovind Singh 		goto clear_master;
10195762613eSGovind Singh 	}
10205762613eSGovind Singh 
10215762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
10225762613eSGovind Singh 	return 0;
10235762613eSGovind Singh 
10245762613eSGovind Singh clear_master:
10255762613eSGovind Singh 	pci_clear_master(pdev);
10265762613eSGovind Singh release_region:
10275762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
10285762613eSGovind Singh disable_device:
10295762613eSGovind Singh 	pci_disable_device(pdev);
10305762613eSGovind Singh out:
10315762613eSGovind Singh 	return ret;
10325762613eSGovind Singh }
10335762613eSGovind Singh 
10345762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
10355762613eSGovind Singh {
10365762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
10375762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
10385762613eSGovind Singh 
10395762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
10405762613eSGovind Singh 	ab->mem = NULL;
10415762613eSGovind Singh 	pci_clear_master(pci_dev);
10425762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
10435762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
10445762613eSGovind Singh 		pci_disable_device(pci_dev);
10455762613eSGovind Singh }
10465762613eSGovind Singh 
1047e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
1048e9603f4bSCarl Huang {
1049e9603f4bSCarl Huang 	struct ath11k_base *ab = ab_pci->ab;
1050e9603f4bSCarl Huang 
1051e9603f4bSCarl Huang 	pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1052e9603f4bSCarl Huang 				  &ab_pci->link_ctl);
1053e9603f4bSCarl Huang 
1054e9603f4bSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n",
1055e9603f4bSCarl Huang 		   ab_pci->link_ctl,
1056e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S),
1057e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
1058e9603f4bSCarl Huang 
1059e9603f4bSCarl Huang 	/* disable L0s and L1 */
1060e9603f4bSCarl Huang 	pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1061e9603f4bSCarl Huang 				   ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
1062e9603f4bSCarl Huang 
1063e9603f4bSCarl Huang 	set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags);
1064e9603f4bSCarl Huang }
1065e9603f4bSCarl Huang 
1066e9603f4bSCarl Huang static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci)
1067e9603f4bSCarl Huang {
1068e9603f4bSCarl Huang 	if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags))
1069e9603f4bSCarl Huang 		pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1070e9603f4bSCarl Huang 					   ab_pci->link_ctl);
1071e9603f4bSCarl Huang }
1072e9603f4bSCarl Huang 
10731399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
10741399fb87SGovind Singh {
10751399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
10761399fb87SGovind Singh 	int ret;
10771399fb87SGovind Singh 
1078a05bd851SCarl Huang 	ab_pci->register_window = 0;
1079a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1080babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, true);
1081f3c603d4SCarl Huang 
1082e9603f4bSCarl Huang 	/* Disable ASPM during firmware download due to problems switching
1083e9603f4bSCarl Huang 	 * to AMSS state.
1084e9603f4bSCarl Huang 	 */
1085e9603f4bSCarl Huang 	ath11k_pci_aspm_disable(ab_pci);
1086e9603f4bSCarl Huang 
108796527d52SBaochen Qiang 	ath11k_pci_msi_enable(ab_pci);
108896527d52SBaochen Qiang 
10891399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
10901399fb87SGovind Singh 	if (ret) {
10911399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
10921399fb87SGovind Singh 		return ret;
10931399fb87SGovind Singh 	}
10941399fb87SGovind Singh 
1095480a7361SKarthikeyan Periyasamy 	if (ab->bus_params.static_window_map)
1096480a7361SKarthikeyan Periyasamy 		ath11k_pci_select_static_window(ab_pci);
1097480a7361SKarthikeyan Periyasamy 
10981399fb87SGovind Singh 	return 0;
10991399fb87SGovind Singh }
11001399fb87SGovind Singh 
11011399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
11021399fb87SGovind Singh {
11031399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
11041399fb87SGovind Singh 
1105e9603f4bSCarl Huang 	/* restore aspm in case firmware bootup fails */
1106e9603f4bSCarl Huang 	ath11k_pci_aspm_restore(ab_pci);
1107e9603f4bSCarl Huang 
1108babb0cedSCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
110996527d52SBaochen Qiang 
111096527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
111196527d52SBaochen Qiang 
11121399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
1113a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1114babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, false);
11151399fb87SGovind Singh }
11161399fb87SGovind Singh 
1117fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab)
1118fa5917e4SCarl Huang {
1119fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
1120fa5917e4SCarl Huang 
1121fa5917e4SCarl Huang 	ath11k_mhi_suspend(ar_pci);
1122fa5917e4SCarl Huang 
1123fa5917e4SCarl Huang 	return 0;
1124fa5917e4SCarl Huang }
1125fa5917e4SCarl Huang 
1126fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab)
1127fa5917e4SCarl Huang {
1128fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
1129fa5917e4SCarl Huang 
1130fa5917e4SCarl Huang 	ath11k_mhi_resume(ar_pci);
1131fa5917e4SCarl Huang 
1132fa5917e4SCarl Huang 	return 0;
1133fa5917e4SCarl Huang }
1134fa5917e4SCarl Huang 
11352c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
11362c3960c2SGovind Singh {
11372c3960c2SGovind Singh 	int i;
11382c3960c2SGovind Singh 
1139d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
11402c3960c2SGovind Singh 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
11412c3960c2SGovind Singh 
1142e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
11432c3960c2SGovind Singh 			continue;
11442c3960c2SGovind Singh 
11452c3960c2SGovind Singh 		tasklet_kill(&ce_pipe->intr_tq);
11462c3960c2SGovind Singh 	}
11472c3960c2SGovind Singh }
11482c3960c2SGovind Singh 
1149d578ec2aSCarl Huang static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab)
11507f4beda2SGovind Singh {
11512c3960c2SGovind Singh 	ath11k_pci_ce_irqs_disable(ab);
11522c3960c2SGovind Singh 	ath11k_pci_sync_ce_irqs(ab);
11532c3960c2SGovind Singh 	ath11k_pci_kill_tasklets(ab);
1154d578ec2aSCarl Huang }
1155d578ec2aSCarl Huang 
1156d578ec2aSCarl Huang static void ath11k_pci_stop(struct ath11k_base *ab)
1157d578ec2aSCarl Huang {
1158d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
11597f4beda2SGovind Singh 	ath11k_ce_cleanup_pipes(ab);
11607f4beda2SGovind Singh }
11617f4beda2SGovind Singh 
11627f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab)
11637f4beda2SGovind Singh {
1164a05bd851SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
1165a05bd851SCarl Huang 
1166a05bd851SCarl Huang 	set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1167a05bd851SCarl Huang 
1168e9603f4bSCarl Huang 	ath11k_pci_aspm_restore(ab_pci);
1169e9603f4bSCarl Huang 
11707f4beda2SGovind Singh 	ath11k_pci_ce_irqs_enable(ab);
11712c3960c2SGovind Singh 	ath11k_ce_rx_post_buf(ab);
11722c3960c2SGovind Singh 
11732c3960c2SGovind Singh 	return 0;
11742c3960c2SGovind Singh }
11752c3960c2SGovind Singh 
1176d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab)
1177d578ec2aSCarl Huang {
1178d578ec2aSCarl Huang 	ath11k_pci_ce_irqs_enable(ab);
1179d578ec2aSCarl Huang }
1180d578ec2aSCarl Huang 
1181d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab)
1182d578ec2aSCarl Huang {
1183d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
1184d578ec2aSCarl Huang }
1185d578ec2aSCarl Huang 
11862c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
11872c3960c2SGovind Singh 					  u8 *ul_pipe, u8 *dl_pipe)
11882c3960c2SGovind Singh {
11892c3960c2SGovind Singh 	const struct service_to_pipe *entry;
11902c3960c2SGovind Singh 	bool ul_set = false, dl_set = false;
11912c3960c2SGovind Singh 	int i;
11922c3960c2SGovind Singh 
1193967c1d11SAnilkumar Kolli 	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
1194967c1d11SAnilkumar Kolli 		entry = &ab->hw_params.svc_to_ce_map[i];
11952c3960c2SGovind Singh 
11962c3960c2SGovind Singh 		if (__le32_to_cpu(entry->service_id) != service_id)
11972c3960c2SGovind Singh 			continue;
11982c3960c2SGovind Singh 
11992c3960c2SGovind Singh 		switch (__le32_to_cpu(entry->pipedir)) {
12002c3960c2SGovind Singh 		case PIPEDIR_NONE:
12012c3960c2SGovind Singh 			break;
12022c3960c2SGovind Singh 		case PIPEDIR_IN:
12032c3960c2SGovind Singh 			WARN_ON(dl_set);
12042c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
12052c3960c2SGovind Singh 			dl_set = true;
12062c3960c2SGovind Singh 			break;
12072c3960c2SGovind Singh 		case PIPEDIR_OUT:
12082c3960c2SGovind Singh 			WARN_ON(ul_set);
12092c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
12102c3960c2SGovind Singh 			ul_set = true;
12112c3960c2SGovind Singh 			break;
12122c3960c2SGovind Singh 		case PIPEDIR_INOUT:
12132c3960c2SGovind Singh 			WARN_ON(dl_set);
12142c3960c2SGovind Singh 			WARN_ON(ul_set);
12152c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
12162c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
12172c3960c2SGovind Singh 			dl_set = true;
12182c3960c2SGovind Singh 			ul_set = true;
12192c3960c2SGovind Singh 			break;
12202c3960c2SGovind Singh 		}
12212c3960c2SGovind Singh 	}
12222c3960c2SGovind Singh 
12232c3960c2SGovind Singh 	if (WARN_ON(!ul_set || !dl_set))
12242c3960c2SGovind Singh 		return -ENOENT;
12257f4beda2SGovind Singh 
12267f4beda2SGovind Singh 	return 0;
12277f4beda2SGovind Singh }
12287f4beda2SGovind Singh 
12297f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
12307f4beda2SGovind Singh 	.start = ath11k_pci_start,
12317f4beda2SGovind Singh 	.stop = ath11k_pci_stop,
1232654e959aSGovind Singh 	.read32 = ath11k_pci_read32,
1233654e959aSGovind Singh 	.write32 = ath11k_pci_write32,
12341399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
12351399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
1236fa5917e4SCarl Huang 	.suspend = ath11k_pci_hif_suspend,
1237fa5917e4SCarl Huang 	.resume = ath11k_pci_hif_resume,
1238d4ecb90bSCarl Huang 	.irq_enable = ath11k_pci_ext_irq_enable,
1239d4ecb90bSCarl Huang 	.irq_disable = ath11k_pci_ext_irq_disable,
1240c4eacabeSGovind Singh 	.get_msi_address =  ath11k_pci_get_msi_address,
1241c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
12422c3960c2SGovind Singh 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
1243d578ec2aSCarl Huang 	.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
1244d578ec2aSCarl Huang 	.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
12456289ac2bSKarthikeyan Periyasamy 	.get_ce_msi_idx = ath11k_pci_get_ce_msi_idx,
12461399fb87SGovind Singh };
12471399fb87SGovind Singh 
12480fbf1957SBaochen Qiang static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor)
12490fbf1957SBaochen Qiang {
12500fbf1957SBaochen Qiang 	u32 soc_hw_version;
12510fbf1957SBaochen Qiang 
12520fbf1957SBaochen Qiang 	soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION);
12530fbf1957SBaochen Qiang 	*major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
12540fbf1957SBaochen Qiang 			   soc_hw_version);
12550fbf1957SBaochen Qiang 	*minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
12560fbf1957SBaochen Qiang 			   soc_hw_version);
12570fbf1957SBaochen Qiang 
12580fbf1957SBaochen Qiang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
12590fbf1957SBaochen Qiang 		   *major, *minor);
12600fbf1957SBaochen Qiang }
12610fbf1957SBaochen Qiang 
12626e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
12636e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
12646e0355afSGovind Singh {
12656e0355afSGovind Singh 	struct ath11k_base *ab;
12665762613eSGovind Singh 	struct ath11k_pci *ab_pci;
12670fbf1957SBaochen Qiang 	u32 soc_hw_version_major, soc_hw_version_minor;
12685762613eSGovind Singh 	int ret;
12696e0355afSGovind Singh 
12701ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
12711ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
12726e0355afSGovind Singh 	if (!ab) {
12736e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
12746e0355afSGovind Singh 		return -ENOMEM;
12756e0355afSGovind Singh 	}
12766e0355afSGovind Singh 
12776e0355afSGovind Singh 	ab->dev = &pdev->dev;
12786e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
12795762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
12805762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
12815762613eSGovind Singh 	ab_pci->ab = ab;
12825697a564SGovind Singh 	ab_pci->pdev = pdev;
12837f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
12845762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
1285654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
12865762613eSGovind Singh 
12875762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
12885762613eSGovind Singh 	if (ret) {
12895762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
12905762613eSGovind Singh 		goto err_free_core;
12915762613eSGovind Singh 	}
12926e0355afSGovind Singh 
1293fc95d10aSWen Gong 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n",
1294fc95d10aSWen Gong 		   pdev->vendor, pdev->device,
1295fc95d10aSWen Gong 		   pdev->subsystem_vendor, pdev->subsystem_device);
1296fc95d10aSWen Gong 
1297fc95d10aSWen Gong 	ab->id.vendor = pdev->vendor;
1298fc95d10aSWen Gong 	ab->id.device = pdev->device;
1299fc95d10aSWen Gong 	ab->id.subsystem_vendor = pdev->subsystem_vendor;
1300fc95d10aSWen Gong 	ab->id.subsystem_device = pdev->subsystem_device;
1301fc95d10aSWen Gong 
130218ac1665SKalle Valo 	switch (pci_dev->device) {
130318ac1665SKalle Valo 	case QCA6390_DEVICE_ID:
13040fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
13050fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
130618ac1665SKalle Valo 		switch (soc_hw_version_major) {
130718ac1665SKalle Valo 		case 2:
130818ac1665SKalle Valo 			ab->hw_rev = ATH11K_HW_QCA6390_HW20;
130918ac1665SKalle Valo 			break;
131018ac1665SKalle Valo 		default:
131118ac1665SKalle Valo 			dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n",
131218ac1665SKalle Valo 				soc_hw_version_major, soc_hw_version_minor);
131318ac1665SKalle Valo 			ret = -EOPNOTSUPP;
131418ac1665SKalle Valo 			goto err_pci_free_region;
131518ac1665SKalle Valo 		}
13164e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[0];
13174e809461SAnilkumar Kolli 		break;
13184e809461SAnilkumar Kolli 	case QCN9074_DEVICE_ID:
13194e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[1];
13204e809461SAnilkumar Kolli 		ab->bus_params.static_window_map = true;
13214e809461SAnilkumar Kolli 		ab->hw_rev = ATH11K_HW_QCN9074_HW10;
132218ac1665SKalle Valo 		break;
13230fbf1957SBaochen Qiang 	case WCN6855_DEVICE_ID:
1324fc95d10aSWen Gong 		ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD;
13250fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
13260fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
13270fbf1957SBaochen Qiang 		switch (soc_hw_version_major) {
13280fbf1957SBaochen Qiang 		case 2:
13290fbf1957SBaochen Qiang 			ab->hw_rev = ATH11K_HW_WCN6855_HW20;
13300fbf1957SBaochen Qiang 			break;
13310fbf1957SBaochen Qiang 		default:
13320fbf1957SBaochen Qiang 			dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n",
13330fbf1957SBaochen Qiang 				soc_hw_version_major, soc_hw_version_minor);
13340fbf1957SBaochen Qiang 			ret = -EOPNOTSUPP;
13350fbf1957SBaochen Qiang 			goto err_pci_free_region;
13360fbf1957SBaochen Qiang 		}
13370fbf1957SBaochen Qiang 		ab_pci->msi_config = &ath11k_msi_config[0];
13380fbf1957SBaochen Qiang 		break;
133918ac1665SKalle Valo 	default:
134018ac1665SKalle Valo 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
134118ac1665SKalle Valo 			pci_dev->device);
134218ac1665SKalle Valo 		ret = -EOPNOTSUPP;
134318ac1665SKalle Valo 		goto err_pci_free_region;
134418ac1665SKalle Valo 	}
134518ac1665SKalle Valo 
134696527d52SBaochen Qiang 	ret = ath11k_pci_alloc_msi(ab_pci);
13475697a564SGovind Singh 	if (ret) {
13485697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
13495697a564SGovind Singh 		goto err_pci_free_region;
13505697a564SGovind Singh 	}
13515697a564SGovind Singh 
1352b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
1353b8246f88SKalle Valo 	if (ret)
1354b8246f88SKalle Valo 		goto err_pci_disable_msi;
1355b8246f88SKalle Valo 
13561399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
13571399fb87SGovind Singh 	if (ret) {
13581399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
13591399fb87SGovind Singh 		goto err_pci_disable_msi;
13601399fb87SGovind Singh 	}
13611399fb87SGovind Singh 
13627f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
13637f4beda2SGovind Singh 	if (ret)
13647f4beda2SGovind Singh 		goto err_mhi_unregister;
13657f4beda2SGovind Singh 
13667f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
13677f4beda2SGovind Singh 	if (ret) {
13687f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
13697f4beda2SGovind Singh 		goto err_hal_srng_deinit;
13707f4beda2SGovind Singh 	}
13717f4beda2SGovind Singh 
13727f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
13737f4beda2SGovind Singh 
13747f4beda2SGovind Singh 	ret = ath11k_pci_config_irq(ab);
13757f4beda2SGovind Singh 	if (ret) {
13767f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
13777f4beda2SGovind Singh 		goto err_ce_free;
13787f4beda2SGovind Singh 	}
13797f4beda2SGovind Singh 
138087b4072dSCarl Huang 	/* kernel may allocate a dummy vector before request_irq and
138187b4072dSCarl Huang 	 * then allocate a real vector when request_irq is called.
138287b4072dSCarl Huang 	 * So get msi_data here again to avoid spurious interrupt
138387b4072dSCarl Huang 	 * as msi_data will configured to srngs.
138487b4072dSCarl Huang 	 */
138587b4072dSCarl Huang 	ret = ath11k_pci_config_msi_data(ab_pci);
138687b4072dSCarl Huang 	if (ret) {
138787b4072dSCarl Huang 		ath11k_err(ab, "failed to config msi_data: %d\n", ret);
138887b4072dSCarl Huang 		goto err_free_irq;
138987b4072dSCarl Huang 	}
139087b4072dSCarl Huang 
13917f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
13927f4beda2SGovind Singh 	if (ret) {
13937f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
13947f4beda2SGovind Singh 		goto err_free_irq;
13957f4beda2SGovind Singh 	}
13966e0355afSGovind Singh 	return 0;
13975762613eSGovind Singh 
13987f4beda2SGovind Singh err_free_irq:
13997f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
14007f4beda2SGovind Singh 
14017f4beda2SGovind Singh err_ce_free:
14027f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
14037f4beda2SGovind Singh 
14047f4beda2SGovind Singh err_hal_srng_deinit:
14057f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
14067f4beda2SGovind Singh 
14077f4beda2SGovind Singh err_mhi_unregister:
14087f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
14097f4beda2SGovind Singh 
1410b8246f88SKalle Valo err_pci_disable_msi:
141196527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
1412b8246f88SKalle Valo 
14135697a564SGovind Singh err_pci_free_region:
14145697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
14155697a564SGovind Singh 
14165762613eSGovind Singh err_free_core:
14175762613eSGovind Singh 	ath11k_core_free(ab);
14185697a564SGovind Singh 
14195762613eSGovind Singh 	return ret;
14206e0355afSGovind Singh }
14216e0355afSGovind Singh 
14226e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
14236e0355afSGovind Singh {
14246e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
14255762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
14266e0355afSGovind Singh 
142761a57e51SAnilkumar Kolli 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
142861a57e51SAnilkumar Kolli 		ath11k_pci_power_down(ab);
142961a57e51SAnilkumar Kolli 		ath11k_debugfs_soc_destroy(ab);
143061a57e51SAnilkumar Kolli 		ath11k_qmi_deinit_service(ab);
143161a57e51SAnilkumar Kolli 		goto qmi_fail;
143261a57e51SAnilkumar Kolli 	}
143361a57e51SAnilkumar Kolli 
14346e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
14356fbd8898SCarl Huang 
14366fbd8898SCarl Huang 	ath11k_core_deinit(ab);
14376fbd8898SCarl Huang 
143861a57e51SAnilkumar Kolli qmi_fail:
14391399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
14406fbd8898SCarl Huang 
14416fbd8898SCarl Huang 	ath11k_pci_free_irq(ab);
144296527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
14435762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
14446fbd8898SCarl Huang 
14456fbd8898SCarl Huang 	ath11k_hal_srng_deinit(ab);
14466fbd8898SCarl Huang 	ath11k_ce_free_pipes(ab);
14476e0355afSGovind Singh 	ath11k_core_free(ab);
14486e0355afSGovind Singh }
14496e0355afSGovind Singh 
14501399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
14511399fb87SGovind Singh {
14521399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
14531399fb87SGovind Singh 
14541399fb87SGovind Singh 	ath11k_pci_power_down(ab);
14551399fb87SGovind Singh }
14561399fb87SGovind Singh 
1457d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
1458d1b0c338SCarl Huang {
1459d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1460d1b0c338SCarl Huang 	int ret;
1461d1b0c338SCarl Huang 
1462d1b0c338SCarl Huang 	ret = ath11k_core_suspend(ab);
1463d1b0c338SCarl Huang 	if (ret)
1464d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to suspend core: %d\n", ret);
1465d1b0c338SCarl Huang 
1466d1b0c338SCarl Huang 	return ret;
1467d1b0c338SCarl Huang }
1468d1b0c338SCarl Huang 
1469d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
1470d1b0c338SCarl Huang {
1471d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1472d1b0c338SCarl Huang 	int ret;
1473d1b0c338SCarl Huang 
1474d1b0c338SCarl Huang 	ret = ath11k_core_resume(ab);
1475d1b0c338SCarl Huang 	if (ret)
1476d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to resume core: %d\n", ret);
1477d1b0c338SCarl Huang 
1478d1b0c338SCarl Huang 	return ret;
1479d1b0c338SCarl Huang }
1480d1b0c338SCarl Huang 
1481d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
1482d1b0c338SCarl Huang 			 ath11k_pci_pm_suspend,
1483d1b0c338SCarl Huang 			 ath11k_pci_pm_resume);
1484d1b0c338SCarl Huang 
14856e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
14866e0355afSGovind Singh 	.name = "ath11k_pci",
14876e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
14886e0355afSGovind Singh 	.probe = ath11k_pci_probe,
14896e0355afSGovind Singh 	.remove = ath11k_pci_remove,
14901399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
1491d1b0c338SCarl Huang #ifdef CONFIG_PM
1492d1b0c338SCarl Huang 	.driver.pm = &ath11k_pci_pm_ops,
1493d1b0c338SCarl Huang #endif
14946e0355afSGovind Singh };
14956e0355afSGovind Singh 
14966e0355afSGovind Singh static int ath11k_pci_init(void)
14976e0355afSGovind Singh {
14986e0355afSGovind Singh 	int ret;
14996e0355afSGovind Singh 
15006e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
15016e0355afSGovind Singh 	if (ret)
15026e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
15036e0355afSGovind Singh 		       ret);
15046e0355afSGovind Singh 
15056e0355afSGovind Singh 	return ret;
15066e0355afSGovind Singh }
15076e0355afSGovind Singh module_init(ath11k_pci_init);
15086e0355afSGovind Singh 
15096e0355afSGovind Singh static void ath11k_pci_exit(void)
15106e0355afSGovind Singh {
15116e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
15126e0355afSGovind Singh }
15136e0355afSGovind Singh 
15146e0355afSGovind Singh module_exit(ath11k_pci_exit);
15156e0355afSGovind Singh 
15166e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
15176e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
15183dbd7fe7SDevin Bayer 
15193dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */
15203dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE);
15213dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE);
15223dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE);
1523