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 2718ac1665SKalle Valo #define TCSR_SOC_HW_VERSION 0x0224 2818ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(16, 8) 2918ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0) 3018ac1665SKalle Valo 31a05bd851SCarl Huang /* BAR0 + 4k is always accessible, and no 32a05bd851SCarl Huang * need to force wakeup. 33a05bd851SCarl Huang * 4K - 32 = 0xFE0 34a05bd851SCarl Huang */ 35a05bd851SCarl Huang #define ACCESS_ALWAYS_OFF 0xFE0 36a05bd851SCarl Huang 376e0355afSGovind Singh #define QCA6390_DEVICE_ID 0x1101 386e0355afSGovind Singh 396e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = { 406e0355afSGovind Singh { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, 416e0355afSGovind Singh {0} 426e0355afSGovind Singh }; 436e0355afSGovind Singh 446e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); 456e0355afSGovind Singh 461ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = { 471ff8ed78SGovind Singh .mhi_support = true, 4856970454SGovind Singh .m3_fw_support = true, 496eb6ea51SGovind Singh .fixed_bdf_addr = false, 506eb6ea51SGovind Singh .fixed_mem_region = false, 511ff8ed78SGovind Singh }; 521ff8ed78SGovind Singh 535697a564SGovind Singh static const struct ath11k_msi_config msi_config = { 545697a564SGovind Singh .total_vectors = 32, 555697a564SGovind Singh .total_users = 4, 565697a564SGovind Singh .users = (struct ath11k_msi_user[]) { 575697a564SGovind Singh { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 585697a564SGovind Singh { .name = "CE", .num_vectors = 10, .base_vector = 3 }, 595697a564SGovind Singh { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, 605697a564SGovind Singh { .name = "DP", .num_vectors = 18, .base_vector = 14 }, 615697a564SGovind Singh }, 625697a564SGovind Singh }; 635697a564SGovind Singh 647f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { 657f4beda2SGovind Singh "bhi", 667f4beda2SGovind Singh "mhi-er0", 677f4beda2SGovind Singh "mhi-er1", 687f4beda2SGovind Singh "ce0", 697f4beda2SGovind Singh "ce1", 707f4beda2SGovind Singh "ce2", 717f4beda2SGovind Singh "ce3", 727f4beda2SGovind Singh "ce4", 737f4beda2SGovind Singh "ce5", 747f4beda2SGovind Singh "ce6", 757f4beda2SGovind Singh "ce7", 767f4beda2SGovind Singh "ce8", 777f4beda2SGovind Singh "ce9", 787f4beda2SGovind Singh "ce10", 797f4beda2SGovind Singh "ce11", 807f4beda2SGovind Singh "host2wbm-desc-feed", 817f4beda2SGovind Singh "host2reo-re-injection", 827f4beda2SGovind Singh "host2reo-command", 837f4beda2SGovind Singh "host2rxdma-monitor-ring3", 847f4beda2SGovind Singh "host2rxdma-monitor-ring2", 857f4beda2SGovind Singh "host2rxdma-monitor-ring1", 867f4beda2SGovind Singh "reo2ost-exception", 877f4beda2SGovind Singh "wbm2host-rx-release", 887f4beda2SGovind Singh "reo2host-status", 897f4beda2SGovind Singh "reo2host-destination-ring4", 907f4beda2SGovind Singh "reo2host-destination-ring3", 917f4beda2SGovind Singh "reo2host-destination-ring2", 927f4beda2SGovind Singh "reo2host-destination-ring1", 937f4beda2SGovind Singh "rxdma2host-monitor-destination-mac3", 947f4beda2SGovind Singh "rxdma2host-monitor-destination-mac2", 957f4beda2SGovind Singh "rxdma2host-monitor-destination-mac1", 967f4beda2SGovind Singh "ppdu-end-interrupts-mac3", 977f4beda2SGovind Singh "ppdu-end-interrupts-mac2", 987f4beda2SGovind Singh "ppdu-end-interrupts-mac1", 997f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac3", 1007f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac2", 1017f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac1", 1027f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac3", 1037f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac2", 1047f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac1", 1057f4beda2SGovind Singh "rxdma2host-destination-ring-mac3", 1067f4beda2SGovind Singh "rxdma2host-destination-ring-mac2", 1077f4beda2SGovind Singh "rxdma2host-destination-ring-mac1", 1087f4beda2SGovind Singh "host2tcl-input-ring4", 1097f4beda2SGovind Singh "host2tcl-input-ring3", 1107f4beda2SGovind Singh "host2tcl-input-ring2", 1117f4beda2SGovind Singh "host2tcl-input-ring1", 1127f4beda2SGovind Singh "wbm2host-tx-completions-ring3", 1137f4beda2SGovind Singh "wbm2host-tx-completions-ring2", 1147f4beda2SGovind Singh "wbm2host-tx-completions-ring1", 1157f4beda2SGovind Singh "tcl2host-status-ring", 1167f4beda2SGovind Singh }; 1177f4beda2SGovind Singh 118654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset) 119654e959aSGovind Singh { 120654e959aSGovind Singh struct ath11k_base *ab = ab_pci->ab; 121654e959aSGovind Singh 122654e959aSGovind Singh u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset); 123654e959aSGovind Singh 124654e959aSGovind Singh lockdep_assert_held(&ab_pci->window_lock); 125654e959aSGovind Singh 126654e959aSGovind Singh if (window != ab_pci->register_window) { 127654e959aSGovind Singh iowrite32(WINDOW_ENABLE_BIT | window, 128654e959aSGovind Singh ab->mem + WINDOW_REG_ADDRESS); 129654e959aSGovind Singh ab_pci->register_window = window; 130654e959aSGovind Singh } 131654e959aSGovind Singh } 132654e959aSGovind Singh 133f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) 134654e959aSGovind Singh { 135654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 136654e959aSGovind Singh 137a05bd851SCarl Huang /* for offset beyond BAR + 4K - 32, may 138a05bd851SCarl Huang * need to wakeup MHI to access. 139a05bd851SCarl Huang */ 140a05bd851SCarl Huang if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 141a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 142a05bd851SCarl Huang mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); 143a05bd851SCarl Huang 144654e959aSGovind Singh if (offset < WINDOW_START) { 145654e959aSGovind Singh iowrite32(value, ab->mem + offset); 146654e959aSGovind Singh } else { 147654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 148654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 149654e959aSGovind Singh iowrite32(value, ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK)); 150654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 151654e959aSGovind Singh } 152a05bd851SCarl Huang 153a05bd851SCarl Huang if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 154a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 155a05bd851SCarl Huang mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); 156654e959aSGovind Singh } 157654e959aSGovind Singh 158f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) 159654e959aSGovind Singh { 160654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 161654e959aSGovind Singh u32 val; 162654e959aSGovind Singh 163a05bd851SCarl Huang /* for offset beyond BAR + 4K - 32, may 164a05bd851SCarl Huang * need to wakeup MHI to access. 165a05bd851SCarl Huang */ 166a05bd851SCarl Huang if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 167a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 168a05bd851SCarl Huang mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); 169a05bd851SCarl Huang 170654e959aSGovind Singh if (offset < WINDOW_START) { 171654e959aSGovind Singh val = ioread32(ab->mem + offset); 172654e959aSGovind Singh } else { 173654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 174654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 175654e959aSGovind Singh val = ioread32(ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK)); 176654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 177654e959aSGovind Singh } 178654e959aSGovind Singh 179a05bd851SCarl Huang if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 180a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 181a05bd851SCarl Huang mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); 182a05bd851SCarl Huang 183654e959aSGovind Singh return val; 184654e959aSGovind Singh } 185654e959aSGovind Singh 186f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) 187f3c603d4SCarl Huang { 188f3c603d4SCarl Huang u32 val, delay; 189f3c603d4SCarl Huang 190f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 191f3c603d4SCarl Huang 192f3c603d4SCarl Huang val |= PCIE_SOC_GLOBAL_RESET_V; 193f3c603d4SCarl Huang 194f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 195f3c603d4SCarl Huang 196f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 197f3c603d4SCarl Huang delay = 10; 198f3c603d4SCarl Huang mdelay(delay); 199f3c603d4SCarl Huang 200f3c603d4SCarl Huang /* Need to toggle V bit back otherwise stuck in reset status */ 201f3c603d4SCarl Huang val &= ~PCIE_SOC_GLOBAL_RESET_V; 202f3c603d4SCarl Huang 203f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 204f3c603d4SCarl Huang 205f3c603d4SCarl Huang mdelay(delay); 206f3c603d4SCarl Huang 207f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 208f3c603d4SCarl Huang if (val == 0xffffffff) 209f3c603d4SCarl Huang ath11k_warn(ab, "link down error during global reset\n"); 210f3c603d4SCarl Huang } 211f3c603d4SCarl Huang 212f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) 213f3c603d4SCarl Huang { 214f3c603d4SCarl Huang u32 val; 215f3c603d4SCarl Huang 216f3c603d4SCarl Huang /* read cookie */ 217f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR); 218f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val); 219f3c603d4SCarl Huang 220f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 221f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 222f3c603d4SCarl Huang 223f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 224f3c603d4SCarl Huang mdelay(10); 225f3c603d4SCarl Huang 226f3c603d4SCarl Huang /* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from 227f3c603d4SCarl Huang * continuing warm path and entering dead loop. 228f3c603d4SCarl Huang */ 229f3c603d4SCarl Huang ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0); 230f3c603d4SCarl Huang mdelay(10); 231f3c603d4SCarl Huang 232f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 233f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 234f3c603d4SCarl Huang 235f3c603d4SCarl Huang /* A read clear register. clear the register to prevent 236f3c603d4SCarl Huang * Q6 from entering wrong code path. 237f3c603d4SCarl Huang */ 238f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG); 239f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val); 240f3c603d4SCarl Huang } 241f3c603d4SCarl Huang 242f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab) 243f3c603d4SCarl Huang { 244f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1); 245f3c603d4SCarl Huang mdelay(5); 246f3c603d4SCarl Huang } 247f3c603d4SCarl Huang 248f3c603d4SCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab) 249f3c603d4SCarl Huang { 250f3c603d4SCarl Huang ath11k_pci_soc_global_reset(ab); 251f3c603d4SCarl Huang ath11k_mhi_clear_vector(ab); 252f3c603d4SCarl Huang ath11k_pci_soc_global_reset(ab); 253f3c603d4SCarl Huang ath11k_mhi_set_mhictrl_reset(ab); 254f3c603d4SCarl Huang ath11k_pci_clear_dbg_registers(ab); 255f3c603d4SCarl Huang } 256f3c603d4SCarl Huang 2571399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) 2581399fb87SGovind Singh { 2591399fb87SGovind Singh struct pci_dev *pci_dev = to_pci_dev(dev); 2601399fb87SGovind Singh 2611399fb87SGovind Singh return pci_irq_vector(pci_dev, vector); 2621399fb87SGovind Singh } 2631399fb87SGovind Singh 264c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, 265c4eacabeSGovind Singh u32 *msi_addr_hi) 266c4eacabeSGovind Singh { 267e8e55d89SAnilkumar Kolli struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 268c4eacabeSGovind Singh struct pci_dev *pci_dev = to_pci_dev(ab->dev); 269c4eacabeSGovind Singh 270c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, 271c4eacabeSGovind Singh msi_addr_lo); 272c4eacabeSGovind Singh 273e8e55d89SAnilkumar Kolli if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) { 274c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, 275c4eacabeSGovind Singh msi_addr_hi); 276e8e55d89SAnilkumar Kolli } else { 277e8e55d89SAnilkumar Kolli *msi_addr_hi = 0; 278e8e55d89SAnilkumar Kolli } 279c4eacabeSGovind Singh } 280c4eacabeSGovind Singh 2811399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, 2821399fb87SGovind Singh int *num_vectors, u32 *user_base_data, 2831399fb87SGovind Singh u32 *base_vector) 2841399fb87SGovind Singh { 2851399fb87SGovind Singh struct ath11k_base *ab = ab_pci->ab; 2861399fb87SGovind Singh int idx; 2871399fb87SGovind Singh 2881399fb87SGovind Singh for (idx = 0; idx < msi_config.total_users; idx++) { 2891399fb87SGovind Singh if (strcmp(user_name, msi_config.users[idx].name) == 0) { 2901399fb87SGovind Singh *num_vectors = msi_config.users[idx].num_vectors; 2911399fb87SGovind Singh *user_base_data = msi_config.users[idx].base_vector 2921399fb87SGovind Singh + ab_pci->msi_ep_base_data; 2931399fb87SGovind Singh *base_vector = msi_config.users[idx].base_vector; 2941399fb87SGovind Singh 2951399fb87SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", 2961399fb87SGovind Singh user_name, *num_vectors, *user_base_data, 2971399fb87SGovind Singh *base_vector); 2981399fb87SGovind Singh 2991399fb87SGovind Singh return 0; 3001399fb87SGovind Singh } 3011399fb87SGovind Singh } 3021399fb87SGovind Singh 3031399fb87SGovind Singh ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name); 3041399fb87SGovind Singh 3051399fb87SGovind Singh return -EINVAL; 3061399fb87SGovind Singh } 3071399fb87SGovind Singh 308c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, 309c4eacabeSGovind Singh int *num_vectors, u32 *user_base_data, 310c4eacabeSGovind Singh u32 *base_vector) 311c4eacabeSGovind Singh { 312c4eacabeSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 313c4eacabeSGovind Singh 314c4eacabeSGovind Singh return ath11k_pci_get_user_msi_assignment(ab_pci, user_name, 315c4eacabeSGovind Singh num_vectors, user_base_data, 316c4eacabeSGovind Singh base_vector); 317c4eacabeSGovind Singh } 318c4eacabeSGovind Singh 319d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab) 320d4ecb90bSCarl Huang { 321d4ecb90bSCarl Huang int i, j; 322d4ecb90bSCarl Huang 323d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 324d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 325d4ecb90bSCarl Huang 326d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) 327d4ecb90bSCarl Huang free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); 328d4ecb90bSCarl Huang 329d4ecb90bSCarl Huang netif_napi_del(&irq_grp->napi); 330d4ecb90bSCarl Huang } 331d4ecb90bSCarl Huang } 332d4ecb90bSCarl Huang 3337f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab) 3347f4beda2SGovind Singh { 3357f4beda2SGovind Singh int i, irq_idx; 3367f4beda2SGovind Singh 337d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 338e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 3397f4beda2SGovind Singh continue; 3407f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 3417f4beda2SGovind Singh free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); 3427f4beda2SGovind Singh } 343d4ecb90bSCarl Huang 344d4ecb90bSCarl Huang ath11k_pci_free_ext_irq(ab); 3457f4beda2SGovind Singh } 3467f4beda2SGovind Singh 3472c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) 3482c3960c2SGovind Singh { 3492c3960c2SGovind Singh u32 irq_idx; 3502c3960c2SGovind Singh 3512c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 3522c3960c2SGovind Singh enable_irq(ab->irq_num[irq_idx]); 3532c3960c2SGovind Singh } 3542c3960c2SGovind Singh 3557f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) 3567f4beda2SGovind Singh { 3577f4beda2SGovind Singh u32 irq_idx; 3587f4beda2SGovind Singh 3597f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 3607f4beda2SGovind Singh disable_irq_nosync(ab->irq_num[irq_idx]); 3617f4beda2SGovind Singh } 3627f4beda2SGovind Singh 3632c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab) 3642c3960c2SGovind Singh { 3652c3960c2SGovind Singh int i; 3662c3960c2SGovind Singh 367d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 368e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 3692c3960c2SGovind Singh continue; 3702c3960c2SGovind Singh ath11k_pci_ce_irq_disable(ab, i); 3712c3960c2SGovind Singh } 3722c3960c2SGovind Singh } 3732c3960c2SGovind Singh 3742c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) 3752c3960c2SGovind Singh { 3762c3960c2SGovind Singh int i; 3772c3960c2SGovind Singh int irq_idx; 3782c3960c2SGovind Singh 379d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 380e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 3812c3960c2SGovind Singh continue; 3822c3960c2SGovind Singh 3832c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 3842c3960c2SGovind Singh synchronize_irq(ab->irq_num[irq_idx]); 3852c3960c2SGovind Singh } 3862c3960c2SGovind Singh } 3872c3960c2SGovind Singh 3880f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t) 3892c3960c2SGovind Singh { 3900f01dcb8SAllen Pais struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); 3912c3960c2SGovind Singh 3922c3960c2SGovind Singh ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); 3932c3960c2SGovind Singh 3942c3960c2SGovind Singh ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num); 3952c3960c2SGovind Singh } 3962c3960c2SGovind Singh 3977f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) 3987f4beda2SGovind Singh { 3997f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe = arg; 4007f4beda2SGovind Singh 4017f4beda2SGovind Singh ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num); 4022c3960c2SGovind Singh tasklet_schedule(&ce_pipe->intr_tq); 4037f4beda2SGovind Singh 4047f4beda2SGovind Singh return IRQ_HANDLED; 4057f4beda2SGovind Singh } 4067f4beda2SGovind Singh 407d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) 408d4ecb90bSCarl Huang { 409d4ecb90bSCarl Huang int i; 410d4ecb90bSCarl Huang 411d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 412d4ecb90bSCarl Huang disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 413d4ecb90bSCarl Huang } 414d4ecb90bSCarl Huang 415d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc) 416d4ecb90bSCarl Huang { 417d4ecb90bSCarl Huang int i; 418d4ecb90bSCarl Huang 419d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 420d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; 421d4ecb90bSCarl Huang 422d4ecb90bSCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 423d4ecb90bSCarl Huang 424d4ecb90bSCarl Huang napi_synchronize(&irq_grp->napi); 425d4ecb90bSCarl Huang napi_disable(&irq_grp->napi); 426d4ecb90bSCarl Huang } 427d4ecb90bSCarl Huang } 428d4ecb90bSCarl Huang 429d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) 430d4ecb90bSCarl Huang { 431d4ecb90bSCarl Huang int i; 432d4ecb90bSCarl Huang 433d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 434d4ecb90bSCarl Huang enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 435d4ecb90bSCarl Huang } 436d4ecb90bSCarl Huang 437d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab) 438d4ecb90bSCarl Huang { 439d4ecb90bSCarl Huang int i; 440d4ecb90bSCarl Huang 441d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 442d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 443d4ecb90bSCarl Huang 444d4ecb90bSCarl Huang napi_enable(&irq_grp->napi); 445d4ecb90bSCarl Huang ath11k_pci_ext_grp_enable(irq_grp); 446d4ecb90bSCarl Huang } 447d4ecb90bSCarl Huang } 448d4ecb90bSCarl Huang 449d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab) 450d4ecb90bSCarl Huang { 451d4ecb90bSCarl Huang int i, j, irq_idx; 452d4ecb90bSCarl Huang 453d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 454d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 455d4ecb90bSCarl Huang 456d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 457d4ecb90bSCarl Huang irq_idx = irq_grp->irqs[j]; 458d4ecb90bSCarl Huang synchronize_irq(ab->irq_num[irq_idx]); 459d4ecb90bSCarl Huang } 460d4ecb90bSCarl Huang } 461d4ecb90bSCarl Huang } 462d4ecb90bSCarl Huang 463d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab) 464d4ecb90bSCarl Huang { 465d4ecb90bSCarl Huang __ath11k_pci_ext_irq_disable(ab); 466d4ecb90bSCarl Huang ath11k_pci_sync_ext_irqs(ab); 467d4ecb90bSCarl Huang } 468d4ecb90bSCarl Huang 469d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) 470d4ecb90bSCarl Huang { 471d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = container_of(napi, 472d4ecb90bSCarl Huang struct ath11k_ext_irq_grp, 473d4ecb90bSCarl Huang napi); 474d4ecb90bSCarl Huang struct ath11k_base *ab = irq_grp->ab; 475d4ecb90bSCarl Huang int work_done; 476d4ecb90bSCarl Huang 477d4ecb90bSCarl Huang work_done = ath11k_dp_service_srng(ab, irq_grp, budget); 478d4ecb90bSCarl Huang if (work_done < budget) { 479d4ecb90bSCarl Huang napi_complete_done(napi, work_done); 480d4ecb90bSCarl Huang ath11k_pci_ext_grp_enable(irq_grp); 481d4ecb90bSCarl Huang } 482d4ecb90bSCarl Huang 483d4ecb90bSCarl Huang if (work_done > budget) 484d4ecb90bSCarl Huang work_done = budget; 485d4ecb90bSCarl Huang 486d4ecb90bSCarl Huang return work_done; 487d4ecb90bSCarl Huang } 488d4ecb90bSCarl Huang 489d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) 490d4ecb90bSCarl Huang { 491d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = arg; 492d4ecb90bSCarl Huang 493d4ecb90bSCarl Huang ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); 494d4ecb90bSCarl Huang 495d4ecb90bSCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 496d4ecb90bSCarl Huang 497d4ecb90bSCarl Huang napi_schedule(&irq_grp->napi); 498d4ecb90bSCarl Huang 499d4ecb90bSCarl Huang return IRQ_HANDLED; 500d4ecb90bSCarl Huang } 501d4ecb90bSCarl Huang 502d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) 503d4ecb90bSCarl Huang { 504d4ecb90bSCarl Huang int i, j, ret, num_vectors = 0; 505d4ecb90bSCarl Huang u32 user_base_data = 0, base_vector = 0; 506d4ecb90bSCarl Huang 507b2c09458SColin Ian King ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", 508b2c09458SColin Ian King &num_vectors, 509b2c09458SColin Ian King &user_base_data, 510d4ecb90bSCarl Huang &base_vector); 511b2c09458SColin Ian King if (ret < 0) 512b2c09458SColin Ian King return ret; 513d4ecb90bSCarl Huang 514d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 515d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 516d4ecb90bSCarl Huang u32 num_irq = 0; 517d4ecb90bSCarl Huang 518d4ecb90bSCarl Huang irq_grp->ab = ab; 519d4ecb90bSCarl Huang irq_grp->grp_id = i; 520d4ecb90bSCarl Huang init_dummy_netdev(&irq_grp->napi_ndev); 521d4ecb90bSCarl Huang netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, 522d4ecb90bSCarl Huang ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT); 523d4ecb90bSCarl Huang 524d4ecb90bSCarl Huang if (ab->hw_params.ring_mask->tx[i] || 525d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx[i] || 526d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_err[i] || 527d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_wbm_rel[i] || 528d4ecb90bSCarl Huang ab->hw_params.ring_mask->reo_status[i] || 529d4ecb90bSCarl Huang ab->hw_params.ring_mask->rxdma2host[i] || 530d4ecb90bSCarl Huang ab->hw_params.ring_mask->host2rxdma[i] || 531d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_mon_status[i]) { 532d4ecb90bSCarl Huang num_irq = 1; 533d4ecb90bSCarl Huang } 534d4ecb90bSCarl Huang 535d4ecb90bSCarl Huang irq_grp->num_irq = num_irq; 536d4ecb90bSCarl Huang irq_grp->irqs[0] = base_vector + i; 537d4ecb90bSCarl Huang 538d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 539d4ecb90bSCarl Huang int irq_idx = irq_grp->irqs[j]; 540d4ecb90bSCarl Huang int vector = (i % num_vectors) + base_vector; 541d4ecb90bSCarl Huang int irq = ath11k_pci_get_msi_irq(ab->dev, vector); 542d4ecb90bSCarl Huang 543d4ecb90bSCarl Huang ab->irq_num[irq_idx] = irq; 544d4ecb90bSCarl Huang 545d4ecb90bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, 546d4ecb90bSCarl Huang "irq:%d group:%d\n", irq, i); 547d4ecb90bSCarl Huang ret = request_irq(irq, ath11k_pci_ext_interrupt_handler, 548d4ecb90bSCarl Huang IRQF_SHARED, 549d4ecb90bSCarl Huang "DP_EXT_IRQ", irq_grp); 550d4ecb90bSCarl Huang if (ret) { 551d4ecb90bSCarl Huang ath11k_err(ab, "failed request irq %d: %d\n", 552d4ecb90bSCarl Huang vector, ret); 553d4ecb90bSCarl Huang return ret; 554d4ecb90bSCarl Huang } 555d4ecb90bSCarl Huang 556d4ecb90bSCarl Huang disable_irq_nosync(ab->irq_num[irq_idx]); 557d4ecb90bSCarl Huang } 558d4ecb90bSCarl Huang } 559d4ecb90bSCarl Huang 560d4ecb90bSCarl Huang return 0; 561d4ecb90bSCarl Huang } 562d4ecb90bSCarl Huang 5637f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab) 5647f4beda2SGovind Singh { 5657f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe; 5667f4beda2SGovind Singh u32 msi_data_start; 5677f4beda2SGovind Singh u32 msi_data_count; 5687f4beda2SGovind Singh u32 msi_irq_start; 5697f4beda2SGovind Singh unsigned int msi_data; 5707f4beda2SGovind Singh int irq, i, ret, irq_idx; 5717f4beda2SGovind Singh 5727f4beda2SGovind Singh ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), 5737f4beda2SGovind Singh "CE", &msi_data_count, 5747f4beda2SGovind Singh &msi_data_start, &msi_irq_start); 5757f4beda2SGovind Singh if (ret) 5767f4beda2SGovind Singh return ret; 5777f4beda2SGovind Singh 5787f4beda2SGovind Singh /* Configure CE irqs */ 579d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 5807f4beda2SGovind Singh msi_data = (i % msi_data_count) + msi_irq_start; 5817f4beda2SGovind Singh irq = ath11k_pci_get_msi_irq(ab->dev, msi_data); 5827f4beda2SGovind Singh ce_pipe = &ab->ce.ce_pipe[i]; 5837f4beda2SGovind Singh 584e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5857f4beda2SGovind Singh continue; 5867f4beda2SGovind Singh 5877f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 5887f4beda2SGovind Singh 5890f01dcb8SAllen Pais tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet); 5902c3960c2SGovind Singh 5917f4beda2SGovind Singh ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, 5927f4beda2SGovind Singh IRQF_SHARED, irq_name[irq_idx], 5937f4beda2SGovind Singh ce_pipe); 5947f4beda2SGovind Singh if (ret) { 5957f4beda2SGovind Singh ath11k_err(ab, "failed to request irq %d: %d\n", 5967f4beda2SGovind Singh irq_idx, ret); 5977f4beda2SGovind Singh return ret; 5987f4beda2SGovind Singh } 5997f4beda2SGovind Singh 6007f4beda2SGovind Singh ab->irq_num[irq_idx] = irq; 601e5c860e1SCarl Huang ath11k_pci_ce_irq_disable(ab, i); 6027f4beda2SGovind Singh } 6037f4beda2SGovind Singh 604d4ecb90bSCarl Huang ret = ath11k_pci_ext_irq_config(ab); 605d4ecb90bSCarl Huang if (ret) 606d4ecb90bSCarl Huang return ret; 607d4ecb90bSCarl Huang 6087f4beda2SGovind Singh return 0; 6097f4beda2SGovind Singh } 6107f4beda2SGovind Singh 6117f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) 6127f4beda2SGovind Singh { 6137f4beda2SGovind Singh struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; 6147f4beda2SGovind Singh 615967c1d11SAnilkumar Kolli cfg->tgt_ce = ab->hw_params.target_ce_config; 616967c1d11SAnilkumar Kolli cfg->tgt_ce_len = ab->hw_params.target_ce_count; 6177f4beda2SGovind Singh 618967c1d11SAnilkumar Kolli cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map; 619967c1d11SAnilkumar Kolli cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len; 620eb8de049SGovind Singh ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390; 621e838c14aSCarl Huang 622e838c14aSCarl Huang ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2, 623e838c14aSCarl Huang &cfg->shadow_reg_v2_len); 6247f4beda2SGovind Singh } 6257f4beda2SGovind Singh 6267f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) 6277f4beda2SGovind Singh { 6287f4beda2SGovind Singh int i; 6297f4beda2SGovind Singh 630d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 631e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 6327f4beda2SGovind Singh continue; 6337f4beda2SGovind Singh ath11k_pci_ce_irq_enable(ab, i); 6347f4beda2SGovind Singh } 6357f4beda2SGovind Singh } 6367f4beda2SGovind Singh 6375697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci) 6385697a564SGovind Singh { 6395697a564SGovind Singh struct ath11k_base *ab = ab_pci->ab; 6405697a564SGovind Singh struct msi_desc *msi_desc; 6415697a564SGovind Singh int num_vectors; 6425697a564SGovind Singh int ret; 6435697a564SGovind Singh 6445697a564SGovind Singh num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 6455697a564SGovind Singh msi_config.total_vectors, 6465697a564SGovind Singh msi_config.total_vectors, 6475697a564SGovind Singh PCI_IRQ_MSI); 6485697a564SGovind Singh if (num_vectors != msi_config.total_vectors) { 6495697a564SGovind Singh ath11k_err(ab, "failed to get %d MSI vectors, only %d available", 6505697a564SGovind Singh msi_config.total_vectors, num_vectors); 6515697a564SGovind Singh 6525697a564SGovind Singh if (num_vectors >= 0) 6535697a564SGovind Singh return -EINVAL; 6545697a564SGovind Singh else 6555697a564SGovind Singh return num_vectors; 6565697a564SGovind Singh } 6575697a564SGovind Singh 6585697a564SGovind Singh msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 6595697a564SGovind Singh if (!msi_desc) { 6605697a564SGovind Singh ath11k_err(ab, "msi_desc is NULL!\n"); 6615697a564SGovind Singh ret = -EINVAL; 6625697a564SGovind Singh goto free_msi_vector; 6635697a564SGovind Singh } 6645697a564SGovind Singh 6655697a564SGovind Singh ab_pci->msi_ep_base_data = msi_desc->msg.data; 666e8e55d89SAnilkumar Kolli if (msi_desc->msi_attrib.is_64) 667e8e55d89SAnilkumar Kolli set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags); 6685697a564SGovind Singh 6695697a564SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); 6705697a564SGovind Singh 6715697a564SGovind Singh return 0; 6725697a564SGovind Singh 6735697a564SGovind Singh free_msi_vector: 6745697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 6755697a564SGovind Singh 6765697a564SGovind Singh return ret; 6775697a564SGovind Singh } 6785697a564SGovind Singh 6795697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci) 6805697a564SGovind Singh { 6815697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 6825697a564SGovind Singh } 6835697a564SGovind Singh 6845762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) 6855762613eSGovind Singh { 6865762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 6875762613eSGovind Singh u16 device_id; 6885762613eSGovind Singh int ret = 0; 6895762613eSGovind Singh 6905762613eSGovind Singh pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 6915762613eSGovind Singh if (device_id != ab_pci->dev_id) { 6925762613eSGovind Singh ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", 6935762613eSGovind Singh device_id, ab_pci->dev_id); 6945762613eSGovind Singh ret = -EIO; 6955762613eSGovind Singh goto out; 6965762613eSGovind Singh } 6975762613eSGovind Singh 6985762613eSGovind Singh ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); 6995762613eSGovind Singh if (ret) { 7005762613eSGovind Singh ath11k_err(ab, "failed to assign pci resource: %d\n", ret); 7015762613eSGovind Singh goto out; 7025762613eSGovind Singh } 7035762613eSGovind Singh 7045762613eSGovind Singh ret = pci_enable_device(pdev); 7055762613eSGovind Singh if (ret) { 7065762613eSGovind Singh ath11k_err(ab, "failed to enable pci device: %d\n", ret); 7075762613eSGovind Singh goto out; 7085762613eSGovind Singh } 7095762613eSGovind Singh 7105762613eSGovind Singh ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); 7115762613eSGovind Singh if (ret) { 7125762613eSGovind Singh ath11k_err(ab, "failed to request pci region: %d\n", ret); 7135762613eSGovind Singh goto disable_device; 7145762613eSGovind Singh } 7155762613eSGovind Singh 7165762613eSGovind Singh ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 7175762613eSGovind Singh if (ret) { 7185762613eSGovind Singh ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", 7195762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 7205762613eSGovind Singh goto release_region; 7215762613eSGovind Singh } 7225762613eSGovind Singh 7235762613eSGovind Singh ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 7245762613eSGovind Singh if (ret) { 7255762613eSGovind Singh ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n", 7265762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 7275762613eSGovind Singh goto release_region; 7285762613eSGovind Singh } 7295762613eSGovind Singh 7305762613eSGovind Singh pci_set_master(pdev); 7315762613eSGovind Singh 7325762613eSGovind Singh ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); 7335762613eSGovind Singh ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); 7345762613eSGovind Singh if (!ab->mem) { 7355762613eSGovind Singh ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); 7365762613eSGovind Singh ret = -EIO; 7375762613eSGovind Singh goto clear_master; 7385762613eSGovind Singh } 7395762613eSGovind Singh 7405762613eSGovind Singh ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); 7415762613eSGovind Singh return 0; 7425762613eSGovind Singh 7435762613eSGovind Singh clear_master: 7445762613eSGovind Singh pci_clear_master(pdev); 7455762613eSGovind Singh release_region: 7465762613eSGovind Singh pci_release_region(pdev, ATH11K_PCI_BAR_NUM); 7475762613eSGovind Singh disable_device: 7485762613eSGovind Singh pci_disable_device(pdev); 7495762613eSGovind Singh out: 7505762613eSGovind Singh return ret; 7515762613eSGovind Singh } 7525762613eSGovind Singh 7535762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) 7545762613eSGovind Singh { 7555762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 7565762613eSGovind Singh struct pci_dev *pci_dev = ab_pci->pdev; 7575762613eSGovind Singh 7585762613eSGovind Singh pci_iounmap(pci_dev, ab->mem); 7595762613eSGovind Singh ab->mem = NULL; 7605762613eSGovind Singh pci_clear_master(pci_dev); 7615762613eSGovind Singh pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); 7625762613eSGovind Singh if (pci_is_enabled(pci_dev)) 7635762613eSGovind Singh pci_disable_device(pci_dev); 7645762613eSGovind Singh } 7655762613eSGovind Singh 7661399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab) 7671399fb87SGovind Singh { 7681399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 7691399fb87SGovind Singh int ret; 7701399fb87SGovind Singh 771a05bd851SCarl Huang ab_pci->register_window = 0; 772a05bd851SCarl Huang clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 773f3c603d4SCarl Huang ath11k_pci_sw_reset(ab_pci->ab); 774f3c603d4SCarl Huang 7751399fb87SGovind Singh ret = ath11k_mhi_start(ab_pci); 7761399fb87SGovind Singh if (ret) { 7771399fb87SGovind Singh ath11k_err(ab, "failed to start mhi: %d\n", ret); 7781399fb87SGovind Singh return ret; 7791399fb87SGovind Singh } 7801399fb87SGovind Singh 7811399fb87SGovind Singh return 0; 7821399fb87SGovind Singh } 7831399fb87SGovind Singh 7841399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab) 7851399fb87SGovind Singh { 7861399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 7871399fb87SGovind Singh 7881399fb87SGovind Singh ath11k_mhi_stop(ab_pci); 789a05bd851SCarl Huang clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 790f3c603d4SCarl Huang ath11k_pci_force_wake(ab_pci->ab); 791f3c603d4SCarl Huang ath11k_pci_sw_reset(ab_pci->ab); 7921399fb87SGovind Singh } 7931399fb87SGovind Singh 7942c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) 7952c3960c2SGovind Singh { 7962c3960c2SGovind Singh int i; 7972c3960c2SGovind Singh 798d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 7992c3960c2SGovind Singh struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; 8002c3960c2SGovind Singh 801e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 8022c3960c2SGovind Singh continue; 8032c3960c2SGovind Singh 8042c3960c2SGovind Singh tasklet_kill(&ce_pipe->intr_tq); 8052c3960c2SGovind Singh } 8062c3960c2SGovind Singh } 8072c3960c2SGovind Singh 8087f4beda2SGovind Singh static void ath11k_pci_stop(struct ath11k_base *ab) 8097f4beda2SGovind Singh { 8102c3960c2SGovind Singh ath11k_pci_ce_irqs_disable(ab); 8112c3960c2SGovind Singh ath11k_pci_sync_ce_irqs(ab); 8122c3960c2SGovind Singh ath11k_pci_kill_tasklets(ab); 8137f4beda2SGovind Singh ath11k_ce_cleanup_pipes(ab); 8147f4beda2SGovind Singh } 8157f4beda2SGovind Singh 8167f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab) 8177f4beda2SGovind Singh { 818a05bd851SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 819a05bd851SCarl Huang 820a05bd851SCarl Huang set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 821a05bd851SCarl Huang 8227f4beda2SGovind Singh ath11k_pci_ce_irqs_enable(ab); 8232c3960c2SGovind Singh ath11k_ce_rx_post_buf(ab); 8242c3960c2SGovind Singh 8252c3960c2SGovind Singh return 0; 8262c3960c2SGovind Singh } 8272c3960c2SGovind Singh 8282c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, 8292c3960c2SGovind Singh u8 *ul_pipe, u8 *dl_pipe) 8302c3960c2SGovind Singh { 8312c3960c2SGovind Singh const struct service_to_pipe *entry; 8322c3960c2SGovind Singh bool ul_set = false, dl_set = false; 8332c3960c2SGovind Singh int i; 8342c3960c2SGovind Singh 835967c1d11SAnilkumar Kolli for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) { 836967c1d11SAnilkumar Kolli entry = &ab->hw_params.svc_to_ce_map[i]; 8372c3960c2SGovind Singh 8382c3960c2SGovind Singh if (__le32_to_cpu(entry->service_id) != service_id) 8392c3960c2SGovind Singh continue; 8402c3960c2SGovind Singh 8412c3960c2SGovind Singh switch (__le32_to_cpu(entry->pipedir)) { 8422c3960c2SGovind Singh case PIPEDIR_NONE: 8432c3960c2SGovind Singh break; 8442c3960c2SGovind Singh case PIPEDIR_IN: 8452c3960c2SGovind Singh WARN_ON(dl_set); 8462c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 8472c3960c2SGovind Singh dl_set = true; 8482c3960c2SGovind Singh break; 8492c3960c2SGovind Singh case PIPEDIR_OUT: 8502c3960c2SGovind Singh WARN_ON(ul_set); 8512c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 8522c3960c2SGovind Singh ul_set = true; 8532c3960c2SGovind Singh break; 8542c3960c2SGovind Singh case PIPEDIR_INOUT: 8552c3960c2SGovind Singh WARN_ON(dl_set); 8562c3960c2SGovind Singh WARN_ON(ul_set); 8572c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 8582c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 8592c3960c2SGovind Singh dl_set = true; 8602c3960c2SGovind Singh ul_set = true; 8612c3960c2SGovind Singh break; 8622c3960c2SGovind Singh } 8632c3960c2SGovind Singh } 8642c3960c2SGovind Singh 8652c3960c2SGovind Singh if (WARN_ON(!ul_set || !dl_set)) 8662c3960c2SGovind Singh return -ENOENT; 8677f4beda2SGovind Singh 8687f4beda2SGovind Singh return 0; 8697f4beda2SGovind Singh } 8707f4beda2SGovind Singh 8717f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = { 8727f4beda2SGovind Singh .start = ath11k_pci_start, 8737f4beda2SGovind Singh .stop = ath11k_pci_stop, 874654e959aSGovind Singh .read32 = ath11k_pci_read32, 875654e959aSGovind Singh .write32 = ath11k_pci_write32, 8761399fb87SGovind Singh .power_down = ath11k_pci_power_down, 8771399fb87SGovind Singh .power_up = ath11k_pci_power_up, 878d4ecb90bSCarl Huang .irq_enable = ath11k_pci_ext_irq_enable, 879d4ecb90bSCarl Huang .irq_disable = ath11k_pci_ext_irq_disable, 880c4eacabeSGovind Singh .get_msi_address = ath11k_pci_get_msi_address, 881c4eacabeSGovind Singh .get_user_msi_vector = ath11k_get_user_msi_assignment, 8822c3960c2SGovind Singh .map_service_to_pipe = ath11k_pci_map_service_to_pipe, 8831399fb87SGovind Singh }; 8841399fb87SGovind Singh 8856e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev, 8866e0355afSGovind Singh const struct pci_device_id *pci_dev) 8876e0355afSGovind Singh { 8886e0355afSGovind Singh struct ath11k_base *ab; 8895762613eSGovind Singh struct ath11k_pci *ab_pci; 89018ac1665SKalle Valo u32 soc_hw_version, soc_hw_version_major, soc_hw_version_minor; 8915762613eSGovind Singh int ret; 8926e0355afSGovind Singh 8936e0355afSGovind Singh dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n"); 8946e0355afSGovind Singh 8951ff8ed78SGovind Singh ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, 8961ff8ed78SGovind Singh &ath11k_pci_bus_params); 8976e0355afSGovind Singh if (!ab) { 8986e0355afSGovind Singh dev_err(&pdev->dev, "failed to allocate ath11k base\n"); 8996e0355afSGovind Singh return -ENOMEM; 9006e0355afSGovind Singh } 9016e0355afSGovind Singh 9026e0355afSGovind Singh ab->dev = &pdev->dev; 9036e0355afSGovind Singh pci_set_drvdata(pdev, ab); 9045762613eSGovind Singh ab_pci = ath11k_pci_priv(ab); 9055762613eSGovind Singh ab_pci->dev_id = pci_dev->device; 9065762613eSGovind Singh ab_pci->ab = ab; 9075697a564SGovind Singh ab_pci->pdev = pdev; 9087f4beda2SGovind Singh ab->hif.ops = &ath11k_pci_hif_ops; 9095762613eSGovind Singh pci_set_drvdata(pdev, ab); 910654e959aSGovind Singh spin_lock_init(&ab_pci->window_lock); 9115762613eSGovind Singh 9125762613eSGovind Singh ret = ath11k_pci_claim(ab_pci, pdev); 9135762613eSGovind Singh if (ret) { 9145762613eSGovind Singh ath11k_err(ab, "failed to claim device: %d\n", ret); 9155762613eSGovind Singh goto err_free_core; 9165762613eSGovind Singh } 9176e0355afSGovind Singh 91818ac1665SKalle Valo switch (pci_dev->device) { 91918ac1665SKalle Valo case QCA6390_DEVICE_ID: 92018ac1665SKalle Valo soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION); 92118ac1665SKalle Valo soc_hw_version_major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK, 92218ac1665SKalle Valo soc_hw_version); 92318ac1665SKalle Valo soc_hw_version_minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK, 92418ac1665SKalle Valo soc_hw_version); 92518ac1665SKalle Valo 92618ac1665SKalle Valo ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n", 92718ac1665SKalle Valo soc_hw_version_major, soc_hw_version_minor); 92818ac1665SKalle Valo 92918ac1665SKalle Valo switch (soc_hw_version_major) { 93018ac1665SKalle Valo case 2: 93118ac1665SKalle Valo ab->hw_rev = ATH11K_HW_QCA6390_HW20; 93218ac1665SKalle Valo break; 93318ac1665SKalle Valo default: 93418ac1665SKalle Valo dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n", 93518ac1665SKalle Valo soc_hw_version_major, soc_hw_version_minor); 93618ac1665SKalle Valo ret = -EOPNOTSUPP; 93718ac1665SKalle Valo goto err_pci_free_region; 93818ac1665SKalle Valo } 93918ac1665SKalle Valo break; 94018ac1665SKalle Valo default: 94118ac1665SKalle Valo dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", 94218ac1665SKalle Valo pci_dev->device); 94318ac1665SKalle Valo ret = -EOPNOTSUPP; 94418ac1665SKalle Valo goto err_pci_free_region; 94518ac1665SKalle Valo } 94618ac1665SKalle Valo 9475697a564SGovind Singh ret = ath11k_pci_enable_msi(ab_pci); 9485697a564SGovind Singh if (ret) { 9495697a564SGovind Singh ath11k_err(ab, "failed to enable msi: %d\n", ret); 9505697a564SGovind Singh goto err_pci_free_region; 9515697a564SGovind Singh } 9525697a564SGovind Singh 953b8246f88SKalle Valo ret = ath11k_core_pre_init(ab); 954b8246f88SKalle Valo if (ret) 955b8246f88SKalle Valo goto err_pci_disable_msi; 956b8246f88SKalle Valo 9571399fb87SGovind Singh ret = ath11k_mhi_register(ab_pci); 9581399fb87SGovind Singh if (ret) { 9591399fb87SGovind Singh ath11k_err(ab, "failed to register mhi: %d\n", ret); 9601399fb87SGovind Singh goto err_pci_disable_msi; 9611399fb87SGovind Singh } 9621399fb87SGovind Singh 9637f4beda2SGovind Singh ret = ath11k_hal_srng_init(ab); 9647f4beda2SGovind Singh if (ret) 9657f4beda2SGovind Singh goto err_mhi_unregister; 9667f4beda2SGovind Singh 9677f4beda2SGovind Singh ret = ath11k_ce_alloc_pipes(ab); 9687f4beda2SGovind Singh if (ret) { 9697f4beda2SGovind Singh ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret); 9707f4beda2SGovind Singh goto err_hal_srng_deinit; 9717f4beda2SGovind Singh } 9727f4beda2SGovind Singh 9737f4beda2SGovind Singh ath11k_pci_init_qmi_ce_config(ab); 9747f4beda2SGovind Singh 9757f4beda2SGovind Singh ret = ath11k_pci_config_irq(ab); 9767f4beda2SGovind Singh if (ret) { 9777f4beda2SGovind Singh ath11k_err(ab, "failed to config irq: %d\n", ret); 9787f4beda2SGovind Singh goto err_ce_free; 9797f4beda2SGovind Singh } 9807f4beda2SGovind Singh 9817f4beda2SGovind Singh ret = ath11k_core_init(ab); 9827f4beda2SGovind Singh if (ret) { 9837f4beda2SGovind Singh ath11k_err(ab, "failed to init core: %d\n", ret); 9847f4beda2SGovind Singh goto err_free_irq; 9857f4beda2SGovind Singh } 9866e0355afSGovind Singh return 0; 9875762613eSGovind Singh 9887f4beda2SGovind Singh err_free_irq: 9897f4beda2SGovind Singh ath11k_pci_free_irq(ab); 9907f4beda2SGovind Singh 9917f4beda2SGovind Singh err_ce_free: 9927f4beda2SGovind Singh ath11k_ce_free_pipes(ab); 9937f4beda2SGovind Singh 9947f4beda2SGovind Singh err_hal_srng_deinit: 9957f4beda2SGovind Singh ath11k_hal_srng_deinit(ab); 9967f4beda2SGovind Singh 9977f4beda2SGovind Singh err_mhi_unregister: 9987f4beda2SGovind Singh ath11k_mhi_unregister(ab_pci); 9997f4beda2SGovind Singh 1000b8246f88SKalle Valo err_pci_disable_msi: 1001b8246f88SKalle Valo ath11k_pci_disable_msi(ab_pci); 1002b8246f88SKalle Valo 10035697a564SGovind Singh err_pci_free_region: 10045697a564SGovind Singh ath11k_pci_free_region(ab_pci); 10055697a564SGovind Singh 10065762613eSGovind Singh err_free_core: 10075762613eSGovind Singh ath11k_core_free(ab); 10085697a564SGovind Singh 10095762613eSGovind Singh return ret; 10106e0355afSGovind Singh } 10116e0355afSGovind Singh 10126e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev) 10136e0355afSGovind Singh { 10146e0355afSGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 10155762613eSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 10166e0355afSGovind Singh 10176e0355afSGovind Singh set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); 10186fbd8898SCarl Huang 10196fbd8898SCarl Huang ath11k_core_deinit(ab); 10206fbd8898SCarl Huang 10211399fb87SGovind Singh ath11k_mhi_unregister(ab_pci); 10226fbd8898SCarl Huang 10236fbd8898SCarl Huang ath11k_pci_free_irq(ab); 10245697a564SGovind Singh ath11k_pci_disable_msi(ab_pci); 10255762613eSGovind Singh ath11k_pci_free_region(ab_pci); 10266fbd8898SCarl Huang 10276fbd8898SCarl Huang ath11k_hal_srng_deinit(ab); 10286fbd8898SCarl Huang ath11k_ce_free_pipes(ab); 10296e0355afSGovind Singh ath11k_core_free(ab); 10306e0355afSGovind Singh } 10316e0355afSGovind Singh 10321399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev) 10331399fb87SGovind Singh { 10341399fb87SGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 10351399fb87SGovind Singh 10361399fb87SGovind Singh ath11k_pci_power_down(ab); 10371399fb87SGovind Singh } 10381399fb87SGovind Singh 10396e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = { 10406e0355afSGovind Singh .name = "ath11k_pci", 10416e0355afSGovind Singh .id_table = ath11k_pci_id_table, 10426e0355afSGovind Singh .probe = ath11k_pci_probe, 10436e0355afSGovind Singh .remove = ath11k_pci_remove, 10441399fb87SGovind Singh .shutdown = ath11k_pci_shutdown, 10456e0355afSGovind Singh }; 10466e0355afSGovind Singh 10476e0355afSGovind Singh static int ath11k_pci_init(void) 10486e0355afSGovind Singh { 10496e0355afSGovind Singh int ret; 10506e0355afSGovind Singh 10516e0355afSGovind Singh ret = pci_register_driver(&ath11k_pci_driver); 10526e0355afSGovind Singh if (ret) 10536e0355afSGovind Singh pr_err("failed to register ath11k pci driver: %d\n", 10546e0355afSGovind Singh ret); 10556e0355afSGovind Singh 10566e0355afSGovind Singh return ret; 10576e0355afSGovind Singh } 10586e0355afSGovind Singh module_init(ath11k_pci_init); 10596e0355afSGovind Singh 10606e0355afSGovind Singh static void ath11k_pci_exit(void) 10616e0355afSGovind Singh { 10626e0355afSGovind Singh pci_unregister_driver(&ath11k_pci_driver); 10636e0355afSGovind Singh } 10646e0355afSGovind Singh 10656e0355afSGovind Singh module_exit(ath11k_pci_exit); 10666e0355afSGovind Singh 10676e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); 10686e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL"); 1069*3dbd7fe7SDevin Bayer 1070*3dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */ 1071*3dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE); 1072*3dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE); 1073*3dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE); 1074