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 3927f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab) 3937f4beda2SGovind Singh { 3947f4beda2SGovind Singh int i, irq_idx; 3957f4beda2SGovind Singh 396*d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 397e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 3987f4beda2SGovind Singh continue; 3997f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 4007f4beda2SGovind Singh free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); 4017f4beda2SGovind Singh } 4027f4beda2SGovind Singh } 4037f4beda2SGovind Singh 4042c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) 4052c3960c2SGovind Singh { 4062c3960c2SGovind Singh u32 irq_idx; 4072c3960c2SGovind Singh 4082c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 4092c3960c2SGovind Singh enable_irq(ab->irq_num[irq_idx]); 4102c3960c2SGovind Singh } 4112c3960c2SGovind Singh 4127f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) 4137f4beda2SGovind Singh { 4147f4beda2SGovind Singh u32 irq_idx; 4157f4beda2SGovind Singh 4167f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 4177f4beda2SGovind Singh disable_irq_nosync(ab->irq_num[irq_idx]); 4187f4beda2SGovind Singh } 4197f4beda2SGovind Singh 4202c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab) 4212c3960c2SGovind Singh { 4222c3960c2SGovind Singh int i; 4232c3960c2SGovind Singh 424*d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 425e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 4262c3960c2SGovind Singh continue; 4272c3960c2SGovind Singh ath11k_pci_ce_irq_disable(ab, i); 4282c3960c2SGovind Singh } 4292c3960c2SGovind Singh } 4302c3960c2SGovind Singh 4312c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) 4322c3960c2SGovind Singh { 4332c3960c2SGovind Singh int i; 4342c3960c2SGovind Singh int irq_idx; 4352c3960c2SGovind Singh 436*d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 437e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 4382c3960c2SGovind Singh continue; 4392c3960c2SGovind Singh 4402c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 4412c3960c2SGovind Singh synchronize_irq(ab->irq_num[irq_idx]); 4422c3960c2SGovind Singh } 4432c3960c2SGovind Singh } 4442c3960c2SGovind Singh 4452c3960c2SGovind Singh static void ath11k_pci_ce_tasklet(unsigned long data) 4462c3960c2SGovind Singh { 4472c3960c2SGovind Singh struct ath11k_ce_pipe *ce_pipe = (struct ath11k_ce_pipe *)data; 4482c3960c2SGovind Singh 4492c3960c2SGovind Singh ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); 4502c3960c2SGovind Singh 4512c3960c2SGovind Singh ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num); 4522c3960c2SGovind Singh } 4532c3960c2SGovind Singh 4547f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) 4557f4beda2SGovind Singh { 4567f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe = arg; 4577f4beda2SGovind Singh 4587f4beda2SGovind Singh ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num); 4592c3960c2SGovind Singh tasklet_schedule(&ce_pipe->intr_tq); 4607f4beda2SGovind Singh 4617f4beda2SGovind Singh return IRQ_HANDLED; 4627f4beda2SGovind Singh } 4637f4beda2SGovind Singh 4647f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab) 4657f4beda2SGovind Singh { 4667f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe; 4677f4beda2SGovind Singh u32 msi_data_start; 4687f4beda2SGovind Singh u32 msi_data_count; 4697f4beda2SGovind Singh u32 msi_irq_start; 4707f4beda2SGovind Singh unsigned int msi_data; 4717f4beda2SGovind Singh int irq, i, ret, irq_idx; 4727f4beda2SGovind Singh 4737f4beda2SGovind Singh ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), 4747f4beda2SGovind Singh "CE", &msi_data_count, 4757f4beda2SGovind Singh &msi_data_start, &msi_irq_start); 4767f4beda2SGovind Singh if (ret) 4777f4beda2SGovind Singh return ret; 4787f4beda2SGovind Singh 4797f4beda2SGovind Singh /* Configure CE irqs */ 480*d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 4817f4beda2SGovind Singh msi_data = (i % msi_data_count) + msi_irq_start; 4827f4beda2SGovind Singh irq = ath11k_pci_get_msi_irq(ab->dev, msi_data); 4837f4beda2SGovind Singh ce_pipe = &ab->ce.ce_pipe[i]; 4847f4beda2SGovind Singh 485e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 4867f4beda2SGovind Singh continue; 4877f4beda2SGovind Singh 4887f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 4897f4beda2SGovind Singh 4902c3960c2SGovind Singh tasklet_init(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet, 4912c3960c2SGovind Singh (unsigned long)ce_pipe); 4922c3960c2SGovind Singh 4937f4beda2SGovind Singh ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, 4947f4beda2SGovind Singh IRQF_SHARED, irq_name[irq_idx], 4957f4beda2SGovind Singh ce_pipe); 4967f4beda2SGovind Singh if (ret) { 4977f4beda2SGovind Singh ath11k_err(ab, "failed to request irq %d: %d\n", 4987f4beda2SGovind Singh irq_idx, ret); 4997f4beda2SGovind Singh return ret; 5007f4beda2SGovind Singh } 5017f4beda2SGovind Singh 5027f4beda2SGovind Singh ab->irq_num[irq_idx] = irq; 5037f4beda2SGovind Singh } 5047f4beda2SGovind Singh 5057f4beda2SGovind Singh return 0; 5067f4beda2SGovind Singh } 5077f4beda2SGovind Singh 5087f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) 5097f4beda2SGovind Singh { 5107f4beda2SGovind Singh struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; 5117f4beda2SGovind Singh 5127f4beda2SGovind Singh cfg->tgt_ce = target_ce_config_wlan; 5137f4beda2SGovind Singh cfg->tgt_ce_len = ARRAY_SIZE(target_ce_config_wlan); 5147f4beda2SGovind Singh 5157f4beda2SGovind Singh cfg->svc_to_ce_map = target_service_to_ce_map_wlan; 5167f4beda2SGovind Singh cfg->svc_to_ce_map_len = ARRAY_SIZE(target_service_to_ce_map_wlan); 517eb8de049SGovind Singh ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390; 5187f4beda2SGovind Singh } 5197f4beda2SGovind Singh 5207f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) 5217f4beda2SGovind Singh { 5227f4beda2SGovind Singh int i; 5237f4beda2SGovind Singh 524*d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 525e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5267f4beda2SGovind Singh continue; 5277f4beda2SGovind Singh ath11k_pci_ce_irq_enable(ab, i); 5287f4beda2SGovind Singh } 5297f4beda2SGovind Singh } 5307f4beda2SGovind Singh 5315697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci) 5325697a564SGovind Singh { 5335697a564SGovind Singh struct ath11k_base *ab = ab_pci->ab; 5345697a564SGovind Singh struct msi_desc *msi_desc; 5355697a564SGovind Singh int num_vectors; 5365697a564SGovind Singh int ret; 5375697a564SGovind Singh 5385697a564SGovind Singh num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 5395697a564SGovind Singh msi_config.total_vectors, 5405697a564SGovind Singh msi_config.total_vectors, 5415697a564SGovind Singh PCI_IRQ_MSI); 5425697a564SGovind Singh if (num_vectors != msi_config.total_vectors) { 5435697a564SGovind Singh ath11k_err(ab, "failed to get %d MSI vectors, only %d available", 5445697a564SGovind Singh msi_config.total_vectors, num_vectors); 5455697a564SGovind Singh 5465697a564SGovind Singh if (num_vectors >= 0) 5475697a564SGovind Singh return -EINVAL; 5485697a564SGovind Singh else 5495697a564SGovind Singh return num_vectors; 5505697a564SGovind Singh } 5515697a564SGovind Singh 5525697a564SGovind Singh msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 5535697a564SGovind Singh if (!msi_desc) { 5545697a564SGovind Singh ath11k_err(ab, "msi_desc is NULL!\n"); 5555697a564SGovind Singh ret = -EINVAL; 5565697a564SGovind Singh goto free_msi_vector; 5575697a564SGovind Singh } 5585697a564SGovind Singh 5595697a564SGovind Singh ab_pci->msi_ep_base_data = msi_desc->msg.data; 5605697a564SGovind Singh 5615697a564SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); 5625697a564SGovind Singh 5635697a564SGovind Singh return 0; 5645697a564SGovind Singh 5655697a564SGovind Singh free_msi_vector: 5665697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 5675697a564SGovind Singh 5685697a564SGovind Singh return ret; 5695697a564SGovind Singh } 5705697a564SGovind Singh 5715697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci) 5725697a564SGovind Singh { 5735697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 5745697a564SGovind Singh } 5755697a564SGovind Singh 5765762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) 5775762613eSGovind Singh { 5785762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 5795762613eSGovind Singh u16 device_id; 5805762613eSGovind Singh int ret = 0; 5815762613eSGovind Singh 5825762613eSGovind Singh pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 5835762613eSGovind Singh if (device_id != ab_pci->dev_id) { 5845762613eSGovind Singh ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", 5855762613eSGovind Singh device_id, ab_pci->dev_id); 5865762613eSGovind Singh ret = -EIO; 5875762613eSGovind Singh goto out; 5885762613eSGovind Singh } 5895762613eSGovind Singh 5905762613eSGovind Singh ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); 5915762613eSGovind Singh if (ret) { 5925762613eSGovind Singh ath11k_err(ab, "failed to assign pci resource: %d\n", ret); 5935762613eSGovind Singh goto out; 5945762613eSGovind Singh } 5955762613eSGovind Singh 5965762613eSGovind Singh ret = pci_enable_device(pdev); 5975762613eSGovind Singh if (ret) { 5985762613eSGovind Singh ath11k_err(ab, "failed to enable pci device: %d\n", ret); 5995762613eSGovind Singh goto out; 6005762613eSGovind Singh } 6015762613eSGovind Singh 6025762613eSGovind Singh ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); 6035762613eSGovind Singh if (ret) { 6045762613eSGovind Singh ath11k_err(ab, "failed to request pci region: %d\n", ret); 6055762613eSGovind Singh goto disable_device; 6065762613eSGovind Singh } 6075762613eSGovind Singh 6085762613eSGovind Singh ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 6095762613eSGovind Singh if (ret) { 6105762613eSGovind Singh ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", 6115762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 6125762613eSGovind Singh goto release_region; 6135762613eSGovind Singh } 6145762613eSGovind Singh 6155762613eSGovind Singh ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 6165762613eSGovind Singh if (ret) { 6175762613eSGovind Singh ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n", 6185762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 6195762613eSGovind Singh goto release_region; 6205762613eSGovind Singh } 6215762613eSGovind Singh 6225762613eSGovind Singh pci_set_master(pdev); 6235762613eSGovind Singh 6245762613eSGovind Singh ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); 6255762613eSGovind Singh ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); 6265762613eSGovind Singh if (!ab->mem) { 6275762613eSGovind Singh ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); 6285762613eSGovind Singh ret = -EIO; 6295762613eSGovind Singh goto clear_master; 6305762613eSGovind Singh } 6315762613eSGovind Singh 6325762613eSGovind Singh ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); 6335762613eSGovind Singh return 0; 6345762613eSGovind Singh 6355762613eSGovind Singh clear_master: 6365762613eSGovind Singh pci_clear_master(pdev); 6375762613eSGovind Singh release_region: 6385762613eSGovind Singh pci_release_region(pdev, ATH11K_PCI_BAR_NUM); 6395762613eSGovind Singh disable_device: 6405762613eSGovind Singh pci_disable_device(pdev); 6415762613eSGovind Singh out: 6425762613eSGovind Singh return ret; 6435762613eSGovind Singh } 6445762613eSGovind Singh 6455762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) 6465762613eSGovind Singh { 6475762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 6485762613eSGovind Singh struct pci_dev *pci_dev = ab_pci->pdev; 6495762613eSGovind Singh 6505762613eSGovind Singh pci_iounmap(pci_dev, ab->mem); 6515762613eSGovind Singh ab->mem = NULL; 6525762613eSGovind Singh pci_clear_master(pci_dev); 6535762613eSGovind Singh pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); 6545762613eSGovind Singh if (pci_is_enabled(pci_dev)) 6555762613eSGovind Singh pci_disable_device(pci_dev); 6565762613eSGovind Singh } 6575762613eSGovind Singh 6581399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab) 6591399fb87SGovind Singh { 6601399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 6611399fb87SGovind Singh int ret; 6621399fb87SGovind Singh 6631399fb87SGovind Singh ret = ath11k_mhi_start(ab_pci); 6641399fb87SGovind Singh if (ret) { 6651399fb87SGovind Singh ath11k_err(ab, "failed to start mhi: %d\n", ret); 6661399fb87SGovind Singh return ret; 6671399fb87SGovind Singh } 6681399fb87SGovind Singh 6691399fb87SGovind Singh return 0; 6701399fb87SGovind Singh } 6711399fb87SGovind Singh 6721399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab) 6731399fb87SGovind Singh { 6741399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 6751399fb87SGovind Singh 6761399fb87SGovind Singh ath11k_mhi_stop(ab_pci); 6771399fb87SGovind Singh } 6781399fb87SGovind Singh 6792c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) 6802c3960c2SGovind Singh { 6812c3960c2SGovind Singh int i; 6822c3960c2SGovind Singh 683*d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 6842c3960c2SGovind Singh struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; 6852c3960c2SGovind Singh 686e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 6872c3960c2SGovind Singh continue; 6882c3960c2SGovind Singh 6892c3960c2SGovind Singh tasklet_kill(&ce_pipe->intr_tq); 6902c3960c2SGovind Singh } 6912c3960c2SGovind Singh } 6922c3960c2SGovind Singh 6937f4beda2SGovind Singh static void ath11k_pci_stop(struct ath11k_base *ab) 6947f4beda2SGovind Singh { 6952c3960c2SGovind Singh ath11k_pci_ce_irqs_disable(ab); 6962c3960c2SGovind Singh ath11k_pci_sync_ce_irqs(ab); 6972c3960c2SGovind Singh ath11k_pci_kill_tasklets(ab); 6987f4beda2SGovind Singh ath11k_ce_cleanup_pipes(ab); 6997f4beda2SGovind Singh } 7007f4beda2SGovind Singh 7017f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab) 7027f4beda2SGovind Singh { 7037f4beda2SGovind Singh ath11k_pci_ce_irqs_enable(ab); 7042c3960c2SGovind Singh ath11k_ce_rx_post_buf(ab); 7052c3960c2SGovind Singh 7062c3960c2SGovind Singh return 0; 7072c3960c2SGovind Singh } 7082c3960c2SGovind Singh 7092c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, 7102c3960c2SGovind Singh u8 *ul_pipe, u8 *dl_pipe) 7112c3960c2SGovind Singh { 7122c3960c2SGovind Singh const struct service_to_pipe *entry; 7132c3960c2SGovind Singh bool ul_set = false, dl_set = false; 7142c3960c2SGovind Singh int i; 7152c3960c2SGovind Singh 7162c3960c2SGovind Singh for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) { 7172c3960c2SGovind Singh entry = &target_service_to_ce_map_wlan[i]; 7182c3960c2SGovind Singh 7192c3960c2SGovind Singh if (__le32_to_cpu(entry->service_id) != service_id) 7202c3960c2SGovind Singh continue; 7212c3960c2SGovind Singh 7222c3960c2SGovind Singh switch (__le32_to_cpu(entry->pipedir)) { 7232c3960c2SGovind Singh case PIPEDIR_NONE: 7242c3960c2SGovind Singh break; 7252c3960c2SGovind Singh case PIPEDIR_IN: 7262c3960c2SGovind Singh WARN_ON(dl_set); 7272c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 7282c3960c2SGovind Singh dl_set = true; 7292c3960c2SGovind Singh break; 7302c3960c2SGovind Singh case PIPEDIR_OUT: 7312c3960c2SGovind Singh WARN_ON(ul_set); 7322c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 7332c3960c2SGovind Singh ul_set = true; 7342c3960c2SGovind Singh break; 7352c3960c2SGovind Singh case PIPEDIR_INOUT: 7362c3960c2SGovind Singh WARN_ON(dl_set); 7372c3960c2SGovind Singh WARN_ON(ul_set); 7382c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 7392c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 7402c3960c2SGovind Singh dl_set = true; 7412c3960c2SGovind Singh ul_set = true; 7422c3960c2SGovind Singh break; 7432c3960c2SGovind Singh } 7442c3960c2SGovind Singh } 7452c3960c2SGovind Singh 7462c3960c2SGovind Singh if (WARN_ON(!ul_set || !dl_set)) 7472c3960c2SGovind Singh return -ENOENT; 7487f4beda2SGovind Singh 7497f4beda2SGovind Singh return 0; 7507f4beda2SGovind Singh } 7517f4beda2SGovind Singh 7527f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = { 7537f4beda2SGovind Singh .start = ath11k_pci_start, 7547f4beda2SGovind Singh .stop = ath11k_pci_stop, 755654e959aSGovind Singh .read32 = ath11k_pci_read32, 756654e959aSGovind Singh .write32 = ath11k_pci_write32, 7571399fb87SGovind Singh .power_down = ath11k_pci_power_down, 7581399fb87SGovind Singh .power_up = ath11k_pci_power_up, 759c4eacabeSGovind Singh .get_msi_address = ath11k_pci_get_msi_address, 760c4eacabeSGovind Singh .get_user_msi_vector = ath11k_get_user_msi_assignment, 7612c3960c2SGovind Singh .map_service_to_pipe = ath11k_pci_map_service_to_pipe, 7621399fb87SGovind Singh }; 7631399fb87SGovind Singh 7646e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev, 7656e0355afSGovind Singh const struct pci_device_id *pci_dev) 7666e0355afSGovind Singh { 7676e0355afSGovind Singh struct ath11k_base *ab; 7685762613eSGovind Singh struct ath11k_pci *ab_pci; 7696e0355afSGovind Singh enum ath11k_hw_rev hw_rev; 7705762613eSGovind Singh int ret; 7716e0355afSGovind Singh 7726e0355afSGovind Singh dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n"); 7736e0355afSGovind Singh 7746e0355afSGovind Singh switch (pci_dev->device) { 7756e0355afSGovind Singh case QCA6390_DEVICE_ID: 7766e0355afSGovind Singh hw_rev = ATH11K_HW_QCA6390_HW20; 7776e0355afSGovind Singh break; 7786e0355afSGovind Singh default: 7796e0355afSGovind Singh dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", 7806e0355afSGovind Singh pci_dev->device); 7816e0355afSGovind Singh return -ENOTSUPP; 7826e0355afSGovind Singh } 7836e0355afSGovind Singh 7841ff8ed78SGovind Singh ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, 7851ff8ed78SGovind Singh &ath11k_pci_bus_params); 7866e0355afSGovind Singh if (!ab) { 7876e0355afSGovind Singh dev_err(&pdev->dev, "failed to allocate ath11k base\n"); 7886e0355afSGovind Singh return -ENOMEM; 7896e0355afSGovind Singh } 7906e0355afSGovind Singh 7916e0355afSGovind Singh ab->dev = &pdev->dev; 7926e0355afSGovind Singh ab->hw_rev = hw_rev; 7936e0355afSGovind Singh pci_set_drvdata(pdev, ab); 7945762613eSGovind Singh ab_pci = ath11k_pci_priv(ab); 7955762613eSGovind Singh ab_pci->dev_id = pci_dev->device; 7965762613eSGovind Singh ab_pci->ab = ab; 7975697a564SGovind Singh ab_pci->pdev = pdev; 7987f4beda2SGovind Singh ab->hif.ops = &ath11k_pci_hif_ops; 7995762613eSGovind Singh pci_set_drvdata(pdev, ab); 800654e959aSGovind Singh spin_lock_init(&ab_pci->window_lock); 8015762613eSGovind Singh 8025762613eSGovind Singh ret = ath11k_pci_claim(ab_pci, pdev); 8035762613eSGovind Singh if (ret) { 8045762613eSGovind Singh ath11k_err(ab, "failed to claim device: %d\n", ret); 8055762613eSGovind Singh goto err_free_core; 8065762613eSGovind Singh } 8076e0355afSGovind Singh 8085697a564SGovind Singh ret = ath11k_pci_enable_msi(ab_pci); 8095697a564SGovind Singh if (ret) { 8105697a564SGovind Singh ath11k_err(ab, "failed to enable msi: %d\n", ret); 8115697a564SGovind Singh goto err_pci_free_region; 8125697a564SGovind Singh } 8135697a564SGovind Singh 814b8246f88SKalle Valo ret = ath11k_core_pre_init(ab); 815b8246f88SKalle Valo if (ret) 816b8246f88SKalle Valo goto err_pci_disable_msi; 817b8246f88SKalle Valo 8181399fb87SGovind Singh ret = ath11k_mhi_register(ab_pci); 8191399fb87SGovind Singh if (ret) { 8201399fb87SGovind Singh ath11k_err(ab, "failed to register mhi: %d\n", ret); 8211399fb87SGovind Singh goto err_pci_disable_msi; 8221399fb87SGovind Singh } 8231399fb87SGovind Singh 8247f4beda2SGovind Singh ret = ath11k_hal_srng_init(ab); 8257f4beda2SGovind Singh if (ret) 8267f4beda2SGovind Singh goto err_mhi_unregister; 8277f4beda2SGovind Singh 8287f4beda2SGovind Singh ret = ath11k_ce_alloc_pipes(ab); 8297f4beda2SGovind Singh if (ret) { 8307f4beda2SGovind Singh ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret); 8317f4beda2SGovind Singh goto err_hal_srng_deinit; 8327f4beda2SGovind Singh } 8337f4beda2SGovind Singh 8347f4beda2SGovind Singh ath11k_pci_init_qmi_ce_config(ab); 8357f4beda2SGovind Singh 8367f4beda2SGovind Singh ret = ath11k_pci_config_irq(ab); 8377f4beda2SGovind Singh if (ret) { 8387f4beda2SGovind Singh ath11k_err(ab, "failed to config irq: %d\n", ret); 8397f4beda2SGovind Singh goto err_ce_free; 8407f4beda2SGovind Singh } 8417f4beda2SGovind Singh 8427f4beda2SGovind Singh ret = ath11k_core_init(ab); 8437f4beda2SGovind Singh if (ret) { 8447f4beda2SGovind Singh ath11k_err(ab, "failed to init core: %d\n", ret); 8457f4beda2SGovind Singh goto err_free_irq; 8467f4beda2SGovind Singh } 8476e0355afSGovind Singh return 0; 8485762613eSGovind Singh 8497f4beda2SGovind Singh err_free_irq: 8507f4beda2SGovind Singh ath11k_pci_free_irq(ab); 8517f4beda2SGovind Singh 8527f4beda2SGovind Singh err_ce_free: 8537f4beda2SGovind Singh ath11k_ce_free_pipes(ab); 8547f4beda2SGovind Singh 8557f4beda2SGovind Singh err_hal_srng_deinit: 8567f4beda2SGovind Singh ath11k_hal_srng_deinit(ab); 8577f4beda2SGovind Singh 8587f4beda2SGovind Singh err_mhi_unregister: 8597f4beda2SGovind Singh ath11k_mhi_unregister(ab_pci); 8607f4beda2SGovind Singh 861b8246f88SKalle Valo err_pci_disable_msi: 862b8246f88SKalle Valo ath11k_pci_disable_msi(ab_pci); 863b8246f88SKalle Valo 8645697a564SGovind Singh err_pci_free_region: 8655697a564SGovind Singh ath11k_pci_free_region(ab_pci); 8665697a564SGovind Singh 8675762613eSGovind Singh err_free_core: 8685762613eSGovind Singh ath11k_core_free(ab); 8695697a564SGovind Singh 8705762613eSGovind Singh return ret; 8716e0355afSGovind Singh } 8726e0355afSGovind Singh 8736e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev) 8746e0355afSGovind Singh { 8756e0355afSGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 8765762613eSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 8776e0355afSGovind Singh 8786e0355afSGovind Singh set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); 8791399fb87SGovind Singh ath11k_mhi_unregister(ab_pci); 8805697a564SGovind Singh ath11k_pci_disable_msi(ab_pci); 8815762613eSGovind Singh ath11k_pci_free_region(ab_pci); 8827f4beda2SGovind Singh ath11k_pci_free_irq(ab); 8836e0355afSGovind Singh ath11k_core_free(ab); 8846e0355afSGovind Singh } 8856e0355afSGovind Singh 8861399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev) 8871399fb87SGovind Singh { 8881399fb87SGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 8891399fb87SGovind Singh 8901399fb87SGovind Singh ath11k_pci_power_down(ab); 8911399fb87SGovind Singh } 8921399fb87SGovind Singh 8936e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = { 8946e0355afSGovind Singh .name = "ath11k_pci", 8956e0355afSGovind Singh .id_table = ath11k_pci_id_table, 8966e0355afSGovind Singh .probe = ath11k_pci_probe, 8976e0355afSGovind Singh .remove = ath11k_pci_remove, 8981399fb87SGovind Singh .shutdown = ath11k_pci_shutdown, 8996e0355afSGovind Singh }; 9006e0355afSGovind Singh 9016e0355afSGovind Singh static int ath11k_pci_init(void) 9026e0355afSGovind Singh { 9036e0355afSGovind Singh int ret; 9046e0355afSGovind Singh 9056e0355afSGovind Singh ret = pci_register_driver(&ath11k_pci_driver); 9066e0355afSGovind Singh if (ret) 9076e0355afSGovind Singh pr_err("failed to register ath11k pci driver: %d\n", 9086e0355afSGovind Singh ret); 9096e0355afSGovind Singh 9106e0355afSGovind Singh return ret; 9116e0355afSGovind Singh } 9126e0355afSGovind Singh module_init(ath11k_pci_init); 9136e0355afSGovind Singh 9146e0355afSGovind Singh static void ath11k_pci_exit(void) 9156e0355afSGovind Singh { 9166e0355afSGovind Singh pci_unregister_driver(&ath11k_pci_driver); 9176e0355afSGovind Singh } 9186e0355afSGovind Singh 9196e0355afSGovind Singh module_exit(ath11k_pci_exit); 9206e0355afSGovind Singh 9216e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); 9226e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL"); 923