xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision 967c1d1131fa09961de48e75878294a5769bbc63)
16e0355afSGovind Singh // SPDX-License-Identifier: BSD-3-Clause-Clear
26e0355afSGovind Singh /*
36e0355afSGovind Singh  * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
46e0355afSGovind Singh  */
56e0355afSGovind Singh 
66e0355afSGovind Singh #include <linux/module.h>
75697a564SGovind Singh #include <linux/msi.h>
86e0355afSGovind Singh #include <linux/pci.h>
96e0355afSGovind Singh 
105762613eSGovind Singh #include "pci.h"
116e0355afSGovind Singh #include "core.h"
121399fb87SGovind Singh #include "hif.h"
131399fb87SGovind Singh #include "mhi.h"
146e0355afSGovind Singh #include "debug.h"
156e0355afSGovind Singh 
165762613eSGovind Singh #define ATH11K_PCI_BAR_NUM		0
175762613eSGovind Singh #define ATH11K_PCI_DMA_MASK		32
185762613eSGovind Singh 
197f4beda2SGovind Singh #define ATH11K_PCI_IRQ_CE0_OFFSET		3
207f4beda2SGovind Singh 
21654e959aSGovind Singh #define WINDOW_ENABLE_BIT		0x40000000
22654e959aSGovind Singh #define WINDOW_REG_ADDRESS		0x310c
23654e959aSGovind Singh #define WINDOW_VALUE_MASK		GENMASK(24, 19)
24654e959aSGovind Singh #define WINDOW_START			0x80000
25654e959aSGovind Singh #define WINDOW_RANGE_MASK		GENMASK(18, 0)
26654e959aSGovind Singh 
276e0355afSGovind Singh #define QCA6390_DEVICE_ID		0x1101
286e0355afSGovind Singh 
296e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = {
306e0355afSGovind Singh 	{ PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) },
316e0355afSGovind Singh 	{0}
326e0355afSGovind Singh };
336e0355afSGovind Singh 
346e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table);
356e0355afSGovind Singh 
361ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = {
371ff8ed78SGovind Singh 	.mhi_support = true,
3856970454SGovind Singh 	.m3_fw_support = true,
396eb6ea51SGovind Singh 	.fixed_bdf_addr = false,
406eb6ea51SGovind Singh 	.fixed_mem_region = false,
411ff8ed78SGovind Singh };
421ff8ed78SGovind Singh 
435697a564SGovind Singh static const struct ath11k_msi_config msi_config = {
445697a564SGovind Singh 	.total_vectors = 32,
455697a564SGovind Singh 	.total_users = 4,
465697a564SGovind Singh 	.users = (struct ath11k_msi_user[]) {
475697a564SGovind Singh 		{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
485697a564SGovind Singh 		{ .name = "CE", .num_vectors = 10, .base_vector = 3 },
495697a564SGovind Singh 		{ .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
505697a564SGovind Singh 		{ .name = "DP", .num_vectors = 18, .base_vector = 14 },
515697a564SGovind Singh 	},
525697a564SGovind Singh };
535697a564SGovind Singh 
547f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
557f4beda2SGovind Singh 	"bhi",
567f4beda2SGovind Singh 	"mhi-er0",
577f4beda2SGovind Singh 	"mhi-er1",
587f4beda2SGovind Singh 	"ce0",
597f4beda2SGovind Singh 	"ce1",
607f4beda2SGovind Singh 	"ce2",
617f4beda2SGovind Singh 	"ce3",
627f4beda2SGovind Singh 	"ce4",
637f4beda2SGovind Singh 	"ce5",
647f4beda2SGovind Singh 	"ce6",
657f4beda2SGovind Singh 	"ce7",
667f4beda2SGovind Singh 	"ce8",
677f4beda2SGovind Singh 	"ce9",
687f4beda2SGovind Singh 	"ce10",
697f4beda2SGovind Singh 	"ce11",
707f4beda2SGovind Singh 	"host2wbm-desc-feed",
717f4beda2SGovind Singh 	"host2reo-re-injection",
727f4beda2SGovind Singh 	"host2reo-command",
737f4beda2SGovind Singh 	"host2rxdma-monitor-ring3",
747f4beda2SGovind Singh 	"host2rxdma-monitor-ring2",
757f4beda2SGovind Singh 	"host2rxdma-monitor-ring1",
767f4beda2SGovind Singh 	"reo2ost-exception",
777f4beda2SGovind Singh 	"wbm2host-rx-release",
787f4beda2SGovind Singh 	"reo2host-status",
797f4beda2SGovind Singh 	"reo2host-destination-ring4",
807f4beda2SGovind Singh 	"reo2host-destination-ring3",
817f4beda2SGovind Singh 	"reo2host-destination-ring2",
827f4beda2SGovind Singh 	"reo2host-destination-ring1",
837f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac3",
847f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac2",
857f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac1",
867f4beda2SGovind Singh 	"ppdu-end-interrupts-mac3",
877f4beda2SGovind Singh 	"ppdu-end-interrupts-mac2",
887f4beda2SGovind Singh 	"ppdu-end-interrupts-mac1",
897f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac3",
907f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac2",
917f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac1",
927f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac3",
937f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac2",
947f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac1",
957f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac3",
967f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac2",
977f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac1",
987f4beda2SGovind Singh 	"host2tcl-input-ring4",
997f4beda2SGovind Singh 	"host2tcl-input-ring3",
1007f4beda2SGovind Singh 	"host2tcl-input-ring2",
1017f4beda2SGovind Singh 	"host2tcl-input-ring1",
1027f4beda2SGovind Singh 	"wbm2host-tx-completions-ring3",
1037f4beda2SGovind Singh 	"wbm2host-tx-completions-ring2",
1047f4beda2SGovind Singh 	"wbm2host-tx-completions-ring1",
1057f4beda2SGovind Singh 	"tcl2host-status-ring",
1067f4beda2SGovind Singh };
1077f4beda2SGovind Singh 
108654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset)
109654e959aSGovind Singh {
110654e959aSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
111654e959aSGovind Singh 
112654e959aSGovind Singh 	u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset);
113654e959aSGovind Singh 
114654e959aSGovind Singh 	lockdep_assert_held(&ab_pci->window_lock);
115654e959aSGovind Singh 
116654e959aSGovind Singh 	if (window != ab_pci->register_window) {
117654e959aSGovind Singh 		iowrite32(WINDOW_ENABLE_BIT | window,
118654e959aSGovind Singh 			  ab->mem + WINDOW_REG_ADDRESS);
119654e959aSGovind Singh 		ab_pci->register_window = window;
120654e959aSGovind Singh 	}
121654e959aSGovind Singh }
122654e959aSGovind Singh 
123f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
124654e959aSGovind Singh {
125654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
126654e959aSGovind Singh 
127654e959aSGovind Singh 	if (offset < WINDOW_START) {
128654e959aSGovind Singh 		iowrite32(value, ab->mem  + offset);
129654e959aSGovind Singh 	} else {
130654e959aSGovind Singh 		spin_lock_bh(&ab_pci->window_lock);
131654e959aSGovind Singh 		ath11k_pci_select_window(ab_pci, offset);
132654e959aSGovind Singh 		iowrite32(value, ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK));
133654e959aSGovind Singh 		spin_unlock_bh(&ab_pci->window_lock);
134654e959aSGovind Singh 	}
135654e959aSGovind Singh }
136654e959aSGovind Singh 
137f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
138654e959aSGovind Singh {
139654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
140654e959aSGovind Singh 	u32 val;
141654e959aSGovind Singh 
142654e959aSGovind Singh 	if (offset < WINDOW_START) {
143654e959aSGovind Singh 		val = ioread32(ab->mem + offset);
144654e959aSGovind Singh 	} else {
145654e959aSGovind Singh 		spin_lock_bh(&ab_pci->window_lock);
146654e959aSGovind Singh 		ath11k_pci_select_window(ab_pci, offset);
147654e959aSGovind Singh 		val = ioread32(ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK));
148654e959aSGovind Singh 		spin_unlock_bh(&ab_pci->window_lock);
149654e959aSGovind Singh 	}
150654e959aSGovind Singh 
151654e959aSGovind Singh 	return val;
152654e959aSGovind Singh }
153654e959aSGovind Singh 
154f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
155f3c603d4SCarl Huang {
156f3c603d4SCarl Huang 	u32 val, delay;
157f3c603d4SCarl Huang 
158f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
159f3c603d4SCarl Huang 
160f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
161f3c603d4SCarl Huang 
162f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
163f3c603d4SCarl Huang 
164f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
165f3c603d4SCarl Huang 	delay = 10;
166f3c603d4SCarl Huang 	mdelay(delay);
167f3c603d4SCarl Huang 
168f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
169f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
170f3c603d4SCarl Huang 
171f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
172f3c603d4SCarl Huang 
173f3c603d4SCarl Huang 	mdelay(delay);
174f3c603d4SCarl Huang 
175f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
176f3c603d4SCarl Huang 	if (val == 0xffffffff)
177f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
178f3c603d4SCarl Huang }
179f3c603d4SCarl Huang 
180f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
181f3c603d4SCarl Huang {
182f3c603d4SCarl Huang 	u32 val;
183f3c603d4SCarl Huang 
184f3c603d4SCarl Huang 	/* read cookie */
185f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR);
186f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val);
187f3c603d4SCarl Huang 
188f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
189f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
190f3c603d4SCarl Huang 
191f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
192f3c603d4SCarl Huang 	mdelay(10);
193f3c603d4SCarl Huang 
194f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
195f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
196f3c603d4SCarl Huang 	 */
197f3c603d4SCarl Huang 	ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0);
198f3c603d4SCarl Huang 	mdelay(10);
199f3c603d4SCarl Huang 
200f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
201f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
202f3c603d4SCarl Huang 
203f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
204f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
205f3c603d4SCarl Huang 	 */
206f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
207f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
208f3c603d4SCarl Huang }
209f3c603d4SCarl Huang 
210f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
211f3c603d4SCarl Huang {
212f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
213f3c603d4SCarl Huang 	mdelay(5);
214f3c603d4SCarl Huang }
215f3c603d4SCarl Huang 
216f3c603d4SCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab)
217f3c603d4SCarl Huang {
218f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
219f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
220f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
221f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
222f3c603d4SCarl Huang 	ath11k_pci_clear_dbg_registers(ab);
223f3c603d4SCarl Huang }
224f3c603d4SCarl Huang 
2251399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
2261399fb87SGovind Singh {
2271399fb87SGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(dev);
2281399fb87SGovind Singh 
2291399fb87SGovind Singh 	return pci_irq_vector(pci_dev, vector);
2301399fb87SGovind Singh }
2311399fb87SGovind Singh 
232c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
233c4eacabeSGovind Singh 				       u32 *msi_addr_hi)
234c4eacabeSGovind Singh {
235c4eacabeSGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
236c4eacabeSGovind Singh 
237c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
238c4eacabeSGovind Singh 			      msi_addr_lo);
239c4eacabeSGovind Singh 
240c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
241c4eacabeSGovind Singh 			      msi_addr_hi);
242c4eacabeSGovind Singh }
243c4eacabeSGovind Singh 
2441399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
2451399fb87SGovind Singh 				       int *num_vectors, u32 *user_base_data,
2461399fb87SGovind Singh 				       u32 *base_vector)
2471399fb87SGovind Singh {
2481399fb87SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
2491399fb87SGovind Singh 	int idx;
2501399fb87SGovind Singh 
2511399fb87SGovind Singh 	for (idx = 0; idx < msi_config.total_users; idx++) {
2521399fb87SGovind Singh 		if (strcmp(user_name, msi_config.users[idx].name) == 0) {
2531399fb87SGovind Singh 			*num_vectors = msi_config.users[idx].num_vectors;
2541399fb87SGovind Singh 			*user_base_data = msi_config.users[idx].base_vector
2551399fb87SGovind Singh 				+ ab_pci->msi_ep_base_data;
2561399fb87SGovind Singh 			*base_vector = msi_config.users[idx].base_vector;
2571399fb87SGovind Singh 
2581399fb87SGovind Singh 			ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
2591399fb87SGovind Singh 				   user_name, *num_vectors, *user_base_data,
2601399fb87SGovind Singh 				   *base_vector);
2611399fb87SGovind Singh 
2621399fb87SGovind Singh 			return 0;
2631399fb87SGovind Singh 		}
2641399fb87SGovind Singh 	}
2651399fb87SGovind Singh 
2661399fb87SGovind Singh 	ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
2671399fb87SGovind Singh 
2681399fb87SGovind Singh 	return -EINVAL;
2691399fb87SGovind Singh }
2701399fb87SGovind Singh 
271c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
272c4eacabeSGovind Singh 					  int *num_vectors, u32 *user_base_data,
273c4eacabeSGovind Singh 					  u32 *base_vector)
274c4eacabeSGovind Singh {
275c4eacabeSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
276c4eacabeSGovind Singh 
277c4eacabeSGovind Singh 	return ath11k_pci_get_user_msi_assignment(ab_pci, user_name,
278c4eacabeSGovind Singh 						  num_vectors, user_base_data,
279c4eacabeSGovind Singh 						  base_vector);
280c4eacabeSGovind Singh }
281c4eacabeSGovind Singh 
282d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
283d4ecb90bSCarl Huang {
284d4ecb90bSCarl Huang 	int i, j;
285d4ecb90bSCarl Huang 
286d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
287d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
288d4ecb90bSCarl Huang 
289d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++)
290d4ecb90bSCarl Huang 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
291d4ecb90bSCarl Huang 
292d4ecb90bSCarl Huang 		netif_napi_del(&irq_grp->napi);
293d4ecb90bSCarl Huang 	}
294d4ecb90bSCarl Huang }
295d4ecb90bSCarl Huang 
2967f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab)
2977f4beda2SGovind Singh {
2987f4beda2SGovind Singh 	int i, irq_idx;
2997f4beda2SGovind Singh 
300d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
301e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
3027f4beda2SGovind Singh 			continue;
3037f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
3047f4beda2SGovind Singh 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
3057f4beda2SGovind Singh 	}
306d4ecb90bSCarl Huang 
307d4ecb90bSCarl Huang 	ath11k_pci_free_ext_irq(ab);
3087f4beda2SGovind Singh }
3097f4beda2SGovind Singh 
3102c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
3112c3960c2SGovind Singh {
3122c3960c2SGovind Singh 	u32 irq_idx;
3132c3960c2SGovind Singh 
3142c3960c2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
3152c3960c2SGovind Singh 	enable_irq(ab->irq_num[irq_idx]);
3162c3960c2SGovind Singh }
3172c3960c2SGovind Singh 
3187f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
3197f4beda2SGovind Singh {
3207f4beda2SGovind Singh 	u32 irq_idx;
3217f4beda2SGovind Singh 
3227f4beda2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
3237f4beda2SGovind Singh 	disable_irq_nosync(ab->irq_num[irq_idx]);
3247f4beda2SGovind Singh }
3257f4beda2SGovind Singh 
3262c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
3272c3960c2SGovind Singh {
3282c3960c2SGovind Singh 	int i;
3292c3960c2SGovind Singh 
330d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
331e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
3322c3960c2SGovind Singh 			continue;
3332c3960c2SGovind Singh 		ath11k_pci_ce_irq_disable(ab, i);
3342c3960c2SGovind Singh 	}
3352c3960c2SGovind Singh }
3362c3960c2SGovind Singh 
3372c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
3382c3960c2SGovind Singh {
3392c3960c2SGovind Singh 	int i;
3402c3960c2SGovind Singh 	int irq_idx;
3412c3960c2SGovind Singh 
342d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
343e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
3442c3960c2SGovind Singh 			continue;
3452c3960c2SGovind Singh 
3462c3960c2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
3472c3960c2SGovind Singh 		synchronize_irq(ab->irq_num[irq_idx]);
3482c3960c2SGovind Singh 	}
3492c3960c2SGovind Singh }
3502c3960c2SGovind Singh 
3512c3960c2SGovind Singh static void ath11k_pci_ce_tasklet(unsigned long data)
3522c3960c2SGovind Singh {
3532c3960c2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = (struct ath11k_ce_pipe *)data;
3542c3960c2SGovind Singh 
3552c3960c2SGovind Singh 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
3562c3960c2SGovind Singh 
3572c3960c2SGovind Singh 	ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
3582c3960c2SGovind Singh }
3592c3960c2SGovind Singh 
3607f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
3617f4beda2SGovind Singh {
3627f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = arg;
3637f4beda2SGovind Singh 
3647f4beda2SGovind Singh 	ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
3652c3960c2SGovind Singh 	tasklet_schedule(&ce_pipe->intr_tq);
3667f4beda2SGovind Singh 
3677f4beda2SGovind Singh 	return IRQ_HANDLED;
3687f4beda2SGovind Singh }
3697f4beda2SGovind Singh 
370d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
371d4ecb90bSCarl Huang {
372d4ecb90bSCarl Huang 	int i;
373d4ecb90bSCarl Huang 
374d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
375d4ecb90bSCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
376d4ecb90bSCarl Huang }
377d4ecb90bSCarl Huang 
378d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
379d4ecb90bSCarl Huang {
380d4ecb90bSCarl Huang 	int i;
381d4ecb90bSCarl Huang 
382d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
383d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
384d4ecb90bSCarl Huang 
385d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
386d4ecb90bSCarl Huang 
387d4ecb90bSCarl Huang 		napi_synchronize(&irq_grp->napi);
388d4ecb90bSCarl Huang 		napi_disable(&irq_grp->napi);
389d4ecb90bSCarl Huang 	}
390d4ecb90bSCarl Huang }
391d4ecb90bSCarl Huang 
392d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
393d4ecb90bSCarl Huang {
394d4ecb90bSCarl Huang 	int i;
395d4ecb90bSCarl Huang 
396d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
397d4ecb90bSCarl Huang 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
398d4ecb90bSCarl Huang }
399d4ecb90bSCarl Huang 
400d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
401d4ecb90bSCarl Huang {
402d4ecb90bSCarl Huang 	int i;
403d4ecb90bSCarl Huang 
404d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
405d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
406d4ecb90bSCarl Huang 
407d4ecb90bSCarl Huang 		napi_enable(&irq_grp->napi);
408d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
409d4ecb90bSCarl Huang 	}
410d4ecb90bSCarl Huang }
411d4ecb90bSCarl Huang 
412d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
413d4ecb90bSCarl Huang {
414d4ecb90bSCarl Huang 	int i, j, irq_idx;
415d4ecb90bSCarl Huang 
416d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
417d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
418d4ecb90bSCarl Huang 
419d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
420d4ecb90bSCarl Huang 			irq_idx = irq_grp->irqs[j];
421d4ecb90bSCarl Huang 			synchronize_irq(ab->irq_num[irq_idx]);
422d4ecb90bSCarl Huang 		}
423d4ecb90bSCarl Huang 	}
424d4ecb90bSCarl Huang }
425d4ecb90bSCarl Huang 
426d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
427d4ecb90bSCarl Huang {
428d4ecb90bSCarl Huang 	__ath11k_pci_ext_irq_disable(ab);
429d4ecb90bSCarl Huang 	ath11k_pci_sync_ext_irqs(ab);
430d4ecb90bSCarl Huang }
431d4ecb90bSCarl Huang 
432d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
433d4ecb90bSCarl Huang {
434d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
435d4ecb90bSCarl Huang 						struct ath11k_ext_irq_grp,
436d4ecb90bSCarl Huang 						napi);
437d4ecb90bSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
438d4ecb90bSCarl Huang 	int work_done;
439d4ecb90bSCarl Huang 
440d4ecb90bSCarl Huang 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
441d4ecb90bSCarl Huang 	if (work_done < budget) {
442d4ecb90bSCarl Huang 		napi_complete_done(napi, work_done);
443d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
444d4ecb90bSCarl Huang 	}
445d4ecb90bSCarl Huang 
446d4ecb90bSCarl Huang 	if (work_done > budget)
447d4ecb90bSCarl Huang 		work_done = budget;
448d4ecb90bSCarl Huang 
449d4ecb90bSCarl Huang 	return work_done;
450d4ecb90bSCarl Huang }
451d4ecb90bSCarl Huang 
452d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
453d4ecb90bSCarl Huang {
454d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = arg;
455d4ecb90bSCarl Huang 
456d4ecb90bSCarl Huang 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
457d4ecb90bSCarl Huang 
458d4ecb90bSCarl Huang 	ath11k_pci_ext_grp_disable(irq_grp);
459d4ecb90bSCarl Huang 
460d4ecb90bSCarl Huang 	napi_schedule(&irq_grp->napi);
461d4ecb90bSCarl Huang 
462d4ecb90bSCarl Huang 	return IRQ_HANDLED;
463d4ecb90bSCarl Huang }
464d4ecb90bSCarl Huang 
465d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
466d4ecb90bSCarl Huang {
467d4ecb90bSCarl Huang 	int i, j, ret, num_vectors = 0;
468d4ecb90bSCarl Huang 	u32 user_base_data = 0, base_vector = 0;
469d4ecb90bSCarl Huang 
470b2c09458SColin Ian King 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
471b2c09458SColin Ian King 						 &num_vectors,
472b2c09458SColin Ian King 						 &user_base_data,
473d4ecb90bSCarl Huang 						 &base_vector);
474b2c09458SColin Ian King 	if (ret < 0)
475b2c09458SColin Ian King 		return ret;
476d4ecb90bSCarl Huang 
477d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
478d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
479d4ecb90bSCarl Huang 		u32 num_irq = 0;
480d4ecb90bSCarl Huang 
481d4ecb90bSCarl Huang 		irq_grp->ab = ab;
482d4ecb90bSCarl Huang 		irq_grp->grp_id = i;
483d4ecb90bSCarl Huang 		init_dummy_netdev(&irq_grp->napi_ndev);
484d4ecb90bSCarl Huang 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
485d4ecb90bSCarl Huang 			       ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
486d4ecb90bSCarl Huang 
487d4ecb90bSCarl Huang 		if (ab->hw_params.ring_mask->tx[i] ||
488d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx[i] ||
489d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_err[i] ||
490d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_wbm_rel[i] ||
491d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->reo_status[i] ||
492d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rxdma2host[i] ||
493d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->host2rxdma[i] ||
494d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_mon_status[i]) {
495d4ecb90bSCarl Huang 			num_irq = 1;
496d4ecb90bSCarl Huang 		}
497d4ecb90bSCarl Huang 
498d4ecb90bSCarl Huang 		irq_grp->num_irq = num_irq;
499d4ecb90bSCarl Huang 		irq_grp->irqs[0] = base_vector + i;
500d4ecb90bSCarl Huang 
501d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
502d4ecb90bSCarl Huang 			int irq_idx = irq_grp->irqs[j];
503d4ecb90bSCarl Huang 			int vector = (i % num_vectors) + base_vector;
504d4ecb90bSCarl Huang 			int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
505d4ecb90bSCarl Huang 
506d4ecb90bSCarl Huang 			ab->irq_num[irq_idx] = irq;
507d4ecb90bSCarl Huang 
508d4ecb90bSCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
509d4ecb90bSCarl Huang 				   "irq:%d group:%d\n", irq, i);
510d4ecb90bSCarl Huang 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
511d4ecb90bSCarl Huang 					  IRQF_SHARED,
512d4ecb90bSCarl Huang 					  "DP_EXT_IRQ", irq_grp);
513d4ecb90bSCarl Huang 			if (ret) {
514d4ecb90bSCarl Huang 				ath11k_err(ab, "failed request irq %d: %d\n",
515d4ecb90bSCarl Huang 					   vector, ret);
516d4ecb90bSCarl Huang 				return ret;
517d4ecb90bSCarl Huang 			}
518d4ecb90bSCarl Huang 
519d4ecb90bSCarl Huang 			disable_irq_nosync(ab->irq_num[irq_idx]);
520d4ecb90bSCarl Huang 		}
521d4ecb90bSCarl Huang 	}
522d4ecb90bSCarl Huang 
523d4ecb90bSCarl Huang 	return 0;
524d4ecb90bSCarl Huang }
525d4ecb90bSCarl Huang 
5267f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab)
5277f4beda2SGovind Singh {
5287f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe;
5297f4beda2SGovind Singh 	u32 msi_data_start;
5307f4beda2SGovind Singh 	u32 msi_data_count;
5317f4beda2SGovind Singh 	u32 msi_irq_start;
5327f4beda2SGovind Singh 	unsigned int msi_data;
5337f4beda2SGovind Singh 	int irq, i, ret, irq_idx;
5347f4beda2SGovind Singh 
5357f4beda2SGovind Singh 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab),
5367f4beda2SGovind Singh 						 "CE", &msi_data_count,
5377f4beda2SGovind Singh 						 &msi_data_start, &msi_irq_start);
5387f4beda2SGovind Singh 	if (ret)
5397f4beda2SGovind Singh 		return ret;
5407f4beda2SGovind Singh 
5417f4beda2SGovind Singh 	/* Configure CE irqs */
542d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
5437f4beda2SGovind Singh 		msi_data = (i % msi_data_count) + msi_irq_start;
5447f4beda2SGovind Singh 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
5457f4beda2SGovind Singh 		ce_pipe = &ab->ce.ce_pipe[i];
5467f4beda2SGovind Singh 
547e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5487f4beda2SGovind Singh 			continue;
5497f4beda2SGovind Singh 
5507f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5517f4beda2SGovind Singh 
5522c3960c2SGovind Singh 		tasklet_init(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet,
5532c3960c2SGovind Singh 			     (unsigned long)ce_pipe);
5542c3960c2SGovind Singh 
5557f4beda2SGovind Singh 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
5567f4beda2SGovind Singh 				  IRQF_SHARED, irq_name[irq_idx],
5577f4beda2SGovind Singh 				  ce_pipe);
5587f4beda2SGovind Singh 		if (ret) {
5597f4beda2SGovind Singh 			ath11k_err(ab, "failed to request irq %d: %d\n",
5607f4beda2SGovind Singh 				   irq_idx, ret);
5617f4beda2SGovind Singh 			return ret;
5627f4beda2SGovind Singh 		}
5637f4beda2SGovind Singh 
5647f4beda2SGovind Singh 		ab->irq_num[irq_idx] = irq;
565e5c860e1SCarl Huang 		ath11k_pci_ce_irq_disable(ab, i);
5667f4beda2SGovind Singh 	}
5677f4beda2SGovind Singh 
568d4ecb90bSCarl Huang 	ret = ath11k_pci_ext_irq_config(ab);
569d4ecb90bSCarl Huang 	if (ret)
570d4ecb90bSCarl Huang 		return ret;
571d4ecb90bSCarl Huang 
5727f4beda2SGovind Singh 	return 0;
5737f4beda2SGovind Singh }
5747f4beda2SGovind Singh 
5757f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
5767f4beda2SGovind Singh {
5777f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
5787f4beda2SGovind Singh 
579*967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
580*967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
5817f4beda2SGovind Singh 
582*967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
583*967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
584eb8de049SGovind Singh 	ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390;
5857f4beda2SGovind Singh }
5867f4beda2SGovind Singh 
5877f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
5887f4beda2SGovind Singh {
5897f4beda2SGovind Singh 	int i;
5907f4beda2SGovind Singh 
591d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
592e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5937f4beda2SGovind Singh 			continue;
5947f4beda2SGovind Singh 		ath11k_pci_ce_irq_enable(ab, i);
5957f4beda2SGovind Singh 	}
5967f4beda2SGovind Singh }
5977f4beda2SGovind Singh 
5985697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
5995697a564SGovind Singh {
6005697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
6015697a564SGovind Singh 	struct msi_desc *msi_desc;
6025697a564SGovind Singh 	int num_vectors;
6035697a564SGovind Singh 	int ret;
6045697a564SGovind Singh 
6055697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
6065697a564SGovind Singh 					    msi_config.total_vectors,
6075697a564SGovind Singh 					    msi_config.total_vectors,
6085697a564SGovind Singh 					    PCI_IRQ_MSI);
6095697a564SGovind Singh 	if (num_vectors != msi_config.total_vectors) {
6105697a564SGovind Singh 		ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
6115697a564SGovind Singh 			   msi_config.total_vectors, num_vectors);
6125697a564SGovind Singh 
6135697a564SGovind Singh 		if (num_vectors >= 0)
6145697a564SGovind Singh 			return -EINVAL;
6155697a564SGovind Singh 		else
6165697a564SGovind Singh 			return num_vectors;
6175697a564SGovind Singh 	}
6185697a564SGovind Singh 
6195697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
6205697a564SGovind Singh 	if (!msi_desc) {
6215697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
6225697a564SGovind Singh 		ret = -EINVAL;
6235697a564SGovind Singh 		goto free_msi_vector;
6245697a564SGovind Singh 	}
6255697a564SGovind Singh 
6265697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
6275697a564SGovind Singh 
6285697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
6295697a564SGovind Singh 
6305697a564SGovind Singh 	return 0;
6315697a564SGovind Singh 
6325697a564SGovind Singh free_msi_vector:
6335697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
6345697a564SGovind Singh 
6355697a564SGovind Singh 	return ret;
6365697a564SGovind Singh }
6375697a564SGovind Singh 
6385697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci)
6395697a564SGovind Singh {
6405697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
6415697a564SGovind Singh }
6425697a564SGovind Singh 
6435762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
6445762613eSGovind Singh {
6455762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
6465762613eSGovind Singh 	u16 device_id;
6475762613eSGovind Singh 	int ret = 0;
6485762613eSGovind Singh 
6495762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
6505762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
6515762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
6525762613eSGovind Singh 			   device_id, ab_pci->dev_id);
6535762613eSGovind Singh 		ret = -EIO;
6545762613eSGovind Singh 		goto out;
6555762613eSGovind Singh 	}
6565762613eSGovind Singh 
6575762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
6585762613eSGovind Singh 	if (ret) {
6595762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
6605762613eSGovind Singh 		goto out;
6615762613eSGovind Singh 	}
6625762613eSGovind Singh 
6635762613eSGovind Singh 	ret = pci_enable_device(pdev);
6645762613eSGovind Singh 	if (ret) {
6655762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
6665762613eSGovind Singh 		goto out;
6675762613eSGovind Singh 	}
6685762613eSGovind Singh 
6695762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
6705762613eSGovind Singh 	if (ret) {
6715762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
6725762613eSGovind Singh 		goto disable_device;
6735762613eSGovind Singh 	}
6745762613eSGovind Singh 
6755762613eSGovind Singh 	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
6765762613eSGovind Singh 	if (ret) {
6775762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
6785762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
6795762613eSGovind Singh 		goto release_region;
6805762613eSGovind Singh 	}
6815762613eSGovind Singh 
6825762613eSGovind Singh 	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
6835762613eSGovind Singh 	if (ret) {
6845762613eSGovind Singh 		ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n",
6855762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
6865762613eSGovind Singh 		goto release_region;
6875762613eSGovind Singh 	}
6885762613eSGovind Singh 
6895762613eSGovind Singh 	pci_set_master(pdev);
6905762613eSGovind Singh 
6915762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
6925762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
6935762613eSGovind Singh 	if (!ab->mem) {
6945762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
6955762613eSGovind Singh 		ret = -EIO;
6965762613eSGovind Singh 		goto clear_master;
6975762613eSGovind Singh 	}
6985762613eSGovind Singh 
6995762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
7005762613eSGovind Singh 	return 0;
7015762613eSGovind Singh 
7025762613eSGovind Singh clear_master:
7035762613eSGovind Singh 	pci_clear_master(pdev);
7045762613eSGovind Singh release_region:
7055762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
7065762613eSGovind Singh disable_device:
7075762613eSGovind Singh 	pci_disable_device(pdev);
7085762613eSGovind Singh out:
7095762613eSGovind Singh 	return ret;
7105762613eSGovind Singh }
7115762613eSGovind Singh 
7125762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
7135762613eSGovind Singh {
7145762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
7155762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
7165762613eSGovind Singh 
7175762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
7185762613eSGovind Singh 	ab->mem = NULL;
7195762613eSGovind Singh 	pci_clear_master(pci_dev);
7205762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
7215762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
7225762613eSGovind Singh 		pci_disable_device(pci_dev);
7235762613eSGovind Singh }
7245762613eSGovind Singh 
7251399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
7261399fb87SGovind Singh {
7271399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
7281399fb87SGovind Singh 	int ret;
7291399fb87SGovind Singh 
730f3c603d4SCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab);
731f3c603d4SCarl Huang 
7321399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
7331399fb87SGovind Singh 	if (ret) {
7341399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
7351399fb87SGovind Singh 		return ret;
7361399fb87SGovind Singh 	}
7371399fb87SGovind Singh 
7381399fb87SGovind Singh 	return 0;
7391399fb87SGovind Singh }
7401399fb87SGovind Singh 
7411399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
7421399fb87SGovind Singh {
7431399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
7441399fb87SGovind Singh 
7451399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
746f3c603d4SCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
747f3c603d4SCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab);
7481399fb87SGovind Singh }
7491399fb87SGovind Singh 
7502c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
7512c3960c2SGovind Singh {
7522c3960c2SGovind Singh 	int i;
7532c3960c2SGovind Singh 
754d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
7552c3960c2SGovind Singh 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
7562c3960c2SGovind Singh 
757e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
7582c3960c2SGovind Singh 			continue;
7592c3960c2SGovind Singh 
7602c3960c2SGovind Singh 		tasklet_kill(&ce_pipe->intr_tq);
7612c3960c2SGovind Singh 	}
7622c3960c2SGovind Singh }
7632c3960c2SGovind Singh 
7647f4beda2SGovind Singh static void ath11k_pci_stop(struct ath11k_base *ab)
7657f4beda2SGovind Singh {
7662c3960c2SGovind Singh 	ath11k_pci_ce_irqs_disable(ab);
7672c3960c2SGovind Singh 	ath11k_pci_sync_ce_irqs(ab);
7682c3960c2SGovind Singh 	ath11k_pci_kill_tasklets(ab);
7697f4beda2SGovind Singh 	ath11k_ce_cleanup_pipes(ab);
7707f4beda2SGovind Singh }
7717f4beda2SGovind Singh 
7727f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab)
7737f4beda2SGovind Singh {
7747f4beda2SGovind Singh 	ath11k_pci_ce_irqs_enable(ab);
7752c3960c2SGovind Singh 	ath11k_ce_rx_post_buf(ab);
7762c3960c2SGovind Singh 
7772c3960c2SGovind Singh 	return 0;
7782c3960c2SGovind Singh }
7792c3960c2SGovind Singh 
7802c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
7812c3960c2SGovind Singh 					  u8 *ul_pipe, u8 *dl_pipe)
7822c3960c2SGovind Singh {
7832c3960c2SGovind Singh 	const struct service_to_pipe *entry;
7842c3960c2SGovind Singh 	bool ul_set = false, dl_set = false;
7852c3960c2SGovind Singh 	int i;
7862c3960c2SGovind Singh 
787*967c1d11SAnilkumar Kolli 	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
788*967c1d11SAnilkumar Kolli 		entry = &ab->hw_params.svc_to_ce_map[i];
7892c3960c2SGovind Singh 
7902c3960c2SGovind Singh 		if (__le32_to_cpu(entry->service_id) != service_id)
7912c3960c2SGovind Singh 			continue;
7922c3960c2SGovind Singh 
7932c3960c2SGovind Singh 		switch (__le32_to_cpu(entry->pipedir)) {
7942c3960c2SGovind Singh 		case PIPEDIR_NONE:
7952c3960c2SGovind Singh 			break;
7962c3960c2SGovind Singh 		case PIPEDIR_IN:
7972c3960c2SGovind Singh 			WARN_ON(dl_set);
7982c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
7992c3960c2SGovind Singh 			dl_set = true;
8002c3960c2SGovind Singh 			break;
8012c3960c2SGovind Singh 		case PIPEDIR_OUT:
8022c3960c2SGovind Singh 			WARN_ON(ul_set);
8032c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
8042c3960c2SGovind Singh 			ul_set = true;
8052c3960c2SGovind Singh 			break;
8062c3960c2SGovind Singh 		case PIPEDIR_INOUT:
8072c3960c2SGovind Singh 			WARN_ON(dl_set);
8082c3960c2SGovind Singh 			WARN_ON(ul_set);
8092c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
8102c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
8112c3960c2SGovind Singh 			dl_set = true;
8122c3960c2SGovind Singh 			ul_set = true;
8132c3960c2SGovind Singh 			break;
8142c3960c2SGovind Singh 		}
8152c3960c2SGovind Singh 	}
8162c3960c2SGovind Singh 
8172c3960c2SGovind Singh 	if (WARN_ON(!ul_set || !dl_set))
8182c3960c2SGovind Singh 		return -ENOENT;
8197f4beda2SGovind Singh 
8207f4beda2SGovind Singh 	return 0;
8217f4beda2SGovind Singh }
8227f4beda2SGovind Singh 
8237f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
8247f4beda2SGovind Singh 	.start = ath11k_pci_start,
8257f4beda2SGovind Singh 	.stop = ath11k_pci_stop,
826654e959aSGovind Singh 	.read32 = ath11k_pci_read32,
827654e959aSGovind Singh 	.write32 = ath11k_pci_write32,
8281399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
8291399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
830d4ecb90bSCarl Huang 	.irq_enable = ath11k_pci_ext_irq_enable,
831d4ecb90bSCarl Huang 	.irq_disable = ath11k_pci_ext_irq_disable,
832c4eacabeSGovind Singh 	.get_msi_address =  ath11k_pci_get_msi_address,
833c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
8342c3960c2SGovind Singh 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
8351399fb87SGovind Singh };
8361399fb87SGovind Singh 
8376e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
8386e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
8396e0355afSGovind Singh {
8406e0355afSGovind Singh 	struct ath11k_base *ab;
8415762613eSGovind Singh 	struct ath11k_pci *ab_pci;
8426e0355afSGovind Singh 	enum ath11k_hw_rev hw_rev;
8435762613eSGovind Singh 	int ret;
8446e0355afSGovind Singh 
8456e0355afSGovind Singh 	dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n");
8466e0355afSGovind Singh 
8476e0355afSGovind Singh 	switch (pci_dev->device) {
8486e0355afSGovind Singh 	case QCA6390_DEVICE_ID:
8496e0355afSGovind Singh 		hw_rev = ATH11K_HW_QCA6390_HW20;
8506e0355afSGovind Singh 		break;
8516e0355afSGovind Singh 	default:
8526e0355afSGovind Singh 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
8536e0355afSGovind Singh 			pci_dev->device);
8546e0355afSGovind Singh 		return -ENOTSUPP;
8556e0355afSGovind Singh 	}
8566e0355afSGovind Singh 
8571ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
8581ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
8596e0355afSGovind Singh 	if (!ab) {
8606e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
8616e0355afSGovind Singh 		return -ENOMEM;
8626e0355afSGovind Singh 	}
8636e0355afSGovind Singh 
8646e0355afSGovind Singh 	ab->dev = &pdev->dev;
8656e0355afSGovind Singh 	ab->hw_rev = hw_rev;
8666e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
8675762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
8685762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
8695762613eSGovind Singh 	ab_pci->ab = ab;
8705697a564SGovind Singh 	ab_pci->pdev = pdev;
8717f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
8725762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
873654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
8745762613eSGovind Singh 
8755762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
8765762613eSGovind Singh 	if (ret) {
8775762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
8785762613eSGovind Singh 		goto err_free_core;
8795762613eSGovind Singh 	}
8806e0355afSGovind Singh 
8815697a564SGovind Singh 	ret = ath11k_pci_enable_msi(ab_pci);
8825697a564SGovind Singh 	if (ret) {
8835697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
8845697a564SGovind Singh 		goto err_pci_free_region;
8855697a564SGovind Singh 	}
8865697a564SGovind Singh 
887b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
888b8246f88SKalle Valo 	if (ret)
889b8246f88SKalle Valo 		goto err_pci_disable_msi;
890b8246f88SKalle Valo 
8911399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
8921399fb87SGovind Singh 	if (ret) {
8931399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
8941399fb87SGovind Singh 		goto err_pci_disable_msi;
8951399fb87SGovind Singh 	}
8961399fb87SGovind Singh 
8977f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
8987f4beda2SGovind Singh 	if (ret)
8997f4beda2SGovind Singh 		goto err_mhi_unregister;
9007f4beda2SGovind Singh 
9017f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
9027f4beda2SGovind Singh 	if (ret) {
9037f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
9047f4beda2SGovind Singh 		goto err_hal_srng_deinit;
9057f4beda2SGovind Singh 	}
9067f4beda2SGovind Singh 
9077f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
9087f4beda2SGovind Singh 
9097f4beda2SGovind Singh 	ret = ath11k_pci_config_irq(ab);
9107f4beda2SGovind Singh 	if (ret) {
9117f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
9127f4beda2SGovind Singh 		goto err_ce_free;
9137f4beda2SGovind Singh 	}
9147f4beda2SGovind Singh 
9157f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
9167f4beda2SGovind Singh 	if (ret) {
9177f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
9187f4beda2SGovind Singh 		goto err_free_irq;
9197f4beda2SGovind Singh 	}
9206e0355afSGovind Singh 	return 0;
9215762613eSGovind Singh 
9227f4beda2SGovind Singh err_free_irq:
9237f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
9247f4beda2SGovind Singh 
9257f4beda2SGovind Singh err_ce_free:
9267f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
9277f4beda2SGovind Singh 
9287f4beda2SGovind Singh err_hal_srng_deinit:
9297f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
9307f4beda2SGovind Singh 
9317f4beda2SGovind Singh err_mhi_unregister:
9327f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
9337f4beda2SGovind Singh 
934b8246f88SKalle Valo err_pci_disable_msi:
935b8246f88SKalle Valo 	ath11k_pci_disable_msi(ab_pci);
936b8246f88SKalle Valo 
9375697a564SGovind Singh err_pci_free_region:
9385697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
9395697a564SGovind Singh 
9405762613eSGovind Singh err_free_core:
9415762613eSGovind Singh 	ath11k_core_free(ab);
9425697a564SGovind Singh 
9435762613eSGovind Singh 	return ret;
9446e0355afSGovind Singh }
9456e0355afSGovind Singh 
9466e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
9476e0355afSGovind Singh {
9486e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
9495762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
9506e0355afSGovind Singh 
9516e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
9521399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
9535697a564SGovind Singh 	ath11k_pci_disable_msi(ab_pci);
9545762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
9557f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
9566e0355afSGovind Singh 	ath11k_core_free(ab);
9576e0355afSGovind Singh }
9586e0355afSGovind Singh 
9591399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
9601399fb87SGovind Singh {
9611399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
9621399fb87SGovind Singh 
9631399fb87SGovind Singh 	ath11k_pci_power_down(ab);
9641399fb87SGovind Singh }
9651399fb87SGovind Singh 
9666e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
9676e0355afSGovind Singh 	.name = "ath11k_pci",
9686e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
9696e0355afSGovind Singh 	.probe = ath11k_pci_probe,
9706e0355afSGovind Singh 	.remove = ath11k_pci_remove,
9711399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
9726e0355afSGovind Singh };
9736e0355afSGovind Singh 
9746e0355afSGovind Singh static int ath11k_pci_init(void)
9756e0355afSGovind Singh {
9766e0355afSGovind Singh 	int ret;
9776e0355afSGovind Singh 
9786e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
9796e0355afSGovind Singh 	if (ret)
9806e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
9816e0355afSGovind Singh 		       ret);
9826e0355afSGovind Singh 
9836e0355afSGovind Singh 	return ret;
9846e0355afSGovind Singh }
9856e0355afSGovind Singh module_init(ath11k_pci_init);
9866e0355afSGovind Singh 
9876e0355afSGovind Singh static void ath11k_pci_exit(void)
9886e0355afSGovind Singh {
9896e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
9906e0355afSGovind Singh }
9916e0355afSGovind Singh 
9926e0355afSGovind Singh module_exit(ath11k_pci_exit);
9936e0355afSGovind Singh 
9946e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
9956e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
996