xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision d1147a316b53df9cb0152e415ec41dcb6ea62c1c)
16e0355afSGovind Singh // SPDX-License-Identifier: BSD-3-Clause-Clear
26e0355afSGovind Singh /*
36e0355afSGovind Singh  * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
46e0355afSGovind Singh  */
56e0355afSGovind Singh 
66e0355afSGovind Singh #include <linux/module.h>
75697a564SGovind Singh #include <linux/msi.h>
86e0355afSGovind Singh #include <linux/pci.h>
96e0355afSGovind Singh 
105762613eSGovind Singh #include "pci.h"
116e0355afSGovind Singh #include "core.h"
121399fb87SGovind Singh #include "hif.h"
131399fb87SGovind Singh #include "mhi.h"
146e0355afSGovind Singh #include "debug.h"
156e0355afSGovind Singh 
165762613eSGovind Singh #define ATH11K_PCI_BAR_NUM		0
175762613eSGovind Singh #define ATH11K_PCI_DMA_MASK		32
185762613eSGovind Singh 
197f4beda2SGovind Singh #define ATH11K_PCI_IRQ_CE0_OFFSET	3
204ab4693fSCarl Huang #define ATH11K_PCI_IRQ_DP_OFFSET	14
217f4beda2SGovind Singh 
22654e959aSGovind Singh #define WINDOW_ENABLE_BIT		0x40000000
23654e959aSGovind Singh #define WINDOW_REG_ADDRESS		0x310c
24654e959aSGovind Singh #define WINDOW_VALUE_MASK		GENMASK(24, 19)
25654e959aSGovind Singh #define WINDOW_START			0x80000
26654e959aSGovind Singh #define WINDOW_RANGE_MASK		GENMASK(18, 0)
27654e959aSGovind Singh 
2818ac1665SKalle Valo #define TCSR_SOC_HW_VERSION		0x0224
29*d1147a31SBaochen Qiang #define TCSR_SOC_HW_VERSION_MAJOR_MASK	GENMASK(11, 8)
3018ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MINOR_MASK	GENMASK(7, 0)
3118ac1665SKalle Valo 
32a05bd851SCarl Huang /* BAR0 + 4k is always accessible, and no
33a05bd851SCarl Huang  * need to force wakeup.
34a05bd851SCarl Huang  * 4K - 32 = 0xFE0
35a05bd851SCarl Huang  */
36a05bd851SCarl Huang #define ACCESS_ALWAYS_OFF 0xFE0
37a05bd851SCarl Huang 
386e0355afSGovind Singh #define QCA6390_DEVICE_ID		0x1101
394e809461SAnilkumar Kolli #define QCN9074_DEVICE_ID		0x1104
400fbf1957SBaochen Qiang #define WCN6855_DEVICE_ID		0x1103
416e0355afSGovind Singh 
426e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = {
436e0355afSGovind Singh 	{ PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) },
440fbf1957SBaochen Qiang 	{ PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) },
4549f5b114SAnilkumar Kolli 	{ PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) },
466e0355afSGovind Singh 	{0}
476e0355afSGovind Singh };
486e0355afSGovind Singh 
496e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table);
506e0355afSGovind Singh 
511ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = {
521ff8ed78SGovind Singh 	.mhi_support = true,
5356970454SGovind Singh 	.m3_fw_support = true,
546eb6ea51SGovind Singh 	.fixed_bdf_addr = false,
556eb6ea51SGovind Singh 	.fixed_mem_region = false,
561ff8ed78SGovind Singh };
571ff8ed78SGovind Singh 
587a3aed0cSAnilkumar Kolli static const struct ath11k_msi_config ath11k_msi_config[] = {
597a3aed0cSAnilkumar Kolli 	{
605697a564SGovind Singh 		.total_vectors = 32,
615697a564SGovind Singh 		.total_users = 4,
625697a564SGovind Singh 		.users = (struct ath11k_msi_user[]) {
635697a564SGovind Singh 			{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
645697a564SGovind Singh 			{ .name = "CE", .num_vectors = 10, .base_vector = 3 },
655697a564SGovind Singh 			{ .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
665697a564SGovind Singh 			{ .name = "DP", .num_vectors = 18, .base_vector = 14 },
675697a564SGovind Singh 		},
687a3aed0cSAnilkumar Kolli 	},
694e809461SAnilkumar Kolli 	{
704e809461SAnilkumar Kolli 		.total_vectors = 16,
714e809461SAnilkumar Kolli 		.total_users = 3,
724e809461SAnilkumar Kolli 		.users = (struct ath11k_msi_user[]) {
734e809461SAnilkumar Kolli 			{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
744e809461SAnilkumar Kolli 			{ .name = "CE", .num_vectors = 5, .base_vector = 3 },
754e809461SAnilkumar Kolli 			{ .name = "DP", .num_vectors = 8, .base_vector = 8 },
764e809461SAnilkumar Kolli 		},
774e809461SAnilkumar Kolli 	},
785697a564SGovind Singh };
795697a564SGovind Singh 
80ac6e7348SCarl Huang static const struct ath11k_msi_config msi_config_one_msi = {
81ac6e7348SCarl Huang 	.total_vectors = 1,
82ac6e7348SCarl Huang 	.total_users = 4,
83ac6e7348SCarl Huang 	.users = (struct ath11k_msi_user[]) {
84ac6e7348SCarl Huang 		{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
85ac6e7348SCarl Huang 		{ .name = "CE", .num_vectors = 1, .base_vector = 0 },
86ac6e7348SCarl Huang 		{ .name = "WAKE", .num_vectors = 1, .base_vector = 0 },
87ac6e7348SCarl Huang 		{ .name = "DP", .num_vectors = 1, .base_vector = 0 },
88ac6e7348SCarl Huang 	},
89ac6e7348SCarl Huang };
90ac6e7348SCarl Huang 
917f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
927f4beda2SGovind Singh 	"bhi",
937f4beda2SGovind Singh 	"mhi-er0",
947f4beda2SGovind Singh 	"mhi-er1",
957f4beda2SGovind Singh 	"ce0",
967f4beda2SGovind Singh 	"ce1",
977f4beda2SGovind Singh 	"ce2",
987f4beda2SGovind Singh 	"ce3",
997f4beda2SGovind Singh 	"ce4",
1007f4beda2SGovind Singh 	"ce5",
1017f4beda2SGovind Singh 	"ce6",
1027f4beda2SGovind Singh 	"ce7",
1037f4beda2SGovind Singh 	"ce8",
1047f4beda2SGovind Singh 	"ce9",
1057f4beda2SGovind Singh 	"ce10",
1067f4beda2SGovind Singh 	"ce11",
1077f4beda2SGovind Singh 	"host2wbm-desc-feed",
1087f4beda2SGovind Singh 	"host2reo-re-injection",
1097f4beda2SGovind Singh 	"host2reo-command",
1107f4beda2SGovind Singh 	"host2rxdma-monitor-ring3",
1117f4beda2SGovind Singh 	"host2rxdma-monitor-ring2",
1127f4beda2SGovind Singh 	"host2rxdma-monitor-ring1",
1137f4beda2SGovind Singh 	"reo2ost-exception",
1147f4beda2SGovind Singh 	"wbm2host-rx-release",
1157f4beda2SGovind Singh 	"reo2host-status",
1167f4beda2SGovind Singh 	"reo2host-destination-ring4",
1177f4beda2SGovind Singh 	"reo2host-destination-ring3",
1187f4beda2SGovind Singh 	"reo2host-destination-ring2",
1197f4beda2SGovind Singh 	"reo2host-destination-ring1",
1207f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac3",
1217f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac2",
1227f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac1",
1237f4beda2SGovind Singh 	"ppdu-end-interrupts-mac3",
1247f4beda2SGovind Singh 	"ppdu-end-interrupts-mac2",
1257f4beda2SGovind Singh 	"ppdu-end-interrupts-mac1",
1267f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac3",
1277f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac2",
1287f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac1",
1297f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac3",
1307f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac2",
1317f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac1",
1327f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac3",
1337f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac2",
1347f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac1",
1357f4beda2SGovind Singh 	"host2tcl-input-ring4",
1367f4beda2SGovind Singh 	"host2tcl-input-ring3",
1377f4beda2SGovind Singh 	"host2tcl-input-ring2",
1387f4beda2SGovind Singh 	"host2tcl-input-ring1",
1397f4beda2SGovind Singh 	"wbm2host-tx-completions-ring3",
1407f4beda2SGovind Singh 	"wbm2host-tx-completions-ring2",
1417f4beda2SGovind Singh 	"wbm2host-tx-completions-ring1",
1427f4beda2SGovind Singh 	"tcl2host-status-ring",
1437f4beda2SGovind Singh };
1447f4beda2SGovind Singh 
145654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset)
146654e959aSGovind Singh {
147654e959aSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
148654e959aSGovind Singh 
149654e959aSGovind Singh 	u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset);
150654e959aSGovind Singh 
151654e959aSGovind Singh 	lockdep_assert_held(&ab_pci->window_lock);
152654e959aSGovind Singh 
153654e959aSGovind Singh 	if (window != ab_pci->register_window) {
154654e959aSGovind Singh 		iowrite32(WINDOW_ENABLE_BIT | window,
155654e959aSGovind Singh 			  ab->mem + WINDOW_REG_ADDRESS);
156f6fa37a4SCarl Huang 		ioread32(ab->mem + WINDOW_REG_ADDRESS);
157654e959aSGovind Singh 		ab_pci->register_window = window;
158654e959aSGovind Singh 	}
159654e959aSGovind Singh }
160654e959aSGovind Singh 
161480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci)
162480a7361SKarthikeyan Periyasamy {
163480a7361SKarthikeyan Periyasamy 	u32 umac_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET);
164480a7361SKarthikeyan Periyasamy 	u32 ce_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE);
165480a7361SKarthikeyan Periyasamy 	u32 window;
166480a7361SKarthikeyan Periyasamy 
167480a7361SKarthikeyan Periyasamy 	window = (umac_window << 12) | (ce_window << 6);
168480a7361SKarthikeyan Periyasamy 
169480a7361SKarthikeyan Periyasamy 	iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + WINDOW_REG_ADDRESS);
170480a7361SKarthikeyan Periyasamy }
171480a7361SKarthikeyan Periyasamy 
172480a7361SKarthikeyan Periyasamy static inline u32 ath11k_pci_get_window_start(struct ath11k_base *ab,
173480a7361SKarthikeyan Periyasamy 					      u32 offset)
174480a7361SKarthikeyan Periyasamy {
175480a7361SKarthikeyan Periyasamy 	u32 window_start;
176480a7361SKarthikeyan Periyasamy 
177480a7361SKarthikeyan Periyasamy 	/* If offset lies within DP register range, use 3rd window */
178480a7361SKarthikeyan Periyasamy 	if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < WINDOW_RANGE_MASK)
179480a7361SKarthikeyan Periyasamy 		window_start = 3 * WINDOW_START;
180480a7361SKarthikeyan Periyasamy 	/* If offset lies within CE register range, use 2nd window */
181480a7361SKarthikeyan Periyasamy 	else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK)
182480a7361SKarthikeyan Periyasamy 		window_start = 2 * WINDOW_START;
183480a7361SKarthikeyan Periyasamy 	else
184480a7361SKarthikeyan Periyasamy 		window_start = WINDOW_START;
185480a7361SKarthikeyan Periyasamy 
186480a7361SKarthikeyan Periyasamy 	return window_start;
187480a7361SKarthikeyan Periyasamy }
188480a7361SKarthikeyan Periyasamy 
189f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
190654e959aSGovind Singh {
191654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
192480a7361SKarthikeyan Periyasamy 	u32 window_start;
193654e959aSGovind Singh 
194a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
195a05bd851SCarl Huang 	 * need to wakeup MHI to access.
196a05bd851SCarl Huang 	 */
197081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
198081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
199a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
200a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
201a05bd851SCarl Huang 
202654e959aSGovind Singh 	if (offset < WINDOW_START) {
203654e959aSGovind Singh 		iowrite32(value, ab->mem  + offset);
204654e959aSGovind Singh 	} else {
205480a7361SKarthikeyan Periyasamy 		if (ab->bus_params.static_window_map)
206480a7361SKarthikeyan Periyasamy 			window_start = ath11k_pci_get_window_start(ab, offset);
207480a7361SKarthikeyan Periyasamy 		else
208480a7361SKarthikeyan Periyasamy 			window_start = WINDOW_START;
209480a7361SKarthikeyan Periyasamy 
210480a7361SKarthikeyan Periyasamy 		if (window_start == WINDOW_START) {
211654e959aSGovind Singh 			spin_lock_bh(&ab_pci->window_lock);
212654e959aSGovind Singh 			ath11k_pci_select_window(ab_pci, offset);
213480a7361SKarthikeyan Periyasamy 			iowrite32(value, ab->mem + window_start +
214480a7361SKarthikeyan Periyasamy 				  (offset & WINDOW_RANGE_MASK));
215654e959aSGovind Singh 			spin_unlock_bh(&ab_pci->window_lock);
216480a7361SKarthikeyan Periyasamy 		} else {
217480a7361SKarthikeyan Periyasamy 			iowrite32(value, ab->mem + window_start +
218480a7361SKarthikeyan Periyasamy 				  (offset & WINDOW_RANGE_MASK));
219480a7361SKarthikeyan Periyasamy 		}
220654e959aSGovind Singh 	}
221a05bd851SCarl Huang 
222081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
223081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
224a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
225a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
226654e959aSGovind Singh }
227654e959aSGovind Singh 
228f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
229654e959aSGovind Singh {
230654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
231480a7361SKarthikeyan Periyasamy 	u32 val, window_start;
232654e959aSGovind Singh 
233a05bd851SCarl Huang 	/* for offset beyond BAR + 4K - 32, may
234a05bd851SCarl Huang 	 * need to wakeup MHI to access.
235a05bd851SCarl Huang 	 */
236081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
237081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
238a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
239a05bd851SCarl Huang 		mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
240a05bd851SCarl Huang 
241654e959aSGovind Singh 	if (offset < WINDOW_START) {
242654e959aSGovind Singh 		val = ioread32(ab->mem + offset);
243654e959aSGovind Singh 	} else {
244480a7361SKarthikeyan Periyasamy 		if (ab->bus_params.static_window_map)
245480a7361SKarthikeyan Periyasamy 			window_start = ath11k_pci_get_window_start(ab, offset);
246480a7361SKarthikeyan Periyasamy 		else
247480a7361SKarthikeyan Periyasamy 			window_start = WINDOW_START;
248480a7361SKarthikeyan Periyasamy 
249480a7361SKarthikeyan Periyasamy 		if (window_start == WINDOW_START) {
250654e959aSGovind Singh 			spin_lock_bh(&ab_pci->window_lock);
251654e959aSGovind Singh 			ath11k_pci_select_window(ab_pci, offset);
252480a7361SKarthikeyan Periyasamy 			val = ioread32(ab->mem + window_start +
253480a7361SKarthikeyan Periyasamy 				       (offset & WINDOW_RANGE_MASK));
254654e959aSGovind Singh 			spin_unlock_bh(&ab_pci->window_lock);
255480a7361SKarthikeyan Periyasamy 		} else {
256480a7361SKarthikeyan Periyasamy 			val = ioread32(ab->mem + window_start +
257480a7361SKarthikeyan Periyasamy 				       (offset & WINDOW_RANGE_MASK));
258480a7361SKarthikeyan Periyasamy 		}
259654e959aSGovind Singh 	}
260654e959aSGovind Singh 
261081e2d64SSeevalamuthu Mariappan 	if (ab->hw_params.wakeup_mhi &&
262081e2d64SSeevalamuthu Mariappan 	    test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
263a05bd851SCarl Huang 	    offset >= ACCESS_ALWAYS_OFF)
264a05bd851SCarl Huang 		mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
265a05bd851SCarl Huang 
266654e959aSGovind Singh 	return val;
267654e959aSGovind Singh }
268654e959aSGovind Singh 
269f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
270f3c603d4SCarl Huang {
271f3c603d4SCarl Huang 	u32 val, delay;
272f3c603d4SCarl Huang 
273f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
274f3c603d4SCarl Huang 
275f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
276f3c603d4SCarl Huang 
277f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
278f3c603d4SCarl Huang 
279f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
280f3c603d4SCarl Huang 	delay = 10;
281f3c603d4SCarl Huang 	mdelay(delay);
282f3c603d4SCarl Huang 
283f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
284f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
285f3c603d4SCarl Huang 
286f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
287f3c603d4SCarl Huang 
288f3c603d4SCarl Huang 	mdelay(delay);
289f3c603d4SCarl Huang 
290f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
291f3c603d4SCarl Huang 	if (val == 0xffffffff)
292f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
293f3c603d4SCarl Huang }
294f3c603d4SCarl Huang 
295f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
296f3c603d4SCarl Huang {
297f3c603d4SCarl Huang 	u32 val;
298f3c603d4SCarl Huang 
299f3c603d4SCarl Huang 	/* read cookie */
300f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR);
301f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val);
302f3c603d4SCarl Huang 
303f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
304f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
305f3c603d4SCarl Huang 
306f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
307f3c603d4SCarl Huang 	mdelay(10);
308f3c603d4SCarl Huang 
309f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
310f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
311f3c603d4SCarl Huang 	 */
312f3c603d4SCarl Huang 	ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0);
313f3c603d4SCarl Huang 	mdelay(10);
314f3c603d4SCarl Huang 
315f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
316f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
317f3c603d4SCarl Huang 
318f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
319f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
320f3c603d4SCarl Huang 	 */
321f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
322f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
323f3c603d4SCarl Huang }
324f3c603d4SCarl Huang 
32506999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab,
32606999407SCarl Huang 				   u32 offset, u32 value, u32 mask)
32706999407SCarl Huang {
32806999407SCarl Huang 	u32 v;
32906999407SCarl Huang 	int i;
33006999407SCarl Huang 
33106999407SCarl Huang 	v = ath11k_pci_read32(ab, offset);
33206999407SCarl Huang 	if ((v & mask) == value)
33306999407SCarl Huang 		return 0;
33406999407SCarl Huang 
33506999407SCarl Huang 	for (i = 0; i < 10; i++) {
33606999407SCarl Huang 		ath11k_pci_write32(ab, offset, (v & ~mask) | value);
33706999407SCarl Huang 
33806999407SCarl Huang 		v = ath11k_pci_read32(ab, offset);
33906999407SCarl Huang 		if ((v & mask) == value)
34006999407SCarl Huang 			return 0;
34106999407SCarl Huang 
34206999407SCarl Huang 		mdelay(2);
34306999407SCarl Huang 	}
34406999407SCarl Huang 
34506999407SCarl Huang 	ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n",
34606999407SCarl Huang 		    offset, v & mask, value);
34706999407SCarl Huang 
34806999407SCarl Huang 	return -ETIMEDOUT;
34906999407SCarl Huang }
35006999407SCarl Huang 
35106999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab)
35206999407SCarl Huang {
35306999407SCarl Huang 	int ret;
35406999407SCarl Huang 
35506999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3566fe6f68fSKarthikeyan Periyasamy 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab),
35706999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL,
35806999407SCarl Huang 				      PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK);
35930d08503SDan Carpenter 	if (ret) {
36006999407SCarl Huang 		ath11k_warn(ab, "failed to set sysclk: %d\n", ret);
36106999407SCarl Huang 		return ret;
36206999407SCarl Huang 	}
36306999407SCarl Huang 
36406999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3656fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab),
3666fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG1_VAL,
3676fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
36830d08503SDan Carpenter 	if (ret) {
36906999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret);
37006999407SCarl Huang 		return ret;
37106999407SCarl Huang 	}
37206999407SCarl Huang 
37306999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3746fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab),
3756fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG2_VAL,
3766fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
37730d08503SDan Carpenter 	if (ret) {
37806999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config2: %d\n", ret);
37906999407SCarl Huang 		return ret;
38006999407SCarl Huang 	}
38106999407SCarl Huang 
38206999407SCarl Huang 	ret = ath11k_pci_set_link_reg(ab,
3836fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab),
3846fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG4_VAL,
3856fe6f68fSKarthikeyan Periyasamy 				      PCIE_PCS_OSC_DTCT_CONFIG_MSK);
38630d08503SDan Carpenter 	if (ret) {
38706999407SCarl Huang 		ath11k_warn(ab, "failed to set dtct config4: %d\n", ret);
38806999407SCarl Huang 		return ret;
38906999407SCarl Huang 	}
39006999407SCarl Huang 
39106999407SCarl Huang 	return 0;
39206999407SCarl Huang }
39306999407SCarl Huang 
394babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
395babb0cedSCarl Huang {
396babb0cedSCarl Huang 	u32 val;
397babb0cedSCarl Huang 	int i;
398babb0cedSCarl Huang 
399babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
400babb0cedSCarl Huang 
401babb0cedSCarl Huang 	/* PCIE link seems very unstable after the Hot Reset*/
402babb0cedSCarl Huang 	for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {
403babb0cedSCarl Huang 		if (val == 0xffffffff)
404babb0cedSCarl Huang 			mdelay(5);
405babb0cedSCarl Huang 
406babb0cedSCarl Huang 		ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);
407babb0cedSCarl Huang 		val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);
408babb0cedSCarl Huang 	}
409babb0cedSCarl Huang 
410babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val);
411babb0cedSCarl Huang 
412babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
413562934adSKalle Valo 	val |= GCC_GCC_PCIE_HOT_RST_VAL;
414babb0cedSCarl Huang 	ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
415babb0cedSCarl Huang 	val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
416babb0cedSCarl Huang 
417babb0cedSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val);
418babb0cedSCarl Huang 
419babb0cedSCarl Huang 	mdelay(5);
420babb0cedSCarl Huang }
421babb0cedSCarl Huang 
422babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab)
423babb0cedSCarl Huang {
424babb0cedSCarl Huang 	/* This is a WAR for PCIE Hotreset.
425babb0cedSCarl Huang 	 * When target receive Hotreset, but will set the interrupt.
426babb0cedSCarl Huang 	 * So when download SBL again, SBL will open Interrupt and
427babb0cedSCarl Huang 	 * receive it, and crash immediately.
428babb0cedSCarl Huang 	 */
429babb0cedSCarl Huang 	ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);
430babb0cedSCarl Huang }
431babb0cedSCarl Huang 
4320ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab)
4330ccdf439SCarl Huang {
4340ccdf439SCarl Huang 	u32 val;
4350ccdf439SCarl Huang 
4360ccdf439SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG);
4370ccdf439SCarl Huang 	val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK;
4380ccdf439SCarl Huang 	ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val);
4390ccdf439SCarl Huang }
4400ccdf439SCarl Huang 
441f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
442f3c603d4SCarl Huang {
443f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
444f3c603d4SCarl Huang 	mdelay(5);
445f3c603d4SCarl Huang }
446f3c603d4SCarl Huang 
447babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on)
448f3c603d4SCarl Huang {
4498a0b899fSBaochen Qiang 	mdelay(100);
4508a0b899fSBaochen Qiang 
451babb0cedSCarl Huang 	if (power_on) {
452babb0cedSCarl Huang 		ath11k_pci_enable_ltssm(ab);
453babb0cedSCarl Huang 		ath11k_pci_clear_all_intrs(ab);
4540ccdf439SCarl Huang 		ath11k_pci_set_wlaon_pwr_ctrl(ab);
4555088df05SBaochen Qiang 		if (ab->hw_params.fix_l1ss)
45606999407SCarl Huang 			ath11k_pci_fix_l1ss(ab);
457babb0cedSCarl Huang 	}
458babb0cedSCarl Huang 
459f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
4608a0b899fSBaochen Qiang 	ath11k_pci_clear_dbg_registers(ab);
461f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
462f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
463f3c603d4SCarl Huang }
464f3c603d4SCarl Huang 
4651399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
4661399fb87SGovind Singh {
4671399fb87SGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(dev);
4681399fb87SGovind Singh 
4691399fb87SGovind Singh 	return pci_irq_vector(pci_dev, vector);
4701399fb87SGovind Singh }
4711399fb87SGovind Singh 
472c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
473c4eacabeSGovind Singh 				       u32 *msi_addr_hi)
474c4eacabeSGovind Singh {
475e8e55d89SAnilkumar Kolli 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
476c4eacabeSGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
477c4eacabeSGovind Singh 
478c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
479c4eacabeSGovind Singh 			      msi_addr_lo);
480c4eacabeSGovind Singh 
481e8e55d89SAnilkumar Kolli 	if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) {
482c4eacabeSGovind Singh 		pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
483c4eacabeSGovind Singh 				      msi_addr_hi);
484e8e55d89SAnilkumar Kolli 	} else {
485e8e55d89SAnilkumar Kolli 		*msi_addr_hi = 0;
486e8e55d89SAnilkumar Kolli 	}
487c4eacabeSGovind Singh }
488c4eacabeSGovind Singh 
4891399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
4901399fb87SGovind Singh 				       int *num_vectors, u32 *user_base_data,
4911399fb87SGovind Singh 				       u32 *base_vector)
4921399fb87SGovind Singh {
4931399fb87SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4947a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
4951399fb87SGovind Singh 	int idx;
4961399fb87SGovind Singh 
4977a3aed0cSAnilkumar Kolli 	for (idx = 0; idx < msi_config->total_users; idx++) {
4987a3aed0cSAnilkumar Kolli 		if (strcmp(user_name, msi_config->users[idx].name) == 0) {
4997a3aed0cSAnilkumar Kolli 			*num_vectors = msi_config->users[idx].num_vectors;
5007a3aed0cSAnilkumar Kolli 			*base_vector =  msi_config->users[idx].base_vector;
501c41a6700SCarl Huang 			*user_base_data = *base_vector + ab_pci->msi_ep_base_data;
5021399fb87SGovind Singh 
503c41a6700SCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
504c41a6700SCarl Huang 				   "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
5051399fb87SGovind Singh 				   user_name, *num_vectors, *user_base_data,
5061399fb87SGovind Singh 				   *base_vector);
5071399fb87SGovind Singh 
5081399fb87SGovind Singh 			return 0;
5091399fb87SGovind Singh 		}
5101399fb87SGovind Singh 	}
5111399fb87SGovind Singh 
5121399fb87SGovind Singh 	ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
5131399fb87SGovind Singh 
5141399fb87SGovind Singh 	return -EINVAL;
5151399fb87SGovind Singh }
5161399fb87SGovind Singh 
5176289ac2bSKarthikeyan Periyasamy static void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id,
5186289ac2bSKarthikeyan Periyasamy 				      u32 *msi_idx)
5196289ac2bSKarthikeyan Periyasamy {
5206289ac2bSKarthikeyan Periyasamy 	u32 i, msi_data_idx;
5216289ac2bSKarthikeyan Periyasamy 
5226289ac2bSKarthikeyan Periyasamy 	for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
5236289ac2bSKarthikeyan Periyasamy 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5246289ac2bSKarthikeyan Periyasamy 			continue;
5256289ac2bSKarthikeyan Periyasamy 
5266289ac2bSKarthikeyan Periyasamy 		if (ce_id == i)
5276289ac2bSKarthikeyan Periyasamy 			break;
5286289ac2bSKarthikeyan Periyasamy 
5296289ac2bSKarthikeyan Periyasamy 		msi_data_idx++;
5306289ac2bSKarthikeyan Periyasamy 	}
5316289ac2bSKarthikeyan Periyasamy 	*msi_idx = msi_data_idx;
5326289ac2bSKarthikeyan Periyasamy }
5336289ac2bSKarthikeyan Periyasamy 
534c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
535c4eacabeSGovind Singh 					  int *num_vectors, u32 *user_base_data,
536c4eacabeSGovind Singh 					  u32 *base_vector)
537c4eacabeSGovind Singh {
538c4eacabeSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
539c4eacabeSGovind Singh 
540c4eacabeSGovind Singh 	return ath11k_pci_get_user_msi_assignment(ab_pci, user_name,
541c4eacabeSGovind Singh 						  num_vectors, user_base_data,
542c4eacabeSGovind Singh 						  base_vector);
543c4eacabeSGovind Singh }
544c4eacabeSGovind Singh 
545d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
546d4ecb90bSCarl Huang {
547d4ecb90bSCarl Huang 	int i, j;
548d4ecb90bSCarl Huang 
549d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
550d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
551d4ecb90bSCarl Huang 
552d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++)
553d4ecb90bSCarl Huang 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
554d4ecb90bSCarl Huang 
555d4ecb90bSCarl Huang 		netif_napi_del(&irq_grp->napi);
556d4ecb90bSCarl Huang 	}
557d4ecb90bSCarl Huang }
558d4ecb90bSCarl Huang 
5597f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab)
5607f4beda2SGovind Singh {
5617f4beda2SGovind Singh 	int i, irq_idx;
5627f4beda2SGovind Singh 
563d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
564e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5657f4beda2SGovind Singh 			continue;
5667f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5677f4beda2SGovind Singh 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
5687f4beda2SGovind Singh 	}
569d4ecb90bSCarl Huang 
570d4ecb90bSCarl Huang 	ath11k_pci_free_ext_irq(ab);
5717f4beda2SGovind Singh }
5727f4beda2SGovind Singh 
5732c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
5742c3960c2SGovind Singh {
575c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
5762c3960c2SGovind Singh 	u32 irq_idx;
5772c3960c2SGovind Singh 
578c41a6700SCarl Huang 	/* In case of one MSI vector, we handle irq enable/disable in a
579c41a6700SCarl Huang 	 * uniform way since we only have one irq
580c41a6700SCarl Huang 	 */
581c41a6700SCarl Huang 	if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
582c41a6700SCarl Huang 		return;
583c41a6700SCarl Huang 
5842c3960c2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
5852c3960c2SGovind Singh 	enable_irq(ab->irq_num[irq_idx]);
5862c3960c2SGovind Singh }
5872c3960c2SGovind Singh 
5887f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
5897f4beda2SGovind Singh {
590c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
5917f4beda2SGovind Singh 	u32 irq_idx;
5927f4beda2SGovind Singh 
593c41a6700SCarl Huang 	/* In case of one MSI vector, we handle irq enable/disable in a
594c41a6700SCarl Huang 	 * uniform way since we only have one irq
595c41a6700SCarl Huang 	 */
596c41a6700SCarl Huang 	if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
597c41a6700SCarl Huang 		return;
598c41a6700SCarl Huang 
5997f4beda2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
6007f4beda2SGovind Singh 	disable_irq_nosync(ab->irq_num[irq_idx]);
6017f4beda2SGovind Singh }
6027f4beda2SGovind Singh 
6032c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
6042c3960c2SGovind Singh {
6052c3960c2SGovind Singh 	int i;
6062c3960c2SGovind Singh 
60701279bcdSCarl Huang 	clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
60801279bcdSCarl Huang 
609d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
610e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
6112c3960c2SGovind Singh 			continue;
6122c3960c2SGovind Singh 		ath11k_pci_ce_irq_disable(ab, i);
6132c3960c2SGovind Singh 	}
6142c3960c2SGovind Singh }
6152c3960c2SGovind Singh 
6162c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
6172c3960c2SGovind Singh {
6182c3960c2SGovind Singh 	int i;
6192c3960c2SGovind Singh 	int irq_idx;
6202c3960c2SGovind Singh 
621d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
622e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
6232c3960c2SGovind Singh 			continue;
6242c3960c2SGovind Singh 
6252c3960c2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
6262c3960c2SGovind Singh 		synchronize_irq(ab->irq_num[irq_idx]);
6272c3960c2SGovind Singh 	}
6282c3960c2SGovind Singh }
6292c3960c2SGovind Singh 
6300f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t)
6312c3960c2SGovind Singh {
6320f01dcb8SAllen Pais 	struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
633ac6e7348SCarl Huang 	int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
6342c3960c2SGovind Singh 
6352c3960c2SGovind Singh 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
6362c3960c2SGovind Singh 
637ac6e7348SCarl Huang 	enable_irq(ce_pipe->ab->irq_num[irq_idx]);
6382c3960c2SGovind Singh }
6392c3960c2SGovind Singh 
6407f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
6417f4beda2SGovind Singh {
6427f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = arg;
64301279bcdSCarl Huang 	struct ath11k_base *ab = ce_pipe->ab;
644ac6e7348SCarl Huang 	int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
64501279bcdSCarl Huang 
64601279bcdSCarl Huang 	if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags))
64701279bcdSCarl Huang 		return IRQ_HANDLED;
6487f4beda2SGovind Singh 
6497dc67af0SKarthikeyan Periyasamy 	/* last interrupt received for this CE */
6507dc67af0SKarthikeyan Periyasamy 	ce_pipe->timestamp = jiffies;
6517dc67af0SKarthikeyan Periyasamy 
652ac6e7348SCarl Huang 	disable_irq_nosync(ab->irq_num[irq_idx]);
653ac6e7348SCarl Huang 
6542c3960c2SGovind Singh 	tasklet_schedule(&ce_pipe->intr_tq);
6557f4beda2SGovind Singh 
6567f4beda2SGovind Singh 	return IRQ_HANDLED;
6577f4beda2SGovind Singh }
6587f4beda2SGovind Singh 
659d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
660d4ecb90bSCarl Huang {
661c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab);
662d4ecb90bSCarl Huang 	int i;
663d4ecb90bSCarl Huang 
664c41a6700SCarl Huang 	/* In case of one MSI vector, we handle irq enable/disable
665c41a6700SCarl Huang 	 * in a uniform way since we only have one irq
666c41a6700SCarl Huang 	 */
667c41a6700SCarl Huang 	if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
668c41a6700SCarl Huang 		return;
669c41a6700SCarl Huang 
670d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
671d4ecb90bSCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
672d4ecb90bSCarl Huang }
673d4ecb90bSCarl Huang 
674d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
675d4ecb90bSCarl Huang {
676d4ecb90bSCarl Huang 	int i;
677d4ecb90bSCarl Huang 
67801279bcdSCarl Huang 	clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags);
67901279bcdSCarl Huang 
680d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
681d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
682d4ecb90bSCarl Huang 
683d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
684d4ecb90bSCarl Huang 
685d4ecb90bSCarl Huang 		napi_synchronize(&irq_grp->napi);
686d4ecb90bSCarl Huang 		napi_disable(&irq_grp->napi);
687d4ecb90bSCarl Huang 	}
688d4ecb90bSCarl Huang }
689d4ecb90bSCarl Huang 
690d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
691d4ecb90bSCarl Huang {
692c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab);
693d4ecb90bSCarl Huang 	int i;
694d4ecb90bSCarl Huang 
695c41a6700SCarl Huang 	/* In case of one MSI vector, we handle irq enable/disable in a
696c41a6700SCarl Huang 	 * uniform way since we only have one irq
697c41a6700SCarl Huang 	 */
698c41a6700SCarl Huang 	if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
699c41a6700SCarl Huang 		return;
700c41a6700SCarl Huang 
701d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
702d4ecb90bSCarl Huang 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
703d4ecb90bSCarl Huang }
704d4ecb90bSCarl Huang 
705d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
706d4ecb90bSCarl Huang {
707d4ecb90bSCarl Huang 	int i;
708d4ecb90bSCarl Huang 
70901279bcdSCarl Huang 	set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags);
71001279bcdSCarl Huang 
711d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
712d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
713d4ecb90bSCarl Huang 
714d4ecb90bSCarl Huang 		napi_enable(&irq_grp->napi);
715d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
716d4ecb90bSCarl Huang 	}
717d4ecb90bSCarl Huang }
718d4ecb90bSCarl Huang 
719d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
720d4ecb90bSCarl Huang {
721d4ecb90bSCarl Huang 	int i, j, irq_idx;
722d4ecb90bSCarl Huang 
723d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
724d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
725d4ecb90bSCarl Huang 
726d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
727d4ecb90bSCarl Huang 			irq_idx = irq_grp->irqs[j];
728d4ecb90bSCarl Huang 			synchronize_irq(ab->irq_num[irq_idx]);
729d4ecb90bSCarl Huang 		}
730d4ecb90bSCarl Huang 	}
731d4ecb90bSCarl Huang }
732d4ecb90bSCarl Huang 
733d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
734d4ecb90bSCarl Huang {
735d4ecb90bSCarl Huang 	__ath11k_pci_ext_irq_disable(ab);
736d4ecb90bSCarl Huang 	ath11k_pci_sync_ext_irqs(ab);
737d4ecb90bSCarl Huang }
738d4ecb90bSCarl Huang 
739d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
740d4ecb90bSCarl Huang {
741d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
742d4ecb90bSCarl Huang 						struct ath11k_ext_irq_grp,
743d4ecb90bSCarl Huang 						napi);
744d4ecb90bSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
745d4ecb90bSCarl Huang 	int work_done;
746ac6e7348SCarl Huang 	int i;
747d4ecb90bSCarl Huang 
748d4ecb90bSCarl Huang 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
749d4ecb90bSCarl Huang 	if (work_done < budget) {
750d4ecb90bSCarl Huang 		napi_complete_done(napi, work_done);
751ac6e7348SCarl Huang 		for (i = 0; i < irq_grp->num_irq; i++)
752ac6e7348SCarl Huang 			enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
753d4ecb90bSCarl Huang 	}
754d4ecb90bSCarl Huang 
755d4ecb90bSCarl Huang 	if (work_done > budget)
756d4ecb90bSCarl Huang 		work_done = budget;
757d4ecb90bSCarl Huang 
758d4ecb90bSCarl Huang 	return work_done;
759d4ecb90bSCarl Huang }
760d4ecb90bSCarl Huang 
761d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
762d4ecb90bSCarl Huang {
763d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = arg;
76401279bcdSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
765ac6e7348SCarl Huang 	int i;
76601279bcdSCarl Huang 
76701279bcdSCarl Huang 	if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags))
76801279bcdSCarl Huang 		return IRQ_HANDLED;
769d4ecb90bSCarl Huang 
770d4ecb90bSCarl Huang 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
771d4ecb90bSCarl Huang 
7727dc67af0SKarthikeyan Periyasamy 	/* last interrupt received for this group */
7737dc67af0SKarthikeyan Periyasamy 	irq_grp->timestamp = jiffies;
7747dc67af0SKarthikeyan Periyasamy 
775ac6e7348SCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
776ac6e7348SCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
777d4ecb90bSCarl Huang 
778d4ecb90bSCarl Huang 	napi_schedule(&irq_grp->napi);
779d4ecb90bSCarl Huang 
780d4ecb90bSCarl Huang 	return IRQ_HANDLED;
781d4ecb90bSCarl Huang }
782d4ecb90bSCarl Huang 
783d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
784d4ecb90bSCarl Huang {
785c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
786d4ecb90bSCarl Huang 	int i, j, ret, num_vectors = 0;
7874ab4693fSCarl Huang 	u32 user_base_data = 0, base_vector = 0;
788d4ecb90bSCarl Huang 
789b2c09458SColin Ian King 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
790b2c09458SColin Ian King 						 &num_vectors,
791b2c09458SColin Ian King 						 &user_base_data,
792d4ecb90bSCarl Huang 						 &base_vector);
793b2c09458SColin Ian King 	if (ret < 0)
794b2c09458SColin Ian King 		return ret;
795d4ecb90bSCarl Huang 
796d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
797d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
798d4ecb90bSCarl Huang 		u32 num_irq = 0;
799d4ecb90bSCarl Huang 
800d4ecb90bSCarl Huang 		irq_grp->ab = ab;
801d4ecb90bSCarl Huang 		irq_grp->grp_id = i;
802d4ecb90bSCarl Huang 		init_dummy_netdev(&irq_grp->napi_ndev);
803d4ecb90bSCarl Huang 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
804d4ecb90bSCarl Huang 			       ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
805d4ecb90bSCarl Huang 
806d4ecb90bSCarl Huang 		if (ab->hw_params.ring_mask->tx[i] ||
807d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx[i] ||
808d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_err[i] ||
809d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_wbm_rel[i] ||
810d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->reo_status[i] ||
811d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rxdma2host[i] ||
812d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->host2rxdma[i] ||
813d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_mon_status[i]) {
814d4ecb90bSCarl Huang 			num_irq = 1;
815d4ecb90bSCarl Huang 		}
816d4ecb90bSCarl Huang 
817d4ecb90bSCarl Huang 		irq_grp->num_irq = num_irq;
8184ab4693fSCarl Huang 		irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i;
819d4ecb90bSCarl Huang 
820d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
821d4ecb90bSCarl Huang 			int irq_idx = irq_grp->irqs[j];
822d4ecb90bSCarl Huang 			int vector = (i % num_vectors) + base_vector;
823d4ecb90bSCarl Huang 			int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
824d4ecb90bSCarl Huang 
825d4ecb90bSCarl Huang 			ab->irq_num[irq_idx] = irq;
826d4ecb90bSCarl Huang 
827d4ecb90bSCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
828d4ecb90bSCarl Huang 				   "irq:%d group:%d\n", irq, i);
8297dc67af0SKarthikeyan Periyasamy 
8307dc67af0SKarthikeyan Periyasamy 			irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
831d4ecb90bSCarl Huang 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
832c41a6700SCarl Huang 					  ab_pci->irq_flags,
833d4ecb90bSCarl Huang 					  "DP_EXT_IRQ", irq_grp);
834d4ecb90bSCarl Huang 			if (ret) {
835d4ecb90bSCarl Huang 				ath11k_err(ab, "failed request irq %d: %d\n",
836d4ecb90bSCarl Huang 					   vector, ret);
837d4ecb90bSCarl Huang 				return ret;
838d4ecb90bSCarl Huang 			}
839d4ecb90bSCarl Huang 		}
840c41a6700SCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
841d4ecb90bSCarl Huang 	}
842d4ecb90bSCarl Huang 
843d4ecb90bSCarl Huang 	return 0;
844d4ecb90bSCarl Huang }
845d4ecb90bSCarl Huang 
846e94b0749SBaochen Qiang static int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci,
847e94b0749SBaochen Qiang 					    const struct cpumask *m)
848e94b0749SBaochen Qiang {
849e94b0749SBaochen Qiang 	if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
850e94b0749SBaochen Qiang 		return 0;
851e94b0749SBaochen Qiang 
852e94b0749SBaochen Qiang 	return irq_set_affinity_hint(ab_pci->pdev->irq, m);
853e94b0749SBaochen Qiang }
854e94b0749SBaochen Qiang 
8557f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab)
8567f4beda2SGovind Singh {
857c41a6700SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
8587f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe;
8597f4beda2SGovind Singh 	u32 msi_data_start;
8606289ac2bSKarthikeyan Periyasamy 	u32 msi_data_count, msi_data_idx;
8617f4beda2SGovind Singh 	u32 msi_irq_start;
8627f4beda2SGovind Singh 	unsigned int msi_data;
8637f4beda2SGovind Singh 	int irq, i, ret, irq_idx;
8647f4beda2SGovind Singh 
8657f4beda2SGovind Singh 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab),
8667f4beda2SGovind Singh 						 "CE", &msi_data_count,
8677f4beda2SGovind Singh 						 &msi_data_start, &msi_irq_start);
8687f4beda2SGovind Singh 	if (ret)
8697f4beda2SGovind Singh 		return ret;
8707f4beda2SGovind Singh 
871e94b0749SBaochen Qiang 	ret = ath11k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0));
872e94b0749SBaochen Qiang 	if (ret) {
873e94b0749SBaochen Qiang 		ath11k_err(ab, "failed to set irq affinity %d\n", ret);
874e94b0749SBaochen Qiang 		return ret;
875e94b0749SBaochen Qiang 	}
876e94b0749SBaochen Qiang 
8777f4beda2SGovind Singh 	/* Configure CE irqs */
8786289ac2bSKarthikeyan Periyasamy 	for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) {
879e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
8807f4beda2SGovind Singh 			continue;
8817f4beda2SGovind Singh 
8826289ac2bSKarthikeyan Periyasamy 		msi_data = (msi_data_idx % msi_data_count) + msi_irq_start;
8836289ac2bSKarthikeyan Periyasamy 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
8846289ac2bSKarthikeyan Periyasamy 		ce_pipe = &ab->ce.ce_pipe[i];
8856289ac2bSKarthikeyan Periyasamy 
8867f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
8877f4beda2SGovind Singh 
8880f01dcb8SAllen Pais 		tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet);
8892c3960c2SGovind Singh 
8907f4beda2SGovind Singh 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
891c41a6700SCarl Huang 				  ab_pci->irq_flags, irq_name[irq_idx],
8927f4beda2SGovind Singh 				  ce_pipe);
8937f4beda2SGovind Singh 		if (ret) {
8947f4beda2SGovind Singh 			ath11k_err(ab, "failed to request irq %d: %d\n",
8957f4beda2SGovind Singh 				   irq_idx, ret);
896e94b0749SBaochen Qiang 			goto err_irq_affinity_cleanup;
8977f4beda2SGovind Singh 		}
8987f4beda2SGovind Singh 
8997f4beda2SGovind Singh 		ab->irq_num[irq_idx] = irq;
9006289ac2bSKarthikeyan Periyasamy 		msi_data_idx++;
901e678fbd4SKarthikeyan Periyasamy 
902e5c860e1SCarl Huang 		ath11k_pci_ce_irq_disable(ab, i);
9037f4beda2SGovind Singh 	}
9047f4beda2SGovind Singh 
905d4ecb90bSCarl Huang 	ret = ath11k_pci_ext_irq_config(ab);
906d4ecb90bSCarl Huang 	if (ret)
907e94b0749SBaochen Qiang 		goto err_irq_affinity_cleanup;
908d4ecb90bSCarl Huang 
9097f4beda2SGovind Singh 	return 0;
910e94b0749SBaochen Qiang 
911e94b0749SBaochen Qiang err_irq_affinity_cleanup:
912e94b0749SBaochen Qiang 	ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
913e94b0749SBaochen Qiang 	return ret;
9147f4beda2SGovind Singh }
9157f4beda2SGovind Singh 
9167f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
9177f4beda2SGovind Singh {
9187f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
9197f4beda2SGovind Singh 
920967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
921967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
9227f4beda2SGovind Singh 
923967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
924967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
92516001e4bSAnilkumar Kolli 	ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
926e838c14aSCarl Huang 
927e838c14aSCarl Huang 	ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
928e838c14aSCarl Huang 				    &cfg->shadow_reg_v2_len);
9297f4beda2SGovind Singh }
9307f4beda2SGovind Singh 
9317f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
9327f4beda2SGovind Singh {
9337f4beda2SGovind Singh 	int i;
9347f4beda2SGovind Singh 
93501279bcdSCarl Huang 	set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
93601279bcdSCarl Huang 
937d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
938e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
9397f4beda2SGovind Singh 			continue;
9407f4beda2SGovind Singh 		ath11k_pci_ce_irq_enable(ab, i);
9417f4beda2SGovind Singh 	}
9427f4beda2SGovind Singh }
9437f4beda2SGovind Singh 
94496527d52SBaochen Qiang static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable)
94596527d52SBaochen Qiang {
94696527d52SBaochen Qiang 	struct pci_dev *dev = ab_pci->pdev;
94796527d52SBaochen Qiang 	u16 control;
94896527d52SBaochen Qiang 
94996527d52SBaochen Qiang 	pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
95096527d52SBaochen Qiang 
95196527d52SBaochen Qiang 	if (enable)
95296527d52SBaochen Qiang 		control |= PCI_MSI_FLAGS_ENABLE;
95396527d52SBaochen Qiang 	else
95496527d52SBaochen Qiang 		control &= ~PCI_MSI_FLAGS_ENABLE;
95596527d52SBaochen Qiang 
95696527d52SBaochen Qiang 	pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
95796527d52SBaochen Qiang }
95896527d52SBaochen Qiang 
95996527d52SBaochen Qiang static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci)
96096527d52SBaochen Qiang {
96196527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, true);
96296527d52SBaochen Qiang }
96396527d52SBaochen Qiang 
96496527d52SBaochen Qiang static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci)
96596527d52SBaochen Qiang {
96696527d52SBaochen Qiang 	ath11k_pci_msi_config(ab_pci, false);
96796527d52SBaochen Qiang }
96896527d52SBaochen Qiang 
96996527d52SBaochen Qiang static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci)
9705697a564SGovind Singh {
9715697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
9727a3aed0cSAnilkumar Kolli 	const struct ath11k_msi_config *msi_config = ab_pci->msi_config;
9735697a564SGovind Singh 	struct msi_desc *msi_desc;
9745697a564SGovind Singh 	int num_vectors;
9755697a564SGovind Singh 	int ret;
9765697a564SGovind Singh 
9775697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
9787a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
9797a3aed0cSAnilkumar Kolli 					    msi_config->total_vectors,
9805697a564SGovind Singh 					    PCI_IRQ_MSI);
981ac6e7348SCarl Huang 	if (num_vectors == msi_config->total_vectors) {
982c41a6700SCarl Huang 		set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
983c41a6700SCarl Huang 		ab_pci->irq_flags = IRQF_SHARED;
984ac6e7348SCarl Huang 	} else {
985ac6e7348SCarl Huang 		num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
986ac6e7348SCarl Huang 						    1,
987ac6e7348SCarl Huang 						    1,
988ac6e7348SCarl Huang 						    PCI_IRQ_MSI);
989ac6e7348SCarl Huang 		if (num_vectors < 0) {
990ac6e7348SCarl Huang 			ret = -EINVAL;
991ac6e7348SCarl Huang 			goto reset_msi_config;
9925697a564SGovind Singh 		}
993ac6e7348SCarl Huang 		clear_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
994ac6e7348SCarl Huang 		ab_pci->msi_config = &msi_config_one_msi;
995ac6e7348SCarl Huang 		ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
996ac6e7348SCarl Huang 		ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n");
997ac6e7348SCarl Huang 	}
998ac6e7348SCarl Huang 	ath11k_info(ab, "MSI vectors: %d\n", num_vectors);
999ac6e7348SCarl Huang 
100096527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
10015697a564SGovind Singh 
10025697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
10035697a564SGovind Singh 	if (!msi_desc) {
10045697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
10055697a564SGovind Singh 		ret = -EINVAL;
10065697a564SGovind Singh 		goto free_msi_vector;
10075697a564SGovind Singh 	}
10085697a564SGovind Singh 
10095697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
1010e8e55d89SAnilkumar Kolli 	if (msi_desc->msi_attrib.is_64)
1011e8e55d89SAnilkumar Kolli 		set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags);
10125697a564SGovind Singh 
10135697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
10145697a564SGovind Singh 
10155697a564SGovind Singh 	return 0;
10165697a564SGovind Singh 
10175697a564SGovind Singh free_msi_vector:
10185697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
10195697a564SGovind Singh 
1020ac6e7348SCarl Huang reset_msi_config:
10215697a564SGovind Singh 	return ret;
10225697a564SGovind Singh }
10235697a564SGovind Singh 
102496527d52SBaochen Qiang static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci)
10255697a564SGovind Singh {
10265697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
10275697a564SGovind Singh }
10285697a564SGovind Singh 
102987b4072dSCarl Huang static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci)
103087b4072dSCarl Huang {
103187b4072dSCarl Huang 	struct msi_desc *msi_desc;
103287b4072dSCarl Huang 
103387b4072dSCarl Huang 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
103487b4072dSCarl Huang 	if (!msi_desc) {
103587b4072dSCarl Huang 		ath11k_err(ab_pci->ab, "msi_desc is NULL!\n");
103687b4072dSCarl Huang 		pci_free_irq_vectors(ab_pci->pdev);
103787b4072dSCarl Huang 		return -EINVAL;
103887b4072dSCarl Huang 	}
103987b4072dSCarl Huang 
104087b4072dSCarl Huang 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
104187b4072dSCarl Huang 
104287b4072dSCarl Huang 	ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n",
104387b4072dSCarl Huang 		   ab_pci->msi_ep_base_data);
104487b4072dSCarl Huang 
104587b4072dSCarl Huang 	return 0;
104687b4072dSCarl Huang }
104787b4072dSCarl Huang 
10485762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
10495762613eSGovind Singh {
10505762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
10515762613eSGovind Singh 	u16 device_id;
10525762613eSGovind Singh 	int ret = 0;
10535762613eSGovind Singh 
10545762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
10555762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
10565762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
10575762613eSGovind Singh 			   device_id, ab_pci->dev_id);
10585762613eSGovind Singh 		ret = -EIO;
10595762613eSGovind Singh 		goto out;
10605762613eSGovind Singh 	}
10615762613eSGovind Singh 
10625762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
10635762613eSGovind Singh 	if (ret) {
10645762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
10655762613eSGovind Singh 		goto out;
10665762613eSGovind Singh 	}
10675762613eSGovind Singh 
10685762613eSGovind Singh 	ret = pci_enable_device(pdev);
10695762613eSGovind Singh 	if (ret) {
10705762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
10715762613eSGovind Singh 		goto out;
10725762613eSGovind Singh 	}
10735762613eSGovind Singh 
10745762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
10755762613eSGovind Singh 	if (ret) {
10765762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
10775762613eSGovind Singh 		goto disable_device;
10785762613eSGovind Singh 	}
10795762613eSGovind Singh 
1080923a1346SChristophe JAILLET 	ret = dma_set_mask_and_coherent(&pdev->dev,
1081923a1346SChristophe JAILLET 					DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
10825762613eSGovind Singh 	if (ret) {
10835762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
10845762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
10855762613eSGovind Singh 		goto release_region;
10865762613eSGovind Singh 	}
10875762613eSGovind Singh 
10885762613eSGovind Singh 	pci_set_master(pdev);
10895762613eSGovind Singh 
10905762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
10915762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
10925762613eSGovind Singh 	if (!ab->mem) {
10935762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
10945762613eSGovind Singh 		ret = -EIO;
10955762613eSGovind Singh 		goto clear_master;
10965762613eSGovind Singh 	}
10975762613eSGovind Singh 
10985762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
10995762613eSGovind Singh 	return 0;
11005762613eSGovind Singh 
11015762613eSGovind Singh clear_master:
11025762613eSGovind Singh 	pci_clear_master(pdev);
11035762613eSGovind Singh release_region:
11045762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
11055762613eSGovind Singh disable_device:
11065762613eSGovind Singh 	pci_disable_device(pdev);
11075762613eSGovind Singh out:
11085762613eSGovind Singh 	return ret;
11095762613eSGovind Singh }
11105762613eSGovind Singh 
11115762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
11125762613eSGovind Singh {
11135762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
11145762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
11155762613eSGovind Singh 
11165762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
11175762613eSGovind Singh 	ab->mem = NULL;
11185762613eSGovind Singh 	pci_clear_master(pci_dev);
11195762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
11205762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
11215762613eSGovind Singh 		pci_disable_device(pci_dev);
11225762613eSGovind Singh }
11235762613eSGovind Singh 
1124e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
1125e9603f4bSCarl Huang {
1126e9603f4bSCarl Huang 	struct ath11k_base *ab = ab_pci->ab;
1127e9603f4bSCarl Huang 
1128e9603f4bSCarl Huang 	pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1129e9603f4bSCarl Huang 				  &ab_pci->link_ctl);
1130e9603f4bSCarl Huang 
1131e9603f4bSCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n",
1132e9603f4bSCarl Huang 		   ab_pci->link_ctl,
1133e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S),
1134e9603f4bSCarl Huang 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
1135e9603f4bSCarl Huang 
1136e9603f4bSCarl Huang 	/* disable L0s and L1 */
1137e9603f4bSCarl Huang 	pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1138e9603f4bSCarl Huang 				   ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);
1139e9603f4bSCarl Huang 
1140e9603f4bSCarl Huang 	set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags);
1141e9603f4bSCarl Huang }
1142e9603f4bSCarl Huang 
1143e9603f4bSCarl Huang static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci)
1144e9603f4bSCarl Huang {
1145e9603f4bSCarl Huang 	if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags))
1146e9603f4bSCarl Huang 		pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,
1147e9603f4bSCarl Huang 					   ab_pci->link_ctl);
1148e9603f4bSCarl Huang }
1149e9603f4bSCarl Huang 
11501399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
11511399fb87SGovind Singh {
11521399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
11531399fb87SGovind Singh 	int ret;
11541399fb87SGovind Singh 
1155a05bd851SCarl Huang 	ab_pci->register_window = 0;
1156a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1157babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, true);
1158f3c603d4SCarl Huang 
1159e9603f4bSCarl Huang 	/* Disable ASPM during firmware download due to problems switching
1160e9603f4bSCarl Huang 	 * to AMSS state.
1161e9603f4bSCarl Huang 	 */
1162e9603f4bSCarl Huang 	ath11k_pci_aspm_disable(ab_pci);
1163e9603f4bSCarl Huang 
116496527d52SBaochen Qiang 	ath11k_pci_msi_enable(ab_pci);
116596527d52SBaochen Qiang 
11661399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
11671399fb87SGovind Singh 	if (ret) {
11681399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
11691399fb87SGovind Singh 		return ret;
11701399fb87SGovind Singh 	}
11711399fb87SGovind Singh 
1172480a7361SKarthikeyan Periyasamy 	if (ab->bus_params.static_window_map)
1173480a7361SKarthikeyan Periyasamy 		ath11k_pci_select_static_window(ab_pci);
1174480a7361SKarthikeyan Periyasamy 
11751399fb87SGovind Singh 	return 0;
11761399fb87SGovind Singh }
11771399fb87SGovind Singh 
11781399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
11791399fb87SGovind Singh {
11801399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
11811399fb87SGovind Singh 
1182e9603f4bSCarl Huang 	/* restore aspm in case firmware bootup fails */
1183e9603f4bSCarl Huang 	ath11k_pci_aspm_restore(ab_pci);
1184e9603f4bSCarl Huang 
1185babb0cedSCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
118696527d52SBaochen Qiang 
118796527d52SBaochen Qiang 	ath11k_pci_msi_disable(ab_pci);
118896527d52SBaochen Qiang 
11891399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
1190a05bd851SCarl Huang 	clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1191babb0cedSCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab, false);
11921399fb87SGovind Singh }
11931399fb87SGovind Singh 
1194fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab)
1195fa5917e4SCarl Huang {
1196fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
1197fa5917e4SCarl Huang 
1198fa5917e4SCarl Huang 	ath11k_mhi_suspend(ar_pci);
1199fa5917e4SCarl Huang 
1200fa5917e4SCarl Huang 	return 0;
1201fa5917e4SCarl Huang }
1202fa5917e4SCarl Huang 
1203fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab)
1204fa5917e4SCarl Huang {
1205fa5917e4SCarl Huang 	struct ath11k_pci *ar_pci = ath11k_pci_priv(ab);
1206fa5917e4SCarl Huang 
1207fa5917e4SCarl Huang 	ath11k_mhi_resume(ar_pci);
1208fa5917e4SCarl Huang 
1209fa5917e4SCarl Huang 	return 0;
1210fa5917e4SCarl Huang }
1211fa5917e4SCarl Huang 
12122c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
12132c3960c2SGovind Singh {
12142c3960c2SGovind Singh 	int i;
12152c3960c2SGovind Singh 
1216d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
12172c3960c2SGovind Singh 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
12182c3960c2SGovind Singh 
1219e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
12202c3960c2SGovind Singh 			continue;
12212c3960c2SGovind Singh 
12222c3960c2SGovind Singh 		tasklet_kill(&ce_pipe->intr_tq);
12232c3960c2SGovind Singh 	}
12242c3960c2SGovind Singh }
12252c3960c2SGovind Singh 
1226d578ec2aSCarl Huang static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab)
12277f4beda2SGovind Singh {
12282c3960c2SGovind Singh 	ath11k_pci_ce_irqs_disable(ab);
12292c3960c2SGovind Singh 	ath11k_pci_sync_ce_irqs(ab);
12302c3960c2SGovind Singh 	ath11k_pci_kill_tasklets(ab);
1231d578ec2aSCarl Huang }
1232d578ec2aSCarl Huang 
1233d578ec2aSCarl Huang static void ath11k_pci_stop(struct ath11k_base *ab)
1234d578ec2aSCarl Huang {
1235d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
12367f4beda2SGovind Singh 	ath11k_ce_cleanup_pipes(ab);
12377f4beda2SGovind Singh }
12387f4beda2SGovind Singh 
12397f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab)
12407f4beda2SGovind Singh {
1241a05bd851SCarl Huang 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
1242a05bd851SCarl Huang 
1243a05bd851SCarl Huang 	set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
1244a05bd851SCarl Huang 
1245915a081fSCarl Huang 	/* TODO: for now don't restore ASPM in case of single MSI
1246915a081fSCarl Huang 	 * vector as MHI register reading in M2 causes system hang.
1247915a081fSCarl Huang 	 */
1248915a081fSCarl Huang 	if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
1249e9603f4bSCarl Huang 		ath11k_pci_aspm_restore(ab_pci);
1250915a081fSCarl Huang 	else
1251915a081fSCarl Huang 		ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n");
1252e9603f4bSCarl Huang 
12537f4beda2SGovind Singh 	ath11k_pci_ce_irqs_enable(ab);
12542c3960c2SGovind Singh 	ath11k_ce_rx_post_buf(ab);
12552c3960c2SGovind Singh 
12562c3960c2SGovind Singh 	return 0;
12572c3960c2SGovind Singh }
12582c3960c2SGovind Singh 
1259d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab)
1260d578ec2aSCarl Huang {
1261d578ec2aSCarl Huang 	ath11k_pci_ce_irqs_enable(ab);
1262d578ec2aSCarl Huang }
1263d578ec2aSCarl Huang 
1264d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab)
1265d578ec2aSCarl Huang {
1266d578ec2aSCarl Huang 	ath11k_pci_ce_irq_disable_sync(ab);
1267d578ec2aSCarl Huang }
1268d578ec2aSCarl Huang 
12692c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
12702c3960c2SGovind Singh 					  u8 *ul_pipe, u8 *dl_pipe)
12712c3960c2SGovind Singh {
12722c3960c2SGovind Singh 	const struct service_to_pipe *entry;
12732c3960c2SGovind Singh 	bool ul_set = false, dl_set = false;
12742c3960c2SGovind Singh 	int i;
12752c3960c2SGovind Singh 
1276967c1d11SAnilkumar Kolli 	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
1277967c1d11SAnilkumar Kolli 		entry = &ab->hw_params.svc_to_ce_map[i];
12782c3960c2SGovind Singh 
12792c3960c2SGovind Singh 		if (__le32_to_cpu(entry->service_id) != service_id)
12802c3960c2SGovind Singh 			continue;
12812c3960c2SGovind Singh 
12822c3960c2SGovind Singh 		switch (__le32_to_cpu(entry->pipedir)) {
12832c3960c2SGovind Singh 		case PIPEDIR_NONE:
12842c3960c2SGovind Singh 			break;
12852c3960c2SGovind Singh 		case PIPEDIR_IN:
12862c3960c2SGovind Singh 			WARN_ON(dl_set);
12872c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
12882c3960c2SGovind Singh 			dl_set = true;
12892c3960c2SGovind Singh 			break;
12902c3960c2SGovind Singh 		case PIPEDIR_OUT:
12912c3960c2SGovind Singh 			WARN_ON(ul_set);
12922c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
12932c3960c2SGovind Singh 			ul_set = true;
12942c3960c2SGovind Singh 			break;
12952c3960c2SGovind Singh 		case PIPEDIR_INOUT:
12962c3960c2SGovind Singh 			WARN_ON(dl_set);
12972c3960c2SGovind Singh 			WARN_ON(ul_set);
12982c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
12992c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
13002c3960c2SGovind Singh 			dl_set = true;
13012c3960c2SGovind Singh 			ul_set = true;
13022c3960c2SGovind Singh 			break;
13032c3960c2SGovind Singh 		}
13042c3960c2SGovind Singh 	}
13052c3960c2SGovind Singh 
13062c3960c2SGovind Singh 	if (WARN_ON(!ul_set || !dl_set))
13072c3960c2SGovind Singh 		return -ENOENT;
13087f4beda2SGovind Singh 
13097f4beda2SGovind Singh 	return 0;
13107f4beda2SGovind Singh }
13117f4beda2SGovind Singh 
13127f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
13137f4beda2SGovind Singh 	.start = ath11k_pci_start,
13147f4beda2SGovind Singh 	.stop = ath11k_pci_stop,
1315654e959aSGovind Singh 	.read32 = ath11k_pci_read32,
1316654e959aSGovind Singh 	.write32 = ath11k_pci_write32,
13171399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
13181399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
1319fa5917e4SCarl Huang 	.suspend = ath11k_pci_hif_suspend,
1320fa5917e4SCarl Huang 	.resume = ath11k_pci_hif_resume,
1321d4ecb90bSCarl Huang 	.irq_enable = ath11k_pci_ext_irq_enable,
1322d4ecb90bSCarl Huang 	.irq_disable = ath11k_pci_ext_irq_disable,
1323c4eacabeSGovind Singh 	.get_msi_address =  ath11k_pci_get_msi_address,
1324c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
13252c3960c2SGovind Singh 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
1326d578ec2aSCarl Huang 	.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
1327d578ec2aSCarl Huang 	.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
13286289ac2bSKarthikeyan Periyasamy 	.get_ce_msi_idx = ath11k_pci_get_ce_msi_idx,
13291399fb87SGovind Singh };
13301399fb87SGovind Singh 
13310fbf1957SBaochen Qiang static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor)
13320fbf1957SBaochen Qiang {
13330fbf1957SBaochen Qiang 	u32 soc_hw_version;
13340fbf1957SBaochen Qiang 
13350fbf1957SBaochen Qiang 	soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION);
13360fbf1957SBaochen Qiang 	*major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
13370fbf1957SBaochen Qiang 			   soc_hw_version);
13380fbf1957SBaochen Qiang 	*minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
13390fbf1957SBaochen Qiang 			   soc_hw_version);
13400fbf1957SBaochen Qiang 
13410fbf1957SBaochen Qiang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
13420fbf1957SBaochen Qiang 		   *major, *minor);
13430fbf1957SBaochen Qiang }
13440fbf1957SBaochen Qiang 
13456e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
13466e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
13476e0355afSGovind Singh {
13486e0355afSGovind Singh 	struct ath11k_base *ab;
13495762613eSGovind Singh 	struct ath11k_pci *ab_pci;
13500fbf1957SBaochen Qiang 	u32 soc_hw_version_major, soc_hw_version_minor;
13515762613eSGovind Singh 	int ret;
13526e0355afSGovind Singh 
13531ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
13541ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
13556e0355afSGovind Singh 	if (!ab) {
13566e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
13576e0355afSGovind Singh 		return -ENOMEM;
13586e0355afSGovind Singh 	}
13596e0355afSGovind Singh 
13606e0355afSGovind Singh 	ab->dev = &pdev->dev;
13616e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
13625762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
13635762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
13645762613eSGovind Singh 	ab_pci->ab = ab;
13655697a564SGovind Singh 	ab_pci->pdev = pdev;
13667f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
13675762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
1368654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
13695762613eSGovind Singh 
13705762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
13715762613eSGovind Singh 	if (ret) {
13725762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
13735762613eSGovind Singh 		goto err_free_core;
13745762613eSGovind Singh 	}
13756e0355afSGovind Singh 
1376fc95d10aSWen Gong 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n",
1377fc95d10aSWen Gong 		   pdev->vendor, pdev->device,
1378fc95d10aSWen Gong 		   pdev->subsystem_vendor, pdev->subsystem_device);
1379fc95d10aSWen Gong 
1380fc95d10aSWen Gong 	ab->id.vendor = pdev->vendor;
1381fc95d10aSWen Gong 	ab->id.device = pdev->device;
1382fc95d10aSWen Gong 	ab->id.subsystem_vendor = pdev->subsystem_vendor;
1383fc95d10aSWen Gong 	ab->id.subsystem_device = pdev->subsystem_device;
1384fc95d10aSWen Gong 
138518ac1665SKalle Valo 	switch (pci_dev->device) {
138618ac1665SKalle Valo 	case QCA6390_DEVICE_ID:
13870fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
13880fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
138918ac1665SKalle Valo 		switch (soc_hw_version_major) {
139018ac1665SKalle Valo 		case 2:
139118ac1665SKalle Valo 			ab->hw_rev = ATH11K_HW_QCA6390_HW20;
139218ac1665SKalle Valo 			break;
139318ac1665SKalle Valo 		default:
139418ac1665SKalle Valo 			dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n",
139518ac1665SKalle Valo 				soc_hw_version_major, soc_hw_version_minor);
139618ac1665SKalle Valo 			ret = -EOPNOTSUPP;
139718ac1665SKalle Valo 			goto err_pci_free_region;
139818ac1665SKalle Valo 		}
13994e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[0];
14004e809461SAnilkumar Kolli 		break;
14014e809461SAnilkumar Kolli 	case QCN9074_DEVICE_ID:
14024e809461SAnilkumar Kolli 		ab_pci->msi_config = &ath11k_msi_config[1];
14034e809461SAnilkumar Kolli 		ab->bus_params.static_window_map = true;
14044e809461SAnilkumar Kolli 		ab->hw_rev = ATH11K_HW_QCN9074_HW10;
140518ac1665SKalle Valo 		break;
14060fbf1957SBaochen Qiang 	case WCN6855_DEVICE_ID:
1407fc95d10aSWen Gong 		ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD;
14080fbf1957SBaochen Qiang 		ath11k_pci_read_hw_version(ab, &soc_hw_version_major,
14090fbf1957SBaochen Qiang 					   &soc_hw_version_minor);
14100fbf1957SBaochen Qiang 		switch (soc_hw_version_major) {
14110fbf1957SBaochen Qiang 		case 2:
1412*d1147a31SBaochen Qiang 			switch (soc_hw_version_minor) {
1413*d1147a31SBaochen Qiang 			case 0x00:
1414*d1147a31SBaochen Qiang 			case 0x01:
14150fbf1957SBaochen Qiang 				ab->hw_rev = ATH11K_HW_WCN6855_HW20;
14160fbf1957SBaochen Qiang 				break;
1417*d1147a31SBaochen Qiang 			case 0x10:
1418*d1147a31SBaochen Qiang 			case 0x11:
1419*d1147a31SBaochen Qiang 				ab->hw_rev = ATH11K_HW_WCN6855_HW21;
1420*d1147a31SBaochen Qiang 				break;
14210fbf1957SBaochen Qiang 			default:
1422*d1147a31SBaochen Qiang 				goto unsupported_wcn6855_soc;
1423*d1147a31SBaochen Qiang 			}
1424*d1147a31SBaochen Qiang 			break;
1425*d1147a31SBaochen Qiang 		default:
1426*d1147a31SBaochen Qiang unsupported_wcn6855_soc:
14270fbf1957SBaochen Qiang 			dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n",
14280fbf1957SBaochen Qiang 				soc_hw_version_major, soc_hw_version_minor);
14290fbf1957SBaochen Qiang 			ret = -EOPNOTSUPP;
14300fbf1957SBaochen Qiang 			goto err_pci_free_region;
14310fbf1957SBaochen Qiang 		}
14320fbf1957SBaochen Qiang 		ab_pci->msi_config = &ath11k_msi_config[0];
14330fbf1957SBaochen Qiang 		break;
143418ac1665SKalle Valo 	default:
143518ac1665SKalle Valo 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
143618ac1665SKalle Valo 			pci_dev->device);
143718ac1665SKalle Valo 		ret = -EOPNOTSUPP;
143818ac1665SKalle Valo 		goto err_pci_free_region;
143918ac1665SKalle Valo 	}
144018ac1665SKalle Valo 
144196527d52SBaochen Qiang 	ret = ath11k_pci_alloc_msi(ab_pci);
14425697a564SGovind Singh 	if (ret) {
14435697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
14445697a564SGovind Singh 		goto err_pci_free_region;
14455697a564SGovind Singh 	}
14465697a564SGovind Singh 
1447b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
1448b8246f88SKalle Valo 	if (ret)
1449b8246f88SKalle Valo 		goto err_pci_disable_msi;
1450b8246f88SKalle Valo 
14511399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
14521399fb87SGovind Singh 	if (ret) {
14531399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
14541399fb87SGovind Singh 		goto err_pci_disable_msi;
14551399fb87SGovind Singh 	}
14561399fb87SGovind Singh 
14577f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
14587f4beda2SGovind Singh 	if (ret)
14597f4beda2SGovind Singh 		goto err_mhi_unregister;
14607f4beda2SGovind Singh 
14617f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
14627f4beda2SGovind Singh 	if (ret) {
14637f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
14647f4beda2SGovind Singh 		goto err_hal_srng_deinit;
14657f4beda2SGovind Singh 	}
14667f4beda2SGovind Singh 
14677f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
14687f4beda2SGovind Singh 
14697f4beda2SGovind Singh 	ret = ath11k_pci_config_irq(ab);
14707f4beda2SGovind Singh 	if (ret) {
14717f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
14727f4beda2SGovind Singh 		goto err_ce_free;
14737f4beda2SGovind Singh 	}
14747f4beda2SGovind Singh 
147587b4072dSCarl Huang 	/* kernel may allocate a dummy vector before request_irq and
147687b4072dSCarl Huang 	 * then allocate a real vector when request_irq is called.
147787b4072dSCarl Huang 	 * So get msi_data here again to avoid spurious interrupt
147887b4072dSCarl Huang 	 * as msi_data will configured to srngs.
147987b4072dSCarl Huang 	 */
148087b4072dSCarl Huang 	ret = ath11k_pci_config_msi_data(ab_pci);
148187b4072dSCarl Huang 	if (ret) {
148287b4072dSCarl Huang 		ath11k_err(ab, "failed to config msi_data: %d\n", ret);
148387b4072dSCarl Huang 		goto err_free_irq;
148487b4072dSCarl Huang 	}
148587b4072dSCarl Huang 
14867f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
14877f4beda2SGovind Singh 	if (ret) {
14887f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
14897f4beda2SGovind Singh 		goto err_free_irq;
14907f4beda2SGovind Singh 	}
14916e0355afSGovind Singh 	return 0;
14925762613eSGovind Singh 
14937f4beda2SGovind Singh err_free_irq:
14947f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
14957f4beda2SGovind Singh 
14967f4beda2SGovind Singh err_ce_free:
14977f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
14987f4beda2SGovind Singh 
14997f4beda2SGovind Singh err_hal_srng_deinit:
15007f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
15017f4beda2SGovind Singh 
15027f4beda2SGovind Singh err_mhi_unregister:
15037f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
15047f4beda2SGovind Singh 
1505b8246f88SKalle Valo err_pci_disable_msi:
150696527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
1507b8246f88SKalle Valo 
15085697a564SGovind Singh err_pci_free_region:
15095697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
15105697a564SGovind Singh 
15115762613eSGovind Singh err_free_core:
15125762613eSGovind Singh 	ath11k_core_free(ab);
15135697a564SGovind Singh 
15145762613eSGovind Singh 	return ret;
15156e0355afSGovind Singh }
15166e0355afSGovind Singh 
15176e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
15186e0355afSGovind Singh {
15196e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
15205762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
15216e0355afSGovind Singh 
1522e94b0749SBaochen Qiang 	ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
1523e94b0749SBaochen Qiang 
152461a57e51SAnilkumar Kolli 	if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
152561a57e51SAnilkumar Kolli 		ath11k_pci_power_down(ab);
152661a57e51SAnilkumar Kolli 		ath11k_debugfs_soc_destroy(ab);
152761a57e51SAnilkumar Kolli 		ath11k_qmi_deinit_service(ab);
152861a57e51SAnilkumar Kolli 		goto qmi_fail;
152961a57e51SAnilkumar Kolli 	}
153061a57e51SAnilkumar Kolli 
15316e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
15326fbd8898SCarl Huang 
15336fbd8898SCarl Huang 	ath11k_core_deinit(ab);
15346fbd8898SCarl Huang 
153561a57e51SAnilkumar Kolli qmi_fail:
15361399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
15376fbd8898SCarl Huang 
15386fbd8898SCarl Huang 	ath11k_pci_free_irq(ab);
153996527d52SBaochen Qiang 	ath11k_pci_free_msi(ab_pci);
15405762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
15416fbd8898SCarl Huang 
15426fbd8898SCarl Huang 	ath11k_hal_srng_deinit(ab);
15436fbd8898SCarl Huang 	ath11k_ce_free_pipes(ab);
15446e0355afSGovind Singh 	ath11k_core_free(ab);
15456e0355afSGovind Singh }
15466e0355afSGovind Singh 
15471399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
15481399fb87SGovind Singh {
15491399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
15501399fb87SGovind Singh 
15511399fb87SGovind Singh 	ath11k_pci_power_down(ab);
15521399fb87SGovind Singh }
15531399fb87SGovind Singh 
1554d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev)
1555d1b0c338SCarl Huang {
1556d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1557d1b0c338SCarl Huang 	int ret;
1558d1b0c338SCarl Huang 
1559d1b0c338SCarl Huang 	ret = ath11k_core_suspend(ab);
1560d1b0c338SCarl Huang 	if (ret)
1561d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to suspend core: %d\n", ret);
1562d1b0c338SCarl Huang 
1563d1b0c338SCarl Huang 	return ret;
1564d1b0c338SCarl Huang }
1565d1b0c338SCarl Huang 
1566d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
1567d1b0c338SCarl Huang {
1568d1b0c338SCarl Huang 	struct ath11k_base *ab = dev_get_drvdata(dev);
1569d1b0c338SCarl Huang 	int ret;
1570d1b0c338SCarl Huang 
1571d1b0c338SCarl Huang 	ret = ath11k_core_resume(ab);
1572d1b0c338SCarl Huang 	if (ret)
1573d1b0c338SCarl Huang 		ath11k_warn(ab, "failed to resume core: %d\n", ret);
1574d1b0c338SCarl Huang 
1575d1b0c338SCarl Huang 	return ret;
1576d1b0c338SCarl Huang }
1577d1b0c338SCarl Huang 
1578d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
1579d1b0c338SCarl Huang 			 ath11k_pci_pm_suspend,
1580d1b0c338SCarl Huang 			 ath11k_pci_pm_resume);
1581d1b0c338SCarl Huang 
15826e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
15836e0355afSGovind Singh 	.name = "ath11k_pci",
15846e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
15856e0355afSGovind Singh 	.probe = ath11k_pci_probe,
15866e0355afSGovind Singh 	.remove = ath11k_pci_remove,
15871399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
1588d1b0c338SCarl Huang #ifdef CONFIG_PM
1589d1b0c338SCarl Huang 	.driver.pm = &ath11k_pci_pm_ops,
1590d1b0c338SCarl Huang #endif
15916e0355afSGovind Singh };
15926e0355afSGovind Singh 
15936e0355afSGovind Singh static int ath11k_pci_init(void)
15946e0355afSGovind Singh {
15956e0355afSGovind Singh 	int ret;
15966e0355afSGovind Singh 
15976e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
15986e0355afSGovind Singh 	if (ret)
15996e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
16006e0355afSGovind Singh 		       ret);
16016e0355afSGovind Singh 
16026e0355afSGovind Singh 	return ret;
16036e0355afSGovind Singh }
16046e0355afSGovind Singh module_init(ath11k_pci_init);
16056e0355afSGovind Singh 
16066e0355afSGovind Singh static void ath11k_pci_exit(void)
16076e0355afSGovind Singh {
16086e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
16096e0355afSGovind Singh }
16106e0355afSGovind Singh 
16116e0355afSGovind Singh module_exit(ath11k_pci_exit);
16126e0355afSGovind Singh 
16136e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
16146e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
16153dbd7fe7SDevin Bayer 
16163dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */
16173dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE);
16183dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE);
16193dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE);
1620