xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/pci.c (revision b2c094582e38d667444a13404271752e5fafb2e2)
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 
304f3c603d4SCarl Huang 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 
318f3c603d4SCarl Huang 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 
335f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
336f3c603d4SCarl Huang {
337f3c603d4SCarl Huang 	u32 val, delay;
338f3c603d4SCarl Huang 
339f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
340f3c603d4SCarl Huang 
341f3c603d4SCarl Huang 	val |= PCIE_SOC_GLOBAL_RESET_V;
342f3c603d4SCarl Huang 
343f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
344f3c603d4SCarl Huang 
345f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
346f3c603d4SCarl Huang 	delay = 10;
347f3c603d4SCarl Huang 	mdelay(delay);
348f3c603d4SCarl Huang 
349f3c603d4SCarl Huang 	/* Need to toggle V bit back otherwise stuck in reset status */
350f3c603d4SCarl Huang 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
351f3c603d4SCarl Huang 
352f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
353f3c603d4SCarl Huang 
354f3c603d4SCarl Huang 	mdelay(delay);
355f3c603d4SCarl Huang 
356f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
357f3c603d4SCarl Huang 	if (val == 0xffffffff)
358f3c603d4SCarl Huang 		ath11k_warn(ab, "link down error during global reset\n");
359f3c603d4SCarl Huang }
360f3c603d4SCarl Huang 
361f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab)
362f3c603d4SCarl Huang {
363f3c603d4SCarl Huang 	u32 val;
364f3c603d4SCarl Huang 
365f3c603d4SCarl Huang 	/* read cookie */
366f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR);
367f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val);
368f3c603d4SCarl Huang 
369f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
370f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
371f3c603d4SCarl Huang 
372f3c603d4SCarl Huang 	/* TODO: exact time to sleep is uncertain */
373f3c603d4SCarl Huang 	mdelay(10);
374f3c603d4SCarl Huang 
375f3c603d4SCarl Huang 	/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from
376f3c603d4SCarl Huang 	 * continuing warm path and entering dead loop.
377f3c603d4SCarl Huang 	 */
378f3c603d4SCarl Huang 	ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0);
379f3c603d4SCarl Huang 	mdelay(10);
380f3c603d4SCarl Huang 
381f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY);
382f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);
383f3c603d4SCarl Huang 
384f3c603d4SCarl Huang 	/* A read clear register. clear the register to prevent
385f3c603d4SCarl Huang 	 * Q6 from entering wrong code path.
386f3c603d4SCarl Huang 	 */
387f3c603d4SCarl Huang 	val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG);
388f3c603d4SCarl Huang 	ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val);
389f3c603d4SCarl Huang }
390f3c603d4SCarl Huang 
391f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab)
392f3c603d4SCarl Huang {
393f3c603d4SCarl Huang 	ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);
394f3c603d4SCarl Huang 	mdelay(5);
395f3c603d4SCarl Huang }
396f3c603d4SCarl Huang 
397f3c603d4SCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab)
398f3c603d4SCarl Huang {
399f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
400f3c603d4SCarl Huang 	ath11k_mhi_clear_vector(ab);
401f3c603d4SCarl Huang 	ath11k_pci_soc_global_reset(ab);
402f3c603d4SCarl Huang 	ath11k_mhi_set_mhictrl_reset(ab);
403f3c603d4SCarl Huang 	ath11k_pci_clear_dbg_registers(ab);
404f3c603d4SCarl Huang }
405f3c603d4SCarl Huang 
4061399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector)
4071399fb87SGovind Singh {
4081399fb87SGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(dev);
4091399fb87SGovind Singh 
4101399fb87SGovind Singh 	return pci_irq_vector(pci_dev, vector);
4111399fb87SGovind Singh }
4121399fb87SGovind Singh 
413c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
414c4eacabeSGovind Singh 				       u32 *msi_addr_hi)
415c4eacabeSGovind Singh {
416c4eacabeSGovind Singh 	struct pci_dev *pci_dev = to_pci_dev(ab->dev);
417c4eacabeSGovind Singh 
418c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
419c4eacabeSGovind Singh 			      msi_addr_lo);
420c4eacabeSGovind Singh 
421c4eacabeSGovind Singh 	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
422c4eacabeSGovind Singh 			      msi_addr_hi);
423c4eacabeSGovind Singh }
424c4eacabeSGovind Singh 
4251399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name,
4261399fb87SGovind Singh 				       int *num_vectors, u32 *user_base_data,
4271399fb87SGovind Singh 				       u32 *base_vector)
4281399fb87SGovind Singh {
4291399fb87SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
4301399fb87SGovind Singh 	int idx;
4311399fb87SGovind Singh 
4321399fb87SGovind Singh 	for (idx = 0; idx < msi_config.total_users; idx++) {
4331399fb87SGovind Singh 		if (strcmp(user_name, msi_config.users[idx].name) == 0) {
4341399fb87SGovind Singh 			*num_vectors = msi_config.users[idx].num_vectors;
4351399fb87SGovind Singh 			*user_base_data = msi_config.users[idx].base_vector
4361399fb87SGovind Singh 				+ ab_pci->msi_ep_base_data;
4371399fb87SGovind Singh 			*base_vector = msi_config.users[idx].base_vector;
4381399fb87SGovind Singh 
4391399fb87SGovind Singh 			ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
4401399fb87SGovind Singh 				   user_name, *num_vectors, *user_base_data,
4411399fb87SGovind Singh 				   *base_vector);
4421399fb87SGovind Singh 
4431399fb87SGovind Singh 			return 0;
4441399fb87SGovind Singh 		}
4451399fb87SGovind Singh 	}
4461399fb87SGovind Singh 
4471399fb87SGovind Singh 	ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);
4481399fb87SGovind Singh 
4491399fb87SGovind Singh 	return -EINVAL;
4501399fb87SGovind Singh }
4511399fb87SGovind Singh 
452c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
453c4eacabeSGovind Singh 					  int *num_vectors, u32 *user_base_data,
454c4eacabeSGovind Singh 					  u32 *base_vector)
455c4eacabeSGovind Singh {
456c4eacabeSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
457c4eacabeSGovind Singh 
458c4eacabeSGovind Singh 	return ath11k_pci_get_user_msi_assignment(ab_pci, user_name,
459c4eacabeSGovind Singh 						  num_vectors, user_base_data,
460c4eacabeSGovind Singh 						  base_vector);
461c4eacabeSGovind Singh }
462c4eacabeSGovind Singh 
463d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab)
464d4ecb90bSCarl Huang {
465d4ecb90bSCarl Huang 	int i, j;
466d4ecb90bSCarl Huang 
467d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
468d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
469d4ecb90bSCarl Huang 
470d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++)
471d4ecb90bSCarl Huang 			free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
472d4ecb90bSCarl Huang 
473d4ecb90bSCarl Huang 		netif_napi_del(&irq_grp->napi);
474d4ecb90bSCarl Huang 	}
475d4ecb90bSCarl Huang }
476d4ecb90bSCarl Huang 
4777f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab)
4787f4beda2SGovind Singh {
4797f4beda2SGovind Singh 	int i, irq_idx;
4807f4beda2SGovind Singh 
481d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
482e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
4837f4beda2SGovind Singh 			continue;
4847f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
4857f4beda2SGovind Singh 		free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
4867f4beda2SGovind Singh 	}
487d4ecb90bSCarl Huang 
488d4ecb90bSCarl Huang 	ath11k_pci_free_ext_irq(ab);
4897f4beda2SGovind Singh }
4907f4beda2SGovind Singh 
4912c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
4922c3960c2SGovind Singh {
4932c3960c2SGovind Singh 	u32 irq_idx;
4942c3960c2SGovind Singh 
4952c3960c2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
4962c3960c2SGovind Singh 	enable_irq(ab->irq_num[irq_idx]);
4972c3960c2SGovind Singh }
4982c3960c2SGovind Singh 
4997f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
5007f4beda2SGovind Singh {
5017f4beda2SGovind Singh 	u32 irq_idx;
5027f4beda2SGovind Singh 
5037f4beda2SGovind Singh 	irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id;
5047f4beda2SGovind Singh 	disable_irq_nosync(ab->irq_num[irq_idx]);
5057f4beda2SGovind Singh }
5067f4beda2SGovind Singh 
5072c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab)
5082c3960c2SGovind Singh {
5092c3960c2SGovind Singh 	int i;
5102c3960c2SGovind Singh 
511d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
512e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5132c3960c2SGovind Singh 			continue;
5142c3960c2SGovind Singh 		ath11k_pci_ce_irq_disable(ab, i);
5152c3960c2SGovind Singh 	}
5162c3960c2SGovind Singh }
5172c3960c2SGovind Singh 
5182c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab)
5192c3960c2SGovind Singh {
5202c3960c2SGovind Singh 	int i;
5212c3960c2SGovind Singh 	int irq_idx;
5222c3960c2SGovind Singh 
523d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
524e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
5252c3960c2SGovind Singh 			continue;
5262c3960c2SGovind Singh 
5272c3960c2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
5282c3960c2SGovind Singh 		synchronize_irq(ab->irq_num[irq_idx]);
5292c3960c2SGovind Singh 	}
5302c3960c2SGovind Singh }
5312c3960c2SGovind Singh 
5322c3960c2SGovind Singh static void ath11k_pci_ce_tasklet(unsigned long data)
5332c3960c2SGovind Singh {
5342c3960c2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = (struct ath11k_ce_pipe *)data;
5352c3960c2SGovind Singh 
5362c3960c2SGovind Singh 	ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
5372c3960c2SGovind Singh 
5382c3960c2SGovind Singh 	ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
5392c3960c2SGovind Singh }
5402c3960c2SGovind Singh 
5417f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg)
5427f4beda2SGovind Singh {
5437f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe = arg;
5447f4beda2SGovind Singh 
5457f4beda2SGovind Singh 	ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
5462c3960c2SGovind Singh 	tasklet_schedule(&ce_pipe->intr_tq);
5477f4beda2SGovind Singh 
5487f4beda2SGovind Singh 	return IRQ_HANDLED;
5497f4beda2SGovind Singh }
5507f4beda2SGovind Singh 
551d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
552d4ecb90bSCarl Huang {
553d4ecb90bSCarl Huang 	int i;
554d4ecb90bSCarl Huang 
555d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
556d4ecb90bSCarl Huang 		disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
557d4ecb90bSCarl Huang }
558d4ecb90bSCarl Huang 
559d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc)
560d4ecb90bSCarl Huang {
561d4ecb90bSCarl Huang 	int i;
562d4ecb90bSCarl Huang 
563d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
564d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];
565d4ecb90bSCarl Huang 
566d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_disable(irq_grp);
567d4ecb90bSCarl Huang 
568d4ecb90bSCarl Huang 		napi_synchronize(&irq_grp->napi);
569d4ecb90bSCarl Huang 		napi_disable(&irq_grp->napi);
570d4ecb90bSCarl Huang 	}
571d4ecb90bSCarl Huang }
572d4ecb90bSCarl Huang 
573d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
574d4ecb90bSCarl Huang {
575d4ecb90bSCarl Huang 	int i;
576d4ecb90bSCarl Huang 
577d4ecb90bSCarl Huang 	for (i = 0; i < irq_grp->num_irq; i++)
578d4ecb90bSCarl Huang 		enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
579d4ecb90bSCarl Huang }
580d4ecb90bSCarl Huang 
581d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
582d4ecb90bSCarl Huang {
583d4ecb90bSCarl Huang 	int i;
584d4ecb90bSCarl Huang 
585d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
586d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
587d4ecb90bSCarl Huang 
588d4ecb90bSCarl Huang 		napi_enable(&irq_grp->napi);
589d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
590d4ecb90bSCarl Huang 	}
591d4ecb90bSCarl Huang }
592d4ecb90bSCarl Huang 
593d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab)
594d4ecb90bSCarl Huang {
595d4ecb90bSCarl Huang 	int i, j, irq_idx;
596d4ecb90bSCarl Huang 
597d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
598d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
599d4ecb90bSCarl Huang 
600d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
601d4ecb90bSCarl Huang 			irq_idx = irq_grp->irqs[j];
602d4ecb90bSCarl Huang 			synchronize_irq(ab->irq_num[irq_idx]);
603d4ecb90bSCarl Huang 		}
604d4ecb90bSCarl Huang 	}
605d4ecb90bSCarl Huang }
606d4ecb90bSCarl Huang 
607d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab)
608d4ecb90bSCarl Huang {
609d4ecb90bSCarl Huang 	__ath11k_pci_ext_irq_disable(ab);
610d4ecb90bSCarl Huang 	ath11k_pci_sync_ext_irqs(ab);
611d4ecb90bSCarl Huang }
612d4ecb90bSCarl Huang 
613d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
614d4ecb90bSCarl Huang {
615d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
616d4ecb90bSCarl Huang 						struct ath11k_ext_irq_grp,
617d4ecb90bSCarl Huang 						napi);
618d4ecb90bSCarl Huang 	struct ath11k_base *ab = irq_grp->ab;
619d4ecb90bSCarl Huang 	int work_done;
620d4ecb90bSCarl Huang 
621d4ecb90bSCarl Huang 	work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
622d4ecb90bSCarl Huang 	if (work_done < budget) {
623d4ecb90bSCarl Huang 		napi_complete_done(napi, work_done);
624d4ecb90bSCarl Huang 		ath11k_pci_ext_grp_enable(irq_grp);
625d4ecb90bSCarl Huang 	}
626d4ecb90bSCarl Huang 
627d4ecb90bSCarl Huang 	if (work_done > budget)
628d4ecb90bSCarl Huang 		work_done = budget;
629d4ecb90bSCarl Huang 
630d4ecb90bSCarl Huang 	return work_done;
631d4ecb90bSCarl Huang }
632d4ecb90bSCarl Huang 
633d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg)
634d4ecb90bSCarl Huang {
635d4ecb90bSCarl Huang 	struct ath11k_ext_irq_grp *irq_grp = arg;
636d4ecb90bSCarl Huang 
637d4ecb90bSCarl Huang 	ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq);
638d4ecb90bSCarl Huang 
639d4ecb90bSCarl Huang 	ath11k_pci_ext_grp_disable(irq_grp);
640d4ecb90bSCarl Huang 
641d4ecb90bSCarl Huang 	napi_schedule(&irq_grp->napi);
642d4ecb90bSCarl Huang 
643d4ecb90bSCarl Huang 	return IRQ_HANDLED;
644d4ecb90bSCarl Huang }
645d4ecb90bSCarl Huang 
646d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab)
647d4ecb90bSCarl Huang {
648d4ecb90bSCarl Huang 	int i, j, ret, num_vectors = 0;
649d4ecb90bSCarl Huang 	u32 user_base_data = 0, base_vector = 0;
650d4ecb90bSCarl Huang 
651*b2c09458SColin Ian King 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP",
652*b2c09458SColin Ian King 						 &num_vectors,
653*b2c09458SColin Ian King 						 &user_base_data,
654d4ecb90bSCarl Huang 						 &base_vector);
655*b2c09458SColin Ian King 	if (ret < 0)
656*b2c09458SColin Ian King 		return ret;
657d4ecb90bSCarl Huang 
658d4ecb90bSCarl Huang 	for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
659d4ecb90bSCarl Huang 		struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
660d4ecb90bSCarl Huang 		u32 num_irq = 0;
661d4ecb90bSCarl Huang 
662d4ecb90bSCarl Huang 		irq_grp->ab = ab;
663d4ecb90bSCarl Huang 		irq_grp->grp_id = i;
664d4ecb90bSCarl Huang 		init_dummy_netdev(&irq_grp->napi_ndev);
665d4ecb90bSCarl Huang 		netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
666d4ecb90bSCarl Huang 			       ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
667d4ecb90bSCarl Huang 
668d4ecb90bSCarl Huang 		if (ab->hw_params.ring_mask->tx[i] ||
669d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx[i] ||
670d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_err[i] ||
671d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_wbm_rel[i] ||
672d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->reo_status[i] ||
673d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rxdma2host[i] ||
674d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->host2rxdma[i] ||
675d4ecb90bSCarl Huang 		    ab->hw_params.ring_mask->rx_mon_status[i]) {
676d4ecb90bSCarl Huang 			num_irq = 1;
677d4ecb90bSCarl Huang 		}
678d4ecb90bSCarl Huang 
679d4ecb90bSCarl Huang 		irq_grp->num_irq = num_irq;
680d4ecb90bSCarl Huang 		irq_grp->irqs[0] = base_vector + i;
681d4ecb90bSCarl Huang 
682d4ecb90bSCarl Huang 		for (j = 0; j < irq_grp->num_irq; j++) {
683d4ecb90bSCarl Huang 			int irq_idx = irq_grp->irqs[j];
684d4ecb90bSCarl Huang 			int vector = (i % num_vectors) + base_vector;
685d4ecb90bSCarl Huang 			int irq = ath11k_pci_get_msi_irq(ab->dev, vector);
686d4ecb90bSCarl Huang 
687d4ecb90bSCarl Huang 			ab->irq_num[irq_idx] = irq;
688d4ecb90bSCarl Huang 
689d4ecb90bSCarl Huang 			ath11k_dbg(ab, ATH11K_DBG_PCI,
690d4ecb90bSCarl Huang 				   "irq:%d group:%d\n", irq, i);
691d4ecb90bSCarl Huang 			ret = request_irq(irq, ath11k_pci_ext_interrupt_handler,
692d4ecb90bSCarl Huang 					  IRQF_SHARED,
693d4ecb90bSCarl Huang 					  "DP_EXT_IRQ", irq_grp);
694d4ecb90bSCarl Huang 			if (ret) {
695d4ecb90bSCarl Huang 				ath11k_err(ab, "failed request irq %d: %d\n",
696d4ecb90bSCarl Huang 					   vector, ret);
697d4ecb90bSCarl Huang 				return ret;
698d4ecb90bSCarl Huang 			}
699d4ecb90bSCarl Huang 
700d4ecb90bSCarl Huang 			disable_irq_nosync(ab->irq_num[irq_idx]);
701d4ecb90bSCarl Huang 		}
702d4ecb90bSCarl Huang 	}
703d4ecb90bSCarl Huang 
704d4ecb90bSCarl Huang 	return 0;
705d4ecb90bSCarl Huang }
706d4ecb90bSCarl Huang 
7077f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab)
7087f4beda2SGovind Singh {
7097f4beda2SGovind Singh 	struct ath11k_ce_pipe *ce_pipe;
7107f4beda2SGovind Singh 	u32 msi_data_start;
7117f4beda2SGovind Singh 	u32 msi_data_count;
7127f4beda2SGovind Singh 	u32 msi_irq_start;
7137f4beda2SGovind Singh 	unsigned int msi_data;
7147f4beda2SGovind Singh 	int irq, i, ret, irq_idx;
7157f4beda2SGovind Singh 
7167f4beda2SGovind Singh 	ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab),
7177f4beda2SGovind Singh 						 "CE", &msi_data_count,
7187f4beda2SGovind Singh 						 &msi_data_start, &msi_irq_start);
7197f4beda2SGovind Singh 	if (ret)
7207f4beda2SGovind Singh 		return ret;
7217f4beda2SGovind Singh 
7227f4beda2SGovind Singh 	/* Configure CE irqs */
723d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
7247f4beda2SGovind Singh 		msi_data = (i % msi_data_count) + msi_irq_start;
7257f4beda2SGovind Singh 		irq = ath11k_pci_get_msi_irq(ab->dev, msi_data);
7267f4beda2SGovind Singh 		ce_pipe = &ab->ce.ce_pipe[i];
7277f4beda2SGovind Singh 
728e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
7297f4beda2SGovind Singh 			continue;
7307f4beda2SGovind Singh 
7317f4beda2SGovind Singh 		irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
7327f4beda2SGovind Singh 
7332c3960c2SGovind Singh 		tasklet_init(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet,
7342c3960c2SGovind Singh 			     (unsigned long)ce_pipe);
7352c3960c2SGovind Singh 
7367f4beda2SGovind Singh 		ret = request_irq(irq, ath11k_pci_ce_interrupt_handler,
7377f4beda2SGovind Singh 				  IRQF_SHARED, irq_name[irq_idx],
7387f4beda2SGovind Singh 				  ce_pipe);
7397f4beda2SGovind Singh 		if (ret) {
7407f4beda2SGovind Singh 			ath11k_err(ab, "failed to request irq %d: %d\n",
7417f4beda2SGovind Singh 				   irq_idx, ret);
7427f4beda2SGovind Singh 			return ret;
7437f4beda2SGovind Singh 		}
7447f4beda2SGovind Singh 
7457f4beda2SGovind Singh 		ab->irq_num[irq_idx] = irq;
746e5c860e1SCarl Huang 		ath11k_pci_ce_irq_disable(ab, i);
7477f4beda2SGovind Singh 	}
7487f4beda2SGovind Singh 
749d4ecb90bSCarl Huang 	ret = ath11k_pci_ext_irq_config(ab);
750d4ecb90bSCarl Huang 	if (ret)
751d4ecb90bSCarl Huang 		return ret;
752d4ecb90bSCarl Huang 
7537f4beda2SGovind Singh 	return 0;
7547f4beda2SGovind Singh }
7557f4beda2SGovind Singh 
7567f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
7577f4beda2SGovind Singh {
7587f4beda2SGovind Singh 	struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
7597f4beda2SGovind Singh 
7607f4beda2SGovind Singh 	cfg->tgt_ce = target_ce_config_wlan;
7617f4beda2SGovind Singh 	cfg->tgt_ce_len = ARRAY_SIZE(target_ce_config_wlan);
7627f4beda2SGovind Singh 
7637f4beda2SGovind Singh 	cfg->svc_to_ce_map = target_service_to_ce_map_wlan;
7647f4beda2SGovind Singh 	cfg->svc_to_ce_map_len = ARRAY_SIZE(target_service_to_ce_map_wlan);
765eb8de049SGovind Singh 	ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390;
7667f4beda2SGovind Singh }
7677f4beda2SGovind Singh 
7687f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab)
7697f4beda2SGovind Singh {
7707f4beda2SGovind Singh 	int i;
7717f4beda2SGovind Singh 
772d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
773e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
7747f4beda2SGovind Singh 			continue;
7757f4beda2SGovind Singh 		ath11k_pci_ce_irq_enable(ab, i);
7767f4beda2SGovind Singh 	}
7777f4beda2SGovind Singh }
7787f4beda2SGovind Singh 
7795697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci)
7805697a564SGovind Singh {
7815697a564SGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
7825697a564SGovind Singh 	struct msi_desc *msi_desc;
7835697a564SGovind Singh 	int num_vectors;
7845697a564SGovind Singh 	int ret;
7855697a564SGovind Singh 
7865697a564SGovind Singh 	num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
7875697a564SGovind Singh 					    msi_config.total_vectors,
7885697a564SGovind Singh 					    msi_config.total_vectors,
7895697a564SGovind Singh 					    PCI_IRQ_MSI);
7905697a564SGovind Singh 	if (num_vectors != msi_config.total_vectors) {
7915697a564SGovind Singh 		ath11k_err(ab, "failed to get %d MSI vectors, only %d available",
7925697a564SGovind Singh 			   msi_config.total_vectors, num_vectors);
7935697a564SGovind Singh 
7945697a564SGovind Singh 		if (num_vectors >= 0)
7955697a564SGovind Singh 			return -EINVAL;
7965697a564SGovind Singh 		else
7975697a564SGovind Singh 			return num_vectors;
7985697a564SGovind Singh 	}
7995697a564SGovind Singh 
8005697a564SGovind Singh 	msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
8015697a564SGovind Singh 	if (!msi_desc) {
8025697a564SGovind Singh 		ath11k_err(ab, "msi_desc is NULL!\n");
8035697a564SGovind Singh 		ret = -EINVAL;
8045697a564SGovind Singh 		goto free_msi_vector;
8055697a564SGovind Singh 	}
8065697a564SGovind Singh 
8075697a564SGovind Singh 	ab_pci->msi_ep_base_data = msi_desc->msg.data;
8085697a564SGovind Singh 
8095697a564SGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);
8105697a564SGovind Singh 
8115697a564SGovind Singh 	return 0;
8125697a564SGovind Singh 
8135697a564SGovind Singh free_msi_vector:
8145697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
8155697a564SGovind Singh 
8165697a564SGovind Singh 	return ret;
8175697a564SGovind Singh }
8185697a564SGovind Singh 
8195697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci)
8205697a564SGovind Singh {
8215697a564SGovind Singh 	pci_free_irq_vectors(ab_pci->pdev);
8225697a564SGovind Singh }
8235697a564SGovind Singh 
8245762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
8255762613eSGovind Singh {
8265762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
8275762613eSGovind Singh 	u16 device_id;
8285762613eSGovind Singh 	int ret = 0;
8295762613eSGovind Singh 
8305762613eSGovind Singh 	pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
8315762613eSGovind Singh 	if (device_id != ab_pci->dev_id)  {
8325762613eSGovind Singh 		ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",
8335762613eSGovind Singh 			   device_id, ab_pci->dev_id);
8345762613eSGovind Singh 		ret = -EIO;
8355762613eSGovind Singh 		goto out;
8365762613eSGovind Singh 	}
8375762613eSGovind Singh 
8385762613eSGovind Singh 	ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM);
8395762613eSGovind Singh 	if (ret) {
8405762613eSGovind Singh 		ath11k_err(ab, "failed to assign pci resource: %d\n", ret);
8415762613eSGovind Singh 		goto out;
8425762613eSGovind Singh 	}
8435762613eSGovind Singh 
8445762613eSGovind Singh 	ret = pci_enable_device(pdev);
8455762613eSGovind Singh 	if (ret) {
8465762613eSGovind Singh 		ath11k_err(ab, "failed to enable pci device: %d\n", ret);
8475762613eSGovind Singh 		goto out;
8485762613eSGovind Singh 	}
8495762613eSGovind Singh 
8505762613eSGovind Singh 	ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci");
8515762613eSGovind Singh 	if (ret) {
8525762613eSGovind Singh 		ath11k_err(ab, "failed to request pci region: %d\n", ret);
8535762613eSGovind Singh 		goto disable_device;
8545762613eSGovind Singh 	}
8555762613eSGovind Singh 
8565762613eSGovind Singh 	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
8575762613eSGovind Singh 	if (ret) {
8585762613eSGovind Singh 		ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
8595762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
8605762613eSGovind Singh 		goto release_region;
8615762613eSGovind Singh 	}
8625762613eSGovind Singh 
8635762613eSGovind Singh 	ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
8645762613eSGovind Singh 	if (ret) {
8655762613eSGovind Singh 		ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n",
8665762613eSGovind Singh 			   ATH11K_PCI_DMA_MASK, ret);
8675762613eSGovind Singh 		goto release_region;
8685762613eSGovind Singh 	}
8695762613eSGovind Singh 
8705762613eSGovind Singh 	pci_set_master(pdev);
8715762613eSGovind Singh 
8725762613eSGovind Singh 	ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
8735762613eSGovind Singh 	ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0);
8745762613eSGovind Singh 	if (!ab->mem) {
8755762613eSGovind Singh 		ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM);
8765762613eSGovind Singh 		ret = -EIO;
8775762613eSGovind Singh 		goto clear_master;
8785762613eSGovind Singh 	}
8795762613eSGovind Singh 
8805762613eSGovind Singh 	ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);
8815762613eSGovind Singh 	return 0;
8825762613eSGovind Singh 
8835762613eSGovind Singh clear_master:
8845762613eSGovind Singh 	pci_clear_master(pdev);
8855762613eSGovind Singh release_region:
8865762613eSGovind Singh 	pci_release_region(pdev, ATH11K_PCI_BAR_NUM);
8875762613eSGovind Singh disable_device:
8885762613eSGovind Singh 	pci_disable_device(pdev);
8895762613eSGovind Singh out:
8905762613eSGovind Singh 	return ret;
8915762613eSGovind Singh }
8925762613eSGovind Singh 
8935762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci)
8945762613eSGovind Singh {
8955762613eSGovind Singh 	struct ath11k_base *ab = ab_pci->ab;
8965762613eSGovind Singh 	struct pci_dev *pci_dev = ab_pci->pdev;
8975762613eSGovind Singh 
8985762613eSGovind Singh 	pci_iounmap(pci_dev, ab->mem);
8995762613eSGovind Singh 	ab->mem = NULL;
9005762613eSGovind Singh 	pci_clear_master(pci_dev);
9015762613eSGovind Singh 	pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM);
9025762613eSGovind Singh 	if (pci_is_enabled(pci_dev))
9035762613eSGovind Singh 		pci_disable_device(pci_dev);
9045762613eSGovind Singh }
9055762613eSGovind Singh 
9061399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab)
9071399fb87SGovind Singh {
9081399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
9091399fb87SGovind Singh 	int ret;
9101399fb87SGovind Singh 
911f3c603d4SCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab);
912f3c603d4SCarl Huang 
9131399fb87SGovind Singh 	ret = ath11k_mhi_start(ab_pci);
9141399fb87SGovind Singh 	if (ret) {
9151399fb87SGovind Singh 		ath11k_err(ab, "failed to start mhi: %d\n", ret);
9161399fb87SGovind Singh 		return ret;
9171399fb87SGovind Singh 	}
9181399fb87SGovind Singh 
9191399fb87SGovind Singh 	return 0;
9201399fb87SGovind Singh }
9211399fb87SGovind Singh 
9221399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab)
9231399fb87SGovind Singh {
9241399fb87SGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
9251399fb87SGovind Singh 
9261399fb87SGovind Singh 	ath11k_mhi_stop(ab_pci);
927f3c603d4SCarl Huang 	ath11k_pci_force_wake(ab_pci->ab);
928f3c603d4SCarl Huang 	ath11k_pci_sw_reset(ab_pci->ab);
9291399fb87SGovind Singh }
9301399fb87SGovind Singh 
9312c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab)
9322c3960c2SGovind Singh {
9332c3960c2SGovind Singh 	int i;
9342c3960c2SGovind Singh 
935d9d4b5f3SKalle Valo 	for (i = 0; i < ab->hw_params.ce_count; i++) {
9362c3960c2SGovind Singh 		struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
9372c3960c2SGovind Singh 
938e3396b8bSCarl Huang 		if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
9392c3960c2SGovind Singh 			continue;
9402c3960c2SGovind Singh 
9412c3960c2SGovind Singh 		tasklet_kill(&ce_pipe->intr_tq);
9422c3960c2SGovind Singh 	}
9432c3960c2SGovind Singh }
9442c3960c2SGovind Singh 
9457f4beda2SGovind Singh static void ath11k_pci_stop(struct ath11k_base *ab)
9467f4beda2SGovind Singh {
9472c3960c2SGovind Singh 	ath11k_pci_ce_irqs_disable(ab);
9482c3960c2SGovind Singh 	ath11k_pci_sync_ce_irqs(ab);
9492c3960c2SGovind Singh 	ath11k_pci_kill_tasklets(ab);
9507f4beda2SGovind Singh 	ath11k_ce_cleanup_pipes(ab);
9517f4beda2SGovind Singh }
9527f4beda2SGovind Singh 
9537f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab)
9547f4beda2SGovind Singh {
9557f4beda2SGovind Singh 	ath11k_pci_ce_irqs_enable(ab);
9562c3960c2SGovind Singh 	ath11k_ce_rx_post_buf(ab);
9572c3960c2SGovind Singh 
9582c3960c2SGovind Singh 	return 0;
9592c3960c2SGovind Singh }
9602c3960c2SGovind Singh 
9612c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
9622c3960c2SGovind Singh 					  u8 *ul_pipe, u8 *dl_pipe)
9632c3960c2SGovind Singh {
9642c3960c2SGovind Singh 	const struct service_to_pipe *entry;
9652c3960c2SGovind Singh 	bool ul_set = false, dl_set = false;
9662c3960c2SGovind Singh 	int i;
9672c3960c2SGovind Singh 
9682c3960c2SGovind Singh 	for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {
9692c3960c2SGovind Singh 		entry = &target_service_to_ce_map_wlan[i];
9702c3960c2SGovind Singh 
9712c3960c2SGovind Singh 		if (__le32_to_cpu(entry->service_id) != service_id)
9722c3960c2SGovind Singh 			continue;
9732c3960c2SGovind Singh 
9742c3960c2SGovind Singh 		switch (__le32_to_cpu(entry->pipedir)) {
9752c3960c2SGovind Singh 		case PIPEDIR_NONE:
9762c3960c2SGovind Singh 			break;
9772c3960c2SGovind Singh 		case PIPEDIR_IN:
9782c3960c2SGovind Singh 			WARN_ON(dl_set);
9792c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
9802c3960c2SGovind Singh 			dl_set = true;
9812c3960c2SGovind Singh 			break;
9822c3960c2SGovind Singh 		case PIPEDIR_OUT:
9832c3960c2SGovind Singh 			WARN_ON(ul_set);
9842c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
9852c3960c2SGovind Singh 			ul_set = true;
9862c3960c2SGovind Singh 			break;
9872c3960c2SGovind Singh 		case PIPEDIR_INOUT:
9882c3960c2SGovind Singh 			WARN_ON(dl_set);
9892c3960c2SGovind Singh 			WARN_ON(ul_set);
9902c3960c2SGovind Singh 			*dl_pipe = __le32_to_cpu(entry->pipenum);
9912c3960c2SGovind Singh 			*ul_pipe = __le32_to_cpu(entry->pipenum);
9922c3960c2SGovind Singh 			dl_set = true;
9932c3960c2SGovind Singh 			ul_set = true;
9942c3960c2SGovind Singh 			break;
9952c3960c2SGovind Singh 		}
9962c3960c2SGovind Singh 	}
9972c3960c2SGovind Singh 
9982c3960c2SGovind Singh 	if (WARN_ON(!ul_set || !dl_set))
9992c3960c2SGovind Singh 		return -ENOENT;
10007f4beda2SGovind Singh 
10017f4beda2SGovind Singh 	return 0;
10027f4beda2SGovind Singh }
10037f4beda2SGovind Singh 
10047f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
10057f4beda2SGovind Singh 	.start = ath11k_pci_start,
10067f4beda2SGovind Singh 	.stop = ath11k_pci_stop,
1007654e959aSGovind Singh 	.read32 = ath11k_pci_read32,
1008654e959aSGovind Singh 	.write32 = ath11k_pci_write32,
10091399fb87SGovind Singh 	.power_down = ath11k_pci_power_down,
10101399fb87SGovind Singh 	.power_up = ath11k_pci_power_up,
1011d4ecb90bSCarl Huang 	.irq_enable = ath11k_pci_ext_irq_enable,
1012d4ecb90bSCarl Huang 	.irq_disable = ath11k_pci_ext_irq_disable,
1013c4eacabeSGovind Singh 	.get_msi_address =  ath11k_pci_get_msi_address,
1014c4eacabeSGovind Singh 	.get_user_msi_vector = ath11k_get_user_msi_assignment,
10152c3960c2SGovind Singh 	.map_service_to_pipe = ath11k_pci_map_service_to_pipe,
10161399fb87SGovind Singh };
10171399fb87SGovind Singh 
10186e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev,
10196e0355afSGovind Singh 			    const struct pci_device_id *pci_dev)
10206e0355afSGovind Singh {
10216e0355afSGovind Singh 	struct ath11k_base *ab;
10225762613eSGovind Singh 	struct ath11k_pci *ab_pci;
10236e0355afSGovind Singh 	enum ath11k_hw_rev hw_rev;
10245762613eSGovind Singh 	int ret;
10256e0355afSGovind Singh 
10266e0355afSGovind Singh 	dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n");
10276e0355afSGovind Singh 
10286e0355afSGovind Singh 	switch (pci_dev->device) {
10296e0355afSGovind Singh 	case QCA6390_DEVICE_ID:
10306e0355afSGovind Singh 		hw_rev = ATH11K_HW_QCA6390_HW20;
10316e0355afSGovind Singh 		break;
10326e0355afSGovind Singh 	default:
10336e0355afSGovind Singh 		dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
10346e0355afSGovind Singh 			pci_dev->device);
10356e0355afSGovind Singh 		return -ENOTSUPP;
10366e0355afSGovind Singh 	}
10376e0355afSGovind Singh 
10381ff8ed78SGovind Singh 	ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI,
10391ff8ed78SGovind Singh 			       &ath11k_pci_bus_params);
10406e0355afSGovind Singh 	if (!ab) {
10416e0355afSGovind Singh 		dev_err(&pdev->dev, "failed to allocate ath11k base\n");
10426e0355afSGovind Singh 		return -ENOMEM;
10436e0355afSGovind Singh 	}
10446e0355afSGovind Singh 
10456e0355afSGovind Singh 	ab->dev = &pdev->dev;
10466e0355afSGovind Singh 	ab->hw_rev = hw_rev;
10476e0355afSGovind Singh 	pci_set_drvdata(pdev, ab);
10485762613eSGovind Singh 	ab_pci = ath11k_pci_priv(ab);
10495762613eSGovind Singh 	ab_pci->dev_id = pci_dev->device;
10505762613eSGovind Singh 	ab_pci->ab = ab;
10515697a564SGovind Singh 	ab_pci->pdev = pdev;
10527f4beda2SGovind Singh 	ab->hif.ops = &ath11k_pci_hif_ops;
10535762613eSGovind Singh 	pci_set_drvdata(pdev, ab);
1054654e959aSGovind Singh 	spin_lock_init(&ab_pci->window_lock);
10555762613eSGovind Singh 
10565762613eSGovind Singh 	ret = ath11k_pci_claim(ab_pci, pdev);
10575762613eSGovind Singh 	if (ret) {
10585762613eSGovind Singh 		ath11k_err(ab, "failed to claim device: %d\n", ret);
10595762613eSGovind Singh 		goto err_free_core;
10605762613eSGovind Singh 	}
10616e0355afSGovind Singh 
10625697a564SGovind Singh 	ret = ath11k_pci_enable_msi(ab_pci);
10635697a564SGovind Singh 	if (ret) {
10645697a564SGovind Singh 		ath11k_err(ab, "failed to enable msi: %d\n", ret);
10655697a564SGovind Singh 		goto err_pci_free_region;
10665697a564SGovind Singh 	}
10675697a564SGovind Singh 
1068b8246f88SKalle Valo 	ret = ath11k_core_pre_init(ab);
1069b8246f88SKalle Valo 	if (ret)
1070b8246f88SKalle Valo 		goto err_pci_disable_msi;
1071b8246f88SKalle Valo 
10721399fb87SGovind Singh 	ret = ath11k_mhi_register(ab_pci);
10731399fb87SGovind Singh 	if (ret) {
10741399fb87SGovind Singh 		ath11k_err(ab, "failed to register mhi: %d\n", ret);
10751399fb87SGovind Singh 		goto err_pci_disable_msi;
10761399fb87SGovind Singh 	}
10771399fb87SGovind Singh 
10787f4beda2SGovind Singh 	ret = ath11k_hal_srng_init(ab);
10797f4beda2SGovind Singh 	if (ret)
10807f4beda2SGovind Singh 		goto err_mhi_unregister;
10817f4beda2SGovind Singh 
10827f4beda2SGovind Singh 	ret = ath11k_ce_alloc_pipes(ab);
10837f4beda2SGovind Singh 	if (ret) {
10847f4beda2SGovind Singh 		ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
10857f4beda2SGovind Singh 		goto err_hal_srng_deinit;
10867f4beda2SGovind Singh 	}
10877f4beda2SGovind Singh 
10887f4beda2SGovind Singh 	ath11k_pci_init_qmi_ce_config(ab);
10897f4beda2SGovind Singh 
10907f4beda2SGovind Singh 	ret = ath11k_pci_config_irq(ab);
10917f4beda2SGovind Singh 	if (ret) {
10927f4beda2SGovind Singh 		ath11k_err(ab, "failed to config irq: %d\n", ret);
10937f4beda2SGovind Singh 		goto err_ce_free;
10947f4beda2SGovind Singh 	}
10957f4beda2SGovind Singh 
10967f4beda2SGovind Singh 	ret = ath11k_core_init(ab);
10977f4beda2SGovind Singh 	if (ret) {
10987f4beda2SGovind Singh 		ath11k_err(ab, "failed to init core: %d\n", ret);
10997f4beda2SGovind Singh 		goto err_free_irq;
11007f4beda2SGovind Singh 	}
11016e0355afSGovind Singh 	return 0;
11025762613eSGovind Singh 
11037f4beda2SGovind Singh err_free_irq:
11047f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
11057f4beda2SGovind Singh 
11067f4beda2SGovind Singh err_ce_free:
11077f4beda2SGovind Singh 	ath11k_ce_free_pipes(ab);
11087f4beda2SGovind Singh 
11097f4beda2SGovind Singh err_hal_srng_deinit:
11107f4beda2SGovind Singh 	ath11k_hal_srng_deinit(ab);
11117f4beda2SGovind Singh 
11127f4beda2SGovind Singh err_mhi_unregister:
11137f4beda2SGovind Singh 	ath11k_mhi_unregister(ab_pci);
11147f4beda2SGovind Singh 
1115b8246f88SKalle Valo err_pci_disable_msi:
1116b8246f88SKalle Valo 	ath11k_pci_disable_msi(ab_pci);
1117b8246f88SKalle Valo 
11185697a564SGovind Singh err_pci_free_region:
11195697a564SGovind Singh 	ath11k_pci_free_region(ab_pci);
11205697a564SGovind Singh 
11215762613eSGovind Singh err_free_core:
11225762613eSGovind Singh 	ath11k_core_free(ab);
11235697a564SGovind Singh 
11245762613eSGovind Singh 	return ret;
11256e0355afSGovind Singh }
11266e0355afSGovind Singh 
11276e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev)
11286e0355afSGovind Singh {
11296e0355afSGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
11305762613eSGovind Singh 	struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
11316e0355afSGovind Singh 
11326e0355afSGovind Singh 	set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
11331399fb87SGovind Singh 	ath11k_mhi_unregister(ab_pci);
11345697a564SGovind Singh 	ath11k_pci_disable_msi(ab_pci);
11355762613eSGovind Singh 	ath11k_pci_free_region(ab_pci);
11367f4beda2SGovind Singh 	ath11k_pci_free_irq(ab);
11376e0355afSGovind Singh 	ath11k_core_free(ab);
11386e0355afSGovind Singh }
11396e0355afSGovind Singh 
11401399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev)
11411399fb87SGovind Singh {
11421399fb87SGovind Singh 	struct ath11k_base *ab = pci_get_drvdata(pdev);
11431399fb87SGovind Singh 
11441399fb87SGovind Singh 	ath11k_pci_power_down(ab);
11451399fb87SGovind Singh }
11461399fb87SGovind Singh 
11476e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = {
11486e0355afSGovind Singh 	.name = "ath11k_pci",
11496e0355afSGovind Singh 	.id_table = ath11k_pci_id_table,
11506e0355afSGovind Singh 	.probe = ath11k_pci_probe,
11516e0355afSGovind Singh 	.remove = ath11k_pci_remove,
11521399fb87SGovind Singh 	.shutdown = ath11k_pci_shutdown,
11536e0355afSGovind Singh };
11546e0355afSGovind Singh 
11556e0355afSGovind Singh static int ath11k_pci_init(void)
11566e0355afSGovind Singh {
11576e0355afSGovind Singh 	int ret;
11586e0355afSGovind Singh 
11596e0355afSGovind Singh 	ret = pci_register_driver(&ath11k_pci_driver);
11606e0355afSGovind Singh 	if (ret)
11616e0355afSGovind Singh 		pr_err("failed to register ath11k pci driver: %d\n",
11626e0355afSGovind Singh 		       ret);
11636e0355afSGovind Singh 
11646e0355afSGovind Singh 	return ret;
11656e0355afSGovind Singh }
11666e0355afSGovind Singh module_init(ath11k_pci_init);
11676e0355afSGovind Singh 
11686e0355afSGovind Singh static void ath11k_pci_exit(void)
11696e0355afSGovind Singh {
11706e0355afSGovind Singh 	pci_unregister_driver(&ath11k_pci_driver);
11716e0355afSGovind Singh }
11726e0355afSGovind Singh 
11736e0355afSGovind Singh module_exit(ath11k_pci_exit);
11746e0355afSGovind Singh 
11756e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
11766e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL");
1177