xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision 948171b5f6fcf11253355bd836e6e8b613bea12f)
16e0355afSGovind Singh // SPDX-License-Identifier: BSD-3-Clause-Clear
26e0355afSGovind Singh /*
36e0355afSGovind Singh  * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
4*948171b5SManikanta Pubbisetty  * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
56e0355afSGovind Singh  */
66e0355afSGovind Singh 
76e0355afSGovind Singh #include <linux/module.h>
85697a564SGovind Singh #include <linux/msi.h>
96e0355afSGovind Singh #include <linux/pci.h>
106ac04bdcSAnilkumar Kolli #include <linux/of.h>
116e0355afSGovind Singh 
125762613eSGovind Singh #include "pci.h"
136e0355afSGovind Singh #include "core.h"
141399fb87SGovind Singh #include "hif.h"
151399fb87SGovind Singh #include "mhi.h"
166e0355afSGovind Singh #include "debug.h"
176e0355afSGovind Singh 
185762613eSGovind Singh #define ATH11K_PCI_BAR_NUM		0
195762613eSGovind Singh #define ATH11K_PCI_DMA_MASK		32
205762613eSGovind Singh 
2118ac1665SKalle Valo #define TCSR_SOC_HW_VERSION		0x0224
22d1147a31SBaochen Qiang #define TCSR_SOC_HW_VERSION_MAJOR_MASK	GENMASK(11, 8)
2318ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MINOR_MASK	GENMASK(7, 0)
2418ac1665SKalle Valo 
256e0355afSGovind Singh #define QCA6390_DEVICE_ID		0x1101
264e809461SAnilkumar Kolli #define QCN9074_DEVICE_ID		0x1104
270fbf1957SBaochen Qiang #define WCN6855_DEVICE_ID		0x1103
286e0355afSGovind Singh 
296e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = {
306e0355afSGovind Singh 	{ PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) },
310fbf1957SBaochen Qiang 	{ PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) },
3249f5b114SAnilkumar Kolli 	{ PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) },
336e0355afSGovind Singh 	{0}
346e0355afSGovind Singh };
356e0355afSGovind Singh 
366e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table);
376e0355afSGovind Singh 
381ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = {
391ff8ed78SGovind Singh 	.mhi_support = true,
4056970454SGovind Singh 	.m3_fw_support = true,
416eb6ea51SGovind Singh 	.fixed_bdf_addr = false,
426eb6ea51SGovind Singh 	.fixed_mem_region = false,
431ff8ed78SGovind Singh };
441ff8ed78SGovind Singh 
457a3aed0cSAnilkumar Kolli static const struct ath11k_msi_config ath11k_msi_config[] = {
467a3aed0cSAnilkumar Kolli 	{
475697a564SGovind Singh 		.total_vectors = 32,
485697a564SGovind Singh 		.total_users = 4,
495697a564SGovind Singh 		.users = (struct ath11k_msi_user[]) {
505697a564SGovind Singh 			{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
515697a564SGovind Singh 			{ .name = "CE", .num_vectors = 10, .base_vector = 3 },
525697a564SGovind Singh 			{ .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
535697a564SGovind Singh 			{ .name = "DP", .num_vectors = 18, .base_vector = 14 },
545697a564SGovind Singh 		},
557a3aed0cSAnilkumar Kolli 	},
564e809461SAnilkumar Kolli 	{
574e809461SAnilkumar Kolli 		.total_vectors = 16,
584e809461SAnilkumar Kolli 		.total_users = 3,
594e809461SAnilkumar Kolli 		.users = (struct ath11k_msi_user[]) {
604e809461SAnilkumar Kolli 			{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
614e809461SAnilkumar Kolli 			{ .name = "CE", .num_vectors = 5, .base_vector = 3 },
624e809461SAnilkumar Kolli 			{ .name = "DP", .num_vectors = 8, .base_vector = 8 },
634e809461SAnilkumar Kolli 		},
644e809461SAnilkumar Kolli 	},
655697a564SGovind Singh };
665697a564SGovind Singh 
67ac6e7348SCarl Huang static const struct ath11k_msi_config msi_config_one_msi = {
68ac6e7348SCarl Huang 	.total_vectors = 1,
69ac6e7348SCarl Huang 	.total_users = 4,
70ac6e7348SCarl Huang 	.users = (struct ath11k_msi_user[]) {
71ac6e7348SCarl Huang 		{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
72ac6e7348SCarl Huang 		{ .name = "CE", .num_vectors = 1, .base_vector = 0 },
73ac6e7348SCarl Huang 		{ .name = "WAKE", .num_vectors = 1, .base_vector = 0 },
74ac6e7348SCarl Huang 		{ .name = "DP", .num_vectors = 1, .base_vector = 0 },
75ac6e7348SCarl Huang 	},
76ac6e7348SCarl Huang };
77ac6e7348SCarl Huang 
787f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
797f4beda2SGovind Singh 	"bhi",
807f4beda2SGovind Singh 	"mhi-er0",
817f4beda2SGovind Singh 	"mhi-er1",
827f4beda2SGovind Singh 	"ce0",
837f4beda2SGovind Singh 	"ce1",
847f4beda2SGovind Singh 	"ce2",
857f4beda2SGovind Singh 	"ce3",
867f4beda2SGovind Singh 	"ce4",
877f4beda2SGovind Singh 	"ce5",
887f4beda2SGovind Singh 	"ce6",
897f4beda2SGovind Singh 	"ce7",
907f4beda2SGovind Singh 	"ce8",
917f4beda2SGovind Singh 	"ce9",
927f4beda2SGovind Singh 	"ce10",
937f4beda2SGovind Singh 	"ce11",
947f4beda2SGovind Singh 	"host2wbm-desc-feed",
957f4beda2SGovind Singh 	"host2reo-re-injection",
967f4beda2SGovind Singh 	"host2reo-command",
977f4beda2SGovind Singh 	"host2rxdma-monitor-ring3",
987f4beda2SGovind Singh 	"host2rxdma-monitor-ring2",
997f4beda2SGovind Singh 	"host2rxdma-monitor-ring1",
1007f4beda2SGovind Singh 	"reo2ost-exception",
1017f4beda2SGovind Singh 	"wbm2host-rx-release",
1027f4beda2SGovind Singh 	"reo2host-status",
1037f4beda2SGovind Singh 	"reo2host-destination-ring4",
1047f4beda2SGovind Singh 	"reo2host-destination-ring3",
1057f4beda2SGovind Singh 	"reo2host-destination-ring2",
1067f4beda2SGovind Singh 	"reo2host-destination-ring1",
1077f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac3",
1087f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac2",
1097f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac1",
1107f4beda2SGovind Singh 	"ppdu-end-interrupts-mac3",
1117f4beda2SGovind Singh 	"ppdu-end-interrupts-mac2",
1127f4beda2SGovind Singh 	"ppdu-end-interrupts-mac1",
1137f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac3",
1147f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac2",
1157f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac1",
1167f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac3",
1177f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac2",
1187f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac1",
1197f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac3",
1207f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac2",
1217f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac1",
1227f4beda2SGovind Singh 	"host2tcl-input-ring4",
1237f4beda2SGovind Singh 	"host2tcl-input-ring3",
1247f4beda2SGovind Singh 	"host2tcl-input-ring2",
1257f4beda2SGovind Singh 	"host2tcl-input-ring1",
1267f4beda2SGovind Singh 	"wbm2host-tx-completions-ring3",
1277f4beda2SGovind Singh 	"wbm2host-tx-completions-ring2",
1287f4beda2SGovind Singh 	"wbm2host-tx-completions-ring1",
1297f4beda2SGovind Singh 	"tcl2host-status-ring",
1307f4beda2SGovind Singh };
1317f4beda2SGovind Singh 
132654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset)
133654e959aSGovind Singh {
134654e959aSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
135654e959aSGovind Singh 
136*948171b5SManikanta Pubbisetty 	u32 window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, offset);
137654e959aSGovind Singh 
138654e959aSGovind Singh 	lockdep_assert_held(&ab_pci->window_lock);
139654e959aSGovind Singh 
140654e959aSGovind Singh 	if (window != ab_pci->register_window) {
141*948171b5SManikanta Pubbisetty 		iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window,
142*948171b5SManikanta Pubbisetty 			  ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS);
143*948171b5SManikanta Pubbisetty 		ioread32(ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS);
144654e959aSGovind Singh 		ab_pci->register_window = window;
145654e959aSGovind Singh 	}
146654e959aSGovind Singh }
147654e959aSGovind Singh 
148480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci)
149480a7361SKarthikeyan Periyasamy {
150*948171b5SManikanta Pubbisetty 	u32 umac_window;
151*948171b5SManikanta Pubbisetty 	u32 ce_window;
152480a7361SKarthikeyan Periyasamy 	u32 window;
153480a7361SKarthikeyan Periyasamy 
154*948171b5SManikanta Pubbisetty 	umac_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET);
155*948171b5SManikanta Pubbisetty 	ce_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE);
156480a7361SKarthikeyan Periyasamy 	window = (umac_window << 12) | (ce_window << 6);
157480a7361SKarthikeyan Periyasamy 
158*948171b5SManikanta Pubbisetty 	iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window,
159*948171b5SManikanta Pubbisetty 		  ab_pci->ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS);
160480a7361SKarthikeyan Periyasamy }
161480a7361SKarthikeyan Periyasamy 
162480a7361SKarthikeyan Periyasamy static inline u32 ath11k_pci_get_window_start(struct ath11k_base *ab,
163480a7361SKarthikeyan Periyasamy 					      u32 offset)
164480a7361SKarthikeyan Periyasamy {
165480a7361SKarthikeyan Periyasamy 	u32 window_start;
166480a7361SKarthikeyan Periyasamy 
167480a7361SKarthikeyan Periyasamy 	/* If offset lies within DP register range, use 3rd window */
168*948171b5SManikanta Pubbisetty 	if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < ATH11K_PCI_WINDOW_RANGE_MASK)
169*948171b5SManikanta Pubbisetty 		window_start = 3 * ATH11K_PCI_WINDOW_START;
170480a7361SKarthikeyan Periyasamy 	/* If offset lies within CE register range, use 2nd window */
171*948171b5SManikanta Pubbisetty 	else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < ATH11K_PCI_WINDOW_RANGE_MASK)
172*948171b5SManikanta Pubbisetty 		window_start = 2 * ATH11K_PCI_WINDOW_START;
173480a7361SKarthikeyan Periyasamy 	else
174*948171b5SManikanta Pubbisetty 		window_start = ATH11K_PCI_WINDOW_START;
175480a7361SKarthikeyan Periyasamy 
176480a7361SKarthikeyan Periyasamy 	return window_start;
177480a7361SKarthikeyan Periyasamy }
178480a7361SKarthikeyan Periyasamy 
179f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
180654e959aSGovind Singh {
181654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
182480a7361SKarthikeyan Periyasamy 	u32 window_start;
1830d7a8a62SWen Gong 	int ret = 0;
184654e959aSGovind Singh 
185a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
186a05bd851SCarl Huang 	 * need to wakeup MHI to access.
187a05bd851SCarl Huang 	 */
188081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
189081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
190*948171b5SManikanta Pubbisetty 	    offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF)
1910d7a8a62SWen Gong 		ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
192a05bd851SCarl Huang 
193*948171b5SManikanta Pubbisetty 	if (offset < ATH11K_PCI_WINDOW_START) {
194654e959aSGovind Singh 		iowrite32(value, ab->mem  + offset);
195654e959aSGovind Singh 	} else {
196480a7361SKarthikeyan Periyasamy 		if (ab->bus_params.static_window_map)
197480a7361SKarthikeyan Periyasamy 			window_start = ath11k_pci_get_window_start(ab, offset);
198480a7361SKarthikeyan Periyasamy 		else
199*948171b5SManikanta Pubbisetty 			window_start = ATH11K_PCI_WINDOW_START;
200480a7361SKarthikeyan Periyasamy 
201*948171b5SManikanta Pubbisetty 		if (window_start == ATH11K_PCI_WINDOW_START) {
202654e959aSGovind Singh 			spin_lock_bh(&ab_pci->window_lock);
203654e959aSGovind Singh 			ath11k_pci_select_window(ab_pci, offset);
204480a7361SKarthikeyan Periyasamy 			iowrite32(value, ab->mem + window_start +
205*948171b5SManikanta Pubbisetty 				  (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
206654e959aSGovind Singh 			spin_unlock_bh(&ab_pci->window_lock);
207480a7361SKarthikeyan Periyasamy 		} else {
208480a7361SKarthikeyan Periyasamy 			iowrite32(value, ab->mem + window_start +
209*948171b5SManikanta Pubbisetty 				  (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
210480a7361SKarthikeyan Periyasamy 		}
211654e959aSGovind Singh 	}
212a05bd851SCarl Huang 
213081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
214081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
215*948171b5SManikanta Pubbisetty 	    offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF &&
2160d7a8a62SWen Gong 	    !ret)
217a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
218654e959aSGovind Singh }
219654e959aSGovind Singh 
220f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
221654e959aSGovind Singh {
222654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
223480a7361SKarthikeyan Periyasamy 	u32 val, window_start;
2240d7a8a62SWen Gong 	int ret = 0;
225654e959aSGovind Singh 
226a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
227a05bd851SCarl Huang 	 * need to wakeup MHI to access.
228a05bd851SCarl Huang 	 */
229081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
230081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
231*948171b5SManikanta Pubbisetty 	    offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF)
2320d7a8a62SWen Gong 		ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
233a05bd851SCarl Huang 
234*948171b5SManikanta Pubbisetty 	if (offset < ATH11K_PCI_WINDOW_START) {
235654e959aSGovind Singh 		val = ioread32(ab->mem + offset);
236654e959aSGovind Singh 	} else {
237480a7361SKarthikeyan Periyasamy 		if (ab->bus_params.static_window_map)
238480a7361SKarthikeyan Periyasamy 			window_start = ath11k_pci_get_window_start(ab, offset);
239480a7361SKarthikeyan Periyasamy 		else
240*948171b5SManikanta Pubbisetty 			window_start = ATH11K_PCI_WINDOW_START;
241480a7361SKarthikeyan Periyasamy 
242*948171b5SManikanta Pubbisetty 		if (window_start == ATH11K_PCI_WINDOW_START) {
243654e959aSGovind Singh 			spin_lock_bh(&ab_pci->window_lock);
244654e959aSGovind Singh 			ath11k_pci_select_window(ab_pci, offset);
245480a7361SKarthikeyan Periyasamy 			val = ioread32(ab->mem + window_start +
246*948171b5SManikanta Pubbisetty 				       (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
247654e959aSGovind Singh 			spin_unlock_bh(&ab_pci->window_lock);
248480a7361SKarthikeyan Periyasamy 		} else {
249480a7361SKarthikeyan Periyasamy 			val = ioread32(ab->mem + window_start +
250*948171b5SManikanta Pubbisetty 				       (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
251480a7361SKarthikeyan Periyasamy 		}
252654e959aSGovind Singh 	}
253654e959aSGovind Singh 
254081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
255081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
256*948171b5SManikanta Pubbisetty 	    offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF &&
2570d7a8a62SWen Gong 	    !ret)
258a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
259a05bd851SCarl Huang 
260654e959aSGovind Singh 	return val;
261654e959aSGovind Singh }
262654e959aSGovind Singh 
263f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
264f3c603d4SCarl Huang {
265f3c603d4SCarl Huang 	u32 val, delay;
266f3c603d4SCarl Huang 
267f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
268f3c603d4SCarl Huang 
269f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
270f3c603d4SCarl Huang 
271f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
272f3c603d4SCarl Huang 
273f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
274f3c603d4SCarl Huang 	delay = 10;
275f3c603d4SCarl Huang 	mdelay(delay);
276f3c603d4SCarl Huang 
277f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
278f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
279f3c603d4SCarl Huang 
280f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
281f3c603d4SCarl Huang 
282f3c603d4SCarl Huang 	mdelay(delay);
283f3c603d4SCarl Huang 
284f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
285f3c603d4SCarl Huang 	if (val == 0xffffffff)
286f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
287f3c603d4SCarl Huang }
288f3c603d4SCarl Huang 
289f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
290f3c603d4SCarl Huang {
291f3c603d4SCarl Huang 	u32 val;
292f3c603d4SCarl Huang 
293f3c603d4SCarl Huang 	/* read cookie */
294f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR);
295f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val);
296f3c603d4SCarl Huang 
297f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
298f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
299f3c603d4SCarl Huang 
300f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
301f3c603d4SCarl Huang 	mdelay(10);
302f3c603d4SCarl Huang 
303f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
304f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
305f3c603d4SCarl Huang 	 */
306f3c603d4SCarl Huang 	ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0);
307f3c603d4SCarl Huang 	mdelay(10);
308f3c603d4SCarl Huang 
309f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
310f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
311f3c603d4SCarl Huang 
312f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
313f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
314f3c603d4SCarl Huang 	 */
315f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
316f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
317f3c603d4SCarl Huang }
318f3c603d4SCarl Huang 
31906999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab,
32006999407SCarl Huang 				   u32 offset, u32 value, u32 mask)
32106999407SCarl Huang {
32206999407SCarl Huang 	u32 v;
32306999407SCarl Huang 	int i;
32406999407SCarl Huang 
32506999407SCarl Huang 	v = ath11k_pci_read32(ab, offset);
32606999407SCarl Huang 	if ((v & mask) == value)
32706999407SCarl Huang 		return 0;
32806999407SCarl Huang 
32906999407SCarl Huang 	for (i = 0; i < 10; i++) {
33006999407SCarl Huang 		ath11k_pci_write32(ab, offset, (v & ~mask) | value);
33106999407SCarl Huang 
33206999407SCarl Huang 		v = ath11k_pci_read32(ab, offset);
33306999407SCarl Huang 		if ((v & mask) == value)
33406999407SCarl Huang 			return 0;
33506999407SCarl Huang 
33606999407SCarl Huang 		mdelay(2);
33706999407SCarl Huang 	}
33806999407SCarl Huang 
33906999407SCarl Huang 	ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n",
34006999407SCarl Huang 		    offset, v & mask, value);
34106999407SCarl Huang 
34206999407SCarl Huang 	return -ETIMEDOUT;
34306999407SCarl Huang }
34406999407SCarl Huang 
34506999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
34606999407SCarl Huang {
34706999407SCarl Huang 	int ret;
34806999407SCarl Huang 
34906999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3506fe6f68fSKarthikeyan Periyasamy 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab),
35106999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL,
35206999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK);
35330d08503SDan Carpenter 	if (ret) {
35406999407SCarl Huang 		ath11k_warn(ab, "failed to set sysclk: %d\n", ret);
35506999407SCarl Huang 		return ret;
35606999407SCarl Huang 	}
35706999407SCarl Huang 
35806999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3596fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab),
3606fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_VAL,
3616fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
36230d08503SDan Carpenter 	if (ret) {
36306999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret);
36406999407SCarl Huang 		return ret;
36506999407SCarl Huang 	}
36606999407SCarl Huang 
36706999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3686fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab),
3696fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_VAL,
3706fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
37130d08503SDan Carpenter 	if (ret) {
37206999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config2: %d\n", ret);
37306999407SCarl Huang 		return ret;
37406999407SCarl Huang 	}
37506999407SCarl Huang 
37606999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3776fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab),
3786fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_VAL,
3796fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
38030d08503SDan Carpenter 	if (ret) {
38106999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config4: %d\n", ret);
38206999407SCarl Huang 		return ret;
38306999407SCarl Huang 	}
38406999407SCarl Huang 
38506999407SCarl Huang 	return 0;
38606999407SCarl Huang }
38706999407SCarl Huang 
388babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
389babb0cedSCarl Huang {
390babb0cedSCarl Huang 	u32 val;
391babb0cedSCarl Huang 	int i;
392babb0cedSCarl Huang 
393babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
394babb0cedSCarl Huang 
395babb0cedSCarl Huang 	/* PCIE link seems very unstable after the Hot Reset*/
396babb0cedSCarl Huang 	for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {
397babb0cedSCarl Huang 		if (val == 0xffffffff)
398babb0cedSCarl Huang 			mdelay(5);
399babb0cedSCarl Huang 
400babb0cedSCarl Huang 		ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
401babb0cedSCarl Huang 		val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
402babb0cedSCarl Huang 	}
403babb0cedSCarl Huang 
404babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val);
405babb0cedSCarl Huang 
406babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
407562934adSKalle Valo 	val |= GCC_GCC_PCIE_HOT_RST_VAL;
408babb0cedSCarl Huang 	ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
409babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
410babb0cedSCarl Huang 
411babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val);
412babb0cedSCarl Huang 
413babb0cedSCarl Huang 	mdelay(5);
414babb0cedSCarl Huang }
415babb0cedSCarl Huang 
416babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
417babb0cedSCarl Huang {
418babb0cedSCarl Huang 	/* This is a WAR for PCIE Hotreset.
419babb0cedSCarl Huang 	 * When target receive Hotreset, but will set the interrupt.
420babb0cedSCarl Huang 	 * So when download SBL again, SBL will open Interrupt and
421babb0cedSCarl Huang 	 * receive it, and crash immediately.
422babb0cedSCarl Huang 	 */
423babb0cedSCarl Huang 	ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
424babb0cedSCarl Huang }
425babb0cedSCarl Huang 
4260ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab)
4270ccdf439SCarl Huang {
4280ccdf439SCarl Huang 	u32 val;
4290ccdf439SCarl Huang 
4300ccdf439SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG);
4310ccdf439SCarl Huang 	val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK;
4320ccdf439SCarl Huang 	ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val);
4330ccdf439SCarl Huang }
4340ccdf439SCarl Huang 
435f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
436f3c603d4SCarl Huang {
437f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
438f3c603d4SCarl Huang 	mdelay(5);
439f3c603d4SCarl Huang }
440f3c603d4SCarl Huang 
441babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
442f3c603d4SCarl Huang {
4438a0b899fSBaochen Qiang 	mdelay(100);
4448a0b899fSBaochen Qiang 
445babb0cedSCarl Huang 	if (power_on) {
446babb0cedSCarl Huang 		ath11k_pci_enable_ltssm(ab);
447babb0cedSCarl Huang 		ath11k_pci_clear_all_intrs(ab);
4480ccdf439SCarl Huang 		ath11k_pci_set_wlaon_pwr_ctrl(ab);
4495088df05SBaochen Qiang 		if (ab->hw_params.fix_l1ss)
45006999407SCarl Huang 			ath11k_pci_fix_l1ss(ab);
451babb0cedSCarl Huang 	}
452babb0cedSCarl Huang 
453f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
4548a0b899fSBaochen Qiang 	ath11k_pci_clear_dbg_registers(ab);
455f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
456f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
457f3c603d4SCarl Huang }
458f3c603d4SCarl Huang 
4591399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
4601399fb87SGovind Singh {
4611399fb87SGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(dev);
4621399fb87SGovind Singh 
4631399fb87SGovind Singh 	return pci_irq_vector(pci_dev, vector);
4641399fb87SGovind Singh }
4651399fb87SGovind Singh 
466*948171b5SManikanta Pubbisetty void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
467c4eacabeSGovind Singh 				u32 *msi_addr_hi)
468c4eacabeSGovind Singh {
469e8e55d89SAnilkumar Kolli 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
470c4eacabeSGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
471c4eacabeSGovind Singh 
472c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
473c4eacabeSGovind Singh 			      msi_addr_lo);
474c4eacabeSGovind Singh 
475e8e55d89SAnilkumar Kolli 	if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) {
476c4eacabeSGovind Singh 		pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
477c4eacabeSGovind Singh 				      msi_addr_hi);
478e8e55d89SAnilkumar Kolli 	} else {
479e8e55d89SAnilkumar Kolli 		*msi_addr_hi = 0;
480e8e55d89SAnilkumar Kolli 	}
481c4eacabeSGovind Singh }
482c4eacabeSGovind Singh 
4831399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
4841399fb87SGovind Singh 				       int *num_vectors, u32 *user_base_data,
4851399fb87SGovind Singh 				       u32 *base_vector)
4861399fb87SGovind Singh {
4871399fb87SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4887a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
4891399fb87SGovind Singh 	int idx;
4901399fb87SGovind Singh 
4917a3aed0cSAnilkumar Kolli 	for (idx = 0; idx < msi_config->total_users; idx++) {
4927a3aed0cSAnilkumar Kolli 		if (strcmp(user_name, msi_config->users[idx].name) == 0) {
4937a3aed0cSAnilkumar Kolli 			*num_vectors = msi_config->users[idx].num_vectors;
4947a3aed0cSAnilkumar Kolli 			*base_vector =  msi_config->users[idx].base_vector;
495c41a6700SCarl Huang 			*user_base_data = *base_vector + ab_pci->msi_ep_base_data;
4961399fb87SGovind Singh 
497c41a6700SCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
498c41a6700SCarl Huang 				   "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
4991399fb87SGovind Singh 				   user_name, *num_vectors, *user_base_data,
5001399fb87SGovind Singh 				   *base_vector);
5011399fb87SGovind Singh 
5021399fb87SGovind Singh 			return 0;
5031399fb87SGovind Singh 		}
5041399fb87SGovind Singh 	}
5051399fb87SGovind Singh 
5061399fb87SGovind Singh 	ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
5071399fb87SGovind Singh 
5081399fb87SGovind Singh 	return -EINVAL;
5091399fb87SGovind Singh }
5101399fb87SGovind Singh 
511*948171b5SManikanta Pubbisetty void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx)
5126289ac2bSKarthikeyan Periyasamy {
5136289ac2bSKarthikeyan Periyasamy 	u32 i, msi_data_idx;
5146289ac2bSKarthikeyan Periyasamy 
5156289ac2bSKarthikeyan Periyasamy 	for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
5166289ac2bSKarthikeyan Periyasamy 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5176289ac2bSKarthikeyan Periyasamy 			continue;
5186289ac2bSKarthikeyan Periyasamy 
5196289ac2bSKarthikeyan Periyasamy 		if (ce_id == i)
5206289ac2bSKarthikeyan Periyasamy 			break;
5216289ac2bSKarthikeyan Periyasamy 
5226289ac2bSKarthikeyan Periyasamy 		msi_data_idx++;
5236289ac2bSKarthikeyan Periyasamy 	}
5246289ac2bSKarthikeyan Periyasamy 	*msi_idx = msi_data_idx;
5256289ac2bSKarthikeyan Periyasamy }
5266289ac2bSKarthikeyan Periyasamy 
527*948171b5SManikanta Pubbisetty int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
528c4eacabeSGovind Singh 				   int *num_vectors, u32 *user_base_data,
529c4eacabeSGovind Singh 				   u32 *base_vector)
530c4eacabeSGovind Singh {
531c4eacabeSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
532c4eacabeSGovind Singh 
533c4eacabeSGovind Singh 	return ath11k_pci_get_user_msi_assignment(ab_pci, user_name,
534c4eacabeSGovind Singh 						  num_vectors, user_base_data,
535c4eacabeSGovind Singh 						  base_vector);
536c4eacabeSGovind Singh }
537c4eacabeSGovind Singh 
538d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
539d4ecb90bSCarl Huang {
540d4ecb90bSCarl Huang 	int i, j;
541d4ecb90bSCarl Huang 
542d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
543d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
544d4ecb90bSCarl Huang 
545d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++)
546d4ecb90bSCarl Huang 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
547d4ecb90bSCarl Huang 
548d4ecb90bSCarl Huang 		netif_napi_del(&irq_grp->napi);
549d4ecb90bSCarl Huang 	}
550d4ecb90bSCarl Huang }
551d4ecb90bSCarl Huang 
552*948171b5SManikanta Pubbisetty void ath11k_pci_free_irq(struct ath11k_base *ab)
5537f4beda2SGovind Singh {
5547f4beda2SGovind Singh 	int i, irq_idx;
5557f4beda2SGovind Singh 
556d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
557e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5587f4beda2SGovind Singh 			continue;
5597f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5607f4beda2SGovind Singh 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
5617f4beda2SGovind Singh 	}
562d4ecb90bSCarl Huang 
563d4ecb90bSCarl Huang 	ath11k_pci_free_ext_irq(ab);
5647f4beda2SGovind Singh }
5657f4beda2SGovind Singh 
5662c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
5672c3960c2SGovind Singh {
568c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
5692c3960c2SGovind Singh 	u32 irq_idx;
5702c3960c2SGovind Singh 
571c41a6700SCarl Huang 	/* In case of one MSI vector, we handle irq enable/disable in a
572c41a6700SCarl Huang 	 * uniform way since we only have one irq
573c41a6700SCarl Huang 	 */
574c41a6700SCarl Huang 	if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
575c41a6700SCarl Huang 		return;
576c41a6700SCarl Huang 
5772c3960c2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
5782c3960c2SGovind Singh 	enable_irq(ab->irq_num[irq_idx]);
5792c3960c2SGovind Singh }
5802c3960c2SGovind Singh 
5817f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
5827f4beda2SGovind Singh {
583c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
5847f4beda2SGovind Singh 	u32 irq_idx;
5857f4beda2SGovind Singh 
586c41a6700SCarl Huang 	/* In case of one MSI vector, we handle irq enable/disable in a
587c41a6700SCarl Huang 	 * uniform way since we only have one irq
588c41a6700SCarl Huang 	 */
589c41a6700SCarl Huang 	if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
590c41a6700SCarl Huang 		return;
591c41a6700SCarl Huang 
5927f4beda2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
5937f4beda2SGovind Singh 	disable_irq_nosync(ab->irq_num[irq_idx]);
5947f4beda2SGovind Singh }
5957f4beda2SGovind Singh 
5962c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
5972c3960c2SGovind Singh {
5982c3960c2SGovind Singh 	int i;
5992c3960c2SGovind Singh 
60001279bcdSCarl Huang 	clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
60101279bcdSCarl Huang 
602d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
603e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
6042c3960c2SGovind Singh 			continue;
6052c3960c2SGovind Singh 		ath11k_pci_ce_irq_disable(ab, i);
6062c3960c2SGovind Singh 	}
6072c3960c2SGovind Singh }
6082c3960c2SGovind Singh 
6092c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
6102c3960c2SGovind Singh {
6112c3960c2SGovind Singh 	int i;
6122c3960c2SGovind Singh 	int irq_idx;
6132c3960c2SGovind Singh 
614d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
615e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
6162c3960c2SGovind Singh 			continue;
6172c3960c2SGovind Singh 
6182c3960c2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
6192c3960c2SGovind Singh 		synchronize_irq(ab->irq_num[irq_idx]);
6202c3960c2SGovind Singh 	}
6212c3960c2SGovind Singh }
6222c3960c2SGovind Singh 
6230f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
6242c3960c2SGovind Singh {
6250f01dcb8SAllen Pais 	struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
626ac6e7348SCarl Huang 	int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
6272c3960c2SGovind Singh 
6282c3960c2SGovind Singh 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
6292c3960c2SGovind Singh 
630ac6e7348SCarl Huang 	enable_irq(ce_pipe->ab->irq_num[irq_idx]);
6312c3960c2SGovind Singh }
6322c3960c2SGovind Singh 
6337f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
6347f4beda2SGovind Singh {
6357f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = arg;
63601279bcdSCarl Huang 	struct ath11k_base *ab = ce_pipe->ab;
637ac6e7348SCarl Huang 	int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
63801279bcdSCarl Huang 
63901279bcdSCarl Huang 	if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags))
64001279bcdSCarl Huang 		return IRQ_HANDLED;
6417f4beda2SGovind Singh 
6427dc67af0SKarthikeyan Periyasamy 	/* last interrupt received for this CE */
6437dc67af0SKarthikeyan Periyasamy 	ce_pipe->timestamp = jiffies;
6447dc67af0SKarthikeyan Periyasamy 
645ac6e7348SCarl Huang 	disable_irq_nosync(ab->irq_num[irq_idx]);
646ac6e7348SCarl Huang 
6472c3960c2SGovind Singh 	tasklet_schedule(&ce_pipe->intr_tq);
6487f4beda2SGovind Singh 
6497f4beda2SGovind Singh 	return IRQ_HANDLED;
6507f4beda2SGovind Singh }
6517f4beda2SGovind Singh 
652d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
653d4ecb90bSCarl Huang {
654c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab);
655d4ecb90bSCarl Huang 	int i;
656d4ecb90bSCarl Huang 
657c41a6700SCarl Huang 	/* In case of one MSI vector, we handle irq enable/disable
658c41a6700SCarl Huang 	 * in a uniform way since we only have one irq
659c41a6700SCarl Huang 	 */
660c41a6700SCarl Huang 	if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
661c41a6700SCarl Huang 		return;
662c41a6700SCarl Huang 
663d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
664d4ecb90bSCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
665d4ecb90bSCarl Huang }
666d4ecb90bSCarl Huang 
667d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
668d4ecb90bSCarl Huang {
669d4ecb90bSCarl Huang 	int i;
670d4ecb90bSCarl Huang 
67101279bcdSCarl Huang 	clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags);
67201279bcdSCarl Huang 
673d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
674d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
675d4ecb90bSCarl Huang 
676d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
677d4ecb90bSCarl Huang 
678d943fdadSBen Greear 		if (irq_grp->napi_enabled) {
679d4ecb90bSCarl Huang 			napi_synchronize(&irq_grp->napi);
680d4ecb90bSCarl Huang 			napi_disable(&irq_grp->napi);
681d943fdadSBen Greear 			irq_grp->napi_enabled = false;
682d943fdadSBen Greear 		}
683d4ecb90bSCarl Huang 	}
684d4ecb90bSCarl Huang }
685d4ecb90bSCarl Huang 
686d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
687d4ecb90bSCarl Huang {
688c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab);
689d4ecb90bSCarl Huang 	int i;
690d4ecb90bSCarl Huang 
691c41a6700SCarl Huang 	/* In case of one MSI vector, we handle irq enable/disable in a
692c41a6700SCarl Huang 	 * uniform way since we only have one irq
693c41a6700SCarl Huang 	 */
694c41a6700SCarl Huang 	if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
695c41a6700SCarl Huang 		return;
696c41a6700SCarl Huang 
697d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
698d4ecb90bSCarl Huang 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
699d4ecb90bSCarl Huang }
700d4ecb90bSCarl Huang 
701*948171b5SManikanta Pubbisetty void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
702d4ecb90bSCarl Huang {
703d4ecb90bSCarl Huang 	int i;
704d4ecb90bSCarl Huang 
70501279bcdSCarl Huang 	set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags);
70601279bcdSCarl Huang 
707d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
708d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
709d4ecb90bSCarl Huang 
710d943fdadSBen Greear 		if (!irq_grp->napi_enabled) {
711d4ecb90bSCarl Huang 			napi_enable(&irq_grp->napi);
712d943fdadSBen Greear 			irq_grp->napi_enabled = true;
713d943fdadSBen Greear 		}
714d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
715d4ecb90bSCarl Huang 	}
716d4ecb90bSCarl Huang }
717d4ecb90bSCarl Huang 
718d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
719d4ecb90bSCarl Huang {
720d4ecb90bSCarl Huang 	int i, j, irq_idx;
721d4ecb90bSCarl Huang 
722d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
723d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
724d4ecb90bSCarl Huang 
725d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
726d4ecb90bSCarl Huang 			irq_idx = irq_grp->irqs[j];
727d4ecb90bSCarl Huang 			synchronize_irq(ab->irq_num[irq_idx]);
728d4ecb90bSCarl Huang 		}
729d4ecb90bSCarl Huang 	}
730d4ecb90bSCarl Huang }
731d4ecb90bSCarl Huang 
732*948171b5SManikanta Pubbisetty void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
733d4ecb90bSCarl Huang {
734d4ecb90bSCarl Huang 	__ath11k_pci_ext_irq_disable(ab);
735d4ecb90bSCarl Huang 	ath11k_pci_sync_ext_irqs(ab);
736d4ecb90bSCarl Huang }
737d4ecb90bSCarl Huang 
738d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
739d4ecb90bSCarl Huang {
740d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
741d4ecb90bSCarl Huang 						struct ath11k_ext_irq_grp,
742d4ecb90bSCarl Huang 						napi);
743d4ecb90bSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
744d4ecb90bSCarl Huang 	int work_done;
745ac6e7348SCarl Huang 	int i;
746d4ecb90bSCarl Huang 
747d4ecb90bSCarl Huang 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
748d4ecb90bSCarl Huang 	if (work_done < budget) {
749d4ecb90bSCarl Huang 		napi_complete_done(napi, work_done);
750ac6e7348SCarl Huang 		for (i = 0; i < irq_grp->num_irq; i++)
751ac6e7348SCarl Huang 			enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
752d4ecb90bSCarl Huang 	}
753d4ecb90bSCarl Huang 
754d4ecb90bSCarl Huang 	if (work_done > budget)
755d4ecb90bSCarl Huang 		work_done = budget;
756d4ecb90bSCarl Huang 
757d4ecb90bSCarl Huang 	return work_done;
758d4ecb90bSCarl Huang }
759d4ecb90bSCarl Huang 
760d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
761d4ecb90bSCarl Huang {
762d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = arg;
76301279bcdSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
764ac6e7348SCarl Huang 	int i;
76501279bcdSCarl Huang 
76601279bcdSCarl Huang 	if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags))
76701279bcdSCarl Huang 		return IRQ_HANDLED;
768d4ecb90bSCarl Huang 
769d4ecb90bSCarl Huang 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
770d4ecb90bSCarl Huang 
7717dc67af0SKarthikeyan Periyasamy 	/* last interrupt received for this group */
7727dc67af0SKarthikeyan Periyasamy 	irq_grp->timestamp = jiffies;
7737dc67af0SKarthikeyan Periyasamy 
774ac6e7348SCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
775ac6e7348SCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
776d4ecb90bSCarl Huang 
777d4ecb90bSCarl Huang 	napi_schedule(&irq_grp->napi);
778d4ecb90bSCarl Huang 
779d4ecb90bSCarl Huang 	return IRQ_HANDLED;
780d4ecb90bSCarl Huang }
781d4ecb90bSCarl Huang 
782d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
783d4ecb90bSCarl Huang {
784c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
785d4ecb90bSCarl Huang 	int i, j, ret, num_vectors = 0;
7864ab4693fSCarl Huang 	u32 user_base_data = 0, base_vector = 0;
787d4ecb90bSCarl Huang 
788b2c09458SColin Ian King 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
789b2c09458SColin Ian King 						 &num_vectors,
790b2c09458SColin Ian King 						 &user_base_data,
791d4ecb90bSCarl Huang 						 &base_vector);
792b2c09458SColin Ian King 	if (ret < 0)
793b2c09458SColin Ian King 		return ret;
794d4ecb90bSCarl Huang 
795d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
796d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
797d4ecb90bSCarl Huang 		u32 num_irq = 0;
798d4ecb90bSCarl Huang 
799d4ecb90bSCarl Huang 		irq_grp->ab = ab;
800d4ecb90bSCarl Huang 		irq_grp->grp_id = i;
801d4ecb90bSCarl Huang 		init_dummy_netdev(&irq_grp->napi_ndev);
802d4ecb90bSCarl Huang 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
803d4ecb90bSCarl Huang 			       ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
804d4ecb90bSCarl Huang 
805d4ecb90bSCarl Huang 		if (ab->hw_params.ring_mask->tx[i] ||
806d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx[i] ||
807d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_err[i] ||
808d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_wbm_rel[i] ||
809d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->reo_status[i] ||
810d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rxdma2host[i] ||
811d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->host2rxdma[i] ||
812d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_mon_status[i]) {
813d4ecb90bSCarl Huang 			num_irq = 1;
814d4ecb90bSCarl Huang 		}
815d4ecb90bSCarl Huang 
816d4ecb90bSCarl Huang 		irq_grp->num_irq = num_irq;
8174ab4693fSCarl Huang 		irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i;
818d4ecb90bSCarl Huang 
819d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
820d4ecb90bSCarl Huang 			int irq_idx = irq_grp->irqs[j];
821d4ecb90bSCarl Huang 			int vector = (i % num_vectors) + base_vector;
822d4ecb90bSCarl Huang 			int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
823d4ecb90bSCarl Huang 
824d4ecb90bSCarl Huang 			ab->irq_num[irq_idx] = irq;
825d4ecb90bSCarl Huang 
826d4ecb90bSCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
827d4ecb90bSCarl Huang 				   "irq:%d group:%d\n", irq, i);
8287dc67af0SKarthikeyan Periyasamy 
8297dc67af0SKarthikeyan Periyasamy 			irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
830d4ecb90bSCarl Huang 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
831c41a6700SCarl Huang 					  ab_pci->irq_flags,
832d4ecb90bSCarl Huang 					  "DP_EXT_IRQ", irq_grp);
833d4ecb90bSCarl Huang 			if (ret) {
834d4ecb90bSCarl Huang 				ath11k_err(ab, "failed request irq %d: %d\n",
835d4ecb90bSCarl Huang 					   vector, ret);
836d4ecb90bSCarl Huang 				return ret;
837d4ecb90bSCarl Huang 			}
838d4ecb90bSCarl Huang 		}
839c41a6700SCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
840d4ecb90bSCarl Huang 	}
841d4ecb90bSCarl Huang 
842d4ecb90bSCarl Huang 	return 0;
843d4ecb90bSCarl Huang }
844d4ecb90bSCarl Huang 
845*948171b5SManikanta Pubbisetty int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci,
846e94b0749SBaochen Qiang 				     const struct cpumask *m)
847e94b0749SBaochen Qiang {
848e94b0749SBaochen Qiang 	if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
849e94b0749SBaochen Qiang 		return 0;
850e94b0749SBaochen Qiang 
851e94b0749SBaochen Qiang 	return irq_set_affinity_hint(ab_pci->pdev->irq, m);
852e94b0749SBaochen Qiang }
853e94b0749SBaochen Qiang 
854*948171b5SManikanta Pubbisetty int ath11k_pci_config_irq(struct ath11k_base *ab)
8557f4beda2SGovind Singh {
856c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
8577f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe;
8587f4beda2SGovind Singh 	u32 msi_data_start;
8596289ac2bSKarthikeyan Periyasamy 	u32 msi_data_count, msi_data_idx;
8607f4beda2SGovind Singh 	u32 msi_irq_start;
8617f4beda2SGovind Singh 	unsigned int msi_data;
8627f4beda2SGovind Singh 	int irq, i, ret, irq_idx;
8637f4beda2SGovind Singh 
8647f4beda2SGovind Singh 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab),
8657f4beda2SGovind Singh 						 "CE", &msi_data_count,
8667f4beda2SGovind Singh 						 &msi_data_start, &msi_irq_start);
8677f4beda2SGovind Singh 	if (ret)
8687f4beda2SGovind Singh 		return ret;
8697f4beda2SGovind Singh 
870e94b0749SBaochen Qiang 	ret = ath11k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0));
871e94b0749SBaochen Qiang 	if (ret) {
872e94b0749SBaochen Qiang 		ath11k_err(ab, "failed to set irq affinity %d\n", ret);
873e94b0749SBaochen Qiang 		return ret;
874e94b0749SBaochen Qiang 	}
875e94b0749SBaochen Qiang 
8767f4beda2SGovind Singh 	/* Configure CE irqs */
8776289ac2bSKarthikeyan Periyasamy 	for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
878e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
8797f4beda2SGovind Singh 			continue;
8807f4beda2SGovind Singh 
8816289ac2bSKarthikeyan Periyasamy 		msi_data = (msi_data_idx % msi_data_count) + msi_irq_start;
8826289ac2bSKarthikeyan Periyasamy 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
8836289ac2bSKarthikeyan Periyasamy 		ce_pipe = &ab->ce.ce_pipe[i];
8846289ac2bSKarthikeyan Periyasamy 
8857f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
8867f4beda2SGovind Singh 
8870f01dcb8SAllen Pais 		tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
8882c3960c2SGovind Singh 
8897f4beda2SGovind Singh 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
890c41a6700SCarl Huang 				  ab_pci->irq_flags, irq_name[irq_idx],
8917f4beda2SGovind Singh 				  ce_pipe);
8927f4beda2SGovind Singh 		if (ret) {
8937f4beda2SGovind Singh 			ath11k_err(ab, "failed to request irq %d: %d\n",
8947f4beda2SGovind Singh 				   irq_idx, ret);
895e94b0749SBaochen Qiang 			goto err_irq_affinity_cleanup;
8967f4beda2SGovind Singh 		}
8977f4beda2SGovind Singh 
8987f4beda2SGovind Singh 		ab->irq_num[irq_idx] = irq;
8996289ac2bSKarthikeyan Periyasamy 		msi_data_idx++;
900e678fbd4SKarthikeyan Periyasamy 
901e5c860e1SCarl Huang 		ath11k_pci_ce_irq_disable(ab, i);
9027f4beda2SGovind Singh 	}
9037f4beda2SGovind Singh 
904d4ecb90bSCarl Huang 	ret = ath11k_pci_ext_irq_config(ab);
905d4ecb90bSCarl Huang 	if (ret)
906e94b0749SBaochen Qiang 		goto err_irq_affinity_cleanup;
907d4ecb90bSCarl Huang 
9087f4beda2SGovind Singh 	return 0;
909e94b0749SBaochen Qiang 
910e94b0749SBaochen Qiang err_irq_affinity_cleanup:
911e94b0749SBaochen Qiang 	ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
912e94b0749SBaochen Qiang 	return ret;
9137f4beda2SGovind Singh }
9147f4beda2SGovind Singh 
9157f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
9167f4beda2SGovind Singh {
9177f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
9187f4beda2SGovind Singh 
919967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
920967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
9217f4beda2SGovind Singh 
922967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
923967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
92416001e4bSAnilkumar Kolli 	ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
925e838c14aSCarl Huang 
926e838c14aSCarl Huang 	ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
927e838c14aSCarl Huang 				    &cfg->shadow_reg_v2_len);
9287f4beda2SGovind Singh }
9297f4beda2SGovind Singh 
930*948171b5SManikanta Pubbisetty void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
9317f4beda2SGovind Singh {
9327f4beda2SGovind Singh 	int i;
9337f4beda2SGovind Singh 
93401279bcdSCarl Huang 	set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
93501279bcdSCarl Huang 
936d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
937e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
9387f4beda2SGovind Singh 			continue;
9397f4beda2SGovind Singh 		ath11k_pci_ce_irq_enable(ab, i);
9407f4beda2SGovind Singh 	}
9417f4beda2SGovind Singh }
9427f4beda2SGovind Singh 
94396527d52SBaochen Qiang static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable)
94496527d52SBaochen Qiang {
94596527d52SBaochen Qiang 	struct pci_dev *dev = ab_pci->pdev;
94696527d52SBaochen Qiang 	u16 control;
94796527d52SBaochen Qiang 
94896527d52SBaochen Qiang 	pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
94996527d52SBaochen Qiang 
95096527d52SBaochen Qiang 	if (enable)
95196527d52SBaochen Qiang 		control |= PCI_MSI_FLAGS_ENABLE;
95296527d52SBaochen Qiang 	else
95396527d52SBaochen Qiang 		control &= ~PCI_MSI_FLAGS_ENABLE;
95496527d52SBaochen Qiang 
95596527d52SBaochen Qiang 	pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
95696527d52SBaochen Qiang }
95796527d52SBaochen Qiang 
95896527d52SBaochen Qiang static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci)
95996527d52SBaochen Qiang {
96096527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, true);
96196527d52SBaochen Qiang }
96296527d52SBaochen Qiang 
96396527d52SBaochen Qiang static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci)
96496527d52SBaochen Qiang {
96596527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, false);
96696527d52SBaochen Qiang }
96796527d52SBaochen Qiang 
96896527d52SBaochen Qiang static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
9695697a564SGovind Singh {
9705697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
9717a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
9725697a564SGovind Singh 	struct msi_desc *msi_desc;
9735697a564SGovind Singh 	int num_vectors;
9745697a564SGovind Singh 	int ret;
9755697a564SGovind Singh 
9765697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
9777a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
9787a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
9795697a564SGovind Singh 					    PCI_IRQ_MSI);
980ac6e7348SCarl Huang 	if (num_vectors == msi_config->total_vectors) {
981c41a6700SCarl Huang 		set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
982c41a6700SCarl Huang 		ab_pci->irq_flags = IRQF_SHARED;
983ac6e7348SCarl Huang 	} else {
984ac6e7348SCarl Huang 		num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
985ac6e7348SCarl Huang 						    1,
986ac6e7348SCarl Huang 						    1,
987ac6e7348SCarl Huang 						    PCI_IRQ_MSI);
988ac6e7348SCarl Huang 		if (num_vectors < 0) {
989ac6e7348SCarl Huang 			ret = -EINVAL;
990ac6e7348SCarl Huang 			goto reset_msi_config;
9915697a564SGovind Singh 		}
992ac6e7348SCarl Huang 		clear_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
993ac6e7348SCarl Huang 		ab_pci->msi_config = &msi_config_one_msi;
994ac6e7348SCarl Huang 		ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
995ac6e7348SCarl Huang 		ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n");
996ac6e7348SCarl Huang 	}
997ac6e7348SCarl Huang 	ath11k_info(ab, "MSI vectors: %d\n", num_vectors);
998ac6e7348SCarl Huang 
99996527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
10005697a564SGovind Singh 
10015697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
10025697a564SGovind Singh 	if (!msi_desc) {
10035697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
10045697a564SGovind Singh 		ret = -EINVAL;
10055697a564SGovind Singh 		goto free_msi_vector;
10065697a564SGovind Singh 	}
10075697a564SGovind Singh 
10085697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
1009e58f2259SThomas Gleixner 	if (msi_desc->pci.msi_attrib.is_64)
1010e8e55d89SAnilkumar Kolli 		set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags);
10115697a564SGovind Singh 
10125697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
10135697a564SGovind Singh 
10145697a564SGovind Singh 	return 0;
10155697a564SGovind Singh 
10165697a564SGovind Singh free_msi_vector:
10175697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
10185697a564SGovind Singh 
1019ac6e7348SCarl Huang reset_msi_config:
10205697a564SGovind Singh 	return ret;
10215697a564SGovind Singh }
10225697a564SGovind Singh 
102396527d52SBaochen Qiang static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci)
10245697a564SGovind Singh {
10255697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
10265697a564SGovind Singh }
10275697a564SGovind Singh 
102887b4072dSCarl Huang static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci)
102987b4072dSCarl Huang {
103087b4072dSCarl Huang 	struct msi_desc *msi_desc;
103187b4072dSCarl Huang 
103287b4072dSCarl Huang 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
103387b4072dSCarl Huang 	if (!msi_desc) {
103487b4072dSCarl Huang 		ath11k_err(ab_pci->ab, "msi_desc is NULL!\n");
103587b4072dSCarl Huang 		pci_free_irq_vectors(ab_pci->pdev);
103687b4072dSCarl Huang 		return -EINVAL;
103787b4072dSCarl Huang 	}
103887b4072dSCarl Huang 
103987b4072dSCarl Huang 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
104087b4072dSCarl Huang 
104187b4072dSCarl Huang 	ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n",
104287b4072dSCarl Huang 		   ab_pci->msi_ep_base_data);
104387b4072dSCarl Huang 
104487b4072dSCarl Huang 	return 0;
104587b4072dSCarl Huang }
104687b4072dSCarl Huang 
10475762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
10485762613eSGovind Singh {
10495762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
10505762613eSGovind Singh 	u16 device_id;
10515762613eSGovind Singh 	int ret = 0;
10525762613eSGovind Singh 
10535762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
10545762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
10555762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
10565762613eSGovind Singh 			   device_id, ab_pci->dev_id);
10575762613eSGovind Singh 		ret = -EIO;
10585762613eSGovind Singh 		goto out;
10595762613eSGovind Singh 	}
10605762613eSGovind Singh 
10615762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
10625762613eSGovind Singh 	if (ret) {
10635762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
10645762613eSGovind Singh 		goto out;
10655762613eSGovind Singh 	}
10665762613eSGovind Singh 
10675762613eSGovind Singh 	ret = pci_enable_device(pdev);
10685762613eSGovind Singh 	if (ret) {
10695762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
10705762613eSGovind Singh 		goto out;
10715762613eSGovind Singh 	}
10725762613eSGovind Singh 
10735762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
10745762613eSGovind Singh 	if (ret) {
10755762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
10765762613eSGovind Singh 		goto disable_device;
10775762613eSGovind Singh 	}
10785762613eSGovind Singh 
1079923a1346SChristophe JAILLET 	ret = dma_set_mask_and_coherent(&pdev->dev,
1080923a1346SChristophe JAILLET 					DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
10815762613eSGovind Singh 	if (ret) {
10825762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
10835762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
10845762613eSGovind Singh 		goto release_region;
10855762613eSGovind Singh 	}
10865762613eSGovind Singh 
10875762613eSGovind Singh 	pci_set_master(pdev);
10885762613eSGovind Singh 
10895762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
10905762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
10915762613eSGovind Singh 	if (!ab->mem) {
10925762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
10935762613eSGovind Singh 		ret = -EIO;
10945762613eSGovind Singh 		goto clear_master;
10955762613eSGovind Singh 	}
10965762613eSGovind Singh 
10975762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
10985762613eSGovind Singh 	return 0;
10995762613eSGovind Singh 
11005762613eSGovind Singh clear_master:
11015762613eSGovind Singh 	pci_clear_master(pdev);
11025762613eSGovind Singh release_region:
11035762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
11045762613eSGovind Singh disable_device:
11055762613eSGovind Singh 	pci_disable_device(pdev);
11065762613eSGovind Singh out:
11075762613eSGovind Singh 	return ret;
11085762613eSGovind Singh }
11095762613eSGovind Singh 
11105762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
11115762613eSGovind Singh {
11125762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
11135762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
11145762613eSGovind Singh 
11155762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
11165762613eSGovind Singh 	ab->mem = NULL;
11175762613eSGovind Singh 	pci_clear_master(pci_dev);
11185762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
11195762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
11205762613eSGovind Singh 		pci_disable_device(pci_dev);
11215762613eSGovind Singh }
11225762613eSGovind Singh 
1123e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
1124e9603f4bSCarl Huang {
1125e9603f4bSCarl Huang 	struct ath11k_base *ab = ab_pci->ab;
1126e9603f4bSCarl Huang 
1127e9603f4bSCarl Huang 	pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1128e9603f4bSCarl Huang 				  &ab_pci->link_ctl);
1129e9603f4bSCarl Huang 
1130e9603f4bSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n",
1131e9603f4bSCarl Huang 		   ab_pci->link_ctl,
1132e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S),
1133e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
1134e9603f4bSCarl Huang 
1135e9603f4bSCarl Huang 	/* disable L0s and L1 */
1136e9603f4bSCarl Huang 	pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1137e9603f4bSCarl Huang 				   ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
1138e9603f4bSCarl Huang 
1139e9603f4bSCarl Huang 	set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags);
1140e9603f4bSCarl Huang }
1141e9603f4bSCarl Huang 
1142*948171b5SManikanta Pubbisetty void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci)
1143e9603f4bSCarl Huang {
1144e9603f4bSCarl Huang 	if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags))
1145e9603f4bSCarl Huang 		pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1146e9603f4bSCarl Huang 					   ab_pci->link_ctl);
1147e9603f4bSCarl Huang }
1148e9603f4bSCarl Huang 
11491399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
11501399fb87SGovind Singh {
11511399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
11521399fb87SGovind Singh 	int ret;
11531399fb87SGovind Singh 
1154a05bd851SCarl Huang 	ab_pci->register_window = 0;
1155a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1156babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, true);
1157f3c603d4SCarl Huang 
1158e9603f4bSCarl Huang 	/* Disable ASPM during firmware download due to problems switching
1159e9603f4bSCarl Huang 	 * to AMSS state.
1160e9603f4bSCarl Huang 	 */
1161e9603f4bSCarl Huang 	ath11k_pci_aspm_disable(ab_pci);
1162e9603f4bSCarl Huang 
116396527d52SBaochen Qiang 	ath11k_pci_msi_enable(ab_pci);
116496527d52SBaochen Qiang 
11651399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
11661399fb87SGovind Singh 	if (ret) {
11671399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
11681399fb87SGovind Singh 		return ret;
11691399fb87SGovind Singh 	}
11701399fb87SGovind Singh 
1171480a7361SKarthikeyan Periyasamy 	if (ab->bus_params.static_window_map)
1172480a7361SKarthikeyan Periyasamy 		ath11k_pci_select_static_window(ab_pci);
1173480a7361SKarthikeyan Periyasamy 
11741399fb87SGovind Singh 	return 0;
11751399fb87SGovind Singh }
11761399fb87SGovind Singh 
11771399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
11781399fb87SGovind Singh {
11791399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
11801399fb87SGovind Singh 
1181e9603f4bSCarl Huang 	/* restore aspm in case firmware bootup fails */
1182e9603f4bSCarl Huang 	ath11k_pci_aspm_restore(ab_pci);
1183e9603f4bSCarl Huang 
1184babb0cedSCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
118596527d52SBaochen Qiang 
118696527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
118796527d52SBaochen Qiang 
11881399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
1189a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1190babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, false);
11911399fb87SGovind Singh }
11921399fb87SGovind Singh 
1193fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab)
1194fa5917e4SCarl Huang {
1195fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
1196fa5917e4SCarl Huang 
1197fa5917e4SCarl Huang 	ath11k_mhi_suspend(ar_pci);
1198fa5917e4SCarl Huang 
1199fa5917e4SCarl Huang 	return 0;
1200fa5917e4SCarl Huang }
1201fa5917e4SCarl Huang 
1202fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab)
1203fa5917e4SCarl Huang {
1204fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
1205fa5917e4SCarl Huang 
1206fa5917e4SCarl Huang 	ath11k_mhi_resume(ar_pci);
1207fa5917e4SCarl Huang 
1208fa5917e4SCarl Huang 	return 0;
1209fa5917e4SCarl Huang }
1210fa5917e4SCarl Huang 
12112c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
12122c3960c2SGovind Singh {
12132c3960c2SGovind Singh 	int i;
12142c3960c2SGovind Singh 
1215d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
12162c3960c2SGovind Singh 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
12172c3960c2SGovind Singh 
1218e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
12192c3960c2SGovind Singh 			continue;
12202c3960c2SGovind Singh 
12212c3960c2SGovind Singh 		tasklet_kill(&ce_pipe->intr_tq);
12222c3960c2SGovind Singh 	}
12232c3960c2SGovind Singh }
12242c3960c2SGovind Singh 
1225*948171b5SManikanta Pubbisetty void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab)
12267f4beda2SGovind Singh {
12272c3960c2SGovind Singh 	ath11k_pci_ce_irqs_disable(ab);
12282c3960c2SGovind Singh 	ath11k_pci_sync_ce_irqs(ab);
12292c3960c2SGovind Singh 	ath11k_pci_kill_tasklets(ab);
1230d578ec2aSCarl Huang }
1231d578ec2aSCarl Huang 
1232*948171b5SManikanta Pubbisetty void ath11k_pci_stop(struct ath11k_base *ab)
1233d578ec2aSCarl Huang {
1234d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
12357f4beda2SGovind Singh 	ath11k_ce_cleanup_pipes(ab);
12367f4beda2SGovind Singh }
12377f4beda2SGovind Singh 
1238*948171b5SManikanta Pubbisetty int ath11k_pci_start(struct ath11k_base *ab)
12397f4beda2SGovind Singh {
1240a05bd851SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
1241a05bd851SCarl Huang 
1242a05bd851SCarl Huang 	set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1243a05bd851SCarl Huang 
1244915a081fSCarl Huang 	/* TODO: for now don't restore ASPM in case of single MSI
1245915a081fSCarl Huang 	 * vector as MHI register reading in M2 causes system hang.
1246915a081fSCarl Huang 	 */
1247915a081fSCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
1248e9603f4bSCarl Huang 		ath11k_pci_aspm_restore(ab_pci);
1249915a081fSCarl Huang 	else
1250915a081fSCarl Huang 		ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n");
1251e9603f4bSCarl Huang 
12527f4beda2SGovind Singh 	ath11k_pci_ce_irqs_enable(ab);
12532c3960c2SGovind Singh 	ath11k_ce_rx_post_buf(ab);
12542c3960c2SGovind Singh 
12552c3960c2SGovind Singh 	return 0;
12562c3960c2SGovind Singh }
12572c3960c2SGovind Singh 
1258d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab)
1259d578ec2aSCarl Huang {
1260d578ec2aSCarl Huang 	ath11k_pci_ce_irqs_enable(ab);
1261d578ec2aSCarl Huang }
1262d578ec2aSCarl Huang 
1263d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab)
1264d578ec2aSCarl Huang {
1265d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
1266d578ec2aSCarl Huang }
1267d578ec2aSCarl Huang 
1268*948171b5SManikanta Pubbisetty int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
12692c3960c2SGovind Singh 				   u8 *ul_pipe, u8 *dl_pipe)
12702c3960c2SGovind Singh {
12712c3960c2SGovind Singh 	const struct service_to_pipe *entry;
12722c3960c2SGovind Singh 	bool ul_set = false, dl_set = false;
12732c3960c2SGovind Singh 	int i;
12742c3960c2SGovind Singh 
1275967c1d11SAnilkumar Kolli 	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
1276967c1d11SAnilkumar Kolli 		entry = &ab->hw_params.svc_to_ce_map[i];
12772c3960c2SGovind Singh 
12782c3960c2SGovind Singh 		if (__le32_to_cpu(entry->service_id) != service_id)
12792c3960c2SGovind Singh 			continue;
12802c3960c2SGovind Singh 
12812c3960c2SGovind Singh 		switch (__le32_to_cpu(entry->pipedir)) {
12822c3960c2SGovind Singh 		case PIPEDIR_NONE:
12832c3960c2SGovind Singh 			break;
12842c3960c2SGovind Singh 		case PIPEDIR_IN:
12852c3960c2SGovind Singh 			WARN_ON(dl_set);
12862c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
12872c3960c2SGovind Singh 			dl_set = true;
12882c3960c2SGovind Singh 			break;
12892c3960c2SGovind Singh 		case PIPEDIR_OUT:
12902c3960c2SGovind Singh 			WARN_ON(ul_set);
12912c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
12922c3960c2SGovind Singh 			ul_set = true;
12932c3960c2SGovind Singh 			break;
12942c3960c2SGovind Singh 		case PIPEDIR_INOUT:
12952c3960c2SGovind Singh 			WARN_ON(dl_set);
12962c3960c2SGovind Singh 			WARN_ON(ul_set);
12972c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
12982c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
12992c3960c2SGovind Singh 			dl_set = true;
13002c3960c2SGovind Singh 			ul_set = true;
13012c3960c2SGovind Singh 			break;
13022c3960c2SGovind Singh 		}
13032c3960c2SGovind Singh 	}
13042c3960c2SGovind Singh 
13052c3960c2SGovind Singh 	if (WARN_ON(!ul_set || !dl_set))
13062c3960c2SGovind Singh 		return -ENOENT;
13077f4beda2SGovind Singh 
13087f4beda2SGovind Singh 	return 0;
13097f4beda2SGovind Singh }
13107f4beda2SGovind Singh 
13117f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
13127f4beda2SGovind Singh 	.start = ath11k_pci_start,
13137f4beda2SGovind Singh 	.stop = ath11k_pci_stop,
1314654e959aSGovind Singh 	.read32 = ath11k_pci_read32,
1315654e959aSGovind Singh 	.write32 = ath11k_pci_write32,
13161399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
13171399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
1318fa5917e4SCarl Huang 	.suspend = ath11k_pci_hif_suspend,
1319fa5917e4SCarl Huang 	.resume = ath11k_pci_hif_resume,
1320d4ecb90bSCarl Huang 	.irq_enable = ath11k_pci_ext_irq_enable,
1321d4ecb90bSCarl Huang 	.irq_disable = ath11k_pci_ext_irq_disable,
1322c4eacabeSGovind Singh 	.get_msi_address =  ath11k_pci_get_msi_address,
1323c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
13242c3960c2SGovind Singh 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
1325d578ec2aSCarl Huang 	.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
1326d578ec2aSCarl Huang 	.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
13276289ac2bSKarthikeyan Periyasamy 	.get_ce_msi_idx = ath11k_pci_get_ce_msi_idx,
13281399fb87SGovind Singh };
13291399fb87SGovind Singh 
13300fbf1957SBaochen Qiang static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor)
13310fbf1957SBaochen Qiang {
13320fbf1957SBaochen Qiang 	u32 soc_hw_version;
13330fbf1957SBaochen Qiang 
13340fbf1957SBaochen Qiang 	soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION);
13350fbf1957SBaochen Qiang 	*major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
13360fbf1957SBaochen Qiang 			   soc_hw_version);
13370fbf1957SBaochen Qiang 	*minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
13380fbf1957SBaochen Qiang 			   soc_hw_version);
13390fbf1957SBaochen Qiang 
13400fbf1957SBaochen Qiang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
13410fbf1957SBaochen Qiang 		   *major, *minor);
13420fbf1957SBaochen Qiang }
13430fbf1957SBaochen Qiang 
13446e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
13456e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
13466e0355afSGovind Singh {
13476e0355afSGovind Singh 	struct ath11k_base *ab;
13485762613eSGovind Singh 	struct ath11k_pci *ab_pci;
13496ac04bdcSAnilkumar Kolli 	u32 soc_hw_version_major, soc_hw_version_minor, addr;
13505762613eSGovind Singh 	int ret;
13516e0355afSGovind Singh 
13521ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
13531ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
13546e0355afSGovind Singh 	if (!ab) {
13556e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
13566e0355afSGovind Singh 		return -ENOMEM;
13576e0355afSGovind Singh 	}
13586e0355afSGovind Singh 
13596e0355afSGovind Singh 	ab->dev = &pdev->dev;
13606e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
13615762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
13625762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
13635762613eSGovind Singh 	ab_pci->ab = ab;
13645697a564SGovind Singh 	ab_pci->pdev = pdev;
13657f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
13665762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
1367654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
13685762613eSGovind Singh 
13696ac04bdcSAnilkumar Kolli 	/* Set fixed_mem_region to true for platforms support reserved memory
13706ac04bdcSAnilkumar Kolli 	 * from DT. If memory is reserved from DT for FW, ath11k driver need not
13716ac04bdcSAnilkumar Kolli 	 * allocate memory.
13726ac04bdcSAnilkumar Kolli 	 */
13736ac04bdcSAnilkumar Kolli 	ret = of_property_read_u32(ab->dev->of_node, "memory-region", &addr);
13746ac04bdcSAnilkumar Kolli 	if (!ret)
13756ac04bdcSAnilkumar Kolli 		set_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags);
13766ac04bdcSAnilkumar Kolli 
13775762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
13785762613eSGovind Singh 	if (ret) {
13795762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
13805762613eSGovind Singh 		goto err_free_core;
13815762613eSGovind Singh 	}
13826e0355afSGovind Singh 
1383fc95d10aSWen Gong 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n",
1384fc95d10aSWen Gong 		   pdev->vendor, pdev->device,
1385fc95d10aSWen Gong 		   pdev->subsystem_vendor, pdev->subsystem_device);
1386fc95d10aSWen Gong 
1387fc95d10aSWen Gong 	ab->id.vendor = pdev->vendor;
1388fc95d10aSWen Gong 	ab->id.device = pdev->device;
1389fc95d10aSWen Gong 	ab->id.subsystem_vendor = pdev->subsystem_vendor;
1390fc95d10aSWen Gong 	ab->id.subsystem_device = pdev->subsystem_device;
1391fc95d10aSWen Gong 
139218ac1665SKalle Valo 	switch (pci_dev->device) {
139318ac1665SKalle Valo 	case QCA6390_DEVICE_ID:
13940fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
13950fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
139618ac1665SKalle Valo 		switch (soc_hw_version_major) {
139718ac1665SKalle Valo 		case 2:
139818ac1665SKalle Valo 			ab->hw_rev = ATH11K_HW_QCA6390_HW20;
139918ac1665SKalle Valo 			break;
140018ac1665SKalle Valo 		default:
140118ac1665SKalle Valo 			dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n",
140218ac1665SKalle Valo 				soc_hw_version_major, soc_hw_version_minor);
140318ac1665SKalle Valo 			ret = -EOPNOTSUPP;
140418ac1665SKalle Valo 			goto err_pci_free_region;
140518ac1665SKalle Valo 		}
14064e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[0];
14074e809461SAnilkumar Kolli 		break;
14084e809461SAnilkumar Kolli 	case QCN9074_DEVICE_ID:
14094e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[1];
14104e809461SAnilkumar Kolli 		ab->bus_params.static_window_map = true;
14114e809461SAnilkumar Kolli 		ab->hw_rev = ATH11K_HW_QCN9074_HW10;
141218ac1665SKalle Valo 		break;
14130fbf1957SBaochen Qiang 	case WCN6855_DEVICE_ID:
1414fc95d10aSWen Gong 		ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD;
14150fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
14160fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
14170fbf1957SBaochen Qiang 		switch (soc_hw_version_major) {
14180fbf1957SBaochen Qiang 		case 2:
1419d1147a31SBaochen Qiang 			switch (soc_hw_version_minor) {
1420d1147a31SBaochen Qiang 			case 0x00:
1421d1147a31SBaochen Qiang 			case 0x01:
14220fbf1957SBaochen Qiang 				ab->hw_rev = ATH11K_HW_WCN6855_HW20;
14230fbf1957SBaochen Qiang 				break;
1424d1147a31SBaochen Qiang 			case 0x10:
1425d1147a31SBaochen Qiang 			case 0x11:
1426d1147a31SBaochen Qiang 				ab->hw_rev = ATH11K_HW_WCN6855_HW21;
1427d1147a31SBaochen Qiang 				break;
14280fbf1957SBaochen Qiang 			default:
1429d1147a31SBaochen Qiang 				goto unsupported_wcn6855_soc;
1430d1147a31SBaochen Qiang 			}
1431d1147a31SBaochen Qiang 			break;
1432d1147a31SBaochen Qiang 		default:
1433d1147a31SBaochen Qiang unsupported_wcn6855_soc:
14340fbf1957SBaochen Qiang 			dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n",
14350fbf1957SBaochen Qiang 				soc_hw_version_major, soc_hw_version_minor);
14360fbf1957SBaochen Qiang 			ret = -EOPNOTSUPP;
14370fbf1957SBaochen Qiang 			goto err_pci_free_region;
14380fbf1957SBaochen Qiang 		}
14390fbf1957SBaochen Qiang 		ab_pci->msi_config = &ath11k_msi_config[0];
14400fbf1957SBaochen Qiang 		break;
144118ac1665SKalle Valo 	default:
144218ac1665SKalle Valo 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
144318ac1665SKalle Valo 			pci_dev->device);
144418ac1665SKalle Valo 		ret = -EOPNOTSUPP;
144518ac1665SKalle Valo 		goto err_pci_free_region;
144618ac1665SKalle Valo 	}
144718ac1665SKalle Valo 
144896527d52SBaochen Qiang 	ret = ath11k_pci_alloc_msi(ab_pci);
14495697a564SGovind Singh 	if (ret) {
14505697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
14515697a564SGovind Singh 		goto err_pci_free_region;
14525697a564SGovind Singh 	}
14535697a564SGovind Singh 
1454b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
1455b8246f88SKalle Valo 	if (ret)
1456b8246f88SKalle Valo 		goto err_pci_disable_msi;
1457b8246f88SKalle Valo 
14581399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
14591399fb87SGovind Singh 	if (ret) {
14601399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
14611399fb87SGovind Singh 		goto err_pci_disable_msi;
14621399fb87SGovind Singh 	}
14631399fb87SGovind Singh 
14647f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
14657f4beda2SGovind Singh 	if (ret)
14667f4beda2SGovind Singh 		goto err_mhi_unregister;
14677f4beda2SGovind Singh 
14687f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
14697f4beda2SGovind Singh 	if (ret) {
14707f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
14717f4beda2SGovind Singh 		goto err_hal_srng_deinit;
14727f4beda2SGovind Singh 	}
14737f4beda2SGovind Singh 
14747f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
14757f4beda2SGovind Singh 
14767f4beda2SGovind Singh 	ret = ath11k_pci_config_irq(ab);
14777f4beda2SGovind Singh 	if (ret) {
14787f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
14797f4beda2SGovind Singh 		goto err_ce_free;
14807f4beda2SGovind Singh 	}
14817f4beda2SGovind Singh 
148287b4072dSCarl Huang 	/* kernel may allocate a dummy vector before request_irq and
148387b4072dSCarl Huang 	 * then allocate a real vector when request_irq is called.
148487b4072dSCarl Huang 	 * So get msi_data here again to avoid spurious interrupt
148587b4072dSCarl Huang 	 * as msi_data will configured to srngs.
148687b4072dSCarl Huang 	 */
148787b4072dSCarl Huang 	ret = ath11k_pci_config_msi_data(ab_pci);
148887b4072dSCarl Huang 	if (ret) {
148987b4072dSCarl Huang 		ath11k_err(ab, "failed to config msi_data: %d\n", ret);
149087b4072dSCarl Huang 		goto err_free_irq;
149187b4072dSCarl Huang 	}
149287b4072dSCarl Huang 
14937f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
14947f4beda2SGovind Singh 	if (ret) {
14957f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
14967f4beda2SGovind Singh 		goto err_free_irq;
14977f4beda2SGovind Singh 	}
14986e0355afSGovind Singh 	return 0;
14995762613eSGovind Singh 
15007f4beda2SGovind Singh err_free_irq:
15017f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
15027f4beda2SGovind Singh 
15037f4beda2SGovind Singh err_ce_free:
15047f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
15057f4beda2SGovind Singh 
15067f4beda2SGovind Singh err_hal_srng_deinit:
15077f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
15087f4beda2SGovind Singh 
15097f4beda2SGovind Singh err_mhi_unregister:
15107f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
15117f4beda2SGovind Singh 
1512b8246f88SKalle Valo err_pci_disable_msi:
151396527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
1514b8246f88SKalle Valo 
15155697a564SGovind Singh err_pci_free_region:
15165697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
15175697a564SGovind Singh 
15185762613eSGovind Singh err_free_core:
15195762613eSGovind Singh 	ath11k_core_free(ab);
15205697a564SGovind Singh 
15215762613eSGovind Singh 	return ret;
15226e0355afSGovind Singh }
15236e0355afSGovind Singh 
15246e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
15256e0355afSGovind Singh {
15266e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
15275762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
15286e0355afSGovind Singh 
1529e94b0749SBaochen Qiang 	ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
1530e94b0749SBaochen Qiang 
153161a57e51SAnilkumar Kolli 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
153261a57e51SAnilkumar Kolli 		ath11k_pci_power_down(ab);
153361a57e51SAnilkumar Kolli 		ath11k_debugfs_soc_destroy(ab);
153461a57e51SAnilkumar Kolli 		ath11k_qmi_deinit_service(ab);
153561a57e51SAnilkumar Kolli 		goto qmi_fail;
153661a57e51SAnilkumar Kolli 	}
153761a57e51SAnilkumar Kolli 
15386e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
15396fbd8898SCarl Huang 
15406fbd8898SCarl Huang 	ath11k_core_deinit(ab);
15416fbd8898SCarl Huang 
154261a57e51SAnilkumar Kolli qmi_fail:
15431399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
15446fbd8898SCarl Huang 
15456fbd8898SCarl Huang 	ath11k_pci_free_irq(ab);
154696527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
15475762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
15486fbd8898SCarl Huang 
15496fbd8898SCarl Huang 	ath11k_hal_srng_deinit(ab);
15506fbd8898SCarl Huang 	ath11k_ce_free_pipes(ab);
15516e0355afSGovind Singh 	ath11k_core_free(ab);
15526e0355afSGovind Singh }
15536e0355afSGovind Singh 
15541399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
15551399fb87SGovind Singh {
15561399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
15571399fb87SGovind Singh 
15581399fb87SGovind Singh 	ath11k_pci_power_down(ab);
15591399fb87SGovind Singh }
15601399fb87SGovind Singh 
1561d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
1562d1b0c338SCarl Huang {
1563d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1564d1b0c338SCarl Huang 	int ret;
1565d1b0c338SCarl Huang 
1566b4f4c564SKalle Valo 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
1567b4f4c564SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci suspend as qmi is not initialised\n");
1568b4f4c564SKalle Valo 		return 0;
1569b4f4c564SKalle Valo 	}
1570b4f4c564SKalle Valo 
1571d1b0c338SCarl Huang 	ret = ath11k_core_suspend(ab);
1572d1b0c338SCarl Huang 	if (ret)
1573d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to suspend core: %d\n", ret);
1574d1b0c338SCarl Huang 
1575d1b0c338SCarl Huang 	return ret;
1576d1b0c338SCarl Huang }
1577d1b0c338SCarl Huang 
1578d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
1579d1b0c338SCarl Huang {
1580d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1581d1b0c338SCarl Huang 	int ret;
1582d1b0c338SCarl Huang 
1583b4f4c564SKalle Valo 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
1584b4f4c564SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci resume as qmi is not initialised\n");
1585b4f4c564SKalle Valo 		return 0;
1586b4f4c564SKalle Valo 	}
1587b4f4c564SKalle Valo 
1588d1b0c338SCarl Huang 	ret = ath11k_core_resume(ab);
1589d1b0c338SCarl Huang 	if (ret)
1590d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to resume core: %d\n", ret);
1591d1b0c338SCarl Huang 
1592d1b0c338SCarl Huang 	return ret;
1593d1b0c338SCarl Huang }
1594d1b0c338SCarl Huang 
1595d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
1596d1b0c338SCarl Huang 			 ath11k_pci_pm_suspend,
1597d1b0c338SCarl Huang 			 ath11k_pci_pm_resume);
1598d1b0c338SCarl Huang 
15996e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
16006e0355afSGovind Singh 	.name = "ath11k_pci",
16016e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
16026e0355afSGovind Singh 	.probe = ath11k_pci_probe,
16036e0355afSGovind Singh 	.remove = ath11k_pci_remove,
16041399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
1605d1b0c338SCarl Huang #ifdef CONFIG_PM
1606d1b0c338SCarl Huang 	.driver.pm = &ath11k_pci_pm_ops,
1607d1b0c338SCarl Huang #endif
16086e0355afSGovind Singh };
16096e0355afSGovind Singh 
16106e0355afSGovind Singh static int ath11k_pci_init(void)
16116e0355afSGovind Singh {
16126e0355afSGovind Singh 	int ret;
16136e0355afSGovind Singh 
16146e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
16156e0355afSGovind Singh 	if (ret)
16166e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
16176e0355afSGovind Singh 		       ret);
16186e0355afSGovind Singh 
16196e0355afSGovind Singh 	return ret;
16206e0355afSGovind Singh }
16216e0355afSGovind Singh module_init(ath11k_pci_init);
16226e0355afSGovind Singh 
16236e0355afSGovind Singh static void ath11k_pci_exit(void)
16246e0355afSGovind Singh {
16256e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
16266e0355afSGovind Singh }
16276e0355afSGovind Singh 
16286e0355afSGovind Singh module_exit(ath11k_pci_exit);
16296e0355afSGovind Singh 
16306e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
16316e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
16323dbd7fe7SDevin Bayer 
16333dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */
16343dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE);
16353dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE);
16363dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE);
1637