xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision d4ecb90b3857db23c83b2578f1fa0341c5e00b82)
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 /* Target firmware's Copy Engine configuration. */
557f4beda2SGovind Singh static const struct ce_pipe_config target_ce_config_wlan[] = {
567f4beda2SGovind Singh 	/* CE0: host->target HTC control and raw streams */
577f4beda2SGovind Singh 	{
587f4beda2SGovind Singh 		.pipenum = __cpu_to_le32(0),
597f4beda2SGovind Singh 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
607f4beda2SGovind Singh 		.nentries = __cpu_to_le32(32),
617f4beda2SGovind Singh 		.nbytes_max = __cpu_to_le32(2048),
627f4beda2SGovind Singh 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
637f4beda2SGovind Singh 		.reserved = __cpu_to_le32(0),
647f4beda2SGovind Singh 	},
657f4beda2SGovind Singh 
667f4beda2SGovind Singh 	/* CE1: target->host HTT + HTC control */
677f4beda2SGovind Singh 	{
687f4beda2SGovind Singh 		.pipenum = __cpu_to_le32(1),
697f4beda2SGovind Singh 		.pipedir = __cpu_to_le32(PIPEDIR_IN),
707f4beda2SGovind Singh 		.nentries = __cpu_to_le32(32),
717f4beda2SGovind Singh 		.nbytes_max = __cpu_to_le32(2048),
727f4beda2SGovind Singh 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
737f4beda2SGovind Singh 		.reserved = __cpu_to_le32(0),
747f4beda2SGovind Singh 	},
757f4beda2SGovind Singh 
767f4beda2SGovind Singh 	/* CE2: target->host WMI */
777f4beda2SGovind Singh 	{
787f4beda2SGovind Singh 		.pipenum = __cpu_to_le32(2),
797f4beda2SGovind Singh 		.pipedir = __cpu_to_le32(PIPEDIR_IN),
807f4beda2SGovind Singh 		.nentries = __cpu_to_le32(32),
817f4beda2SGovind Singh 		.nbytes_max = __cpu_to_le32(2048),
827f4beda2SGovind Singh 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
837f4beda2SGovind Singh 		.reserved = __cpu_to_le32(0),
847f4beda2SGovind Singh 	},
857f4beda2SGovind Singh 
867f4beda2SGovind Singh 	/* CE3: host->target WMI */
877f4beda2SGovind Singh 	{
887f4beda2SGovind Singh 		.pipenum = __cpu_to_le32(3),
897f4beda2SGovind Singh 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
907f4beda2SGovind Singh 		.nentries = __cpu_to_le32(32),
917f4beda2SGovind Singh 		.nbytes_max = __cpu_to_le32(2048),
927f4beda2SGovind Singh 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
937f4beda2SGovind Singh 		.reserved = __cpu_to_le32(0),
947f4beda2SGovind Singh 	},
957f4beda2SGovind Singh 
967f4beda2SGovind Singh 	/* CE4: host->target HTT */
977f4beda2SGovind Singh 	{
987f4beda2SGovind Singh 		.pipenum = __cpu_to_le32(4),
997f4beda2SGovind Singh 		.pipedir = __cpu_to_le32(PIPEDIR_OUT),
1007f4beda2SGovind Singh 		.nentries = __cpu_to_le32(256),
1017f4beda2SGovind Singh 		.nbytes_max = __cpu_to_le32(256),
1027f4beda2SGovind Singh 		.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
1037f4beda2SGovind Singh 		.reserved = __cpu_to_le32(0),
1047f4beda2SGovind Singh 	},
1057f4beda2SGovind Singh 
1067f4beda2SGovind Singh 	/* CE5: target->host Pktlog */
1077f4beda2SGovind Singh 	{
1087f4beda2SGovind Singh 		.pipenum = __cpu_to_le32(5),
1097f4beda2SGovind Singh 		.pipedir = __cpu_to_le32(PIPEDIR_IN),
1107f4beda2SGovind Singh 		.nentries = __cpu_to_le32(32),
1117f4beda2SGovind Singh 		.nbytes_max = __cpu_to_le32(2048),
1127f4beda2SGovind Singh 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
1137f4beda2SGovind Singh 		.reserved = __cpu_to_le32(0),
1147f4beda2SGovind Singh 	},
1157f4beda2SGovind Singh 
1167f4beda2SGovind Singh 	/* CE6: Reserved for target autonomous hif_memcpy */
1177f4beda2SGovind Singh 	{
1187f4beda2SGovind Singh 		.pipenum = __cpu_to_le32(6),
1197f4beda2SGovind Singh 		.pipedir = __cpu_to_le32(PIPEDIR_INOUT),
1207f4beda2SGovind Singh 		.nentries = __cpu_to_le32(32),
1217f4beda2SGovind Singh 		.nbytes_max = __cpu_to_le32(16384),
1227f4beda2SGovind Singh 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
1237f4beda2SGovind Singh 		.reserved = __cpu_to_le32(0),
1247f4beda2SGovind Singh 	},
1257f4beda2SGovind Singh 
1267f4beda2SGovind Singh 	/* CE7 used only by Host */
1277f4beda2SGovind Singh 	{
1287f4beda2SGovind Singh 		.pipenum = __cpu_to_le32(7),
1297f4beda2SGovind Singh 		.pipedir = __cpu_to_le32(PIPEDIR_INOUT_H2H),
1307f4beda2SGovind Singh 		.nentries = __cpu_to_le32(0),
1317f4beda2SGovind Singh 		.nbytes_max = __cpu_to_le32(0),
1327f4beda2SGovind Singh 		.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
1337f4beda2SGovind Singh 		.reserved = __cpu_to_le32(0),
1347f4beda2SGovind Singh 	},
1357f4beda2SGovind Singh 
1367f4beda2SGovind Singh 	/* CE8 target->host used only by IPA */
1377f4beda2SGovind Singh 	{
1387f4beda2SGovind Singh 		.pipenum = __cpu_to_le32(8),
1397f4beda2SGovind Singh 		.pipedir = __cpu_to_le32(PIPEDIR_INOUT),
1407f4beda2SGovind Singh 		.nentries = __cpu_to_le32(32),
1417f4beda2SGovind Singh 		.nbytes_max = __cpu_to_le32(16384),
1427f4beda2SGovind Singh 		.flags = __cpu_to_le32(CE_ATTR_FLAGS),
1437f4beda2SGovind Singh 		.reserved = __cpu_to_le32(0),
1447f4beda2SGovind Singh 	},
1457f4beda2SGovind Singh 	/* CE 9, 10, 11 are used by MHI driver */
1467f4beda2SGovind Singh };
1477f4beda2SGovind Singh 
1487f4beda2SGovind Singh /* Map from service/endpoint to Copy Engine.
1497f4beda2SGovind Singh  * This table is derived from the CE_PCI TABLE, above.
1507f4beda2SGovind Singh  * It is passed to the Target at startup for use by firmware.
1517f4beda2SGovind Singh  */
1527f4beda2SGovind Singh static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
1537f4beda2SGovind Singh 	{
1547f4beda2SGovind Singh 		__cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VO),
1557f4beda2SGovind Singh 		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
1567f4beda2SGovind Singh 		__cpu_to_le32(3),
1577f4beda2SGovind Singh 	},
1587f4beda2SGovind Singh 	{
1597f4beda2SGovind Singh 		__cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VO),
1607f4beda2SGovind Singh 		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
1617f4beda2SGovind Singh 		__cpu_to_le32(2),
1627f4beda2SGovind Singh 	},
1637f4beda2SGovind Singh 	{
1647f4beda2SGovind Singh 		__cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BK),
1657f4beda2SGovind Singh 		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
1667f4beda2SGovind Singh 		__cpu_to_le32(3),
1677f4beda2SGovind Singh 	},
1687f4beda2SGovind Singh 	{
1697f4beda2SGovind Singh 		__cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BK),
1707f4beda2SGovind Singh 		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
1717f4beda2SGovind Singh 		__cpu_to_le32(2),
1727f4beda2SGovind Singh 	},
1737f4beda2SGovind Singh 	{
1747f4beda2SGovind Singh 		__cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BE),
1757f4beda2SGovind Singh 		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
1767f4beda2SGovind Singh 		__cpu_to_le32(3),
1777f4beda2SGovind Singh 	},
1787f4beda2SGovind Singh 	{
1797f4beda2SGovind Singh 		__cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BE),
1807f4beda2SGovind Singh 		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
1817f4beda2SGovind Singh 		__cpu_to_le32(2),
1827f4beda2SGovind Singh 	},
1837f4beda2SGovind Singh 	{
1847f4beda2SGovind Singh 		__cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VI),
1857f4beda2SGovind Singh 		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
1867f4beda2SGovind Singh 		__cpu_to_le32(3),
1877f4beda2SGovind Singh 	},
1887f4beda2SGovind Singh 	{
1897f4beda2SGovind Singh 		__cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VI),
1907f4beda2SGovind Singh 		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
1917f4beda2SGovind Singh 		__cpu_to_le32(2),
1927f4beda2SGovind Singh 	},
1937f4beda2SGovind Singh 	{
1947f4beda2SGovind Singh 		__cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL),
1957f4beda2SGovind Singh 		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
1967f4beda2SGovind Singh 		__cpu_to_le32(3),
1977f4beda2SGovind Singh 	},
1987f4beda2SGovind Singh 	{
1997f4beda2SGovind Singh 		__cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL),
2007f4beda2SGovind Singh 		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
2017f4beda2SGovind Singh 		__cpu_to_le32(2),
2027f4beda2SGovind Singh 	},
2037f4beda2SGovind Singh 
2047f4beda2SGovind Singh 	{
2057f4beda2SGovind Singh 		__cpu_to_le32(ATH11K_HTC_SVC_ID_RSVD_CTRL),
2067f4beda2SGovind Singh 		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
2077f4beda2SGovind Singh 		__cpu_to_le32(0),
2087f4beda2SGovind Singh 	},
2097f4beda2SGovind Singh 	{
2107f4beda2SGovind Singh 		__cpu_to_le32(ATH11K_HTC_SVC_ID_RSVD_CTRL),
2117f4beda2SGovind Singh 		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
2127f4beda2SGovind Singh 		__cpu_to_le32(2),
2137f4beda2SGovind Singh 	},
2147f4beda2SGovind Singh 
2157f4beda2SGovind Singh 	{
2167f4beda2SGovind Singh 		__cpu_to_le32(ATH11K_HTC_SVC_ID_HTT_DATA_MSG),
2177f4beda2SGovind Singh 		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */
2187f4beda2SGovind Singh 		__cpu_to_le32(4),
2197f4beda2SGovind Singh 	},
2207f4beda2SGovind Singh 	{
2217f4beda2SGovind Singh 		__cpu_to_le32(ATH11K_HTC_SVC_ID_HTT_DATA_MSG),
2227f4beda2SGovind Singh 		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */
2237f4beda2SGovind Singh 		__cpu_to_le32(1),
2247f4beda2SGovind Singh 	},
2257f4beda2SGovind Singh 
2267f4beda2SGovind Singh 	/* (Additions here) */
2277f4beda2SGovind Singh 
2287f4beda2SGovind Singh 	{ /* must be last */
2297f4beda2SGovind Singh 		__cpu_to_le32(0),
2307f4beda2SGovind Singh 		__cpu_to_le32(0),
2317f4beda2SGovind Singh 		__cpu_to_le32(0),
2327f4beda2SGovind Singh 	},
2337f4beda2SGovind Singh };
2347f4beda2SGovind Singh 
2357f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
2367f4beda2SGovind Singh 	"bhi",
2377f4beda2SGovind Singh 	"mhi-er0",
2387f4beda2SGovind Singh 	"mhi-er1",
2397f4beda2SGovind Singh 	"ce0",
2407f4beda2SGovind Singh 	"ce1",
2417f4beda2SGovind Singh 	"ce2",
2427f4beda2SGovind Singh 	"ce3",
2437f4beda2SGovind Singh 	"ce4",
2447f4beda2SGovind Singh 	"ce5",
2457f4beda2SGovind Singh 	"ce6",
2467f4beda2SGovind Singh 	"ce7",
2477f4beda2SGovind Singh 	"ce8",
2487f4beda2SGovind Singh 	"ce9",
2497f4beda2SGovind Singh 	"ce10",
2507f4beda2SGovind Singh 	"ce11",
2517f4beda2SGovind Singh 	"host2wbm-desc-feed",
2527f4beda2SGovind Singh 	"host2reo-re-injection",
2537f4beda2SGovind Singh 	"host2reo-command",
2547f4beda2SGovind Singh 	"host2rxdma-monitor-ring3",
2557f4beda2SGovind Singh 	"host2rxdma-monitor-ring2",
2567f4beda2SGovind Singh 	"host2rxdma-monitor-ring1",
2577f4beda2SGovind Singh 	"reo2ost-exception",
2587f4beda2SGovind Singh 	"wbm2host-rx-release",
2597f4beda2SGovind Singh 	"reo2host-status",
2607f4beda2SGovind Singh 	"reo2host-destination-ring4",
2617f4beda2SGovind Singh 	"reo2host-destination-ring3",
2627f4beda2SGovind Singh 	"reo2host-destination-ring2",
2637f4beda2SGovind Singh 	"reo2host-destination-ring1",
2647f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac3",
2657f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac2",
2667f4beda2SGovind Singh 	"rxdma2host-monitor-destination-mac1",
2677f4beda2SGovind Singh 	"ppdu-end-interrupts-mac3",
2687f4beda2SGovind Singh 	"ppdu-end-interrupts-mac2",
2697f4beda2SGovind Singh 	"ppdu-end-interrupts-mac1",
2707f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac3",
2717f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac2",
2727f4beda2SGovind Singh 	"rxdma2host-monitor-status-ring-mac1",
2737f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac3",
2747f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac2",
2757f4beda2SGovind Singh 	"host2rxdma-host-buf-ring-mac1",
2767f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac3",
2777f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac2",
2787f4beda2SGovind Singh 	"rxdma2host-destination-ring-mac1",
2797f4beda2SGovind Singh 	"host2tcl-input-ring4",
2807f4beda2SGovind Singh 	"host2tcl-input-ring3",
2817f4beda2SGovind Singh 	"host2tcl-input-ring2",
2827f4beda2SGovind Singh 	"host2tcl-input-ring1",
2837f4beda2SGovind Singh 	"wbm2host-tx-completions-ring3",
2847f4beda2SGovind Singh 	"wbm2host-tx-completions-ring2",
2857f4beda2SGovind Singh 	"wbm2host-tx-completions-ring1",
2867f4beda2SGovind Singh 	"tcl2host-status-ring",
2877f4beda2SGovind Singh };
2887f4beda2SGovind Singh 
289654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset)
290654e959aSGovind Singh {
291654e959aSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
292654e959aSGovind Singh 
293654e959aSGovind Singh 	u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset);
294654e959aSGovind Singh 
295654e959aSGovind Singh 	lockdep_assert_held(&ab_pci->window_lock);
296654e959aSGovind Singh 
297654e959aSGovind Singh 	if (window != ab_pci->register_window) {
298654e959aSGovind Singh 		iowrite32(WINDOW_ENABLE_BIT | window,
299654e959aSGovind Singh 			  ab->mem + WINDOW_REG_ADDRESS);
300654e959aSGovind Singh 		ab_pci->register_window = window;
301654e959aSGovind Singh 	}
302654e959aSGovind Singh }
303654e959aSGovind Singh 
304654e959aSGovind Singh static void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value)
305654e959aSGovind Singh {
306654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
307654e959aSGovind Singh 
308654e959aSGovind Singh 	if (offset < WINDOW_START) {
309654e959aSGovind Singh 		iowrite32(value, ab->mem  + offset);
310654e959aSGovind Singh 	} else {
311654e959aSGovind Singh 		spin_lock_bh(&ab_pci->window_lock);
312654e959aSGovind Singh 		ath11k_pci_select_window(ab_pci, offset);
313654e959aSGovind Singh 		iowrite32(value, ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK));
314654e959aSGovind Singh 		spin_unlock_bh(&ab_pci->window_lock);
315654e959aSGovind Singh 	}
316654e959aSGovind Singh }
317654e959aSGovind Singh 
318654e959aSGovind Singh static u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
319654e959aSGovind Singh {
320654e959aSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
321654e959aSGovind Singh 	u32 val;
322654e959aSGovind Singh 
323654e959aSGovind Singh 	if (offset < WINDOW_START) {
324654e959aSGovind Singh 		val = ioread32(ab->mem + offset);
325654e959aSGovind Singh 	} else {
326654e959aSGovind Singh 		spin_lock_bh(&ab_pci->window_lock);
327654e959aSGovind Singh 		ath11k_pci_select_window(ab_pci, offset);
328654e959aSGovind Singh 		val = ioread32(ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK));
329654e959aSGovind Singh 		spin_unlock_bh(&ab_pci->window_lock);
330654e959aSGovind Singh 	}
331654e959aSGovind Singh 
332654e959aSGovind Singh 	return val;
333654e959aSGovind Singh }
334654e959aSGovind Singh 
3351399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
3361399fb87SGovind Singh {
3371399fb87SGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(dev);
3381399fb87SGovind Singh 
3391399fb87SGovind Singh 	return pci_irq_vector(pci_dev, vector);
3401399fb87SGovind Singh }
3411399fb87SGovind Singh 
342c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
343c4eacabeSGovind Singh 				       u32 *msi_addr_hi)
344c4eacabeSGovind Singh {
345c4eacabeSGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
346c4eacabeSGovind Singh 
347c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
348c4eacabeSGovind Singh 			      msi_addr_lo);
349c4eacabeSGovind Singh 
350c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
351c4eacabeSGovind Singh 			      msi_addr_hi);
352c4eacabeSGovind Singh }
353c4eacabeSGovind Singh 
3541399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
3551399fb87SGovind Singh 				       int *num_vectors, u32 *user_base_data,
3561399fb87SGovind Singh 				       u32 *base_vector)
3571399fb87SGovind Singh {
3581399fb87SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
3591399fb87SGovind Singh 	int idx;
3601399fb87SGovind Singh 
3611399fb87SGovind Singh 	for (idx = 0; idx < msi_config.total_users; idx++) {
3621399fb87SGovind Singh 		if (strcmp(user_name, msi_config.users[idx].name) == 0) {
3631399fb87SGovind Singh 			*num_vectors = msi_config.users[idx].num_vectors;
3641399fb87SGovind Singh 			*user_base_data = msi_config.users[idx].base_vector
3651399fb87SGovind Singh 				+ ab_pci->msi_ep_base_data;
3661399fb87SGovind Singh 			*base_vector = msi_config.users[idx].base_vector;
3671399fb87SGovind Singh 
3681399fb87SGovind Singh 			ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
3691399fb87SGovind Singh 				   user_name, *num_vectors, *user_base_data,
3701399fb87SGovind Singh 				   *base_vector);
3711399fb87SGovind Singh 
3721399fb87SGovind Singh 			return 0;
3731399fb87SGovind Singh 		}
3741399fb87SGovind Singh 	}
3751399fb87SGovind Singh 
3761399fb87SGovind Singh 	ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
3771399fb87SGovind Singh 
3781399fb87SGovind Singh 	return -EINVAL;
3791399fb87SGovind Singh }
3801399fb87SGovind Singh 
381c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
382c4eacabeSGovind Singh 					  int *num_vectors, u32 *user_base_data,
383c4eacabeSGovind Singh 					  u32 *base_vector)
384c4eacabeSGovind Singh {
385c4eacabeSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
386c4eacabeSGovind Singh 
387c4eacabeSGovind Singh 	return ath11k_pci_get_user_msi_assignment(ab_pci, user_name,
388c4eacabeSGovind Singh 						  num_vectors, user_base_data,
389c4eacabeSGovind Singh 						  base_vector);
390c4eacabeSGovind Singh }
391c4eacabeSGovind Singh 
392*d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
393*d4ecb90bSCarl Huang {
394*d4ecb90bSCarl Huang 	int i, j;
395*d4ecb90bSCarl Huang 
396*d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
397*d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
398*d4ecb90bSCarl Huang 
399*d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++)
400*d4ecb90bSCarl Huang 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
401*d4ecb90bSCarl Huang 
402*d4ecb90bSCarl Huang 		netif_napi_del(&irq_grp->napi);
403*d4ecb90bSCarl Huang 	}
404*d4ecb90bSCarl Huang }
405*d4ecb90bSCarl Huang 
4067f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab)
4077f4beda2SGovind Singh {
4087f4beda2SGovind Singh 	int i, irq_idx;
4097f4beda2SGovind Singh 
410d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
411e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
4127f4beda2SGovind Singh 			continue;
4137f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
4147f4beda2SGovind Singh 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
4157f4beda2SGovind Singh 	}
416*d4ecb90bSCarl Huang 
417*d4ecb90bSCarl Huang 	ath11k_pci_free_ext_irq(ab);
4187f4beda2SGovind Singh }
4197f4beda2SGovind Singh 
4202c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
4212c3960c2SGovind Singh {
4222c3960c2SGovind Singh 	u32 irq_idx;
4232c3960c2SGovind Singh 
4242c3960c2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
4252c3960c2SGovind Singh 	enable_irq(ab->irq_num[irq_idx]);
4262c3960c2SGovind Singh }
4272c3960c2SGovind Singh 
4287f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
4297f4beda2SGovind Singh {
4307f4beda2SGovind Singh 	u32 irq_idx;
4317f4beda2SGovind Singh 
4327f4beda2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
4337f4beda2SGovind Singh 	disable_irq_nosync(ab->irq_num[irq_idx]);
4347f4beda2SGovind Singh }
4357f4beda2SGovind Singh 
4362c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
4372c3960c2SGovind Singh {
4382c3960c2SGovind Singh 	int i;
4392c3960c2SGovind Singh 
440d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
441e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
4422c3960c2SGovind Singh 			continue;
4432c3960c2SGovind Singh 		ath11k_pci_ce_irq_disable(ab, i);
4442c3960c2SGovind Singh 	}
4452c3960c2SGovind Singh }
4462c3960c2SGovind Singh 
4472c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
4482c3960c2SGovind Singh {
4492c3960c2SGovind Singh 	int i;
4502c3960c2SGovind Singh 	int irq_idx;
4512c3960c2SGovind Singh 
452d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
453e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
4542c3960c2SGovind Singh 			continue;
4552c3960c2SGovind Singh 
4562c3960c2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
4572c3960c2SGovind Singh 		synchronize_irq(ab->irq_num[irq_idx]);
4582c3960c2SGovind Singh 	}
4592c3960c2SGovind Singh }
4602c3960c2SGovind Singh 
4612c3960c2SGovind Singh static void ath11k_pci_ce_tasklet(unsigned long data)
4622c3960c2SGovind Singh {
4632c3960c2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = (struct ath11k_ce_pipe *)data;
4642c3960c2SGovind Singh 
4652c3960c2SGovind Singh 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
4662c3960c2SGovind Singh 
4672c3960c2SGovind Singh 	ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
4682c3960c2SGovind Singh }
4692c3960c2SGovind Singh 
4707f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
4717f4beda2SGovind Singh {
4727f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = arg;
4737f4beda2SGovind Singh 
4747f4beda2SGovind Singh 	ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
4752c3960c2SGovind Singh 	tasklet_schedule(&ce_pipe->intr_tq);
4767f4beda2SGovind Singh 
4777f4beda2SGovind Singh 	return IRQ_HANDLED;
4787f4beda2SGovind Singh }
4797f4beda2SGovind Singh 
480*d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
481*d4ecb90bSCarl Huang {
482*d4ecb90bSCarl Huang 	int i;
483*d4ecb90bSCarl Huang 
484*d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
485*d4ecb90bSCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
486*d4ecb90bSCarl Huang }
487*d4ecb90bSCarl Huang 
488*d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
489*d4ecb90bSCarl Huang {
490*d4ecb90bSCarl Huang 	int i;
491*d4ecb90bSCarl Huang 
492*d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
493*d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
494*d4ecb90bSCarl Huang 
495*d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
496*d4ecb90bSCarl Huang 
497*d4ecb90bSCarl Huang 		napi_synchronize(&irq_grp->napi);
498*d4ecb90bSCarl Huang 		napi_disable(&irq_grp->napi);
499*d4ecb90bSCarl Huang 	}
500*d4ecb90bSCarl Huang }
501*d4ecb90bSCarl Huang 
502*d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
503*d4ecb90bSCarl Huang {
504*d4ecb90bSCarl Huang 	int i;
505*d4ecb90bSCarl Huang 
506*d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
507*d4ecb90bSCarl Huang 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
508*d4ecb90bSCarl Huang }
509*d4ecb90bSCarl Huang 
510*d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
511*d4ecb90bSCarl Huang {
512*d4ecb90bSCarl Huang 	int i;
513*d4ecb90bSCarl Huang 
514*d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
515*d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
516*d4ecb90bSCarl Huang 
517*d4ecb90bSCarl Huang 		napi_enable(&irq_grp->napi);
518*d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
519*d4ecb90bSCarl Huang 	}
520*d4ecb90bSCarl Huang }
521*d4ecb90bSCarl Huang 
522*d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
523*d4ecb90bSCarl Huang {
524*d4ecb90bSCarl Huang 	int i, j, irq_idx;
525*d4ecb90bSCarl Huang 
526*d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
527*d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
528*d4ecb90bSCarl Huang 
529*d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
530*d4ecb90bSCarl Huang 			irq_idx = irq_grp->irqs[j];
531*d4ecb90bSCarl Huang 			synchronize_irq(ab->irq_num[irq_idx]);
532*d4ecb90bSCarl Huang 		}
533*d4ecb90bSCarl Huang 	}
534*d4ecb90bSCarl Huang }
535*d4ecb90bSCarl Huang 
536*d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
537*d4ecb90bSCarl Huang {
538*d4ecb90bSCarl Huang 	__ath11k_pci_ext_irq_disable(ab);
539*d4ecb90bSCarl Huang 	ath11k_pci_sync_ext_irqs(ab);
540*d4ecb90bSCarl Huang }
541*d4ecb90bSCarl Huang 
542*d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
543*d4ecb90bSCarl Huang {
544*d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
545*d4ecb90bSCarl Huang 						struct ath11k_ext_irq_grp,
546*d4ecb90bSCarl Huang 						napi);
547*d4ecb90bSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
548*d4ecb90bSCarl Huang 	int work_done;
549*d4ecb90bSCarl Huang 
550*d4ecb90bSCarl Huang 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
551*d4ecb90bSCarl Huang 	if (work_done < budget) {
552*d4ecb90bSCarl Huang 		napi_complete_done(napi, work_done);
553*d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
554*d4ecb90bSCarl Huang 	}
555*d4ecb90bSCarl Huang 
556*d4ecb90bSCarl Huang 	if (work_done > budget)
557*d4ecb90bSCarl Huang 		work_done = budget;
558*d4ecb90bSCarl Huang 
559*d4ecb90bSCarl Huang 	return work_done;
560*d4ecb90bSCarl Huang }
561*d4ecb90bSCarl Huang 
562*d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
563*d4ecb90bSCarl Huang {
564*d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = arg;
565*d4ecb90bSCarl Huang 
566*d4ecb90bSCarl Huang 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
567*d4ecb90bSCarl Huang 
568*d4ecb90bSCarl Huang 	ath11k_pci_ext_grp_disable(irq_grp);
569*d4ecb90bSCarl Huang 
570*d4ecb90bSCarl Huang 	napi_schedule(&irq_grp->napi);
571*d4ecb90bSCarl Huang 
572*d4ecb90bSCarl Huang 	return IRQ_HANDLED;
573*d4ecb90bSCarl Huang }
574*d4ecb90bSCarl Huang 
575*d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
576*d4ecb90bSCarl Huang {
577*d4ecb90bSCarl Huang 	int i, j, ret, num_vectors = 0;
578*d4ecb90bSCarl Huang 	u32 user_base_data = 0, base_vector = 0;
579*d4ecb90bSCarl Huang 
580*d4ecb90bSCarl Huang 	ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
581*d4ecb90bSCarl Huang 					   &num_vectors, &user_base_data,
582*d4ecb90bSCarl Huang 					   &base_vector);
583*d4ecb90bSCarl Huang 
584*d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
585*d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
586*d4ecb90bSCarl Huang 		u32 num_irq = 0;
587*d4ecb90bSCarl Huang 
588*d4ecb90bSCarl Huang 		irq_grp->ab = ab;
589*d4ecb90bSCarl Huang 		irq_grp->grp_id = i;
590*d4ecb90bSCarl Huang 		init_dummy_netdev(&irq_grp->napi_ndev);
591*d4ecb90bSCarl Huang 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
592*d4ecb90bSCarl Huang 			       ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
593*d4ecb90bSCarl Huang 
594*d4ecb90bSCarl Huang 		if (ab->hw_params.ring_mask->tx[i] ||
595*d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx[i] ||
596*d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_err[i] ||
597*d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_wbm_rel[i] ||
598*d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->reo_status[i] ||
599*d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rxdma2host[i] ||
600*d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->host2rxdma[i] ||
601*d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_mon_status[i]) {
602*d4ecb90bSCarl Huang 			num_irq = 1;
603*d4ecb90bSCarl Huang 		}
604*d4ecb90bSCarl Huang 
605*d4ecb90bSCarl Huang 		irq_grp->num_irq = num_irq;
606*d4ecb90bSCarl Huang 		irq_grp->irqs[0] = base_vector + i;
607*d4ecb90bSCarl Huang 
608*d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
609*d4ecb90bSCarl Huang 			int irq_idx = irq_grp->irqs[j];
610*d4ecb90bSCarl Huang 			int vector = (i % num_vectors) + base_vector;
611*d4ecb90bSCarl Huang 			int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
612*d4ecb90bSCarl Huang 
613*d4ecb90bSCarl Huang 			ab->irq_num[irq_idx] = irq;
614*d4ecb90bSCarl Huang 
615*d4ecb90bSCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
616*d4ecb90bSCarl Huang 				   "irq:%d group:%d\n", irq, i);
617*d4ecb90bSCarl Huang 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
618*d4ecb90bSCarl Huang 					  IRQF_SHARED,
619*d4ecb90bSCarl Huang 					  "DP_EXT_IRQ", irq_grp);
620*d4ecb90bSCarl Huang 			if (ret) {
621*d4ecb90bSCarl Huang 				ath11k_err(ab, "failed request irq %d: %d\n",
622*d4ecb90bSCarl Huang 					   vector, ret);
623*d4ecb90bSCarl Huang 				return ret;
624*d4ecb90bSCarl Huang 			}
625*d4ecb90bSCarl Huang 
626*d4ecb90bSCarl Huang 			disable_irq_nosync(ab->irq_num[irq_idx]);
627*d4ecb90bSCarl Huang 		}
628*d4ecb90bSCarl Huang 	}
629*d4ecb90bSCarl Huang 
630*d4ecb90bSCarl Huang 	return 0;
631*d4ecb90bSCarl Huang }
632*d4ecb90bSCarl Huang 
6337f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab)
6347f4beda2SGovind Singh {
6357f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe;
6367f4beda2SGovind Singh 	u32 msi_data_start;
6377f4beda2SGovind Singh 	u32 msi_data_count;
6387f4beda2SGovind Singh 	u32 msi_irq_start;
6397f4beda2SGovind Singh 	unsigned int msi_data;
6407f4beda2SGovind Singh 	int irq, i, ret, irq_idx;
6417f4beda2SGovind Singh 
6427f4beda2SGovind Singh 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab),
6437f4beda2SGovind Singh 						 "CE", &msi_data_count,
6447f4beda2SGovind Singh 						 &msi_data_start, &msi_irq_start);
6457f4beda2SGovind Singh 	if (ret)
6467f4beda2SGovind Singh 		return ret;
6477f4beda2SGovind Singh 
6487f4beda2SGovind Singh 	/* Configure CE irqs */
649d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
6507f4beda2SGovind Singh 		msi_data = (i % msi_data_count) + msi_irq_start;
6517f4beda2SGovind Singh 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
6527f4beda2SGovind Singh 		ce_pipe = &ab->ce.ce_pipe[i];
6537f4beda2SGovind Singh 
654e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
6557f4beda2SGovind Singh 			continue;
6567f4beda2SGovind Singh 
6577f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
6587f4beda2SGovind Singh 
6592c3960c2SGovind Singh 		tasklet_init(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet,
6602c3960c2SGovind Singh 			     (unsigned long)ce_pipe);
6612c3960c2SGovind Singh 
6627f4beda2SGovind Singh 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
6637f4beda2SGovind Singh 				  IRQF_SHARED, irq_name[irq_idx],
6647f4beda2SGovind Singh 				  ce_pipe);
6657f4beda2SGovind Singh 		if (ret) {
6667f4beda2SGovind Singh 			ath11k_err(ab, "failed to request irq %d: %d\n",
6677f4beda2SGovind Singh 				   irq_idx, ret);
6687f4beda2SGovind Singh 			return ret;
6697f4beda2SGovind Singh 		}
6707f4beda2SGovind Singh 
6717f4beda2SGovind Singh 		ab->irq_num[irq_idx] = irq;
672e5c860e1SCarl Huang 		ath11k_pci_ce_irq_disable(ab, i);
6737f4beda2SGovind Singh 	}
6747f4beda2SGovind Singh 
675*d4ecb90bSCarl Huang 	ret = ath11k_pci_ext_irq_config(ab);
676*d4ecb90bSCarl Huang 	if (ret)
677*d4ecb90bSCarl Huang 		return ret;
678*d4ecb90bSCarl Huang 
6797f4beda2SGovind Singh 	return 0;
6807f4beda2SGovind Singh }
6817f4beda2SGovind Singh 
6827f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
6837f4beda2SGovind Singh {
6847f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
6857f4beda2SGovind Singh 
6867f4beda2SGovind Singh 	cfg->tgt_ce = target_ce_config_wlan;
6877f4beda2SGovind Singh 	cfg->tgt_ce_len = ARRAY_SIZE(target_ce_config_wlan);
6887f4beda2SGovind Singh 
6897f4beda2SGovind Singh 	cfg->svc_to_ce_map = target_service_to_ce_map_wlan;
6907f4beda2SGovind Singh 	cfg->svc_to_ce_map_len = ARRAY_SIZE(target_service_to_ce_map_wlan);
691eb8de049SGovind Singh 	ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390;
6927f4beda2SGovind Singh }
6937f4beda2SGovind Singh 
6947f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
6957f4beda2SGovind Singh {
6967f4beda2SGovind Singh 	int i;
6977f4beda2SGovind Singh 
698d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
699e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
7007f4beda2SGovind Singh 			continue;
7017f4beda2SGovind Singh 		ath11k_pci_ce_irq_enable(ab, i);
7027f4beda2SGovind Singh 	}
7037f4beda2SGovind Singh }
7047f4beda2SGovind Singh 
7055697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
7065697a564SGovind Singh {
7075697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
7085697a564SGovind Singh 	struct msi_desc *msi_desc;
7095697a564SGovind Singh 	int num_vectors;
7105697a564SGovind Singh 	int ret;
7115697a564SGovind Singh 
7125697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
7135697a564SGovind Singh 					    msi_config.total_vectors,
7145697a564SGovind Singh 					    msi_config.total_vectors,
7155697a564SGovind Singh 					    PCI_IRQ_MSI);
7165697a564SGovind Singh 	if (num_vectors != msi_config.total_vectors) {
7175697a564SGovind Singh 		ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
7185697a564SGovind Singh 			   msi_config.total_vectors, num_vectors);
7195697a564SGovind Singh 
7205697a564SGovind Singh 		if (num_vectors >= 0)
7215697a564SGovind Singh 			return -EINVAL;
7225697a564SGovind Singh 		else
7235697a564SGovind Singh 			return num_vectors;
7245697a564SGovind Singh 	}
7255697a564SGovind Singh 
7265697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
7275697a564SGovind Singh 	if (!msi_desc) {
7285697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
7295697a564SGovind Singh 		ret = -EINVAL;
7305697a564SGovind Singh 		goto free_msi_vector;
7315697a564SGovind Singh 	}
7325697a564SGovind Singh 
7335697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
7345697a564SGovind Singh 
7355697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
7365697a564SGovind Singh 
7375697a564SGovind Singh 	return 0;
7385697a564SGovind Singh 
7395697a564SGovind Singh free_msi_vector:
7405697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
7415697a564SGovind Singh 
7425697a564SGovind Singh 	return ret;
7435697a564SGovind Singh }
7445697a564SGovind Singh 
7455697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci)
7465697a564SGovind Singh {
7475697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
7485697a564SGovind Singh }
7495697a564SGovind Singh 
7505762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
7515762613eSGovind Singh {
7525762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
7535762613eSGovind Singh 	u16 device_id;
7545762613eSGovind Singh 	int ret = 0;
7555762613eSGovind Singh 
7565762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
7575762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
7585762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
7595762613eSGovind Singh 			   device_id, ab_pci->dev_id);
7605762613eSGovind Singh 		ret = -EIO;
7615762613eSGovind Singh 		goto out;
7625762613eSGovind Singh 	}
7635762613eSGovind Singh 
7645762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
7655762613eSGovind Singh 	if (ret) {
7665762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
7675762613eSGovind Singh 		goto out;
7685762613eSGovind Singh 	}
7695762613eSGovind Singh 
7705762613eSGovind Singh 	ret = pci_enable_device(pdev);
7715762613eSGovind Singh 	if (ret) {
7725762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
7735762613eSGovind Singh 		goto out;
7745762613eSGovind Singh 	}
7755762613eSGovind Singh 
7765762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
7775762613eSGovind Singh 	if (ret) {
7785762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
7795762613eSGovind Singh 		goto disable_device;
7805762613eSGovind Singh 	}
7815762613eSGovind Singh 
7825762613eSGovind Singh 	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
7835762613eSGovind Singh 	if (ret) {
7845762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
7855762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
7865762613eSGovind Singh 		goto release_region;
7875762613eSGovind Singh 	}
7885762613eSGovind Singh 
7895762613eSGovind Singh 	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
7905762613eSGovind Singh 	if (ret) {
7915762613eSGovind Singh 		ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n",
7925762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
7935762613eSGovind Singh 		goto release_region;
7945762613eSGovind Singh 	}
7955762613eSGovind Singh 
7965762613eSGovind Singh 	pci_set_master(pdev);
7975762613eSGovind Singh 
7985762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
7995762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
8005762613eSGovind Singh 	if (!ab->mem) {
8015762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
8025762613eSGovind Singh 		ret = -EIO;
8035762613eSGovind Singh 		goto clear_master;
8045762613eSGovind Singh 	}
8055762613eSGovind Singh 
8065762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
8075762613eSGovind Singh 	return 0;
8085762613eSGovind Singh 
8095762613eSGovind Singh clear_master:
8105762613eSGovind Singh 	pci_clear_master(pdev);
8115762613eSGovind Singh release_region:
8125762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
8135762613eSGovind Singh disable_device:
8145762613eSGovind Singh 	pci_disable_device(pdev);
8155762613eSGovind Singh out:
8165762613eSGovind Singh 	return ret;
8175762613eSGovind Singh }
8185762613eSGovind Singh 
8195762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
8205762613eSGovind Singh {
8215762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
8225762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
8235762613eSGovind Singh 
8245762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
8255762613eSGovind Singh 	ab->mem = NULL;
8265762613eSGovind Singh 	pci_clear_master(pci_dev);
8275762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
8285762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
8295762613eSGovind Singh 		pci_disable_device(pci_dev);
8305762613eSGovind Singh }
8315762613eSGovind Singh 
8321399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
8331399fb87SGovind Singh {
8341399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
8351399fb87SGovind Singh 	int ret;
8361399fb87SGovind Singh 
8371399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
8381399fb87SGovind Singh 	if (ret) {
8391399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
8401399fb87SGovind Singh 		return ret;
8411399fb87SGovind Singh 	}
8421399fb87SGovind Singh 
8431399fb87SGovind Singh 	return 0;
8441399fb87SGovind Singh }
8451399fb87SGovind Singh 
8461399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
8471399fb87SGovind Singh {
8481399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
8491399fb87SGovind Singh 
8501399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
8511399fb87SGovind Singh }
8521399fb87SGovind Singh 
8532c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
8542c3960c2SGovind Singh {
8552c3960c2SGovind Singh 	int i;
8562c3960c2SGovind Singh 
857d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
8582c3960c2SGovind Singh 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
8592c3960c2SGovind Singh 
860e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
8612c3960c2SGovind Singh 			continue;
8622c3960c2SGovind Singh 
8632c3960c2SGovind Singh 		tasklet_kill(&ce_pipe->intr_tq);
8642c3960c2SGovind Singh 	}
8652c3960c2SGovind Singh }
8662c3960c2SGovind Singh 
8677f4beda2SGovind Singh static void ath11k_pci_stop(struct ath11k_base *ab)
8687f4beda2SGovind Singh {
8692c3960c2SGovind Singh 	ath11k_pci_ce_irqs_disable(ab);
8702c3960c2SGovind Singh 	ath11k_pci_sync_ce_irqs(ab);
8712c3960c2SGovind Singh 	ath11k_pci_kill_tasklets(ab);
8727f4beda2SGovind Singh 	ath11k_ce_cleanup_pipes(ab);
8737f4beda2SGovind Singh }
8747f4beda2SGovind Singh 
8757f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab)
8767f4beda2SGovind Singh {
8777f4beda2SGovind Singh 	ath11k_pci_ce_irqs_enable(ab);
8782c3960c2SGovind Singh 	ath11k_ce_rx_post_buf(ab);
8792c3960c2SGovind Singh 
8802c3960c2SGovind Singh 	return 0;
8812c3960c2SGovind Singh }
8822c3960c2SGovind Singh 
8832c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
8842c3960c2SGovind Singh 					  u8 *ul_pipe, u8 *dl_pipe)
8852c3960c2SGovind Singh {
8862c3960c2SGovind Singh 	const struct service_to_pipe *entry;
8872c3960c2SGovind Singh 	bool ul_set = false, dl_set = false;
8882c3960c2SGovind Singh 	int i;
8892c3960c2SGovind Singh 
8902c3960c2SGovind Singh 	for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {
8912c3960c2SGovind Singh 		entry = &target_service_to_ce_map_wlan[i];
8922c3960c2SGovind Singh 
8932c3960c2SGovind Singh 		if (__le32_to_cpu(entry->service_id) != service_id)
8942c3960c2SGovind Singh 			continue;
8952c3960c2SGovind Singh 
8962c3960c2SGovind Singh 		switch (__le32_to_cpu(entry->pipedir)) {
8972c3960c2SGovind Singh 		case PIPEDIR_NONE:
8982c3960c2SGovind Singh 			break;
8992c3960c2SGovind Singh 		case PIPEDIR_IN:
9002c3960c2SGovind Singh 			WARN_ON(dl_set);
9012c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
9022c3960c2SGovind Singh 			dl_set = true;
9032c3960c2SGovind Singh 			break;
9042c3960c2SGovind Singh 		case PIPEDIR_OUT:
9052c3960c2SGovind Singh 			WARN_ON(ul_set);
9062c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
9072c3960c2SGovind Singh 			ul_set = true;
9082c3960c2SGovind Singh 			break;
9092c3960c2SGovind Singh 		case PIPEDIR_INOUT:
9102c3960c2SGovind Singh 			WARN_ON(dl_set);
9112c3960c2SGovind Singh 			WARN_ON(ul_set);
9122c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
9132c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
9142c3960c2SGovind Singh 			dl_set = true;
9152c3960c2SGovind Singh 			ul_set = true;
9162c3960c2SGovind Singh 			break;
9172c3960c2SGovind Singh 		}
9182c3960c2SGovind Singh 	}
9192c3960c2SGovind Singh 
9202c3960c2SGovind Singh 	if (WARN_ON(!ul_set || !dl_set))
9212c3960c2SGovind Singh 		return -ENOENT;
9227f4beda2SGovind Singh 
9237f4beda2SGovind Singh 	return 0;
9247f4beda2SGovind Singh }
9257f4beda2SGovind Singh 
9267f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
9277f4beda2SGovind Singh 	.start = ath11k_pci_start,
9287f4beda2SGovind Singh 	.stop = ath11k_pci_stop,
929654e959aSGovind Singh 	.read32 = ath11k_pci_read32,
930654e959aSGovind Singh 	.write32 = ath11k_pci_write32,
9311399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
9321399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
933*d4ecb90bSCarl Huang 	.irq_enable = ath11k_pci_ext_irq_enable,
934*d4ecb90bSCarl Huang 	.irq_disable = ath11k_pci_ext_irq_disable,
935c4eacabeSGovind Singh 	.get_msi_address =  ath11k_pci_get_msi_address,
936c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
9372c3960c2SGovind Singh 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
9381399fb87SGovind Singh };
9391399fb87SGovind Singh 
9406e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
9416e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
9426e0355afSGovind Singh {
9436e0355afSGovind Singh 	struct ath11k_base *ab;
9445762613eSGovind Singh 	struct ath11k_pci *ab_pci;
9456e0355afSGovind Singh 	enum ath11k_hw_rev hw_rev;
9465762613eSGovind Singh 	int ret;
9476e0355afSGovind Singh 
9486e0355afSGovind Singh 	dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n");
9496e0355afSGovind Singh 
9506e0355afSGovind Singh 	switch (pci_dev->device) {
9516e0355afSGovind Singh 	case QCA6390_DEVICE_ID:
9526e0355afSGovind Singh 		hw_rev = ATH11K_HW_QCA6390_HW20;
9536e0355afSGovind Singh 		break;
9546e0355afSGovind Singh 	default:
9556e0355afSGovind Singh 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
9566e0355afSGovind Singh 			pci_dev->device);
9576e0355afSGovind Singh 		return -ENOTSUPP;
9586e0355afSGovind Singh 	}
9596e0355afSGovind Singh 
9601ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
9611ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
9626e0355afSGovind Singh 	if (!ab) {
9636e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
9646e0355afSGovind Singh 		return -ENOMEM;
9656e0355afSGovind Singh 	}
9666e0355afSGovind Singh 
9676e0355afSGovind Singh 	ab->dev = &pdev->dev;
9686e0355afSGovind Singh 	ab->hw_rev = hw_rev;
9696e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
9705762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
9715762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
9725762613eSGovind Singh 	ab_pci->ab = ab;
9735697a564SGovind Singh 	ab_pci->pdev = pdev;
9747f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
9755762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
976654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
9775762613eSGovind Singh 
9785762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
9795762613eSGovind Singh 	if (ret) {
9805762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
9815762613eSGovind Singh 		goto err_free_core;
9825762613eSGovind Singh 	}
9836e0355afSGovind Singh 
9845697a564SGovind Singh 	ret = ath11k_pci_enable_msi(ab_pci);
9855697a564SGovind Singh 	if (ret) {
9865697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
9875697a564SGovind Singh 		goto err_pci_free_region;
9885697a564SGovind Singh 	}
9895697a564SGovind Singh 
990b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
991b8246f88SKalle Valo 	if (ret)
992b8246f88SKalle Valo 		goto err_pci_disable_msi;
993b8246f88SKalle Valo 
9941399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
9951399fb87SGovind Singh 	if (ret) {
9961399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
9971399fb87SGovind Singh 		goto err_pci_disable_msi;
9981399fb87SGovind Singh 	}
9991399fb87SGovind Singh 
10007f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
10017f4beda2SGovind Singh 	if (ret)
10027f4beda2SGovind Singh 		goto err_mhi_unregister;
10037f4beda2SGovind Singh 
10047f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
10057f4beda2SGovind Singh 	if (ret) {
10067f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
10077f4beda2SGovind Singh 		goto err_hal_srng_deinit;
10087f4beda2SGovind Singh 	}
10097f4beda2SGovind Singh 
10107f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
10117f4beda2SGovind Singh 
10127f4beda2SGovind Singh 	ret = ath11k_pci_config_irq(ab);
10137f4beda2SGovind Singh 	if (ret) {
10147f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
10157f4beda2SGovind Singh 		goto err_ce_free;
10167f4beda2SGovind Singh 	}
10177f4beda2SGovind Singh 
10187f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
10197f4beda2SGovind Singh 	if (ret) {
10207f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
10217f4beda2SGovind Singh 		goto err_free_irq;
10227f4beda2SGovind Singh 	}
10236e0355afSGovind Singh 	return 0;
10245762613eSGovind Singh 
10257f4beda2SGovind Singh err_free_irq:
10267f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
10277f4beda2SGovind Singh 
10287f4beda2SGovind Singh err_ce_free:
10297f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
10307f4beda2SGovind Singh 
10317f4beda2SGovind Singh err_hal_srng_deinit:
10327f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
10337f4beda2SGovind Singh 
10347f4beda2SGovind Singh err_mhi_unregister:
10357f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
10367f4beda2SGovind Singh 
1037b8246f88SKalle Valo err_pci_disable_msi:
1038b8246f88SKalle Valo 	ath11k_pci_disable_msi(ab_pci);
1039b8246f88SKalle Valo 
10405697a564SGovind Singh err_pci_free_region:
10415697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
10425697a564SGovind Singh 
10435762613eSGovind Singh err_free_core:
10445762613eSGovind Singh 	ath11k_core_free(ab);
10455697a564SGovind Singh 
10465762613eSGovind Singh 	return ret;
10476e0355afSGovind Singh }
10486e0355afSGovind Singh 
10496e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
10506e0355afSGovind Singh {
10516e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
10525762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
10536e0355afSGovind Singh 
10546e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
10551399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
10565697a564SGovind Singh 	ath11k_pci_disable_msi(ab_pci);
10575762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
10587f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
10596e0355afSGovind Singh 	ath11k_core_free(ab);
10606e0355afSGovind Singh }
10616e0355afSGovind Singh 
10621399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
10631399fb87SGovind Singh {
10641399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
10651399fb87SGovind Singh 
10661399fb87SGovind Singh 	ath11k_pci_power_down(ab);
10671399fb87SGovind Singh }
10681399fb87SGovind Singh 
10696e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
10706e0355afSGovind Singh 	.name = "ath11k_pci",
10716e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
10726e0355afSGovind Singh 	.probe = ath11k_pci_probe,
10736e0355afSGovind Singh 	.remove = ath11k_pci_remove,
10741399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
10756e0355afSGovind Singh };
10766e0355afSGovind Singh 
10776e0355afSGovind Singh static int ath11k_pci_init(void)
10786e0355afSGovind Singh {
10796e0355afSGovind Singh 	int ret;
10806e0355afSGovind Singh 
10816e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
10826e0355afSGovind Singh 	if (ret)
10836e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
10846e0355afSGovind Singh 		       ret);
10856e0355afSGovind Singh 
10866e0355afSGovind Singh 	return ret;
10876e0355afSGovind Singh }
10886e0355afSGovind Singh module_init(ath11k_pci_init);
10896e0355afSGovind Singh 
10906e0355afSGovind Singh static void ath11k_pci_exit(void)
10916e0355afSGovind Singh {
10926e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
10936e0355afSGovind Singh }
10946e0355afSGovind Singh 
10956e0355afSGovind Singh module_exit(ath11k_pci_exit);
10966e0355afSGovind Singh 
10976e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
10986e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
1099