xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision 0d7a8a6204ea9271f1d0a8c66a9fd2f54d2e3cbc)
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>
96ac04bdcSAnilkumar Kolli #include <linux/of.h>
106e0355afSGovind Singh 
115762613eSGovind Singh #include "pci.h"
126e0355afSGovind Singh #include "core.h"
131399fb87SGovind Singh #include "hif.h"
141399fb87SGovind Singh #include "mhi.h"
156e0355afSGovind Singh #include "debug.h"
166e0355afSGovind Singh 
175762613eSGovind Singh #define ATH11K_PCI_BAR_NUM		0
185762613eSGovind Singh #define ATH11K_PCI_DMA_MASK		32
195762613eSGovind Singh 
207f4beda2SGovind Singh #define ATH11K_PCI_IRQ_CE0_OFFSET	3
214ab4693fSCarl Huang #define ATH11K_PCI_IRQ_DP_OFFSET	14
227f4beda2SGovind Singh 
23654e959aSGovind Singh #define WINDOW_ENABLE_BIT		0x40000000
24654e959aSGovind Singh #define WINDOW_REG_ADDRESS		0x310c
25654e959aSGovind Singh #define WINDOW_VALUE_MASK		GENMASK(24, 19)
26654e959aSGovind Singh #define WINDOW_START			0x80000
27654e959aSGovind Singh #define WINDOW_RANGE_MASK		GENMASK(18, 0)
28654e959aSGovind Singh 
2918ac1665SKalle Valo #define TCSR_SOC_HW_VERSION		0x0224
30d1147a31SBaochen Qiang #define TCSR_SOC_HW_VERSION_MAJOR_MASK	GENMASK(11, 8)
3118ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MINOR_MASK	GENMASK(7, 0)
3218ac1665SKalle Valo 
33a05bd851SCarl Huang /* BAR0 + 4k is always accessible, and no
34a05bd851SCarl Huang  * need to force wakeup.
35a05bd851SCarl Huang  * 4K - 32 = 0xFE0
36a05bd851SCarl Huang  */
37a05bd851SCarl Huang #define ACCESS_ALWAYS_OFF 0xFE0
38a05bd851SCarl Huang 
396e0355afSGovind Singh #define QCA6390_DEVICE_ID		0x1101
404e809461SAnilkumar Kolli #define QCN9074_DEVICE_ID		0x1104
410fbf1957SBaochen Qiang #define WCN6855_DEVICE_ID		0x1103
426e0355afSGovind Singh 
436e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = {
446e0355afSGovind Singh 	{ PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) },
450fbf1957SBaochen Qiang 	{ PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) },
4649f5b114SAnilkumar Kolli 	{ PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) },
476e0355afSGovind Singh 	{0}
486e0355afSGovind Singh };
496e0355afSGovind Singh 
506e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table);
516e0355afSGovind Singh 
521ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = {
531ff8ed78SGovind Singh 	.mhi_support = true,
5456970454SGovind Singh 	.m3_fw_support = true,
556eb6ea51SGovind Singh 	.fixed_bdf_addr = false,
566eb6ea51SGovind Singh 	.fixed_mem_region = false,
571ff8ed78SGovind Singh };
581ff8ed78SGovind Singh 
597a3aed0cSAnilkumar Kolli static const struct ath11k_msi_config ath11k_msi_config[] = {
607a3aed0cSAnilkumar Kolli 	{
615697a564SGovind Singh 		.total_vectors = 32,
625697a564SGovind Singh 		.total_users = 4,
635697a564SGovind Singh 		.users = (struct ath11k_msi_user[]) {
645697a564SGovind Singh 			{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
655697a564SGovind Singh 			{ .name = "CE", .num_vectors = 10, .base_vector = 3 },
665697a564SGovind Singh 			{ .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
675697a564SGovind Singh 			{ .name = "DP", .num_vectors = 18, .base_vector = 14 },
685697a564SGovind Singh 		},
697a3aed0cSAnilkumar Kolli 	},
704e809461SAnilkumar Kolli 	{
714e809461SAnilkumar Kolli 		.total_vectors = 16,
724e809461SAnilkumar Kolli 		.total_users = 3,
734e809461SAnilkumar Kolli 		.users = (struct ath11k_msi_user[]) {
744e809461SAnilkumar Kolli 			{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
754e809461SAnilkumar Kolli 			{ .name = "CE", .num_vectors = 5, .base_vector = 3 },
764e809461SAnilkumar Kolli 			{ .name = "DP", .num_vectors = 8, .base_vector = 8 },
774e809461SAnilkumar Kolli 		},
784e809461SAnilkumar Kolli 	},
795697a564SGovind Singh };
805697a564SGovind Singh 
81ac6e7348SCarl Huang static const struct ath11k_msi_config msi_config_one_msi = {
82ac6e7348SCarl Huang 	.total_vectors = 1,
83ac6e7348SCarl Huang 	.total_users = 4,
84ac6e7348SCarl Huang 	.users = (struct ath11k_msi_user[]) {
85ac6e7348SCarl Huang 		{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
86ac6e7348SCarl Huang 		{ .name = "CE", .num_vectors = 1, .base_vector = 0 },
87ac6e7348SCarl Huang 		{ .name = "WAKE", .num_vectors = 1, .base_vector = 0 },
88ac6e7348SCarl Huang 		{ .name = "DP", .num_vectors = 1, .base_vector = 0 },
89ac6e7348SCarl Huang 	},
90ac6e7348SCarl Huang };
91ac6e7348SCarl Huang 
927f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
937f4beda2SGovind Singh 	"bhi",
947f4beda2SGovind Singh 	"mhi-er0",
957f4beda2SGovind Singh 	"mhi-er1",
967f4beda2SGovind Singh 	"ce0",
977f4beda2SGovind Singh 	"ce1",
987f4beda2SGovind Singh 	"ce2",
997f4beda2SGovind Singh 	"ce3",
1007f4beda2SGovind Singh 	"ce4",
1017f4beda2SGovind Singh 	"ce5",
1027f4beda2SGovind Singh 	"ce6",
1037f4beda2SGovind Singh 	"ce7",
1047f4beda2SGovind Singh 	"ce8",
1057f4beda2SGovind Singh 	"ce9",
1067f4beda2SGovind Singh 	"ce10",
1077f4beda2SGovind Singh 	"ce11",
1087f4beda2SGovind Singh 	"host2wbm-desc-feed",
1097f4beda2SGovind Singh 	"host2reo-re-injection",
1107f4beda2SGovind Singh 	"host2reo-command",
1117f4beda2SGovind Singh 	"host2rxdma-monitor-ring3",
1127f4beda2SGovind Singh 	"host2rxdma-monitor-ring2",
1137f4beda2SGovind Singh 	"host2rxdma-monitor-ring1",
1147f4beda2SGovind Singh 	"reo2ost-exception",
1157f4beda2SGovind Singh 	"wbm2host-rx-release",
1167f4beda2SGovind Singh 	"reo2host-status",
1177f4beda2SGovind Singh 	"reo2host-destination-ring4",
1187f4beda2SGovind Singh 	"reo2host-destination-ring3",
1197f4beda2SGovind Singh 	"reo2host-destination-ring2",
1207f4beda2SGovind Singh 	"reo2host-destination-ring1",
1217f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac3",
1227f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac2",
1237f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac1",
1247f4beda2SGovind Singh 	"ppdu-end-interrupts-mac3",
1257f4beda2SGovind Singh 	"ppdu-end-interrupts-mac2",
1267f4beda2SGovind Singh 	"ppdu-end-interrupts-mac1",
1277f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac3",
1287f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac2",
1297f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac1",
1307f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac3",
1317f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac2",
1327f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac1",
1337f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac3",
1347f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac2",
1357f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac1",
1367f4beda2SGovind Singh 	"host2tcl-input-ring4",
1377f4beda2SGovind Singh 	"host2tcl-input-ring3",
1387f4beda2SGovind Singh 	"host2tcl-input-ring2",
1397f4beda2SGovind Singh 	"host2tcl-input-ring1",
1407f4beda2SGovind Singh 	"wbm2host-tx-completions-ring3",
1417f4beda2SGovind Singh 	"wbm2host-tx-completions-ring2",
1427f4beda2SGovind Singh 	"wbm2host-tx-completions-ring1",
1437f4beda2SGovind Singh 	"tcl2host-status-ring",
1447f4beda2SGovind Singh };
1457f4beda2SGovind Singh 
146654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset)
147654e959aSGovind Singh {
148654e959aSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
149654e959aSGovind Singh 
150654e959aSGovind Singh 	u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset);
151654e959aSGovind Singh 
152654e959aSGovind Singh 	lockdep_assert_held(&ab_pci->window_lock);
153654e959aSGovind Singh 
154654e959aSGovind Singh 	if (window != ab_pci->register_window) {
155654e959aSGovind Singh 		iowrite32(WINDOW_ENABLE_BIT | window,
156654e959aSGovind Singh 			  ab->mem + WINDOW_REG_ADDRESS);
157f6fa37a4SCarl Huang 		ioread32(ab->mem + WINDOW_REG_ADDRESS);
158654e959aSGovind Singh 		ab_pci->register_window = window;
159654e959aSGovind Singh 	}
160654e959aSGovind Singh }
161654e959aSGovind Singh 
162480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci)
163480a7361SKarthikeyan Periyasamy {
164480a7361SKarthikeyan Periyasamy 	u32 umac_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET);
165480a7361SKarthikeyan Periyasamy 	u32 ce_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE);
166480a7361SKarthikeyan Periyasamy 	u32 window;
167480a7361SKarthikeyan Periyasamy 
168480a7361SKarthikeyan Periyasamy 	window = (umac_window << 12) | (ce_window << 6);
169480a7361SKarthikeyan Periyasamy 
170480a7361SKarthikeyan Periyasamy 	iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + WINDOW_REG_ADDRESS);
171480a7361SKarthikeyan Periyasamy }
172480a7361SKarthikeyan Periyasamy 
173480a7361SKarthikeyan Periyasamy static inline u32 ath11k_pci_get_window_start(struct ath11k_base *ab,
174480a7361SKarthikeyan Periyasamy 					      u32 offset)
175480a7361SKarthikeyan Periyasamy {
176480a7361SKarthikeyan Periyasamy 	u32 window_start;
177480a7361SKarthikeyan Periyasamy 
178480a7361SKarthikeyan Periyasamy 	/* If offset lies within DP register range, use 3rd window */
179480a7361SKarthikeyan Periyasamy 	if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < WINDOW_RANGE_MASK)
180480a7361SKarthikeyan Periyasamy 		window_start = 3 * WINDOW_START;
181480a7361SKarthikeyan Periyasamy 	/* If offset lies within CE register range, use 2nd window */
182480a7361SKarthikeyan Periyasamy 	else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK)
183480a7361SKarthikeyan Periyasamy 		window_start = 2 * WINDOW_START;
184480a7361SKarthikeyan Periyasamy 	else
185480a7361SKarthikeyan Periyasamy 		window_start = WINDOW_START;
186480a7361SKarthikeyan Periyasamy 
187480a7361SKarthikeyan Periyasamy 	return window_start;
188480a7361SKarthikeyan Periyasamy }
189480a7361SKarthikeyan Periyasamy 
190f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
191654e959aSGovind Singh {
192654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
193480a7361SKarthikeyan Periyasamy 	u32 window_start;
194*0d7a8a62SWen Gong 	int ret = 0;
195654e959aSGovind Singh 
196a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
197a05bd851SCarl Huang 	 * need to wakeup MHI to access.
198a05bd851SCarl Huang 	 */
199081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
200081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
201a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
202*0d7a8a62SWen Gong 		ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
203a05bd851SCarl Huang 
204654e959aSGovind Singh 	if (offset < WINDOW_START) {
205654e959aSGovind Singh 		iowrite32(value, ab->mem  + offset);
206654e959aSGovind Singh 	} else {
207480a7361SKarthikeyan Periyasamy 		if (ab->bus_params.static_window_map)
208480a7361SKarthikeyan Periyasamy 			window_start = ath11k_pci_get_window_start(ab, offset);
209480a7361SKarthikeyan Periyasamy 		else
210480a7361SKarthikeyan Periyasamy 			window_start = WINDOW_START;
211480a7361SKarthikeyan Periyasamy 
212480a7361SKarthikeyan Periyasamy 		if (window_start == WINDOW_START) {
213654e959aSGovind Singh 			spin_lock_bh(&ab_pci->window_lock);
214654e959aSGovind Singh 			ath11k_pci_select_window(ab_pci, offset);
215480a7361SKarthikeyan Periyasamy 			iowrite32(value, ab->mem + window_start +
216480a7361SKarthikeyan Periyasamy 				  (offset & WINDOW_RANGE_MASK));
217654e959aSGovind Singh 			spin_unlock_bh(&ab_pci->window_lock);
218480a7361SKarthikeyan Periyasamy 		} else {
219480a7361SKarthikeyan Periyasamy 			iowrite32(value, ab->mem + window_start +
220480a7361SKarthikeyan Periyasamy 				  (offset & WINDOW_RANGE_MASK));
221480a7361SKarthikeyan Periyasamy 		}
222654e959aSGovind Singh 	}
223a05bd851SCarl Huang 
224081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
225081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
226*0d7a8a62SWen Gong 	    offset >= ACCESS_ALWAYS_OFF &&
227*0d7a8a62SWen Gong 	    !ret)
228a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
229654e959aSGovind Singh }
230654e959aSGovind Singh 
231f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
232654e959aSGovind Singh {
233654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
234480a7361SKarthikeyan Periyasamy 	u32 val, window_start;
235*0d7a8a62SWen Gong 	int ret = 0;
236654e959aSGovind Singh 
237a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
238a05bd851SCarl Huang 	 * need to wakeup MHI to access.
239a05bd851SCarl Huang 	 */
240081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
241081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
242a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
243*0d7a8a62SWen Gong 		ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
244a05bd851SCarl Huang 
245654e959aSGovind Singh 	if (offset < WINDOW_START) {
246654e959aSGovind Singh 		val = ioread32(ab->mem + offset);
247654e959aSGovind Singh 	} else {
248480a7361SKarthikeyan Periyasamy 		if (ab->bus_params.static_window_map)
249480a7361SKarthikeyan Periyasamy 			window_start = ath11k_pci_get_window_start(ab, offset);
250480a7361SKarthikeyan Periyasamy 		else
251480a7361SKarthikeyan Periyasamy 			window_start = WINDOW_START;
252480a7361SKarthikeyan Periyasamy 
253480a7361SKarthikeyan Periyasamy 		if (window_start == WINDOW_START) {
254654e959aSGovind Singh 			spin_lock_bh(&ab_pci->window_lock);
255654e959aSGovind Singh 			ath11k_pci_select_window(ab_pci, offset);
256480a7361SKarthikeyan Periyasamy 			val = ioread32(ab->mem + window_start +
257480a7361SKarthikeyan Periyasamy 				       (offset & WINDOW_RANGE_MASK));
258654e959aSGovind Singh 			spin_unlock_bh(&ab_pci->window_lock);
259480a7361SKarthikeyan Periyasamy 		} else {
260480a7361SKarthikeyan Periyasamy 			val = ioread32(ab->mem + window_start +
261480a7361SKarthikeyan Periyasamy 				       (offset & WINDOW_RANGE_MASK));
262480a7361SKarthikeyan Periyasamy 		}
263654e959aSGovind Singh 	}
264654e959aSGovind Singh 
265081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
266081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
267*0d7a8a62SWen Gong 	    offset >= ACCESS_ALWAYS_OFF &&
268*0d7a8a62SWen Gong 	    !ret)
269a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
270a05bd851SCarl Huang 
271654e959aSGovind Singh 	return val;
272654e959aSGovind Singh }
273654e959aSGovind Singh 
274f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
275f3c603d4SCarl Huang {
276f3c603d4SCarl Huang 	u32 val, delay;
277f3c603d4SCarl Huang 
278f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
279f3c603d4SCarl Huang 
280f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
281f3c603d4SCarl Huang 
282f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
283f3c603d4SCarl Huang 
284f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
285f3c603d4SCarl Huang 	delay = 10;
286f3c603d4SCarl Huang 	mdelay(delay);
287f3c603d4SCarl Huang 
288f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
289f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
290f3c603d4SCarl Huang 
291f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
292f3c603d4SCarl Huang 
293f3c603d4SCarl Huang 	mdelay(delay);
294f3c603d4SCarl Huang 
295f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
296f3c603d4SCarl Huang 	if (val == 0xffffffff)
297f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
298f3c603d4SCarl Huang }
299f3c603d4SCarl Huang 
300f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
301f3c603d4SCarl Huang {
302f3c603d4SCarl Huang 	u32 val;
303f3c603d4SCarl Huang 
304f3c603d4SCarl Huang 	/* read cookie */
305f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR);
306f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val);
307f3c603d4SCarl Huang 
308f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
309f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
310f3c603d4SCarl Huang 
311f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
312f3c603d4SCarl Huang 	mdelay(10);
313f3c603d4SCarl Huang 
314f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
315f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
316f3c603d4SCarl Huang 	 */
317f3c603d4SCarl Huang 	ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0);
318f3c603d4SCarl Huang 	mdelay(10);
319f3c603d4SCarl Huang 
320f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
321f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
322f3c603d4SCarl Huang 
323f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
324f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
325f3c603d4SCarl Huang 	 */
326f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
327f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
328f3c603d4SCarl Huang }
329f3c603d4SCarl Huang 
33006999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab,
33106999407SCarl Huang 				   u32 offset, u32 value, u32 mask)
33206999407SCarl Huang {
33306999407SCarl Huang 	u32 v;
33406999407SCarl Huang 	int i;
33506999407SCarl Huang 
33606999407SCarl Huang 	v = ath11k_pci_read32(ab, offset);
33706999407SCarl Huang 	if ((v & mask) == value)
33806999407SCarl Huang 		return 0;
33906999407SCarl Huang 
34006999407SCarl Huang 	for (i = 0; i < 10; i++) {
34106999407SCarl Huang 		ath11k_pci_write32(ab, offset, (v & ~mask) | value);
34206999407SCarl Huang 
34306999407SCarl Huang 		v = ath11k_pci_read32(ab, offset);
34406999407SCarl Huang 		if ((v & mask) == value)
34506999407SCarl Huang 			return 0;
34606999407SCarl Huang 
34706999407SCarl Huang 		mdelay(2);
34806999407SCarl Huang 	}
34906999407SCarl Huang 
35006999407SCarl Huang 	ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n",
35106999407SCarl Huang 		    offset, v & mask, value);
35206999407SCarl Huang 
35306999407SCarl Huang 	return -ETIMEDOUT;
35406999407SCarl Huang }
35506999407SCarl Huang 
35606999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
35706999407SCarl Huang {
35806999407SCarl Huang 	int ret;
35906999407SCarl Huang 
36006999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3616fe6f68fSKarthikeyan Periyasamy 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab),
36206999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL,
36306999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK);
36430d08503SDan Carpenter 	if (ret) {
36506999407SCarl Huang 		ath11k_warn(ab, "failed to set sysclk: %d\n", ret);
36606999407SCarl Huang 		return ret;
36706999407SCarl Huang 	}
36806999407SCarl Huang 
36906999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3706fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab),
3716fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_VAL,
3726fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
37330d08503SDan Carpenter 	if (ret) {
37406999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret);
37506999407SCarl Huang 		return ret;
37606999407SCarl Huang 	}
37706999407SCarl Huang 
37806999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3796fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab),
3806fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_VAL,
3816fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
38230d08503SDan Carpenter 	if (ret) {
38306999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config2: %d\n", ret);
38406999407SCarl Huang 		return ret;
38506999407SCarl Huang 	}
38606999407SCarl Huang 
38706999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3886fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab),
3896fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_VAL,
3906fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
39130d08503SDan Carpenter 	if (ret) {
39206999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config4: %d\n", ret);
39306999407SCarl Huang 		return ret;
39406999407SCarl Huang 	}
39506999407SCarl Huang 
39606999407SCarl Huang 	return 0;
39706999407SCarl Huang }
39806999407SCarl Huang 
399babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
400babb0cedSCarl Huang {
401babb0cedSCarl Huang 	u32 val;
402babb0cedSCarl Huang 	int i;
403babb0cedSCarl Huang 
404babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
405babb0cedSCarl Huang 
406babb0cedSCarl Huang 	/* PCIE link seems very unstable after the Hot Reset*/
407babb0cedSCarl Huang 	for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {
408babb0cedSCarl Huang 		if (val == 0xffffffff)
409babb0cedSCarl Huang 			mdelay(5);
410babb0cedSCarl Huang 
411babb0cedSCarl Huang 		ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
412babb0cedSCarl Huang 		val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
413babb0cedSCarl Huang 	}
414babb0cedSCarl Huang 
415babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val);
416babb0cedSCarl Huang 
417babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
418562934adSKalle Valo 	val |= GCC_GCC_PCIE_HOT_RST_VAL;
419babb0cedSCarl Huang 	ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
420babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
421babb0cedSCarl Huang 
422babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val);
423babb0cedSCarl Huang 
424babb0cedSCarl Huang 	mdelay(5);
425babb0cedSCarl Huang }
426babb0cedSCarl Huang 
427babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
428babb0cedSCarl Huang {
429babb0cedSCarl Huang 	/* This is a WAR for PCIE Hotreset.
430babb0cedSCarl Huang 	 * When target receive Hotreset, but will set the interrupt.
431babb0cedSCarl Huang 	 * So when download SBL again, SBL will open Interrupt and
432babb0cedSCarl Huang 	 * receive it, and crash immediately.
433babb0cedSCarl Huang 	 */
434babb0cedSCarl Huang 	ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
435babb0cedSCarl Huang }
436babb0cedSCarl Huang 
4370ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab)
4380ccdf439SCarl Huang {
4390ccdf439SCarl Huang 	u32 val;
4400ccdf439SCarl Huang 
4410ccdf439SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG);
4420ccdf439SCarl Huang 	val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK;
4430ccdf439SCarl Huang 	ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val);
4440ccdf439SCarl Huang }
4450ccdf439SCarl Huang 
446f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
447f3c603d4SCarl Huang {
448f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
449f3c603d4SCarl Huang 	mdelay(5);
450f3c603d4SCarl Huang }
451f3c603d4SCarl Huang 
452babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
453f3c603d4SCarl Huang {
4548a0b899fSBaochen Qiang 	mdelay(100);
4558a0b899fSBaochen Qiang 
456babb0cedSCarl Huang 	if (power_on) {
457babb0cedSCarl Huang 		ath11k_pci_enable_ltssm(ab);
458babb0cedSCarl Huang 		ath11k_pci_clear_all_intrs(ab);
4590ccdf439SCarl Huang 		ath11k_pci_set_wlaon_pwr_ctrl(ab);
4605088df05SBaochen Qiang 		if (ab->hw_params.fix_l1ss)
46106999407SCarl Huang 			ath11k_pci_fix_l1ss(ab);
462babb0cedSCarl Huang 	}
463babb0cedSCarl Huang 
464f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
4658a0b899fSBaochen Qiang 	ath11k_pci_clear_dbg_registers(ab);
466f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
467f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
468f3c603d4SCarl Huang }
469f3c603d4SCarl Huang 
4701399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
4711399fb87SGovind Singh {
4721399fb87SGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(dev);
4731399fb87SGovind Singh 
4741399fb87SGovind Singh 	return pci_irq_vector(pci_dev, vector);
4751399fb87SGovind Singh }
4761399fb87SGovind Singh 
477c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
478c4eacabeSGovind Singh 				       u32 *msi_addr_hi)
479c4eacabeSGovind Singh {
480e8e55d89SAnilkumar Kolli 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
481c4eacabeSGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
482c4eacabeSGovind Singh 
483c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
484c4eacabeSGovind Singh 			      msi_addr_lo);
485c4eacabeSGovind Singh 
486e8e55d89SAnilkumar Kolli 	if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) {
487c4eacabeSGovind Singh 		pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
488c4eacabeSGovind Singh 				      msi_addr_hi);
489e8e55d89SAnilkumar Kolli 	} else {
490e8e55d89SAnilkumar Kolli 		*msi_addr_hi = 0;
491e8e55d89SAnilkumar Kolli 	}
492c4eacabeSGovind Singh }
493c4eacabeSGovind Singh 
4941399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
4951399fb87SGovind Singh 				       int *num_vectors, u32 *user_base_data,
4961399fb87SGovind Singh 				       u32 *base_vector)
4971399fb87SGovind Singh {
4981399fb87SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4997a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
5001399fb87SGovind Singh 	int idx;
5011399fb87SGovind Singh 
5027a3aed0cSAnilkumar Kolli 	for (idx = 0; idx < msi_config->total_users; idx++) {
5037a3aed0cSAnilkumar Kolli 		if (strcmp(user_name, msi_config->users[idx].name) == 0) {
5047a3aed0cSAnilkumar Kolli 			*num_vectors = msi_config->users[idx].num_vectors;
5057a3aed0cSAnilkumar Kolli 			*base_vector =  msi_config->users[idx].base_vector;
506c41a6700SCarl Huang 			*user_base_data = *base_vector + ab_pci->msi_ep_base_data;
5071399fb87SGovind Singh 
508c41a6700SCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
509c41a6700SCarl Huang 				   "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
5101399fb87SGovind Singh 				   user_name, *num_vectors, *user_base_data,
5111399fb87SGovind Singh 				   *base_vector);
5121399fb87SGovind Singh 
5131399fb87SGovind Singh 			return 0;
5141399fb87SGovind Singh 		}
5151399fb87SGovind Singh 	}
5161399fb87SGovind Singh 
5171399fb87SGovind Singh 	ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
5181399fb87SGovind Singh 
5191399fb87SGovind Singh 	return -EINVAL;
5201399fb87SGovind Singh }
5211399fb87SGovind Singh 
5226289ac2bSKarthikeyan Periyasamy static void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id,
5236289ac2bSKarthikeyan Periyasamy 				      u32 *msi_idx)
5246289ac2bSKarthikeyan Periyasamy {
5256289ac2bSKarthikeyan Periyasamy 	u32 i, msi_data_idx;
5266289ac2bSKarthikeyan Periyasamy 
5276289ac2bSKarthikeyan Periyasamy 	for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
5286289ac2bSKarthikeyan Periyasamy 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5296289ac2bSKarthikeyan Periyasamy 			continue;
5306289ac2bSKarthikeyan Periyasamy 
5316289ac2bSKarthikeyan Periyasamy 		if (ce_id == i)
5326289ac2bSKarthikeyan Periyasamy 			break;
5336289ac2bSKarthikeyan Periyasamy 
5346289ac2bSKarthikeyan Periyasamy 		msi_data_idx++;
5356289ac2bSKarthikeyan Periyasamy 	}
5366289ac2bSKarthikeyan Periyasamy 	*msi_idx = msi_data_idx;
5376289ac2bSKarthikeyan Periyasamy }
5386289ac2bSKarthikeyan Periyasamy 
539c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
540c4eacabeSGovind Singh 					  int *num_vectors, u32 *user_base_data,
541c4eacabeSGovind Singh 					  u32 *base_vector)
542c4eacabeSGovind Singh {
543c4eacabeSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
544c4eacabeSGovind Singh 
545c4eacabeSGovind Singh 	return ath11k_pci_get_user_msi_assignment(ab_pci, user_name,
546c4eacabeSGovind Singh 						  num_vectors, user_base_data,
547c4eacabeSGovind Singh 						  base_vector);
548c4eacabeSGovind Singh }
549c4eacabeSGovind Singh 
550d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
551d4ecb90bSCarl Huang {
552d4ecb90bSCarl Huang 	int i, j;
553d4ecb90bSCarl Huang 
554d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
555d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
556d4ecb90bSCarl Huang 
557d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++)
558d4ecb90bSCarl Huang 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
559d4ecb90bSCarl Huang 
560d4ecb90bSCarl Huang 		netif_napi_del(&irq_grp->napi);
561d4ecb90bSCarl Huang 	}
562d4ecb90bSCarl Huang }
563d4ecb90bSCarl Huang 
5647f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab)
5657f4beda2SGovind Singh {
5667f4beda2SGovind Singh 	int i, irq_idx;
5677f4beda2SGovind Singh 
568d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
569e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5707f4beda2SGovind Singh 			continue;
5717f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5727f4beda2SGovind Singh 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
5737f4beda2SGovind Singh 	}
574d4ecb90bSCarl Huang 
575d4ecb90bSCarl Huang 	ath11k_pci_free_ext_irq(ab);
5767f4beda2SGovind Singh }
5777f4beda2SGovind Singh 
5782c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
5792c3960c2SGovind Singh {
580c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
5812c3960c2SGovind Singh 	u32 irq_idx;
5822c3960c2SGovind Singh 
583c41a6700SCarl Huang 	/* In case of one MSI vector, we handle irq enable/disable in a
584c41a6700SCarl Huang 	 * uniform way since we only have one irq
585c41a6700SCarl Huang 	 */
586c41a6700SCarl Huang 	if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
587c41a6700SCarl Huang 		return;
588c41a6700SCarl Huang 
5892c3960c2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
5902c3960c2SGovind Singh 	enable_irq(ab->irq_num[irq_idx]);
5912c3960c2SGovind Singh }
5922c3960c2SGovind Singh 
5937f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
5947f4beda2SGovind Singh {
595c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
5967f4beda2SGovind Singh 	u32 irq_idx;
5977f4beda2SGovind Singh 
598c41a6700SCarl Huang 	/* In case of one MSI vector, we handle irq enable/disable in a
599c41a6700SCarl Huang 	 * uniform way since we only have one irq
600c41a6700SCarl Huang 	 */
601c41a6700SCarl Huang 	if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
602c41a6700SCarl Huang 		return;
603c41a6700SCarl Huang 
6047f4beda2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
6057f4beda2SGovind Singh 	disable_irq_nosync(ab->irq_num[irq_idx]);
6067f4beda2SGovind Singh }
6077f4beda2SGovind Singh 
6082c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
6092c3960c2SGovind Singh {
6102c3960c2SGovind Singh 	int i;
6112c3960c2SGovind Singh 
61201279bcdSCarl Huang 	clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
61301279bcdSCarl Huang 
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 		ath11k_pci_ce_irq_disable(ab, i);
6182c3960c2SGovind Singh 	}
6192c3960c2SGovind Singh }
6202c3960c2SGovind Singh 
6212c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
6222c3960c2SGovind Singh {
6232c3960c2SGovind Singh 	int i;
6242c3960c2SGovind Singh 	int irq_idx;
6252c3960c2SGovind Singh 
626d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
627e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
6282c3960c2SGovind Singh 			continue;
6292c3960c2SGovind Singh 
6302c3960c2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
6312c3960c2SGovind Singh 		synchronize_irq(ab->irq_num[irq_idx]);
6322c3960c2SGovind Singh 	}
6332c3960c2SGovind Singh }
6342c3960c2SGovind Singh 
6350f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
6362c3960c2SGovind Singh {
6370f01dcb8SAllen Pais 	struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
638ac6e7348SCarl Huang 	int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
6392c3960c2SGovind Singh 
6402c3960c2SGovind Singh 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
6412c3960c2SGovind Singh 
642ac6e7348SCarl Huang 	enable_irq(ce_pipe->ab->irq_num[irq_idx]);
6432c3960c2SGovind Singh }
6442c3960c2SGovind Singh 
6457f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
6467f4beda2SGovind Singh {
6477f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = arg;
64801279bcdSCarl Huang 	struct ath11k_base *ab = ce_pipe->ab;
649ac6e7348SCarl Huang 	int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
65001279bcdSCarl Huang 
65101279bcdSCarl Huang 	if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags))
65201279bcdSCarl Huang 		return IRQ_HANDLED;
6537f4beda2SGovind Singh 
6547dc67af0SKarthikeyan Periyasamy 	/* last interrupt received for this CE */
6557dc67af0SKarthikeyan Periyasamy 	ce_pipe->timestamp = jiffies;
6567dc67af0SKarthikeyan Periyasamy 
657ac6e7348SCarl Huang 	disable_irq_nosync(ab->irq_num[irq_idx]);
658ac6e7348SCarl Huang 
6592c3960c2SGovind Singh 	tasklet_schedule(&ce_pipe->intr_tq);
6607f4beda2SGovind Singh 
6617f4beda2SGovind Singh 	return IRQ_HANDLED;
6627f4beda2SGovind Singh }
6637f4beda2SGovind Singh 
664d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
665d4ecb90bSCarl Huang {
666c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab);
667d4ecb90bSCarl Huang 	int i;
668d4ecb90bSCarl Huang 
669c41a6700SCarl Huang 	/* In case of one MSI vector, we handle irq enable/disable
670c41a6700SCarl Huang 	 * in a uniform way since we only have one irq
671c41a6700SCarl Huang 	 */
672c41a6700SCarl Huang 	if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
673c41a6700SCarl Huang 		return;
674c41a6700SCarl Huang 
675d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
676d4ecb90bSCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
677d4ecb90bSCarl Huang }
678d4ecb90bSCarl Huang 
679d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
680d4ecb90bSCarl Huang {
681d4ecb90bSCarl Huang 	int i;
682d4ecb90bSCarl Huang 
68301279bcdSCarl Huang 	clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags);
68401279bcdSCarl Huang 
685d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
686d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
687d4ecb90bSCarl Huang 
688d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
689d4ecb90bSCarl Huang 
690d943fdadSBen Greear 		if (irq_grp->napi_enabled) {
691d4ecb90bSCarl Huang 			napi_synchronize(&irq_grp->napi);
692d4ecb90bSCarl Huang 			napi_disable(&irq_grp->napi);
693d943fdadSBen Greear 			irq_grp->napi_enabled = false;
694d943fdadSBen Greear 		}
695d4ecb90bSCarl Huang 	}
696d4ecb90bSCarl Huang }
697d4ecb90bSCarl Huang 
698d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
699d4ecb90bSCarl Huang {
700c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab);
701d4ecb90bSCarl Huang 	int i;
702d4ecb90bSCarl Huang 
703c41a6700SCarl Huang 	/* In case of one MSI vector, we handle irq enable/disable in a
704c41a6700SCarl Huang 	 * uniform way since we only have one irq
705c41a6700SCarl Huang 	 */
706c41a6700SCarl Huang 	if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
707c41a6700SCarl Huang 		return;
708c41a6700SCarl Huang 
709d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
710d4ecb90bSCarl Huang 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
711d4ecb90bSCarl Huang }
712d4ecb90bSCarl Huang 
713d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
714d4ecb90bSCarl Huang {
715d4ecb90bSCarl Huang 	int i;
716d4ecb90bSCarl Huang 
71701279bcdSCarl Huang 	set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags);
71801279bcdSCarl Huang 
719d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
720d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
721d4ecb90bSCarl Huang 
722d943fdadSBen Greear 		if (!irq_grp->napi_enabled) {
723d4ecb90bSCarl Huang 			napi_enable(&irq_grp->napi);
724d943fdadSBen Greear 			irq_grp->napi_enabled = true;
725d943fdadSBen Greear 		}
726d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
727d4ecb90bSCarl Huang 	}
728d4ecb90bSCarl Huang }
729d4ecb90bSCarl Huang 
730d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
731d4ecb90bSCarl Huang {
732d4ecb90bSCarl Huang 	int i, j, irq_idx;
733d4ecb90bSCarl Huang 
734d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
735d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
736d4ecb90bSCarl Huang 
737d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
738d4ecb90bSCarl Huang 			irq_idx = irq_grp->irqs[j];
739d4ecb90bSCarl Huang 			synchronize_irq(ab->irq_num[irq_idx]);
740d4ecb90bSCarl Huang 		}
741d4ecb90bSCarl Huang 	}
742d4ecb90bSCarl Huang }
743d4ecb90bSCarl Huang 
744d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
745d4ecb90bSCarl Huang {
746d4ecb90bSCarl Huang 	__ath11k_pci_ext_irq_disable(ab);
747d4ecb90bSCarl Huang 	ath11k_pci_sync_ext_irqs(ab);
748d4ecb90bSCarl Huang }
749d4ecb90bSCarl Huang 
750d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
751d4ecb90bSCarl Huang {
752d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
753d4ecb90bSCarl Huang 						struct ath11k_ext_irq_grp,
754d4ecb90bSCarl Huang 						napi);
755d4ecb90bSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
756d4ecb90bSCarl Huang 	int work_done;
757ac6e7348SCarl Huang 	int i;
758d4ecb90bSCarl Huang 
759d4ecb90bSCarl Huang 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
760d4ecb90bSCarl Huang 	if (work_done < budget) {
761d4ecb90bSCarl Huang 		napi_complete_done(napi, work_done);
762ac6e7348SCarl Huang 		for (i = 0; i < irq_grp->num_irq; i++)
763ac6e7348SCarl Huang 			enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
764d4ecb90bSCarl Huang 	}
765d4ecb90bSCarl Huang 
766d4ecb90bSCarl Huang 	if (work_done > budget)
767d4ecb90bSCarl Huang 		work_done = budget;
768d4ecb90bSCarl Huang 
769d4ecb90bSCarl Huang 	return work_done;
770d4ecb90bSCarl Huang }
771d4ecb90bSCarl Huang 
772d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
773d4ecb90bSCarl Huang {
774d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = arg;
77501279bcdSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
776ac6e7348SCarl Huang 	int i;
77701279bcdSCarl Huang 
77801279bcdSCarl Huang 	if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags))
77901279bcdSCarl Huang 		return IRQ_HANDLED;
780d4ecb90bSCarl Huang 
781d4ecb90bSCarl Huang 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
782d4ecb90bSCarl Huang 
7837dc67af0SKarthikeyan Periyasamy 	/* last interrupt received for this group */
7847dc67af0SKarthikeyan Periyasamy 	irq_grp->timestamp = jiffies;
7857dc67af0SKarthikeyan Periyasamy 
786ac6e7348SCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
787ac6e7348SCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
788d4ecb90bSCarl Huang 
789d4ecb90bSCarl Huang 	napi_schedule(&irq_grp->napi);
790d4ecb90bSCarl Huang 
791d4ecb90bSCarl Huang 	return IRQ_HANDLED;
792d4ecb90bSCarl Huang }
793d4ecb90bSCarl Huang 
794d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
795d4ecb90bSCarl Huang {
796c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
797d4ecb90bSCarl Huang 	int i, j, ret, num_vectors = 0;
7984ab4693fSCarl Huang 	u32 user_base_data = 0, base_vector = 0;
799d4ecb90bSCarl Huang 
800b2c09458SColin Ian King 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
801b2c09458SColin Ian King 						 &num_vectors,
802b2c09458SColin Ian King 						 &user_base_data,
803d4ecb90bSCarl Huang 						 &base_vector);
804b2c09458SColin Ian King 	if (ret < 0)
805b2c09458SColin Ian King 		return ret;
806d4ecb90bSCarl Huang 
807d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
808d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
809d4ecb90bSCarl Huang 		u32 num_irq = 0;
810d4ecb90bSCarl Huang 
811d4ecb90bSCarl Huang 		irq_grp->ab = ab;
812d4ecb90bSCarl Huang 		irq_grp->grp_id = i;
813d4ecb90bSCarl Huang 		init_dummy_netdev(&irq_grp->napi_ndev);
814d4ecb90bSCarl Huang 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
815d4ecb90bSCarl Huang 			       ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
816d4ecb90bSCarl Huang 
817d4ecb90bSCarl Huang 		if (ab->hw_params.ring_mask->tx[i] ||
818d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx[i] ||
819d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_err[i] ||
820d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_wbm_rel[i] ||
821d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->reo_status[i] ||
822d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rxdma2host[i] ||
823d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->host2rxdma[i] ||
824d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_mon_status[i]) {
825d4ecb90bSCarl Huang 			num_irq = 1;
826d4ecb90bSCarl Huang 		}
827d4ecb90bSCarl Huang 
828d4ecb90bSCarl Huang 		irq_grp->num_irq = num_irq;
8294ab4693fSCarl Huang 		irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i;
830d4ecb90bSCarl Huang 
831d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
832d4ecb90bSCarl Huang 			int irq_idx = irq_grp->irqs[j];
833d4ecb90bSCarl Huang 			int vector = (i % num_vectors) + base_vector;
834d4ecb90bSCarl Huang 			int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
835d4ecb90bSCarl Huang 
836d4ecb90bSCarl Huang 			ab->irq_num[irq_idx] = irq;
837d4ecb90bSCarl Huang 
838d4ecb90bSCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
839d4ecb90bSCarl Huang 				   "irq:%d group:%d\n", irq, i);
8407dc67af0SKarthikeyan Periyasamy 
8417dc67af0SKarthikeyan Periyasamy 			irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
842d4ecb90bSCarl Huang 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
843c41a6700SCarl Huang 					  ab_pci->irq_flags,
844d4ecb90bSCarl Huang 					  "DP_EXT_IRQ", irq_grp);
845d4ecb90bSCarl Huang 			if (ret) {
846d4ecb90bSCarl Huang 				ath11k_err(ab, "failed request irq %d: %d\n",
847d4ecb90bSCarl Huang 					   vector, ret);
848d4ecb90bSCarl Huang 				return ret;
849d4ecb90bSCarl Huang 			}
850d4ecb90bSCarl Huang 		}
851c41a6700SCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
852d4ecb90bSCarl Huang 	}
853d4ecb90bSCarl Huang 
854d4ecb90bSCarl Huang 	return 0;
855d4ecb90bSCarl Huang }
856d4ecb90bSCarl Huang 
857e94b0749SBaochen Qiang static int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci,
858e94b0749SBaochen Qiang 					    const struct cpumask *m)
859e94b0749SBaochen Qiang {
860e94b0749SBaochen Qiang 	if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
861e94b0749SBaochen Qiang 		return 0;
862e94b0749SBaochen Qiang 
863e94b0749SBaochen Qiang 	return irq_set_affinity_hint(ab_pci->pdev->irq, m);
864e94b0749SBaochen Qiang }
865e94b0749SBaochen Qiang 
8667f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab)
8677f4beda2SGovind Singh {
868c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
8697f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe;
8707f4beda2SGovind Singh 	u32 msi_data_start;
8716289ac2bSKarthikeyan Periyasamy 	u32 msi_data_count, msi_data_idx;
8727f4beda2SGovind Singh 	u32 msi_irq_start;
8737f4beda2SGovind Singh 	unsigned int msi_data;
8747f4beda2SGovind Singh 	int irq, i, ret, irq_idx;
8757f4beda2SGovind Singh 
8767f4beda2SGovind Singh 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab),
8777f4beda2SGovind Singh 						 "CE", &msi_data_count,
8787f4beda2SGovind Singh 						 &msi_data_start, &msi_irq_start);
8797f4beda2SGovind Singh 	if (ret)
8807f4beda2SGovind Singh 		return ret;
8817f4beda2SGovind Singh 
882e94b0749SBaochen Qiang 	ret = ath11k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0));
883e94b0749SBaochen Qiang 	if (ret) {
884e94b0749SBaochen Qiang 		ath11k_err(ab, "failed to set irq affinity %d\n", ret);
885e94b0749SBaochen Qiang 		return ret;
886e94b0749SBaochen Qiang 	}
887e94b0749SBaochen Qiang 
8887f4beda2SGovind Singh 	/* Configure CE irqs */
8896289ac2bSKarthikeyan Periyasamy 	for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
890e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
8917f4beda2SGovind Singh 			continue;
8927f4beda2SGovind Singh 
8936289ac2bSKarthikeyan Periyasamy 		msi_data = (msi_data_idx % msi_data_count) + msi_irq_start;
8946289ac2bSKarthikeyan Periyasamy 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
8956289ac2bSKarthikeyan Periyasamy 		ce_pipe = &ab->ce.ce_pipe[i];
8966289ac2bSKarthikeyan Periyasamy 
8977f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
8987f4beda2SGovind Singh 
8990f01dcb8SAllen Pais 		tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
9002c3960c2SGovind Singh 
9017f4beda2SGovind Singh 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
902c41a6700SCarl Huang 				  ab_pci->irq_flags, irq_name[irq_idx],
9037f4beda2SGovind Singh 				  ce_pipe);
9047f4beda2SGovind Singh 		if (ret) {
9057f4beda2SGovind Singh 			ath11k_err(ab, "failed to request irq %d: %d\n",
9067f4beda2SGovind Singh 				   irq_idx, ret);
907e94b0749SBaochen Qiang 			goto err_irq_affinity_cleanup;
9087f4beda2SGovind Singh 		}
9097f4beda2SGovind Singh 
9107f4beda2SGovind Singh 		ab->irq_num[irq_idx] = irq;
9116289ac2bSKarthikeyan Periyasamy 		msi_data_idx++;
912e678fbd4SKarthikeyan Periyasamy 
913e5c860e1SCarl Huang 		ath11k_pci_ce_irq_disable(ab, i);
9147f4beda2SGovind Singh 	}
9157f4beda2SGovind Singh 
916d4ecb90bSCarl Huang 	ret = ath11k_pci_ext_irq_config(ab);
917d4ecb90bSCarl Huang 	if (ret)
918e94b0749SBaochen Qiang 		goto err_irq_affinity_cleanup;
919d4ecb90bSCarl Huang 
9207f4beda2SGovind Singh 	return 0;
921e94b0749SBaochen Qiang 
922e94b0749SBaochen Qiang err_irq_affinity_cleanup:
923e94b0749SBaochen Qiang 	ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
924e94b0749SBaochen Qiang 	return ret;
9257f4beda2SGovind Singh }
9267f4beda2SGovind Singh 
9277f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
9287f4beda2SGovind Singh {
9297f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
9307f4beda2SGovind Singh 
931967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
932967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
9337f4beda2SGovind Singh 
934967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
935967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
93616001e4bSAnilkumar Kolli 	ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
937e838c14aSCarl Huang 
938e838c14aSCarl Huang 	ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
939e838c14aSCarl Huang 				    &cfg->shadow_reg_v2_len);
9407f4beda2SGovind Singh }
9417f4beda2SGovind Singh 
9427f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
9437f4beda2SGovind Singh {
9447f4beda2SGovind Singh 	int i;
9457f4beda2SGovind Singh 
94601279bcdSCarl Huang 	set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
94701279bcdSCarl Huang 
948d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
949e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
9507f4beda2SGovind Singh 			continue;
9517f4beda2SGovind Singh 		ath11k_pci_ce_irq_enable(ab, i);
9527f4beda2SGovind Singh 	}
9537f4beda2SGovind Singh }
9547f4beda2SGovind Singh 
95596527d52SBaochen Qiang static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable)
95696527d52SBaochen Qiang {
95796527d52SBaochen Qiang 	struct pci_dev *dev = ab_pci->pdev;
95896527d52SBaochen Qiang 	u16 control;
95996527d52SBaochen Qiang 
96096527d52SBaochen Qiang 	pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
96196527d52SBaochen Qiang 
96296527d52SBaochen Qiang 	if (enable)
96396527d52SBaochen Qiang 		control |= PCI_MSI_FLAGS_ENABLE;
96496527d52SBaochen Qiang 	else
96596527d52SBaochen Qiang 		control &= ~PCI_MSI_FLAGS_ENABLE;
96696527d52SBaochen Qiang 
96796527d52SBaochen Qiang 	pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
96896527d52SBaochen Qiang }
96996527d52SBaochen Qiang 
97096527d52SBaochen Qiang static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci)
97196527d52SBaochen Qiang {
97296527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, true);
97396527d52SBaochen Qiang }
97496527d52SBaochen Qiang 
97596527d52SBaochen Qiang static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci)
97696527d52SBaochen Qiang {
97796527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, false);
97896527d52SBaochen Qiang }
97996527d52SBaochen Qiang 
98096527d52SBaochen Qiang static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
9815697a564SGovind Singh {
9825697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
9837a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
9845697a564SGovind Singh 	struct msi_desc *msi_desc;
9855697a564SGovind Singh 	int num_vectors;
9865697a564SGovind Singh 	int ret;
9875697a564SGovind Singh 
9885697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
9897a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
9907a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
9915697a564SGovind Singh 					    PCI_IRQ_MSI);
992ac6e7348SCarl Huang 	if (num_vectors == msi_config->total_vectors) {
993c41a6700SCarl Huang 		set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
994c41a6700SCarl Huang 		ab_pci->irq_flags = IRQF_SHARED;
995ac6e7348SCarl Huang 	} else {
996ac6e7348SCarl Huang 		num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
997ac6e7348SCarl Huang 						    1,
998ac6e7348SCarl Huang 						    1,
999ac6e7348SCarl Huang 						    PCI_IRQ_MSI);
1000ac6e7348SCarl Huang 		if (num_vectors < 0) {
1001ac6e7348SCarl Huang 			ret = -EINVAL;
1002ac6e7348SCarl Huang 			goto reset_msi_config;
10035697a564SGovind Singh 		}
1004ac6e7348SCarl Huang 		clear_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
1005ac6e7348SCarl Huang 		ab_pci->msi_config = &msi_config_one_msi;
1006ac6e7348SCarl Huang 		ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
1007ac6e7348SCarl Huang 		ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n");
1008ac6e7348SCarl Huang 	}
1009ac6e7348SCarl Huang 	ath11k_info(ab, "MSI vectors: %d\n", num_vectors);
1010ac6e7348SCarl Huang 
101196527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
10125697a564SGovind Singh 
10135697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
10145697a564SGovind Singh 	if (!msi_desc) {
10155697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
10165697a564SGovind Singh 		ret = -EINVAL;
10175697a564SGovind Singh 		goto free_msi_vector;
10185697a564SGovind Singh 	}
10195697a564SGovind Singh 
10205697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
1021e58f2259SThomas Gleixner 	if (msi_desc->pci.msi_attrib.is_64)
1022e8e55d89SAnilkumar Kolli 		set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags);
10235697a564SGovind Singh 
10245697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
10255697a564SGovind Singh 
10265697a564SGovind Singh 	return 0;
10275697a564SGovind Singh 
10285697a564SGovind Singh free_msi_vector:
10295697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
10305697a564SGovind Singh 
1031ac6e7348SCarl Huang reset_msi_config:
10325697a564SGovind Singh 	return ret;
10335697a564SGovind Singh }
10345697a564SGovind Singh 
103596527d52SBaochen Qiang static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci)
10365697a564SGovind Singh {
10375697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
10385697a564SGovind Singh }
10395697a564SGovind Singh 
104087b4072dSCarl Huang static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci)
104187b4072dSCarl Huang {
104287b4072dSCarl Huang 	struct msi_desc *msi_desc;
104387b4072dSCarl Huang 
104487b4072dSCarl Huang 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
104587b4072dSCarl Huang 	if (!msi_desc) {
104687b4072dSCarl Huang 		ath11k_err(ab_pci->ab, "msi_desc is NULL!\n");
104787b4072dSCarl Huang 		pci_free_irq_vectors(ab_pci->pdev);
104887b4072dSCarl Huang 		return -EINVAL;
104987b4072dSCarl Huang 	}
105087b4072dSCarl Huang 
105187b4072dSCarl Huang 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
105287b4072dSCarl Huang 
105387b4072dSCarl Huang 	ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n",
105487b4072dSCarl Huang 		   ab_pci->msi_ep_base_data);
105587b4072dSCarl Huang 
105687b4072dSCarl Huang 	return 0;
105787b4072dSCarl Huang }
105887b4072dSCarl Huang 
10595762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
10605762613eSGovind Singh {
10615762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
10625762613eSGovind Singh 	u16 device_id;
10635762613eSGovind Singh 	int ret = 0;
10645762613eSGovind Singh 
10655762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
10665762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
10675762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
10685762613eSGovind Singh 			   device_id, ab_pci->dev_id);
10695762613eSGovind Singh 		ret = -EIO;
10705762613eSGovind Singh 		goto out;
10715762613eSGovind Singh 	}
10725762613eSGovind Singh 
10735762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
10745762613eSGovind Singh 	if (ret) {
10755762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
10765762613eSGovind Singh 		goto out;
10775762613eSGovind Singh 	}
10785762613eSGovind Singh 
10795762613eSGovind Singh 	ret = pci_enable_device(pdev);
10805762613eSGovind Singh 	if (ret) {
10815762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
10825762613eSGovind Singh 		goto out;
10835762613eSGovind Singh 	}
10845762613eSGovind Singh 
10855762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
10865762613eSGovind Singh 	if (ret) {
10875762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
10885762613eSGovind Singh 		goto disable_device;
10895762613eSGovind Singh 	}
10905762613eSGovind Singh 
1091923a1346SChristophe JAILLET 	ret = dma_set_mask_and_coherent(&pdev->dev,
1092923a1346SChristophe JAILLET 					DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
10935762613eSGovind Singh 	if (ret) {
10945762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
10955762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
10965762613eSGovind Singh 		goto release_region;
10975762613eSGovind Singh 	}
10985762613eSGovind Singh 
10995762613eSGovind Singh 	pci_set_master(pdev);
11005762613eSGovind Singh 
11015762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
11025762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
11035762613eSGovind Singh 	if (!ab->mem) {
11045762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
11055762613eSGovind Singh 		ret = -EIO;
11065762613eSGovind Singh 		goto clear_master;
11075762613eSGovind Singh 	}
11085762613eSGovind Singh 
11095762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
11105762613eSGovind Singh 	return 0;
11115762613eSGovind Singh 
11125762613eSGovind Singh clear_master:
11135762613eSGovind Singh 	pci_clear_master(pdev);
11145762613eSGovind Singh release_region:
11155762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
11165762613eSGovind Singh disable_device:
11175762613eSGovind Singh 	pci_disable_device(pdev);
11185762613eSGovind Singh out:
11195762613eSGovind Singh 	return ret;
11205762613eSGovind Singh }
11215762613eSGovind Singh 
11225762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
11235762613eSGovind Singh {
11245762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
11255762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
11265762613eSGovind Singh 
11275762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
11285762613eSGovind Singh 	ab->mem = NULL;
11295762613eSGovind Singh 	pci_clear_master(pci_dev);
11305762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
11315762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
11325762613eSGovind Singh 		pci_disable_device(pci_dev);
11335762613eSGovind Singh }
11345762613eSGovind Singh 
1135e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
1136e9603f4bSCarl Huang {
1137e9603f4bSCarl Huang 	struct ath11k_base *ab = ab_pci->ab;
1138e9603f4bSCarl Huang 
1139e9603f4bSCarl Huang 	pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1140e9603f4bSCarl Huang 				  &ab_pci->link_ctl);
1141e9603f4bSCarl Huang 
1142e9603f4bSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n",
1143e9603f4bSCarl Huang 		   ab_pci->link_ctl,
1144e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S),
1145e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
1146e9603f4bSCarl Huang 
1147e9603f4bSCarl Huang 	/* disable L0s and L1 */
1148e9603f4bSCarl Huang 	pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1149e9603f4bSCarl Huang 				   ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
1150e9603f4bSCarl Huang 
1151e9603f4bSCarl Huang 	set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags);
1152e9603f4bSCarl Huang }
1153e9603f4bSCarl Huang 
1154e9603f4bSCarl Huang static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci)
1155e9603f4bSCarl Huang {
1156e9603f4bSCarl Huang 	if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags))
1157e9603f4bSCarl Huang 		pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1158e9603f4bSCarl Huang 					   ab_pci->link_ctl);
1159e9603f4bSCarl Huang }
1160e9603f4bSCarl Huang 
11611399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
11621399fb87SGovind Singh {
11631399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
11641399fb87SGovind Singh 	int ret;
11651399fb87SGovind Singh 
1166a05bd851SCarl Huang 	ab_pci->register_window = 0;
1167a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1168babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, true);
1169f3c603d4SCarl Huang 
1170e9603f4bSCarl Huang 	/* Disable ASPM during firmware download due to problems switching
1171e9603f4bSCarl Huang 	 * to AMSS state.
1172e9603f4bSCarl Huang 	 */
1173e9603f4bSCarl Huang 	ath11k_pci_aspm_disable(ab_pci);
1174e9603f4bSCarl Huang 
117596527d52SBaochen Qiang 	ath11k_pci_msi_enable(ab_pci);
117696527d52SBaochen Qiang 
11771399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
11781399fb87SGovind Singh 	if (ret) {
11791399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
11801399fb87SGovind Singh 		return ret;
11811399fb87SGovind Singh 	}
11821399fb87SGovind Singh 
1183480a7361SKarthikeyan Periyasamy 	if (ab->bus_params.static_window_map)
1184480a7361SKarthikeyan Periyasamy 		ath11k_pci_select_static_window(ab_pci);
1185480a7361SKarthikeyan Periyasamy 
11861399fb87SGovind Singh 	return 0;
11871399fb87SGovind Singh }
11881399fb87SGovind Singh 
11891399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
11901399fb87SGovind Singh {
11911399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
11921399fb87SGovind Singh 
1193e9603f4bSCarl Huang 	/* restore aspm in case firmware bootup fails */
1194e9603f4bSCarl Huang 	ath11k_pci_aspm_restore(ab_pci);
1195e9603f4bSCarl Huang 
1196babb0cedSCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
119796527d52SBaochen Qiang 
119896527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
119996527d52SBaochen Qiang 
12001399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
1201a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1202babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, false);
12031399fb87SGovind Singh }
12041399fb87SGovind Singh 
1205fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab)
1206fa5917e4SCarl Huang {
1207fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
1208fa5917e4SCarl Huang 
1209fa5917e4SCarl Huang 	ath11k_mhi_suspend(ar_pci);
1210fa5917e4SCarl Huang 
1211fa5917e4SCarl Huang 	return 0;
1212fa5917e4SCarl Huang }
1213fa5917e4SCarl Huang 
1214fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab)
1215fa5917e4SCarl Huang {
1216fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
1217fa5917e4SCarl Huang 
1218fa5917e4SCarl Huang 	ath11k_mhi_resume(ar_pci);
1219fa5917e4SCarl Huang 
1220fa5917e4SCarl Huang 	return 0;
1221fa5917e4SCarl Huang }
1222fa5917e4SCarl Huang 
12232c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
12242c3960c2SGovind Singh {
12252c3960c2SGovind Singh 	int i;
12262c3960c2SGovind Singh 
1227d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
12282c3960c2SGovind Singh 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
12292c3960c2SGovind Singh 
1230e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
12312c3960c2SGovind Singh 			continue;
12322c3960c2SGovind Singh 
12332c3960c2SGovind Singh 		tasklet_kill(&ce_pipe->intr_tq);
12342c3960c2SGovind Singh 	}
12352c3960c2SGovind Singh }
12362c3960c2SGovind Singh 
1237d578ec2aSCarl Huang static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab)
12387f4beda2SGovind Singh {
12392c3960c2SGovind Singh 	ath11k_pci_ce_irqs_disable(ab);
12402c3960c2SGovind Singh 	ath11k_pci_sync_ce_irqs(ab);
12412c3960c2SGovind Singh 	ath11k_pci_kill_tasklets(ab);
1242d578ec2aSCarl Huang }
1243d578ec2aSCarl Huang 
1244d578ec2aSCarl Huang static void ath11k_pci_stop(struct ath11k_base *ab)
1245d578ec2aSCarl Huang {
1246d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
12477f4beda2SGovind Singh 	ath11k_ce_cleanup_pipes(ab);
12487f4beda2SGovind Singh }
12497f4beda2SGovind Singh 
12507f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab)
12517f4beda2SGovind Singh {
1252a05bd851SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
1253a05bd851SCarl Huang 
1254a05bd851SCarl Huang 	set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1255a05bd851SCarl Huang 
1256915a081fSCarl Huang 	/* TODO: for now don't restore ASPM in case of single MSI
1257915a081fSCarl Huang 	 * vector as MHI register reading in M2 causes system hang.
1258915a081fSCarl Huang 	 */
1259915a081fSCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
1260e9603f4bSCarl Huang 		ath11k_pci_aspm_restore(ab_pci);
1261915a081fSCarl Huang 	else
1262915a081fSCarl Huang 		ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n");
1263e9603f4bSCarl Huang 
12647f4beda2SGovind Singh 	ath11k_pci_ce_irqs_enable(ab);
12652c3960c2SGovind Singh 	ath11k_ce_rx_post_buf(ab);
12662c3960c2SGovind Singh 
12672c3960c2SGovind Singh 	return 0;
12682c3960c2SGovind Singh }
12692c3960c2SGovind Singh 
1270d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab)
1271d578ec2aSCarl Huang {
1272d578ec2aSCarl Huang 	ath11k_pci_ce_irqs_enable(ab);
1273d578ec2aSCarl Huang }
1274d578ec2aSCarl Huang 
1275d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab)
1276d578ec2aSCarl Huang {
1277d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
1278d578ec2aSCarl Huang }
1279d578ec2aSCarl Huang 
12802c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
12812c3960c2SGovind Singh 					  u8 *ul_pipe, u8 *dl_pipe)
12822c3960c2SGovind Singh {
12832c3960c2SGovind Singh 	const struct service_to_pipe *entry;
12842c3960c2SGovind Singh 	bool ul_set = false, dl_set = false;
12852c3960c2SGovind Singh 	int i;
12862c3960c2SGovind Singh 
1287967c1d11SAnilkumar Kolli 	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
1288967c1d11SAnilkumar Kolli 		entry = &ab->hw_params.svc_to_ce_map[i];
12892c3960c2SGovind Singh 
12902c3960c2SGovind Singh 		if (__le32_to_cpu(entry->service_id) != service_id)
12912c3960c2SGovind Singh 			continue;
12922c3960c2SGovind Singh 
12932c3960c2SGovind Singh 		switch (__le32_to_cpu(entry->pipedir)) {
12942c3960c2SGovind Singh 		case PIPEDIR_NONE:
12952c3960c2SGovind Singh 			break;
12962c3960c2SGovind Singh 		case PIPEDIR_IN:
12972c3960c2SGovind Singh 			WARN_ON(dl_set);
12982c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
12992c3960c2SGovind Singh 			dl_set = true;
13002c3960c2SGovind Singh 			break;
13012c3960c2SGovind Singh 		case PIPEDIR_OUT:
13022c3960c2SGovind Singh 			WARN_ON(ul_set);
13032c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
13042c3960c2SGovind Singh 			ul_set = true;
13052c3960c2SGovind Singh 			break;
13062c3960c2SGovind Singh 		case PIPEDIR_INOUT:
13072c3960c2SGovind Singh 			WARN_ON(dl_set);
13082c3960c2SGovind Singh 			WARN_ON(ul_set);
13092c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
13102c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
13112c3960c2SGovind Singh 			dl_set = true;
13122c3960c2SGovind Singh 			ul_set = true;
13132c3960c2SGovind Singh 			break;
13142c3960c2SGovind Singh 		}
13152c3960c2SGovind Singh 	}
13162c3960c2SGovind Singh 
13172c3960c2SGovind Singh 	if (WARN_ON(!ul_set || !dl_set))
13182c3960c2SGovind Singh 		return -ENOENT;
13197f4beda2SGovind Singh 
13207f4beda2SGovind Singh 	return 0;
13217f4beda2SGovind Singh }
13227f4beda2SGovind Singh 
13237f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
13247f4beda2SGovind Singh 	.start = ath11k_pci_start,
13257f4beda2SGovind Singh 	.stop = ath11k_pci_stop,
1326654e959aSGovind Singh 	.read32 = ath11k_pci_read32,
1327654e959aSGovind Singh 	.write32 = ath11k_pci_write32,
13281399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
13291399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
1330fa5917e4SCarl Huang 	.suspend = ath11k_pci_hif_suspend,
1331fa5917e4SCarl Huang 	.resume = ath11k_pci_hif_resume,
1332d4ecb90bSCarl Huang 	.irq_enable = ath11k_pci_ext_irq_enable,
1333d4ecb90bSCarl Huang 	.irq_disable = ath11k_pci_ext_irq_disable,
1334c4eacabeSGovind Singh 	.get_msi_address =  ath11k_pci_get_msi_address,
1335c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
13362c3960c2SGovind Singh 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
1337d578ec2aSCarl Huang 	.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
1338d578ec2aSCarl Huang 	.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
13396289ac2bSKarthikeyan Periyasamy 	.get_ce_msi_idx = ath11k_pci_get_ce_msi_idx,
13401399fb87SGovind Singh };
13411399fb87SGovind Singh 
13420fbf1957SBaochen Qiang static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor)
13430fbf1957SBaochen Qiang {
13440fbf1957SBaochen Qiang 	u32 soc_hw_version;
13450fbf1957SBaochen Qiang 
13460fbf1957SBaochen Qiang 	soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION);
13470fbf1957SBaochen Qiang 	*major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
13480fbf1957SBaochen Qiang 			   soc_hw_version);
13490fbf1957SBaochen Qiang 	*minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
13500fbf1957SBaochen Qiang 			   soc_hw_version);
13510fbf1957SBaochen Qiang 
13520fbf1957SBaochen Qiang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
13530fbf1957SBaochen Qiang 		   *major, *minor);
13540fbf1957SBaochen Qiang }
13550fbf1957SBaochen Qiang 
13566e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
13576e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
13586e0355afSGovind Singh {
13596e0355afSGovind Singh 	struct ath11k_base *ab;
13605762613eSGovind Singh 	struct ath11k_pci *ab_pci;
13616ac04bdcSAnilkumar Kolli 	u32 soc_hw_version_major, soc_hw_version_minor, addr;
13625762613eSGovind Singh 	int ret;
13636e0355afSGovind Singh 
13641ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
13651ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
13666e0355afSGovind Singh 	if (!ab) {
13676e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
13686e0355afSGovind Singh 		return -ENOMEM;
13696e0355afSGovind Singh 	}
13706e0355afSGovind Singh 
13716e0355afSGovind Singh 	ab->dev = &pdev->dev;
13726e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
13735762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
13745762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
13755762613eSGovind Singh 	ab_pci->ab = ab;
13765697a564SGovind Singh 	ab_pci->pdev = pdev;
13777f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
13785762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
1379654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
13805762613eSGovind Singh 
13816ac04bdcSAnilkumar Kolli 	/* Set fixed_mem_region to true for platforms support reserved memory
13826ac04bdcSAnilkumar Kolli 	 * from DT. If memory is reserved from DT for FW, ath11k driver need not
13836ac04bdcSAnilkumar Kolli 	 * allocate memory.
13846ac04bdcSAnilkumar Kolli 	 */
13856ac04bdcSAnilkumar Kolli 	ret = of_property_read_u32(ab->dev->of_node, "memory-region", &addr);
13866ac04bdcSAnilkumar Kolli 	if (!ret)
13876ac04bdcSAnilkumar Kolli 		set_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags);
13886ac04bdcSAnilkumar Kolli 
13895762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
13905762613eSGovind Singh 	if (ret) {
13915762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
13925762613eSGovind Singh 		goto err_free_core;
13935762613eSGovind Singh 	}
13946e0355afSGovind Singh 
1395fc95d10aSWen Gong 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n",
1396fc95d10aSWen Gong 		   pdev->vendor, pdev->device,
1397fc95d10aSWen Gong 		   pdev->subsystem_vendor, pdev->subsystem_device);
1398fc95d10aSWen Gong 
1399fc95d10aSWen Gong 	ab->id.vendor = pdev->vendor;
1400fc95d10aSWen Gong 	ab->id.device = pdev->device;
1401fc95d10aSWen Gong 	ab->id.subsystem_vendor = pdev->subsystem_vendor;
1402fc95d10aSWen Gong 	ab->id.subsystem_device = pdev->subsystem_device;
1403fc95d10aSWen Gong 
140418ac1665SKalle Valo 	switch (pci_dev->device) {
140518ac1665SKalle Valo 	case QCA6390_DEVICE_ID:
14060fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
14070fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
140818ac1665SKalle Valo 		switch (soc_hw_version_major) {
140918ac1665SKalle Valo 		case 2:
141018ac1665SKalle Valo 			ab->hw_rev = ATH11K_HW_QCA6390_HW20;
141118ac1665SKalle Valo 			break;
141218ac1665SKalle Valo 		default:
141318ac1665SKalle Valo 			dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n",
141418ac1665SKalle Valo 				soc_hw_version_major, soc_hw_version_minor);
141518ac1665SKalle Valo 			ret = -EOPNOTSUPP;
141618ac1665SKalle Valo 			goto err_pci_free_region;
141718ac1665SKalle Valo 		}
14184e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[0];
14194e809461SAnilkumar Kolli 		break;
14204e809461SAnilkumar Kolli 	case QCN9074_DEVICE_ID:
14214e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[1];
14224e809461SAnilkumar Kolli 		ab->bus_params.static_window_map = true;
14234e809461SAnilkumar Kolli 		ab->hw_rev = ATH11K_HW_QCN9074_HW10;
142418ac1665SKalle Valo 		break;
14250fbf1957SBaochen Qiang 	case WCN6855_DEVICE_ID:
1426fc95d10aSWen Gong 		ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD;
14270fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
14280fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
14290fbf1957SBaochen Qiang 		switch (soc_hw_version_major) {
14300fbf1957SBaochen Qiang 		case 2:
1431d1147a31SBaochen Qiang 			switch (soc_hw_version_minor) {
1432d1147a31SBaochen Qiang 			case 0x00:
1433d1147a31SBaochen Qiang 			case 0x01:
14340fbf1957SBaochen Qiang 				ab->hw_rev = ATH11K_HW_WCN6855_HW20;
14350fbf1957SBaochen Qiang 				break;
1436d1147a31SBaochen Qiang 			case 0x10:
1437d1147a31SBaochen Qiang 			case 0x11:
1438d1147a31SBaochen Qiang 				ab->hw_rev = ATH11K_HW_WCN6855_HW21;
1439d1147a31SBaochen Qiang 				break;
14400fbf1957SBaochen Qiang 			default:
1441d1147a31SBaochen Qiang 				goto unsupported_wcn6855_soc;
1442d1147a31SBaochen Qiang 			}
1443d1147a31SBaochen Qiang 			break;
1444d1147a31SBaochen Qiang 		default:
1445d1147a31SBaochen Qiang unsupported_wcn6855_soc:
14460fbf1957SBaochen Qiang 			dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n",
14470fbf1957SBaochen Qiang 				soc_hw_version_major, soc_hw_version_minor);
14480fbf1957SBaochen Qiang 			ret = -EOPNOTSUPP;
14490fbf1957SBaochen Qiang 			goto err_pci_free_region;
14500fbf1957SBaochen Qiang 		}
14510fbf1957SBaochen Qiang 		ab_pci->msi_config = &ath11k_msi_config[0];
14520fbf1957SBaochen Qiang 		break;
145318ac1665SKalle Valo 	default:
145418ac1665SKalle Valo 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
145518ac1665SKalle Valo 			pci_dev->device);
145618ac1665SKalle Valo 		ret = -EOPNOTSUPP;
145718ac1665SKalle Valo 		goto err_pci_free_region;
145818ac1665SKalle Valo 	}
145918ac1665SKalle Valo 
146096527d52SBaochen Qiang 	ret = ath11k_pci_alloc_msi(ab_pci);
14615697a564SGovind Singh 	if (ret) {
14625697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
14635697a564SGovind Singh 		goto err_pci_free_region;
14645697a564SGovind Singh 	}
14655697a564SGovind Singh 
1466b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
1467b8246f88SKalle Valo 	if (ret)
1468b8246f88SKalle Valo 		goto err_pci_disable_msi;
1469b8246f88SKalle Valo 
14701399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
14711399fb87SGovind Singh 	if (ret) {
14721399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
14731399fb87SGovind Singh 		goto err_pci_disable_msi;
14741399fb87SGovind Singh 	}
14751399fb87SGovind Singh 
14767f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
14777f4beda2SGovind Singh 	if (ret)
14787f4beda2SGovind Singh 		goto err_mhi_unregister;
14797f4beda2SGovind Singh 
14807f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
14817f4beda2SGovind Singh 	if (ret) {
14827f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
14837f4beda2SGovind Singh 		goto err_hal_srng_deinit;
14847f4beda2SGovind Singh 	}
14857f4beda2SGovind Singh 
14867f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
14877f4beda2SGovind Singh 
14887f4beda2SGovind Singh 	ret = ath11k_pci_config_irq(ab);
14897f4beda2SGovind Singh 	if (ret) {
14907f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
14917f4beda2SGovind Singh 		goto err_ce_free;
14927f4beda2SGovind Singh 	}
14937f4beda2SGovind Singh 
149487b4072dSCarl Huang 	/* kernel may allocate a dummy vector before request_irq and
149587b4072dSCarl Huang 	 * then allocate a real vector when request_irq is called.
149687b4072dSCarl Huang 	 * So get msi_data here again to avoid spurious interrupt
149787b4072dSCarl Huang 	 * as msi_data will configured to srngs.
149887b4072dSCarl Huang 	 */
149987b4072dSCarl Huang 	ret = ath11k_pci_config_msi_data(ab_pci);
150087b4072dSCarl Huang 	if (ret) {
150187b4072dSCarl Huang 		ath11k_err(ab, "failed to config msi_data: %d\n", ret);
150287b4072dSCarl Huang 		goto err_free_irq;
150387b4072dSCarl Huang 	}
150487b4072dSCarl Huang 
15057f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
15067f4beda2SGovind Singh 	if (ret) {
15077f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
15087f4beda2SGovind Singh 		goto err_free_irq;
15097f4beda2SGovind Singh 	}
15106e0355afSGovind Singh 	return 0;
15115762613eSGovind Singh 
15127f4beda2SGovind Singh err_free_irq:
15137f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
15147f4beda2SGovind Singh 
15157f4beda2SGovind Singh err_ce_free:
15167f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
15177f4beda2SGovind Singh 
15187f4beda2SGovind Singh err_hal_srng_deinit:
15197f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
15207f4beda2SGovind Singh 
15217f4beda2SGovind Singh err_mhi_unregister:
15227f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
15237f4beda2SGovind Singh 
1524b8246f88SKalle Valo err_pci_disable_msi:
152596527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
1526b8246f88SKalle Valo 
15275697a564SGovind Singh err_pci_free_region:
15285697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
15295697a564SGovind Singh 
15305762613eSGovind Singh err_free_core:
15315762613eSGovind Singh 	ath11k_core_free(ab);
15325697a564SGovind Singh 
15335762613eSGovind Singh 	return ret;
15346e0355afSGovind Singh }
15356e0355afSGovind Singh 
15366e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
15376e0355afSGovind Singh {
15386e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
15395762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
15406e0355afSGovind Singh 
1541e94b0749SBaochen Qiang 	ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
1542e94b0749SBaochen Qiang 
154361a57e51SAnilkumar Kolli 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
154461a57e51SAnilkumar Kolli 		ath11k_pci_power_down(ab);
154561a57e51SAnilkumar Kolli 		ath11k_debugfs_soc_destroy(ab);
154661a57e51SAnilkumar Kolli 		ath11k_qmi_deinit_service(ab);
154761a57e51SAnilkumar Kolli 		goto qmi_fail;
154861a57e51SAnilkumar Kolli 	}
154961a57e51SAnilkumar Kolli 
15506e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
15516fbd8898SCarl Huang 
15526fbd8898SCarl Huang 	ath11k_core_deinit(ab);
15536fbd8898SCarl Huang 
155461a57e51SAnilkumar Kolli qmi_fail:
15551399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
15566fbd8898SCarl Huang 
15576fbd8898SCarl Huang 	ath11k_pci_free_irq(ab);
155896527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
15595762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
15606fbd8898SCarl Huang 
15616fbd8898SCarl Huang 	ath11k_hal_srng_deinit(ab);
15626fbd8898SCarl Huang 	ath11k_ce_free_pipes(ab);
15636e0355afSGovind Singh 	ath11k_core_free(ab);
15646e0355afSGovind Singh }
15656e0355afSGovind Singh 
15661399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
15671399fb87SGovind Singh {
15681399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
15691399fb87SGovind Singh 
15701399fb87SGovind Singh 	ath11k_pci_power_down(ab);
15711399fb87SGovind Singh }
15721399fb87SGovind Singh 
1573d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
1574d1b0c338SCarl Huang {
1575d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1576d1b0c338SCarl Huang 	int ret;
1577d1b0c338SCarl Huang 
1578b4f4c564SKalle Valo 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
1579b4f4c564SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci suspend as qmi is not initialised\n");
1580b4f4c564SKalle Valo 		return 0;
1581b4f4c564SKalle Valo 	}
1582b4f4c564SKalle Valo 
1583d1b0c338SCarl Huang 	ret = ath11k_core_suspend(ab);
1584d1b0c338SCarl Huang 	if (ret)
1585d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to suspend core: %d\n", ret);
1586d1b0c338SCarl Huang 
1587d1b0c338SCarl Huang 	return ret;
1588d1b0c338SCarl Huang }
1589d1b0c338SCarl Huang 
1590d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
1591d1b0c338SCarl Huang {
1592d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1593d1b0c338SCarl Huang 	int ret;
1594d1b0c338SCarl Huang 
1595b4f4c564SKalle Valo 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
1596b4f4c564SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci resume as qmi is not initialised\n");
1597b4f4c564SKalle Valo 		return 0;
1598b4f4c564SKalle Valo 	}
1599b4f4c564SKalle Valo 
1600d1b0c338SCarl Huang 	ret = ath11k_core_resume(ab);
1601d1b0c338SCarl Huang 	if (ret)
1602d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to resume core: %d\n", ret);
1603d1b0c338SCarl Huang 
1604d1b0c338SCarl Huang 	return ret;
1605d1b0c338SCarl Huang }
1606d1b0c338SCarl Huang 
1607d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
1608d1b0c338SCarl Huang 			 ath11k_pci_pm_suspend,
1609d1b0c338SCarl Huang 			 ath11k_pci_pm_resume);
1610d1b0c338SCarl Huang 
16116e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
16126e0355afSGovind Singh 	.name = "ath11k_pci",
16136e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
16146e0355afSGovind Singh 	.probe = ath11k_pci_probe,
16156e0355afSGovind Singh 	.remove = ath11k_pci_remove,
16161399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
1617d1b0c338SCarl Huang #ifdef CONFIG_PM
1618d1b0c338SCarl Huang 	.driver.pm = &ath11k_pci_pm_ops,
1619d1b0c338SCarl Huang #endif
16206e0355afSGovind Singh };
16216e0355afSGovind Singh 
16226e0355afSGovind Singh static int ath11k_pci_init(void)
16236e0355afSGovind Singh {
16246e0355afSGovind Singh 	int ret;
16256e0355afSGovind Singh 
16266e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
16276e0355afSGovind Singh 	if (ret)
16286e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
16296e0355afSGovind Singh 		       ret);
16306e0355afSGovind Singh 
16316e0355afSGovind Singh 	return ret;
16326e0355afSGovind Singh }
16336e0355afSGovind Singh module_init(ath11k_pci_init);
16346e0355afSGovind Singh 
16356e0355afSGovind Singh static void ath11k_pci_exit(void)
16366e0355afSGovind Singh {
16376e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
16386e0355afSGovind Singh }
16396e0355afSGovind Singh 
16406e0355afSGovind Singh module_exit(ath11k_pci_exit);
16416e0355afSGovind Singh 
16426e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
16436e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
16443dbd7fe7SDevin Bayer 
16453dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */
16463dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE);
16473dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE);
16483dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE);
1649