xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision 18ac1665e78575a5148b2bd2c90749c2bcbf135a)
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 
27*18ac1665SKalle Valo #define TCSR_SOC_HW_VERSION		0x0224
28*18ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MAJOR_MASK	GENMASK(16, 8)
29*18ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MINOR_MASK	GENMASK(7, 0)
30*18ac1665SKalle Valo 
316e0355afSGovind Singh #define QCA6390_DEVICE_ID		0x1101
326e0355afSGovind Singh 
336e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = {
346e0355afSGovind Singh 	{ PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) },
356e0355afSGovind Singh 	{0}
366e0355afSGovind Singh };
376e0355afSGovind Singh 
386e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table);
396e0355afSGovind Singh 
401ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = {
411ff8ed78SGovind Singh 	.mhi_support = true,
4256970454SGovind Singh 	.m3_fw_support = true,
436eb6ea51SGovind Singh 	.fixed_bdf_addr = false,
446eb6ea51SGovind Singh 	.fixed_mem_region = false,
451ff8ed78SGovind Singh };
461ff8ed78SGovind Singh 
475697a564SGovind Singh static const struct ath11k_msi_config msi_config = {
485697a564SGovind Singh 	.total_vectors = 32,
495697a564SGovind Singh 	.total_users = 4,
505697a564SGovind Singh 	.users = (struct ath11k_msi_user[]) {
515697a564SGovind Singh 		{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
525697a564SGovind Singh 		{ .name = "CE", .num_vectors = 10, .base_vector = 3 },
535697a564SGovind Singh 		{ .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
545697a564SGovind Singh 		{ .name = "DP", .num_vectors = 18, .base_vector = 14 },
555697a564SGovind Singh 	},
565697a564SGovind Singh };
575697a564SGovind Singh 
587f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
597f4beda2SGovind Singh 	"bhi",
607f4beda2SGovind Singh 	"mhi-er0",
617f4beda2SGovind Singh 	"mhi-er1",
627f4beda2SGovind Singh 	"ce0",
637f4beda2SGovind Singh 	"ce1",
647f4beda2SGovind Singh 	"ce2",
657f4beda2SGovind Singh 	"ce3",
667f4beda2SGovind Singh 	"ce4",
677f4beda2SGovind Singh 	"ce5",
687f4beda2SGovind Singh 	"ce6",
697f4beda2SGovind Singh 	"ce7",
707f4beda2SGovind Singh 	"ce8",
717f4beda2SGovind Singh 	"ce9",
727f4beda2SGovind Singh 	"ce10",
737f4beda2SGovind Singh 	"ce11",
747f4beda2SGovind Singh 	"host2wbm-desc-feed",
757f4beda2SGovind Singh 	"host2reo-re-injection",
767f4beda2SGovind Singh 	"host2reo-command",
777f4beda2SGovind Singh 	"host2rxdma-monitor-ring3",
787f4beda2SGovind Singh 	"host2rxdma-monitor-ring2",
797f4beda2SGovind Singh 	"host2rxdma-monitor-ring1",
807f4beda2SGovind Singh 	"reo2ost-exception",
817f4beda2SGovind Singh 	"wbm2host-rx-release",
827f4beda2SGovind Singh 	"reo2host-status",
837f4beda2SGovind Singh 	"reo2host-destination-ring4",
847f4beda2SGovind Singh 	"reo2host-destination-ring3",
857f4beda2SGovind Singh 	"reo2host-destination-ring2",
867f4beda2SGovind Singh 	"reo2host-destination-ring1",
877f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac3",
887f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac2",
897f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac1",
907f4beda2SGovind Singh 	"ppdu-end-interrupts-mac3",
917f4beda2SGovind Singh 	"ppdu-end-interrupts-mac2",
927f4beda2SGovind Singh 	"ppdu-end-interrupts-mac1",
937f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac3",
947f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac2",
957f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac1",
967f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac3",
977f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac2",
987f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac1",
997f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac3",
1007f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac2",
1017f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac1",
1027f4beda2SGovind Singh 	"host2tcl-input-ring4",
1037f4beda2SGovind Singh 	"host2tcl-input-ring3",
1047f4beda2SGovind Singh 	"host2tcl-input-ring2",
1057f4beda2SGovind Singh 	"host2tcl-input-ring1",
1067f4beda2SGovind Singh 	"wbm2host-tx-completions-ring3",
1077f4beda2SGovind Singh 	"wbm2host-tx-completions-ring2",
1087f4beda2SGovind Singh 	"wbm2host-tx-completions-ring1",
1097f4beda2SGovind Singh 	"tcl2host-status-ring",
1107f4beda2SGovind Singh };
1117f4beda2SGovind Singh 
112654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset)
113654e959aSGovind Singh {
114654e959aSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
115654e959aSGovind Singh 
116654e959aSGovind Singh 	u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset);
117654e959aSGovind Singh 
118654e959aSGovind Singh 	lockdep_assert_held(&ab_pci->window_lock);
119654e959aSGovind Singh 
120654e959aSGovind Singh 	if (window != ab_pci->register_window) {
121654e959aSGovind Singh 		iowrite32(WINDOW_ENABLE_BIT | window,
122654e959aSGovind Singh 			  ab->mem + WINDOW_REG_ADDRESS);
123654e959aSGovind Singh 		ab_pci->register_window = window;
124654e959aSGovind Singh 	}
125654e959aSGovind Singh }
126654e959aSGovind Singh 
127f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
128654e959aSGovind Singh {
129654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
130654e959aSGovind Singh 
131654e959aSGovind Singh 	if (offset < WINDOW_START) {
132654e959aSGovind Singh 		iowrite32(value, ab->mem  + offset);
133654e959aSGovind Singh 	} else {
134654e959aSGovind Singh 		spin_lock_bh(&ab_pci->window_lock);
135654e959aSGovind Singh 		ath11k_pci_select_window(ab_pci, offset);
136654e959aSGovind Singh 		iowrite32(value, ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK));
137654e959aSGovind Singh 		spin_unlock_bh(&ab_pci->window_lock);
138654e959aSGovind Singh 	}
139654e959aSGovind Singh }
140654e959aSGovind Singh 
141f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
142654e959aSGovind Singh {
143654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
144654e959aSGovind Singh 	u32 val;
145654e959aSGovind Singh 
146654e959aSGovind Singh 	if (offset < WINDOW_START) {
147654e959aSGovind Singh 		val = ioread32(ab->mem + offset);
148654e959aSGovind Singh 	} else {
149654e959aSGovind Singh 		spin_lock_bh(&ab_pci->window_lock);
150654e959aSGovind Singh 		ath11k_pci_select_window(ab_pci, offset);
151654e959aSGovind Singh 		val = ioread32(ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK));
152654e959aSGovind Singh 		spin_unlock_bh(&ab_pci->window_lock);
153654e959aSGovind Singh 	}
154654e959aSGovind Singh 
155654e959aSGovind Singh 	return val;
156654e959aSGovind Singh }
157654e959aSGovind Singh 
158f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
159f3c603d4SCarl Huang {
160f3c603d4SCarl Huang 	u32 val, delay;
161f3c603d4SCarl Huang 
162f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
163f3c603d4SCarl Huang 
164f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
165f3c603d4SCarl Huang 
166f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
167f3c603d4SCarl Huang 
168f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
169f3c603d4SCarl Huang 	delay = 10;
170f3c603d4SCarl Huang 	mdelay(delay);
171f3c603d4SCarl Huang 
172f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
173f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
174f3c603d4SCarl Huang 
175f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
176f3c603d4SCarl Huang 
177f3c603d4SCarl Huang 	mdelay(delay);
178f3c603d4SCarl Huang 
179f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
180f3c603d4SCarl Huang 	if (val == 0xffffffff)
181f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
182f3c603d4SCarl Huang }
183f3c603d4SCarl Huang 
184f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
185f3c603d4SCarl Huang {
186f3c603d4SCarl Huang 	u32 val;
187f3c603d4SCarl Huang 
188f3c603d4SCarl Huang 	/* read cookie */
189f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR);
190f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val);
191f3c603d4SCarl Huang 
192f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
193f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
194f3c603d4SCarl Huang 
195f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
196f3c603d4SCarl Huang 	mdelay(10);
197f3c603d4SCarl Huang 
198f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
199f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
200f3c603d4SCarl Huang 	 */
201f3c603d4SCarl Huang 	ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0);
202f3c603d4SCarl Huang 	mdelay(10);
203f3c603d4SCarl Huang 
204f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
205f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
206f3c603d4SCarl Huang 
207f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
208f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
209f3c603d4SCarl Huang 	 */
210f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
211f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
212f3c603d4SCarl Huang }
213f3c603d4SCarl Huang 
214f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
215f3c603d4SCarl Huang {
216f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
217f3c603d4SCarl Huang 	mdelay(5);
218f3c603d4SCarl Huang }
219f3c603d4SCarl Huang 
220f3c603d4SCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab)
221f3c603d4SCarl Huang {
222f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
223f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
224f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
225f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
226f3c603d4SCarl Huang 	ath11k_pci_clear_dbg_registers(ab);
227f3c603d4SCarl Huang }
228f3c603d4SCarl Huang 
2291399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
2301399fb87SGovind Singh {
2311399fb87SGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(dev);
2321399fb87SGovind Singh 
2331399fb87SGovind Singh 	return pci_irq_vector(pci_dev, vector);
2341399fb87SGovind Singh }
2351399fb87SGovind Singh 
236c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
237c4eacabeSGovind Singh 				       u32 *msi_addr_hi)
238c4eacabeSGovind Singh {
239c4eacabeSGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
240c4eacabeSGovind Singh 
241c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
242c4eacabeSGovind Singh 			      msi_addr_lo);
243c4eacabeSGovind Singh 
244c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
245c4eacabeSGovind Singh 			      msi_addr_hi);
246c4eacabeSGovind Singh }
247c4eacabeSGovind Singh 
2481399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
2491399fb87SGovind Singh 				       int *num_vectors, u32 *user_base_data,
2501399fb87SGovind Singh 				       u32 *base_vector)
2511399fb87SGovind Singh {
2521399fb87SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
2531399fb87SGovind Singh 	int idx;
2541399fb87SGovind Singh 
2551399fb87SGovind Singh 	for (idx = 0; idx < msi_config.total_users; idx++) {
2561399fb87SGovind Singh 		if (strcmp(user_name, msi_config.users[idx].name) == 0) {
2571399fb87SGovind Singh 			*num_vectors = msi_config.users[idx].num_vectors;
2581399fb87SGovind Singh 			*user_base_data = msi_config.users[idx].base_vector
2591399fb87SGovind Singh 				+ ab_pci->msi_ep_base_data;
2601399fb87SGovind Singh 			*base_vector = msi_config.users[idx].base_vector;
2611399fb87SGovind Singh 
2621399fb87SGovind Singh 			ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
2631399fb87SGovind Singh 				   user_name, *num_vectors, *user_base_data,
2641399fb87SGovind Singh 				   *base_vector);
2651399fb87SGovind Singh 
2661399fb87SGovind Singh 			return 0;
2671399fb87SGovind Singh 		}
2681399fb87SGovind Singh 	}
2691399fb87SGovind Singh 
2701399fb87SGovind Singh 	ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
2711399fb87SGovind Singh 
2721399fb87SGovind Singh 	return -EINVAL;
2731399fb87SGovind Singh }
2741399fb87SGovind Singh 
275c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
276c4eacabeSGovind Singh 					  int *num_vectors, u32 *user_base_data,
277c4eacabeSGovind Singh 					  u32 *base_vector)
278c4eacabeSGovind Singh {
279c4eacabeSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
280c4eacabeSGovind Singh 
281c4eacabeSGovind Singh 	return ath11k_pci_get_user_msi_assignment(ab_pci, user_name,
282c4eacabeSGovind Singh 						  num_vectors, user_base_data,
283c4eacabeSGovind Singh 						  base_vector);
284c4eacabeSGovind Singh }
285c4eacabeSGovind Singh 
286d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
287d4ecb90bSCarl Huang {
288d4ecb90bSCarl Huang 	int i, j;
289d4ecb90bSCarl Huang 
290d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
291d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
292d4ecb90bSCarl Huang 
293d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++)
294d4ecb90bSCarl Huang 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
295d4ecb90bSCarl Huang 
296d4ecb90bSCarl Huang 		netif_napi_del(&irq_grp->napi);
297d4ecb90bSCarl Huang 	}
298d4ecb90bSCarl Huang }
299d4ecb90bSCarl Huang 
3007f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab)
3017f4beda2SGovind Singh {
3027f4beda2SGovind Singh 	int i, irq_idx;
3037f4beda2SGovind Singh 
304d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
305e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
3067f4beda2SGovind Singh 			continue;
3077f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
3087f4beda2SGovind Singh 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
3097f4beda2SGovind Singh 	}
310d4ecb90bSCarl Huang 
311d4ecb90bSCarl Huang 	ath11k_pci_free_ext_irq(ab);
3127f4beda2SGovind Singh }
3137f4beda2SGovind Singh 
3142c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
3152c3960c2SGovind Singh {
3162c3960c2SGovind Singh 	u32 irq_idx;
3172c3960c2SGovind Singh 
3182c3960c2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
3192c3960c2SGovind Singh 	enable_irq(ab->irq_num[irq_idx]);
3202c3960c2SGovind Singh }
3212c3960c2SGovind Singh 
3227f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
3237f4beda2SGovind Singh {
3247f4beda2SGovind Singh 	u32 irq_idx;
3257f4beda2SGovind Singh 
3267f4beda2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
3277f4beda2SGovind Singh 	disable_irq_nosync(ab->irq_num[irq_idx]);
3287f4beda2SGovind Singh }
3297f4beda2SGovind Singh 
3302c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
3312c3960c2SGovind Singh {
3322c3960c2SGovind Singh 	int i;
3332c3960c2SGovind Singh 
334d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
335e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
3362c3960c2SGovind Singh 			continue;
3372c3960c2SGovind Singh 		ath11k_pci_ce_irq_disable(ab, i);
3382c3960c2SGovind Singh 	}
3392c3960c2SGovind Singh }
3402c3960c2SGovind Singh 
3412c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
3422c3960c2SGovind Singh {
3432c3960c2SGovind Singh 	int i;
3442c3960c2SGovind Singh 	int irq_idx;
3452c3960c2SGovind Singh 
346d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
347e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
3482c3960c2SGovind Singh 			continue;
3492c3960c2SGovind Singh 
3502c3960c2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
3512c3960c2SGovind Singh 		synchronize_irq(ab->irq_num[irq_idx]);
3522c3960c2SGovind Singh 	}
3532c3960c2SGovind Singh }
3542c3960c2SGovind Singh 
3552c3960c2SGovind Singh static void ath11k_pci_ce_tasklet(unsigned long data)
3562c3960c2SGovind Singh {
3572c3960c2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = (struct ath11k_ce_pipe *)data;
3582c3960c2SGovind Singh 
3592c3960c2SGovind Singh 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
3602c3960c2SGovind Singh 
3612c3960c2SGovind Singh 	ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
3622c3960c2SGovind Singh }
3632c3960c2SGovind Singh 
3647f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
3657f4beda2SGovind Singh {
3667f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = arg;
3677f4beda2SGovind Singh 
3687f4beda2SGovind Singh 	ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
3692c3960c2SGovind Singh 	tasklet_schedule(&ce_pipe->intr_tq);
3707f4beda2SGovind Singh 
3717f4beda2SGovind Singh 	return IRQ_HANDLED;
3727f4beda2SGovind Singh }
3737f4beda2SGovind Singh 
374d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
375d4ecb90bSCarl Huang {
376d4ecb90bSCarl Huang 	int i;
377d4ecb90bSCarl Huang 
378d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
379d4ecb90bSCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
380d4ecb90bSCarl Huang }
381d4ecb90bSCarl Huang 
382d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
383d4ecb90bSCarl Huang {
384d4ecb90bSCarl Huang 	int i;
385d4ecb90bSCarl Huang 
386d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
387d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
388d4ecb90bSCarl Huang 
389d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
390d4ecb90bSCarl Huang 
391d4ecb90bSCarl Huang 		napi_synchronize(&irq_grp->napi);
392d4ecb90bSCarl Huang 		napi_disable(&irq_grp->napi);
393d4ecb90bSCarl Huang 	}
394d4ecb90bSCarl Huang }
395d4ecb90bSCarl Huang 
396d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
397d4ecb90bSCarl Huang {
398d4ecb90bSCarl Huang 	int i;
399d4ecb90bSCarl Huang 
400d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
401d4ecb90bSCarl Huang 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
402d4ecb90bSCarl Huang }
403d4ecb90bSCarl Huang 
404d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
405d4ecb90bSCarl Huang {
406d4ecb90bSCarl Huang 	int i;
407d4ecb90bSCarl Huang 
408d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
409d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
410d4ecb90bSCarl Huang 
411d4ecb90bSCarl Huang 		napi_enable(&irq_grp->napi);
412d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
413d4ecb90bSCarl Huang 	}
414d4ecb90bSCarl Huang }
415d4ecb90bSCarl Huang 
416d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
417d4ecb90bSCarl Huang {
418d4ecb90bSCarl Huang 	int i, j, irq_idx;
419d4ecb90bSCarl Huang 
420d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
421d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
422d4ecb90bSCarl Huang 
423d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
424d4ecb90bSCarl Huang 			irq_idx = irq_grp->irqs[j];
425d4ecb90bSCarl Huang 			synchronize_irq(ab->irq_num[irq_idx]);
426d4ecb90bSCarl Huang 		}
427d4ecb90bSCarl Huang 	}
428d4ecb90bSCarl Huang }
429d4ecb90bSCarl Huang 
430d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
431d4ecb90bSCarl Huang {
432d4ecb90bSCarl Huang 	__ath11k_pci_ext_irq_disable(ab);
433d4ecb90bSCarl Huang 	ath11k_pci_sync_ext_irqs(ab);
434d4ecb90bSCarl Huang }
435d4ecb90bSCarl Huang 
436d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
437d4ecb90bSCarl Huang {
438d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
439d4ecb90bSCarl Huang 						struct ath11k_ext_irq_grp,
440d4ecb90bSCarl Huang 						napi);
441d4ecb90bSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
442d4ecb90bSCarl Huang 	int work_done;
443d4ecb90bSCarl Huang 
444d4ecb90bSCarl Huang 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
445d4ecb90bSCarl Huang 	if (work_done < budget) {
446d4ecb90bSCarl Huang 		napi_complete_done(napi, work_done);
447d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
448d4ecb90bSCarl Huang 	}
449d4ecb90bSCarl Huang 
450d4ecb90bSCarl Huang 	if (work_done > budget)
451d4ecb90bSCarl Huang 		work_done = budget;
452d4ecb90bSCarl Huang 
453d4ecb90bSCarl Huang 	return work_done;
454d4ecb90bSCarl Huang }
455d4ecb90bSCarl Huang 
456d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
457d4ecb90bSCarl Huang {
458d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = arg;
459d4ecb90bSCarl Huang 
460d4ecb90bSCarl Huang 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
461d4ecb90bSCarl Huang 
462d4ecb90bSCarl Huang 	ath11k_pci_ext_grp_disable(irq_grp);
463d4ecb90bSCarl Huang 
464d4ecb90bSCarl Huang 	napi_schedule(&irq_grp->napi);
465d4ecb90bSCarl Huang 
466d4ecb90bSCarl Huang 	return IRQ_HANDLED;
467d4ecb90bSCarl Huang }
468d4ecb90bSCarl Huang 
469d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
470d4ecb90bSCarl Huang {
471d4ecb90bSCarl Huang 	int i, j, ret, num_vectors = 0;
472d4ecb90bSCarl Huang 	u32 user_base_data = 0, base_vector = 0;
473d4ecb90bSCarl Huang 
474b2c09458SColin Ian King 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
475b2c09458SColin Ian King 						 &num_vectors,
476b2c09458SColin Ian King 						 &user_base_data,
477d4ecb90bSCarl Huang 						 &base_vector);
478b2c09458SColin Ian King 	if (ret < 0)
479b2c09458SColin Ian King 		return ret;
480d4ecb90bSCarl Huang 
481d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
482d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
483d4ecb90bSCarl Huang 		u32 num_irq = 0;
484d4ecb90bSCarl Huang 
485d4ecb90bSCarl Huang 		irq_grp->ab = ab;
486d4ecb90bSCarl Huang 		irq_grp->grp_id = i;
487d4ecb90bSCarl Huang 		init_dummy_netdev(&irq_grp->napi_ndev);
488d4ecb90bSCarl Huang 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
489d4ecb90bSCarl Huang 			       ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
490d4ecb90bSCarl Huang 
491d4ecb90bSCarl Huang 		if (ab->hw_params.ring_mask->tx[i] ||
492d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx[i] ||
493d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_err[i] ||
494d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_wbm_rel[i] ||
495d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->reo_status[i] ||
496d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rxdma2host[i] ||
497d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->host2rxdma[i] ||
498d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_mon_status[i]) {
499d4ecb90bSCarl Huang 			num_irq = 1;
500d4ecb90bSCarl Huang 		}
501d4ecb90bSCarl Huang 
502d4ecb90bSCarl Huang 		irq_grp->num_irq = num_irq;
503d4ecb90bSCarl Huang 		irq_grp->irqs[0] = base_vector + i;
504d4ecb90bSCarl Huang 
505d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
506d4ecb90bSCarl Huang 			int irq_idx = irq_grp->irqs[j];
507d4ecb90bSCarl Huang 			int vector = (i % num_vectors) + base_vector;
508d4ecb90bSCarl Huang 			int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
509d4ecb90bSCarl Huang 
510d4ecb90bSCarl Huang 			ab->irq_num[irq_idx] = irq;
511d4ecb90bSCarl Huang 
512d4ecb90bSCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
513d4ecb90bSCarl Huang 				   "irq:%d group:%d\n", irq, i);
514d4ecb90bSCarl Huang 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
515d4ecb90bSCarl Huang 					  IRQF_SHARED,
516d4ecb90bSCarl Huang 					  "DP_EXT_IRQ", irq_grp);
517d4ecb90bSCarl Huang 			if (ret) {
518d4ecb90bSCarl Huang 				ath11k_err(ab, "failed request irq %d: %d\n",
519d4ecb90bSCarl Huang 					   vector, ret);
520d4ecb90bSCarl Huang 				return ret;
521d4ecb90bSCarl Huang 			}
522d4ecb90bSCarl Huang 
523d4ecb90bSCarl Huang 			disable_irq_nosync(ab->irq_num[irq_idx]);
524d4ecb90bSCarl Huang 		}
525d4ecb90bSCarl Huang 	}
526d4ecb90bSCarl Huang 
527d4ecb90bSCarl Huang 	return 0;
528d4ecb90bSCarl Huang }
529d4ecb90bSCarl Huang 
5307f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab)
5317f4beda2SGovind Singh {
5327f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe;
5337f4beda2SGovind Singh 	u32 msi_data_start;
5347f4beda2SGovind Singh 	u32 msi_data_count;
5357f4beda2SGovind Singh 	u32 msi_irq_start;
5367f4beda2SGovind Singh 	unsigned int msi_data;
5377f4beda2SGovind Singh 	int irq, i, ret, irq_idx;
5387f4beda2SGovind Singh 
5397f4beda2SGovind Singh 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab),
5407f4beda2SGovind Singh 						 "CE", &msi_data_count,
5417f4beda2SGovind Singh 						 &msi_data_start, &msi_irq_start);
5427f4beda2SGovind Singh 	if (ret)
5437f4beda2SGovind Singh 		return ret;
5447f4beda2SGovind Singh 
5457f4beda2SGovind Singh 	/* Configure CE irqs */
546d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
5477f4beda2SGovind Singh 		msi_data = (i % msi_data_count) + msi_irq_start;
5487f4beda2SGovind Singh 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
5497f4beda2SGovind Singh 		ce_pipe = &ab->ce.ce_pipe[i];
5507f4beda2SGovind Singh 
551e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5527f4beda2SGovind Singh 			continue;
5537f4beda2SGovind Singh 
5547f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5557f4beda2SGovind Singh 
5562c3960c2SGovind Singh 		tasklet_init(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet,
5572c3960c2SGovind Singh 			     (unsigned long)ce_pipe);
5582c3960c2SGovind Singh 
5597f4beda2SGovind Singh 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
5607f4beda2SGovind Singh 				  IRQF_SHARED, irq_name[irq_idx],
5617f4beda2SGovind Singh 				  ce_pipe);
5627f4beda2SGovind Singh 		if (ret) {
5637f4beda2SGovind Singh 			ath11k_err(ab, "failed to request irq %d: %d\n",
5647f4beda2SGovind Singh 				   irq_idx, ret);
5657f4beda2SGovind Singh 			return ret;
5667f4beda2SGovind Singh 		}
5677f4beda2SGovind Singh 
5687f4beda2SGovind Singh 		ab->irq_num[irq_idx] = irq;
569e5c860e1SCarl Huang 		ath11k_pci_ce_irq_disable(ab, i);
5707f4beda2SGovind Singh 	}
5717f4beda2SGovind Singh 
572d4ecb90bSCarl Huang 	ret = ath11k_pci_ext_irq_config(ab);
573d4ecb90bSCarl Huang 	if (ret)
574d4ecb90bSCarl Huang 		return ret;
575d4ecb90bSCarl Huang 
5767f4beda2SGovind Singh 	return 0;
5777f4beda2SGovind Singh }
5787f4beda2SGovind Singh 
5797f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
5807f4beda2SGovind Singh {
5817f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
5827f4beda2SGovind Singh 
583967c1d11SAnilkumar Kolli 	cfg->tgt_ce = ab->hw_params.target_ce_config;
584967c1d11SAnilkumar Kolli 	cfg->tgt_ce_len = ab->hw_params.target_ce_count;
5857f4beda2SGovind Singh 
586967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
587967c1d11SAnilkumar Kolli 	cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
588eb8de049SGovind Singh 	ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390;
5897f4beda2SGovind Singh }
5907f4beda2SGovind Singh 
5917f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
5927f4beda2SGovind Singh {
5937f4beda2SGovind Singh 	int i;
5947f4beda2SGovind Singh 
595d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
596e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5977f4beda2SGovind Singh 			continue;
5987f4beda2SGovind Singh 		ath11k_pci_ce_irq_enable(ab, i);
5997f4beda2SGovind Singh 	}
6007f4beda2SGovind Singh }
6017f4beda2SGovind Singh 
6025697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
6035697a564SGovind Singh {
6045697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
6055697a564SGovind Singh 	struct msi_desc *msi_desc;
6065697a564SGovind Singh 	int num_vectors;
6075697a564SGovind Singh 	int ret;
6085697a564SGovind Singh 
6095697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
6105697a564SGovind Singh 					    msi_config.total_vectors,
6115697a564SGovind Singh 					    msi_config.total_vectors,
6125697a564SGovind Singh 					    PCI_IRQ_MSI);
6135697a564SGovind Singh 	if (num_vectors != msi_config.total_vectors) {
6145697a564SGovind Singh 		ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
6155697a564SGovind Singh 			   msi_config.total_vectors, num_vectors);
6165697a564SGovind Singh 
6175697a564SGovind Singh 		if (num_vectors >= 0)
6185697a564SGovind Singh 			return -EINVAL;
6195697a564SGovind Singh 		else
6205697a564SGovind Singh 			return num_vectors;
6215697a564SGovind Singh 	}
6225697a564SGovind Singh 
6235697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
6245697a564SGovind Singh 	if (!msi_desc) {
6255697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
6265697a564SGovind Singh 		ret = -EINVAL;
6275697a564SGovind Singh 		goto free_msi_vector;
6285697a564SGovind Singh 	}
6295697a564SGovind Singh 
6305697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
6315697a564SGovind Singh 
6325697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
6335697a564SGovind Singh 
6345697a564SGovind Singh 	return 0;
6355697a564SGovind Singh 
6365697a564SGovind Singh free_msi_vector:
6375697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
6385697a564SGovind Singh 
6395697a564SGovind Singh 	return ret;
6405697a564SGovind Singh }
6415697a564SGovind Singh 
6425697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci)
6435697a564SGovind Singh {
6445697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
6455697a564SGovind Singh }
6465697a564SGovind Singh 
6475762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
6485762613eSGovind Singh {
6495762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
6505762613eSGovind Singh 	u16 device_id;
6515762613eSGovind Singh 	int ret = 0;
6525762613eSGovind Singh 
6535762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
6545762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
6555762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
6565762613eSGovind Singh 			   device_id, ab_pci->dev_id);
6575762613eSGovind Singh 		ret = -EIO;
6585762613eSGovind Singh 		goto out;
6595762613eSGovind Singh 	}
6605762613eSGovind Singh 
6615762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
6625762613eSGovind Singh 	if (ret) {
6635762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
6645762613eSGovind Singh 		goto out;
6655762613eSGovind Singh 	}
6665762613eSGovind Singh 
6675762613eSGovind Singh 	ret = pci_enable_device(pdev);
6685762613eSGovind Singh 	if (ret) {
6695762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
6705762613eSGovind Singh 		goto out;
6715762613eSGovind Singh 	}
6725762613eSGovind Singh 
6735762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
6745762613eSGovind Singh 	if (ret) {
6755762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
6765762613eSGovind Singh 		goto disable_device;
6775762613eSGovind Singh 	}
6785762613eSGovind Singh 
6795762613eSGovind Singh 	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
6805762613eSGovind Singh 	if (ret) {
6815762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
6825762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
6835762613eSGovind Singh 		goto release_region;
6845762613eSGovind Singh 	}
6855762613eSGovind Singh 
6865762613eSGovind Singh 	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
6875762613eSGovind Singh 	if (ret) {
6885762613eSGovind Singh 		ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n",
6895762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
6905762613eSGovind Singh 		goto release_region;
6915762613eSGovind Singh 	}
6925762613eSGovind Singh 
6935762613eSGovind Singh 	pci_set_master(pdev);
6945762613eSGovind Singh 
6955762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
6965762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
6975762613eSGovind Singh 	if (!ab->mem) {
6985762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
6995762613eSGovind Singh 		ret = -EIO;
7005762613eSGovind Singh 		goto clear_master;
7015762613eSGovind Singh 	}
7025762613eSGovind Singh 
7035762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
7045762613eSGovind Singh 	return 0;
7055762613eSGovind Singh 
7065762613eSGovind Singh clear_master:
7075762613eSGovind Singh 	pci_clear_master(pdev);
7085762613eSGovind Singh release_region:
7095762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
7105762613eSGovind Singh disable_device:
7115762613eSGovind Singh 	pci_disable_device(pdev);
7125762613eSGovind Singh out:
7135762613eSGovind Singh 	return ret;
7145762613eSGovind Singh }
7155762613eSGovind Singh 
7165762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
7175762613eSGovind Singh {
7185762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
7195762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
7205762613eSGovind Singh 
7215762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
7225762613eSGovind Singh 	ab->mem = NULL;
7235762613eSGovind Singh 	pci_clear_master(pci_dev);
7245762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
7255762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
7265762613eSGovind Singh 		pci_disable_device(pci_dev);
7275762613eSGovind Singh }
7285762613eSGovind Singh 
7291399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
7301399fb87SGovind Singh {
7311399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
7321399fb87SGovind Singh 	int ret;
7331399fb87SGovind Singh 
734f3c603d4SCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab);
735f3c603d4SCarl Huang 
7361399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
7371399fb87SGovind Singh 	if (ret) {
7381399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
7391399fb87SGovind Singh 		return ret;
7401399fb87SGovind Singh 	}
7411399fb87SGovind Singh 
7421399fb87SGovind Singh 	return 0;
7431399fb87SGovind Singh }
7441399fb87SGovind Singh 
7451399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
7461399fb87SGovind Singh {
7471399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
7481399fb87SGovind Singh 
7491399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
750f3c603d4SCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
751f3c603d4SCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab);
7521399fb87SGovind Singh }
7531399fb87SGovind Singh 
7542c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
7552c3960c2SGovind Singh {
7562c3960c2SGovind Singh 	int i;
7572c3960c2SGovind Singh 
758d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
7592c3960c2SGovind Singh 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
7602c3960c2SGovind Singh 
761e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
7622c3960c2SGovind Singh 			continue;
7632c3960c2SGovind Singh 
7642c3960c2SGovind Singh 		tasklet_kill(&ce_pipe->intr_tq);
7652c3960c2SGovind Singh 	}
7662c3960c2SGovind Singh }
7672c3960c2SGovind Singh 
7687f4beda2SGovind Singh static void ath11k_pci_stop(struct ath11k_base *ab)
7697f4beda2SGovind Singh {
7702c3960c2SGovind Singh 	ath11k_pci_ce_irqs_disable(ab);
7712c3960c2SGovind Singh 	ath11k_pci_sync_ce_irqs(ab);
7722c3960c2SGovind Singh 	ath11k_pci_kill_tasklets(ab);
7737f4beda2SGovind Singh 	ath11k_ce_cleanup_pipes(ab);
7747f4beda2SGovind Singh }
7757f4beda2SGovind Singh 
7767f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab)
7777f4beda2SGovind Singh {
7787f4beda2SGovind Singh 	ath11k_pci_ce_irqs_enable(ab);
7792c3960c2SGovind Singh 	ath11k_ce_rx_post_buf(ab);
7802c3960c2SGovind Singh 
7812c3960c2SGovind Singh 	return 0;
7822c3960c2SGovind Singh }
7832c3960c2SGovind Singh 
7842c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
7852c3960c2SGovind Singh 					  u8 *ul_pipe, u8 *dl_pipe)
7862c3960c2SGovind Singh {
7872c3960c2SGovind Singh 	const struct service_to_pipe *entry;
7882c3960c2SGovind Singh 	bool ul_set = false, dl_set = false;
7892c3960c2SGovind Singh 	int i;
7902c3960c2SGovind Singh 
791967c1d11SAnilkumar Kolli 	for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {
792967c1d11SAnilkumar Kolli 		entry = &ab->hw_params.svc_to_ce_map[i];
7932c3960c2SGovind Singh 
7942c3960c2SGovind Singh 		if (__le32_to_cpu(entry->service_id) != service_id)
7952c3960c2SGovind Singh 			continue;
7962c3960c2SGovind Singh 
7972c3960c2SGovind Singh 		switch (__le32_to_cpu(entry->pipedir)) {
7982c3960c2SGovind Singh 		case PIPEDIR_NONE:
7992c3960c2SGovind Singh 			break;
8002c3960c2SGovind Singh 		case PIPEDIR_IN:
8012c3960c2SGovind Singh 			WARN_ON(dl_set);
8022c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
8032c3960c2SGovind Singh 			dl_set = true;
8042c3960c2SGovind Singh 			break;
8052c3960c2SGovind Singh 		case PIPEDIR_OUT:
8062c3960c2SGovind Singh 			WARN_ON(ul_set);
8072c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
8082c3960c2SGovind Singh 			ul_set = true;
8092c3960c2SGovind Singh 			break;
8102c3960c2SGovind Singh 		case PIPEDIR_INOUT:
8112c3960c2SGovind Singh 			WARN_ON(dl_set);
8122c3960c2SGovind Singh 			WARN_ON(ul_set);
8132c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
8142c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
8152c3960c2SGovind Singh 			dl_set = true;
8162c3960c2SGovind Singh 			ul_set = true;
8172c3960c2SGovind Singh 			break;
8182c3960c2SGovind Singh 		}
8192c3960c2SGovind Singh 	}
8202c3960c2SGovind Singh 
8212c3960c2SGovind Singh 	if (WARN_ON(!ul_set || !dl_set))
8222c3960c2SGovind Singh 		return -ENOENT;
8237f4beda2SGovind Singh 
8247f4beda2SGovind Singh 	return 0;
8257f4beda2SGovind Singh }
8267f4beda2SGovind Singh 
8277f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
8287f4beda2SGovind Singh 	.start = ath11k_pci_start,
8297f4beda2SGovind Singh 	.stop = ath11k_pci_stop,
830654e959aSGovind Singh 	.read32 = ath11k_pci_read32,
831654e959aSGovind Singh 	.write32 = ath11k_pci_write32,
8321399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
8331399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
834d4ecb90bSCarl Huang 	.irq_enable = ath11k_pci_ext_irq_enable,
835d4ecb90bSCarl Huang 	.irq_disable = ath11k_pci_ext_irq_disable,
836c4eacabeSGovind Singh 	.get_msi_address =  ath11k_pci_get_msi_address,
837c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
8382c3960c2SGovind Singh 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
8391399fb87SGovind Singh };
8401399fb87SGovind Singh 
8416e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
8426e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
8436e0355afSGovind Singh {
8446e0355afSGovind Singh 	struct ath11k_base *ab;
8455762613eSGovind Singh 	struct ath11k_pci *ab_pci;
846*18ac1665SKalle Valo 	u32 soc_hw_version, soc_hw_version_major, soc_hw_version_minor;
8475762613eSGovind Singh 	int ret;
8486e0355afSGovind Singh 
8496e0355afSGovind Singh 	dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n");
8506e0355afSGovind Singh 
8511ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
8521ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
8536e0355afSGovind Singh 	if (!ab) {
8546e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
8556e0355afSGovind Singh 		return -ENOMEM;
8566e0355afSGovind Singh 	}
8576e0355afSGovind Singh 
8586e0355afSGovind Singh 	ab->dev = &pdev->dev;
8596e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
8605762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
8615762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
8625762613eSGovind Singh 	ab_pci->ab = ab;
8635697a564SGovind Singh 	ab_pci->pdev = pdev;
8647f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
8655762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
866654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
8675762613eSGovind Singh 
8685762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
8695762613eSGovind Singh 	if (ret) {
8705762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
8715762613eSGovind Singh 		goto err_free_core;
8725762613eSGovind Singh 	}
8736e0355afSGovind Singh 
874*18ac1665SKalle Valo 	switch (pci_dev->device) {
875*18ac1665SKalle Valo 	case QCA6390_DEVICE_ID:
876*18ac1665SKalle Valo 		soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION);
877*18ac1665SKalle Valo 		soc_hw_version_major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
878*18ac1665SKalle Valo 						 soc_hw_version);
879*18ac1665SKalle Valo 		soc_hw_version_minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
880*18ac1665SKalle Valo 						 soc_hw_version);
881*18ac1665SKalle Valo 
882*18ac1665SKalle Valo 		ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n",
883*18ac1665SKalle Valo 			   soc_hw_version_major, soc_hw_version_minor);
884*18ac1665SKalle Valo 
885*18ac1665SKalle Valo 		switch (soc_hw_version_major) {
886*18ac1665SKalle Valo 		case 2:
887*18ac1665SKalle Valo 			ab->hw_rev = ATH11K_HW_QCA6390_HW20;
888*18ac1665SKalle Valo 			break;
889*18ac1665SKalle Valo 		default:
890*18ac1665SKalle Valo 			dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n",
891*18ac1665SKalle Valo 				soc_hw_version_major, soc_hw_version_minor);
892*18ac1665SKalle Valo 			ret = -EOPNOTSUPP;
893*18ac1665SKalle Valo 			goto err_pci_free_region;
894*18ac1665SKalle Valo 		}
895*18ac1665SKalle Valo 		break;
896*18ac1665SKalle Valo 	default:
897*18ac1665SKalle Valo 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
898*18ac1665SKalle Valo 			pci_dev->device);
899*18ac1665SKalle Valo 		ret = -EOPNOTSUPP;
900*18ac1665SKalle Valo 		goto err_pci_free_region;
901*18ac1665SKalle Valo 	}
902*18ac1665SKalle Valo 
9035697a564SGovind Singh 	ret = ath11k_pci_enable_msi(ab_pci);
9045697a564SGovind Singh 	if (ret) {
9055697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
9065697a564SGovind Singh 		goto err_pci_free_region;
9075697a564SGovind Singh 	}
9085697a564SGovind Singh 
909b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
910b8246f88SKalle Valo 	if (ret)
911b8246f88SKalle Valo 		goto err_pci_disable_msi;
912b8246f88SKalle Valo 
9131399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
9141399fb87SGovind Singh 	if (ret) {
9151399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
9161399fb87SGovind Singh 		goto err_pci_disable_msi;
9171399fb87SGovind Singh 	}
9181399fb87SGovind Singh 
9197f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
9207f4beda2SGovind Singh 	if (ret)
9217f4beda2SGovind Singh 		goto err_mhi_unregister;
9227f4beda2SGovind Singh 
9237f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
9247f4beda2SGovind Singh 	if (ret) {
9257f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
9267f4beda2SGovind Singh 		goto err_hal_srng_deinit;
9277f4beda2SGovind Singh 	}
9287f4beda2SGovind Singh 
9297f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
9307f4beda2SGovind Singh 
9317f4beda2SGovind Singh 	ret = ath11k_pci_config_irq(ab);
9327f4beda2SGovind Singh 	if (ret) {
9337f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
9347f4beda2SGovind Singh 		goto err_ce_free;
9357f4beda2SGovind Singh 	}
9367f4beda2SGovind Singh 
9377f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
9387f4beda2SGovind Singh 	if (ret) {
9397f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
9407f4beda2SGovind Singh 		goto err_free_irq;
9417f4beda2SGovind Singh 	}
9426e0355afSGovind Singh 	return 0;
9435762613eSGovind Singh 
9447f4beda2SGovind Singh err_free_irq:
9457f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
9467f4beda2SGovind Singh 
9477f4beda2SGovind Singh err_ce_free:
9487f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
9497f4beda2SGovind Singh 
9507f4beda2SGovind Singh err_hal_srng_deinit:
9517f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
9527f4beda2SGovind Singh 
9537f4beda2SGovind Singh err_mhi_unregister:
9547f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
9557f4beda2SGovind Singh 
956b8246f88SKalle Valo err_pci_disable_msi:
957b8246f88SKalle Valo 	ath11k_pci_disable_msi(ab_pci);
958b8246f88SKalle Valo 
9595697a564SGovind Singh err_pci_free_region:
9605697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
9615697a564SGovind Singh 
9625762613eSGovind Singh err_free_core:
9635762613eSGovind Singh 	ath11k_core_free(ab);
9645697a564SGovind Singh 
9655762613eSGovind Singh 	return ret;
9666e0355afSGovind Singh }
9676e0355afSGovind Singh 
9686e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
9696e0355afSGovind Singh {
9706e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
9715762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
9726e0355afSGovind Singh 
9736e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
9741399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
9755697a564SGovind Singh 	ath11k_pci_disable_msi(ab_pci);
9765762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
9777f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
9786e0355afSGovind Singh 	ath11k_core_free(ab);
9796e0355afSGovind Singh }
9806e0355afSGovind Singh 
9811399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
9821399fb87SGovind Singh {
9831399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
9841399fb87SGovind Singh 
9851399fb87SGovind Singh 	ath11k_pci_power_down(ab);
9861399fb87SGovind Singh }
9871399fb87SGovind Singh 
9886e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
9896e0355afSGovind Singh 	.name = "ath11k_pci",
9906e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
9916e0355afSGovind Singh 	.probe = ath11k_pci_probe,
9926e0355afSGovind Singh 	.remove = ath11k_pci_remove,
9931399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
9946e0355afSGovind Singh };
9956e0355afSGovind Singh 
9966e0355afSGovind Singh static int ath11k_pci_init(void)
9976e0355afSGovind Singh {
9986e0355afSGovind Singh 	int ret;
9996e0355afSGovind Singh 
10006e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
10016e0355afSGovind Singh 	if (ret)
10026e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
10036e0355afSGovind Singh 		       ret);
10046e0355afSGovind Singh 
10056e0355afSGovind Singh 	return ret;
10066e0355afSGovind Singh }
10076e0355afSGovind Singh module_init(ath11k_pci_init);
10086e0355afSGovind Singh 
10096e0355afSGovind Singh static void ath11k_pci_exit(void)
10106e0355afSGovind Singh {
10116e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
10126e0355afSGovind Singh }
10136e0355afSGovind Singh 
10146e0355afSGovind Singh module_exit(ath11k_pci_exit);
10156e0355afSGovind Singh 
10166e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
10176e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
1018