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 static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { 557f4beda2SGovind Singh "bhi", 567f4beda2SGovind Singh "mhi-er0", 577f4beda2SGovind Singh "mhi-er1", 587f4beda2SGovind Singh "ce0", 597f4beda2SGovind Singh "ce1", 607f4beda2SGovind Singh "ce2", 617f4beda2SGovind Singh "ce3", 627f4beda2SGovind Singh "ce4", 637f4beda2SGovind Singh "ce5", 647f4beda2SGovind Singh "ce6", 657f4beda2SGovind Singh "ce7", 667f4beda2SGovind Singh "ce8", 677f4beda2SGovind Singh "ce9", 687f4beda2SGovind Singh "ce10", 697f4beda2SGovind Singh "ce11", 707f4beda2SGovind Singh "host2wbm-desc-feed", 717f4beda2SGovind Singh "host2reo-re-injection", 727f4beda2SGovind Singh "host2reo-command", 737f4beda2SGovind Singh "host2rxdma-monitor-ring3", 747f4beda2SGovind Singh "host2rxdma-monitor-ring2", 757f4beda2SGovind Singh "host2rxdma-monitor-ring1", 767f4beda2SGovind Singh "reo2ost-exception", 777f4beda2SGovind Singh "wbm2host-rx-release", 787f4beda2SGovind Singh "reo2host-status", 797f4beda2SGovind Singh "reo2host-destination-ring4", 807f4beda2SGovind Singh "reo2host-destination-ring3", 817f4beda2SGovind Singh "reo2host-destination-ring2", 827f4beda2SGovind Singh "reo2host-destination-ring1", 837f4beda2SGovind Singh "rxdma2host-monitor-destination-mac3", 847f4beda2SGovind Singh "rxdma2host-monitor-destination-mac2", 857f4beda2SGovind Singh "rxdma2host-monitor-destination-mac1", 867f4beda2SGovind Singh "ppdu-end-interrupts-mac3", 877f4beda2SGovind Singh "ppdu-end-interrupts-mac2", 887f4beda2SGovind Singh "ppdu-end-interrupts-mac1", 897f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac3", 907f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac2", 917f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac1", 927f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac3", 937f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac2", 947f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac1", 957f4beda2SGovind Singh "rxdma2host-destination-ring-mac3", 967f4beda2SGovind Singh "rxdma2host-destination-ring-mac2", 977f4beda2SGovind Singh "rxdma2host-destination-ring-mac1", 987f4beda2SGovind Singh "host2tcl-input-ring4", 997f4beda2SGovind Singh "host2tcl-input-ring3", 1007f4beda2SGovind Singh "host2tcl-input-ring2", 1017f4beda2SGovind Singh "host2tcl-input-ring1", 1027f4beda2SGovind Singh "wbm2host-tx-completions-ring3", 1037f4beda2SGovind Singh "wbm2host-tx-completions-ring2", 1047f4beda2SGovind Singh "wbm2host-tx-completions-ring1", 1057f4beda2SGovind Singh "tcl2host-status-ring", 1067f4beda2SGovind Singh }; 1077f4beda2SGovind Singh 108654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset) 109654e959aSGovind Singh { 110654e959aSGovind Singh struct ath11k_base *ab = ab_pci->ab; 111654e959aSGovind Singh 112654e959aSGovind Singh u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset); 113654e959aSGovind Singh 114654e959aSGovind Singh lockdep_assert_held(&ab_pci->window_lock); 115654e959aSGovind Singh 116654e959aSGovind Singh if (window != ab_pci->register_window) { 117654e959aSGovind Singh iowrite32(WINDOW_ENABLE_BIT | window, 118654e959aSGovind Singh ab->mem + WINDOW_REG_ADDRESS); 119654e959aSGovind Singh ab_pci->register_window = window; 120654e959aSGovind Singh } 121654e959aSGovind Singh } 122654e959aSGovind Singh 123f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) 124654e959aSGovind Singh { 125654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 126654e959aSGovind Singh 127654e959aSGovind Singh if (offset < WINDOW_START) { 128654e959aSGovind Singh iowrite32(value, ab->mem + offset); 129654e959aSGovind Singh } else { 130654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 131654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 132654e959aSGovind Singh iowrite32(value, ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK)); 133654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 134654e959aSGovind Singh } 135654e959aSGovind Singh } 136654e959aSGovind Singh 137f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) 138654e959aSGovind Singh { 139654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 140654e959aSGovind Singh u32 val; 141654e959aSGovind Singh 142654e959aSGovind Singh if (offset < WINDOW_START) { 143654e959aSGovind Singh val = ioread32(ab->mem + offset); 144654e959aSGovind Singh } else { 145654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 146654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 147654e959aSGovind Singh val = ioread32(ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK)); 148654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 149654e959aSGovind Singh } 150654e959aSGovind Singh 151654e959aSGovind Singh return val; 152654e959aSGovind Singh } 153654e959aSGovind Singh 154f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) 155f3c603d4SCarl Huang { 156f3c603d4SCarl Huang u32 val, delay; 157f3c603d4SCarl Huang 158f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 159f3c603d4SCarl Huang 160f3c603d4SCarl Huang val |= PCIE_SOC_GLOBAL_RESET_V; 161f3c603d4SCarl Huang 162f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 163f3c603d4SCarl Huang 164f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 165f3c603d4SCarl Huang delay = 10; 166f3c603d4SCarl Huang mdelay(delay); 167f3c603d4SCarl Huang 168f3c603d4SCarl Huang /* Need to toggle V bit back otherwise stuck in reset status */ 169f3c603d4SCarl Huang val &= ~PCIE_SOC_GLOBAL_RESET_V; 170f3c603d4SCarl Huang 171f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 172f3c603d4SCarl Huang 173f3c603d4SCarl Huang mdelay(delay); 174f3c603d4SCarl Huang 175f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 176f3c603d4SCarl Huang if (val == 0xffffffff) 177f3c603d4SCarl Huang ath11k_warn(ab, "link down error during global reset\n"); 178f3c603d4SCarl Huang } 179f3c603d4SCarl Huang 180f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) 181f3c603d4SCarl Huang { 182f3c603d4SCarl Huang u32 val; 183f3c603d4SCarl Huang 184f3c603d4SCarl Huang /* read cookie */ 185f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR); 186f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val); 187f3c603d4SCarl Huang 188f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 189f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 190f3c603d4SCarl Huang 191f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 192f3c603d4SCarl Huang mdelay(10); 193f3c603d4SCarl Huang 194f3c603d4SCarl Huang /* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from 195f3c603d4SCarl Huang * continuing warm path and entering dead loop. 196f3c603d4SCarl Huang */ 197f3c603d4SCarl Huang ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0); 198f3c603d4SCarl Huang mdelay(10); 199f3c603d4SCarl Huang 200f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 201f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 202f3c603d4SCarl Huang 203f3c603d4SCarl Huang /* A read clear register. clear the register to prevent 204f3c603d4SCarl Huang * Q6 from entering wrong code path. 205f3c603d4SCarl Huang */ 206f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG); 207f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val); 208f3c603d4SCarl Huang } 209f3c603d4SCarl Huang 210f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab) 211f3c603d4SCarl Huang { 212f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1); 213f3c603d4SCarl Huang mdelay(5); 214f3c603d4SCarl Huang } 215f3c603d4SCarl Huang 216f3c603d4SCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab) 217f3c603d4SCarl Huang { 218f3c603d4SCarl Huang ath11k_pci_soc_global_reset(ab); 219f3c603d4SCarl Huang ath11k_mhi_clear_vector(ab); 220f3c603d4SCarl Huang ath11k_pci_soc_global_reset(ab); 221f3c603d4SCarl Huang ath11k_mhi_set_mhictrl_reset(ab); 222f3c603d4SCarl Huang ath11k_pci_clear_dbg_registers(ab); 223f3c603d4SCarl Huang } 224f3c603d4SCarl Huang 2251399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) 2261399fb87SGovind Singh { 2271399fb87SGovind Singh struct pci_dev *pci_dev = to_pci_dev(dev); 2281399fb87SGovind Singh 2291399fb87SGovind Singh return pci_irq_vector(pci_dev, vector); 2301399fb87SGovind Singh } 2311399fb87SGovind Singh 232c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, 233c4eacabeSGovind Singh u32 *msi_addr_hi) 234c4eacabeSGovind Singh { 235c4eacabeSGovind Singh struct pci_dev *pci_dev = to_pci_dev(ab->dev); 236c4eacabeSGovind Singh 237c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, 238c4eacabeSGovind Singh msi_addr_lo); 239c4eacabeSGovind Singh 240c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, 241c4eacabeSGovind Singh msi_addr_hi); 242c4eacabeSGovind Singh } 243c4eacabeSGovind Singh 2441399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, 2451399fb87SGovind Singh int *num_vectors, u32 *user_base_data, 2461399fb87SGovind Singh u32 *base_vector) 2471399fb87SGovind Singh { 2481399fb87SGovind Singh struct ath11k_base *ab = ab_pci->ab; 2491399fb87SGovind Singh int idx; 2501399fb87SGovind Singh 2511399fb87SGovind Singh for (idx = 0; idx < msi_config.total_users; idx++) { 2521399fb87SGovind Singh if (strcmp(user_name, msi_config.users[idx].name) == 0) { 2531399fb87SGovind Singh *num_vectors = msi_config.users[idx].num_vectors; 2541399fb87SGovind Singh *user_base_data = msi_config.users[idx].base_vector 2551399fb87SGovind Singh + ab_pci->msi_ep_base_data; 2561399fb87SGovind Singh *base_vector = msi_config.users[idx].base_vector; 2571399fb87SGovind Singh 2581399fb87SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", 2591399fb87SGovind Singh user_name, *num_vectors, *user_base_data, 2601399fb87SGovind Singh *base_vector); 2611399fb87SGovind Singh 2621399fb87SGovind Singh return 0; 2631399fb87SGovind Singh } 2641399fb87SGovind Singh } 2651399fb87SGovind Singh 2661399fb87SGovind Singh ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name); 2671399fb87SGovind Singh 2681399fb87SGovind Singh return -EINVAL; 2691399fb87SGovind Singh } 2701399fb87SGovind Singh 271c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, 272c4eacabeSGovind Singh int *num_vectors, u32 *user_base_data, 273c4eacabeSGovind Singh u32 *base_vector) 274c4eacabeSGovind Singh { 275c4eacabeSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 276c4eacabeSGovind Singh 277c4eacabeSGovind Singh return ath11k_pci_get_user_msi_assignment(ab_pci, user_name, 278c4eacabeSGovind Singh num_vectors, user_base_data, 279c4eacabeSGovind Singh base_vector); 280c4eacabeSGovind Singh } 281c4eacabeSGovind Singh 282d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab) 283d4ecb90bSCarl Huang { 284d4ecb90bSCarl Huang int i, j; 285d4ecb90bSCarl Huang 286d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 287d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 288d4ecb90bSCarl Huang 289d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) 290d4ecb90bSCarl Huang free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); 291d4ecb90bSCarl Huang 292d4ecb90bSCarl Huang netif_napi_del(&irq_grp->napi); 293d4ecb90bSCarl Huang } 294d4ecb90bSCarl Huang } 295d4ecb90bSCarl Huang 2967f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab) 2977f4beda2SGovind Singh { 2987f4beda2SGovind Singh int i, irq_idx; 2997f4beda2SGovind Singh 300d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 301e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 3027f4beda2SGovind Singh continue; 3037f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 3047f4beda2SGovind Singh free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); 3057f4beda2SGovind Singh } 306d4ecb90bSCarl Huang 307d4ecb90bSCarl Huang ath11k_pci_free_ext_irq(ab); 3087f4beda2SGovind Singh } 3097f4beda2SGovind Singh 3102c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) 3112c3960c2SGovind Singh { 3122c3960c2SGovind Singh u32 irq_idx; 3132c3960c2SGovind Singh 3142c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 3152c3960c2SGovind Singh enable_irq(ab->irq_num[irq_idx]); 3162c3960c2SGovind Singh } 3172c3960c2SGovind Singh 3187f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) 3197f4beda2SGovind Singh { 3207f4beda2SGovind Singh u32 irq_idx; 3217f4beda2SGovind Singh 3227f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 3237f4beda2SGovind Singh disable_irq_nosync(ab->irq_num[irq_idx]); 3247f4beda2SGovind Singh } 3257f4beda2SGovind Singh 3262c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab) 3272c3960c2SGovind Singh { 3282c3960c2SGovind Singh int i; 3292c3960c2SGovind Singh 330d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 331e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 3322c3960c2SGovind Singh continue; 3332c3960c2SGovind Singh ath11k_pci_ce_irq_disable(ab, i); 3342c3960c2SGovind Singh } 3352c3960c2SGovind Singh } 3362c3960c2SGovind Singh 3372c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) 3382c3960c2SGovind Singh { 3392c3960c2SGovind Singh int i; 3402c3960c2SGovind Singh int irq_idx; 3412c3960c2SGovind Singh 342d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 343e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 3442c3960c2SGovind Singh continue; 3452c3960c2SGovind Singh 3462c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 3472c3960c2SGovind Singh synchronize_irq(ab->irq_num[irq_idx]); 3482c3960c2SGovind Singh } 3492c3960c2SGovind Singh } 3502c3960c2SGovind Singh 3512c3960c2SGovind Singh static void ath11k_pci_ce_tasklet(unsigned long data) 3522c3960c2SGovind Singh { 3532c3960c2SGovind Singh struct ath11k_ce_pipe *ce_pipe = (struct ath11k_ce_pipe *)data; 3542c3960c2SGovind Singh 3552c3960c2SGovind Singh ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); 3562c3960c2SGovind Singh 3572c3960c2SGovind Singh ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num); 3582c3960c2SGovind Singh } 3592c3960c2SGovind Singh 3607f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) 3617f4beda2SGovind Singh { 3627f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe = arg; 3637f4beda2SGovind Singh 3647f4beda2SGovind Singh ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num); 3652c3960c2SGovind Singh tasklet_schedule(&ce_pipe->intr_tq); 3667f4beda2SGovind Singh 3677f4beda2SGovind Singh return IRQ_HANDLED; 3687f4beda2SGovind Singh } 3697f4beda2SGovind Singh 370d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) 371d4ecb90bSCarl Huang { 372d4ecb90bSCarl Huang int i; 373d4ecb90bSCarl Huang 374d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 375d4ecb90bSCarl Huang disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 376d4ecb90bSCarl Huang } 377d4ecb90bSCarl Huang 378d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc) 379d4ecb90bSCarl Huang { 380d4ecb90bSCarl Huang int i; 381d4ecb90bSCarl Huang 382d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 383d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; 384d4ecb90bSCarl Huang 385d4ecb90bSCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 386d4ecb90bSCarl Huang 387d4ecb90bSCarl Huang napi_synchronize(&irq_grp->napi); 388d4ecb90bSCarl Huang napi_disable(&irq_grp->napi); 389d4ecb90bSCarl Huang } 390d4ecb90bSCarl Huang } 391d4ecb90bSCarl Huang 392d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) 393d4ecb90bSCarl Huang { 394d4ecb90bSCarl Huang int i; 395d4ecb90bSCarl Huang 396d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 397d4ecb90bSCarl Huang enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 398d4ecb90bSCarl Huang } 399d4ecb90bSCarl Huang 400d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab) 401d4ecb90bSCarl Huang { 402d4ecb90bSCarl Huang int i; 403d4ecb90bSCarl Huang 404d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 405d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 406d4ecb90bSCarl Huang 407d4ecb90bSCarl Huang napi_enable(&irq_grp->napi); 408d4ecb90bSCarl Huang ath11k_pci_ext_grp_enable(irq_grp); 409d4ecb90bSCarl Huang } 410d4ecb90bSCarl Huang } 411d4ecb90bSCarl Huang 412d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab) 413d4ecb90bSCarl Huang { 414d4ecb90bSCarl Huang int i, j, irq_idx; 415d4ecb90bSCarl Huang 416d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 417d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 418d4ecb90bSCarl Huang 419d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 420d4ecb90bSCarl Huang irq_idx = irq_grp->irqs[j]; 421d4ecb90bSCarl Huang synchronize_irq(ab->irq_num[irq_idx]); 422d4ecb90bSCarl Huang } 423d4ecb90bSCarl Huang } 424d4ecb90bSCarl Huang } 425d4ecb90bSCarl Huang 426d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab) 427d4ecb90bSCarl Huang { 428d4ecb90bSCarl Huang __ath11k_pci_ext_irq_disable(ab); 429d4ecb90bSCarl Huang ath11k_pci_sync_ext_irqs(ab); 430d4ecb90bSCarl Huang } 431d4ecb90bSCarl Huang 432d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) 433d4ecb90bSCarl Huang { 434d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = container_of(napi, 435d4ecb90bSCarl Huang struct ath11k_ext_irq_grp, 436d4ecb90bSCarl Huang napi); 437d4ecb90bSCarl Huang struct ath11k_base *ab = irq_grp->ab; 438d4ecb90bSCarl Huang int work_done; 439d4ecb90bSCarl Huang 440d4ecb90bSCarl Huang work_done = ath11k_dp_service_srng(ab, irq_grp, budget); 441d4ecb90bSCarl Huang if (work_done < budget) { 442d4ecb90bSCarl Huang napi_complete_done(napi, work_done); 443d4ecb90bSCarl Huang ath11k_pci_ext_grp_enable(irq_grp); 444d4ecb90bSCarl Huang } 445d4ecb90bSCarl Huang 446d4ecb90bSCarl Huang if (work_done > budget) 447d4ecb90bSCarl Huang work_done = budget; 448d4ecb90bSCarl Huang 449d4ecb90bSCarl Huang return work_done; 450d4ecb90bSCarl Huang } 451d4ecb90bSCarl Huang 452d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) 453d4ecb90bSCarl Huang { 454d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = arg; 455d4ecb90bSCarl Huang 456d4ecb90bSCarl Huang ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); 457d4ecb90bSCarl Huang 458d4ecb90bSCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 459d4ecb90bSCarl Huang 460d4ecb90bSCarl Huang napi_schedule(&irq_grp->napi); 461d4ecb90bSCarl Huang 462d4ecb90bSCarl Huang return IRQ_HANDLED; 463d4ecb90bSCarl Huang } 464d4ecb90bSCarl Huang 465d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) 466d4ecb90bSCarl Huang { 467d4ecb90bSCarl Huang int i, j, ret, num_vectors = 0; 468d4ecb90bSCarl Huang u32 user_base_data = 0, base_vector = 0; 469d4ecb90bSCarl Huang 470b2c09458SColin Ian King ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", 471b2c09458SColin Ian King &num_vectors, 472b2c09458SColin Ian King &user_base_data, 473d4ecb90bSCarl Huang &base_vector); 474b2c09458SColin Ian King if (ret < 0) 475b2c09458SColin Ian King return ret; 476d4ecb90bSCarl Huang 477d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 478d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 479d4ecb90bSCarl Huang u32 num_irq = 0; 480d4ecb90bSCarl Huang 481d4ecb90bSCarl Huang irq_grp->ab = ab; 482d4ecb90bSCarl Huang irq_grp->grp_id = i; 483d4ecb90bSCarl Huang init_dummy_netdev(&irq_grp->napi_ndev); 484d4ecb90bSCarl Huang netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, 485d4ecb90bSCarl Huang ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT); 486d4ecb90bSCarl Huang 487d4ecb90bSCarl Huang if (ab->hw_params.ring_mask->tx[i] || 488d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx[i] || 489d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_err[i] || 490d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_wbm_rel[i] || 491d4ecb90bSCarl Huang ab->hw_params.ring_mask->reo_status[i] || 492d4ecb90bSCarl Huang ab->hw_params.ring_mask->rxdma2host[i] || 493d4ecb90bSCarl Huang ab->hw_params.ring_mask->host2rxdma[i] || 494d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_mon_status[i]) { 495d4ecb90bSCarl Huang num_irq = 1; 496d4ecb90bSCarl Huang } 497d4ecb90bSCarl Huang 498d4ecb90bSCarl Huang irq_grp->num_irq = num_irq; 499d4ecb90bSCarl Huang irq_grp->irqs[0] = base_vector + i; 500d4ecb90bSCarl Huang 501d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 502d4ecb90bSCarl Huang int irq_idx = irq_grp->irqs[j]; 503d4ecb90bSCarl Huang int vector = (i % num_vectors) + base_vector; 504d4ecb90bSCarl Huang int irq = ath11k_pci_get_msi_irq(ab->dev, vector); 505d4ecb90bSCarl Huang 506d4ecb90bSCarl Huang ab->irq_num[irq_idx] = irq; 507d4ecb90bSCarl Huang 508d4ecb90bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, 509d4ecb90bSCarl Huang "irq:%d group:%d\n", irq, i); 510d4ecb90bSCarl Huang ret = request_irq(irq, ath11k_pci_ext_interrupt_handler, 511d4ecb90bSCarl Huang IRQF_SHARED, 512d4ecb90bSCarl Huang "DP_EXT_IRQ", irq_grp); 513d4ecb90bSCarl Huang if (ret) { 514d4ecb90bSCarl Huang ath11k_err(ab, "failed request irq %d: %d\n", 515d4ecb90bSCarl Huang vector, ret); 516d4ecb90bSCarl Huang return ret; 517d4ecb90bSCarl Huang } 518d4ecb90bSCarl Huang 519d4ecb90bSCarl Huang disable_irq_nosync(ab->irq_num[irq_idx]); 520d4ecb90bSCarl Huang } 521d4ecb90bSCarl Huang } 522d4ecb90bSCarl Huang 523d4ecb90bSCarl Huang return 0; 524d4ecb90bSCarl Huang } 525d4ecb90bSCarl Huang 5267f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab) 5277f4beda2SGovind Singh { 5287f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe; 5297f4beda2SGovind Singh u32 msi_data_start; 5307f4beda2SGovind Singh u32 msi_data_count; 5317f4beda2SGovind Singh u32 msi_irq_start; 5327f4beda2SGovind Singh unsigned int msi_data; 5337f4beda2SGovind Singh int irq, i, ret, irq_idx; 5347f4beda2SGovind Singh 5357f4beda2SGovind Singh ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), 5367f4beda2SGovind Singh "CE", &msi_data_count, 5377f4beda2SGovind Singh &msi_data_start, &msi_irq_start); 5387f4beda2SGovind Singh if (ret) 5397f4beda2SGovind Singh return ret; 5407f4beda2SGovind Singh 5417f4beda2SGovind Singh /* Configure CE irqs */ 542d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 5437f4beda2SGovind Singh msi_data = (i % msi_data_count) + msi_irq_start; 5447f4beda2SGovind Singh irq = ath11k_pci_get_msi_irq(ab->dev, msi_data); 5457f4beda2SGovind Singh ce_pipe = &ab->ce.ce_pipe[i]; 5467f4beda2SGovind Singh 547e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5487f4beda2SGovind Singh continue; 5497f4beda2SGovind Singh 5507f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 5517f4beda2SGovind Singh 5522c3960c2SGovind Singh tasklet_init(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet, 5532c3960c2SGovind Singh (unsigned long)ce_pipe); 5542c3960c2SGovind Singh 5557f4beda2SGovind Singh ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, 5567f4beda2SGovind Singh IRQF_SHARED, irq_name[irq_idx], 5577f4beda2SGovind Singh ce_pipe); 5587f4beda2SGovind Singh if (ret) { 5597f4beda2SGovind Singh ath11k_err(ab, "failed to request irq %d: %d\n", 5607f4beda2SGovind Singh irq_idx, ret); 5617f4beda2SGovind Singh return ret; 5627f4beda2SGovind Singh } 5637f4beda2SGovind Singh 5647f4beda2SGovind Singh ab->irq_num[irq_idx] = irq; 565e5c860e1SCarl Huang ath11k_pci_ce_irq_disable(ab, i); 5667f4beda2SGovind Singh } 5677f4beda2SGovind Singh 568d4ecb90bSCarl Huang ret = ath11k_pci_ext_irq_config(ab); 569d4ecb90bSCarl Huang if (ret) 570d4ecb90bSCarl Huang return ret; 571d4ecb90bSCarl Huang 5727f4beda2SGovind Singh return 0; 5737f4beda2SGovind Singh } 5747f4beda2SGovind Singh 5757f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) 5767f4beda2SGovind Singh { 5777f4beda2SGovind Singh struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; 5787f4beda2SGovind Singh 579*967c1d11SAnilkumar Kolli cfg->tgt_ce = ab->hw_params.target_ce_config; 580*967c1d11SAnilkumar Kolli cfg->tgt_ce_len = ab->hw_params.target_ce_count; 5817f4beda2SGovind Singh 582*967c1d11SAnilkumar Kolli cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map; 583*967c1d11SAnilkumar Kolli cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len; 584eb8de049SGovind Singh ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390; 5857f4beda2SGovind Singh } 5867f4beda2SGovind Singh 5877f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) 5887f4beda2SGovind Singh { 5897f4beda2SGovind Singh int i; 5907f4beda2SGovind Singh 591d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 592e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5937f4beda2SGovind Singh continue; 5947f4beda2SGovind Singh ath11k_pci_ce_irq_enable(ab, i); 5957f4beda2SGovind Singh } 5967f4beda2SGovind Singh } 5977f4beda2SGovind Singh 5985697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci) 5995697a564SGovind Singh { 6005697a564SGovind Singh struct ath11k_base *ab = ab_pci->ab; 6015697a564SGovind Singh struct msi_desc *msi_desc; 6025697a564SGovind Singh int num_vectors; 6035697a564SGovind Singh int ret; 6045697a564SGovind Singh 6055697a564SGovind Singh num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 6065697a564SGovind Singh msi_config.total_vectors, 6075697a564SGovind Singh msi_config.total_vectors, 6085697a564SGovind Singh PCI_IRQ_MSI); 6095697a564SGovind Singh if (num_vectors != msi_config.total_vectors) { 6105697a564SGovind Singh ath11k_err(ab, "failed to get %d MSI vectors, only %d available", 6115697a564SGovind Singh msi_config.total_vectors, num_vectors); 6125697a564SGovind Singh 6135697a564SGovind Singh if (num_vectors >= 0) 6145697a564SGovind Singh return -EINVAL; 6155697a564SGovind Singh else 6165697a564SGovind Singh return num_vectors; 6175697a564SGovind Singh } 6185697a564SGovind Singh 6195697a564SGovind Singh msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 6205697a564SGovind Singh if (!msi_desc) { 6215697a564SGovind Singh ath11k_err(ab, "msi_desc is NULL!\n"); 6225697a564SGovind Singh ret = -EINVAL; 6235697a564SGovind Singh goto free_msi_vector; 6245697a564SGovind Singh } 6255697a564SGovind Singh 6265697a564SGovind Singh ab_pci->msi_ep_base_data = msi_desc->msg.data; 6275697a564SGovind Singh 6285697a564SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); 6295697a564SGovind Singh 6305697a564SGovind Singh return 0; 6315697a564SGovind Singh 6325697a564SGovind Singh free_msi_vector: 6335697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 6345697a564SGovind Singh 6355697a564SGovind Singh return ret; 6365697a564SGovind Singh } 6375697a564SGovind Singh 6385697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci) 6395697a564SGovind Singh { 6405697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 6415697a564SGovind Singh } 6425697a564SGovind Singh 6435762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) 6445762613eSGovind Singh { 6455762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 6465762613eSGovind Singh u16 device_id; 6475762613eSGovind Singh int ret = 0; 6485762613eSGovind Singh 6495762613eSGovind Singh pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 6505762613eSGovind Singh if (device_id != ab_pci->dev_id) { 6515762613eSGovind Singh ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", 6525762613eSGovind Singh device_id, ab_pci->dev_id); 6535762613eSGovind Singh ret = -EIO; 6545762613eSGovind Singh goto out; 6555762613eSGovind Singh } 6565762613eSGovind Singh 6575762613eSGovind Singh ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); 6585762613eSGovind Singh if (ret) { 6595762613eSGovind Singh ath11k_err(ab, "failed to assign pci resource: %d\n", ret); 6605762613eSGovind Singh goto out; 6615762613eSGovind Singh } 6625762613eSGovind Singh 6635762613eSGovind Singh ret = pci_enable_device(pdev); 6645762613eSGovind Singh if (ret) { 6655762613eSGovind Singh ath11k_err(ab, "failed to enable pci device: %d\n", ret); 6665762613eSGovind Singh goto out; 6675762613eSGovind Singh } 6685762613eSGovind Singh 6695762613eSGovind Singh ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); 6705762613eSGovind Singh if (ret) { 6715762613eSGovind Singh ath11k_err(ab, "failed to request pci region: %d\n", ret); 6725762613eSGovind Singh goto disable_device; 6735762613eSGovind Singh } 6745762613eSGovind Singh 6755762613eSGovind Singh ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 6765762613eSGovind Singh if (ret) { 6775762613eSGovind Singh ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", 6785762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 6795762613eSGovind Singh goto release_region; 6805762613eSGovind Singh } 6815762613eSGovind Singh 6825762613eSGovind Singh ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 6835762613eSGovind Singh if (ret) { 6845762613eSGovind Singh ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n", 6855762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 6865762613eSGovind Singh goto release_region; 6875762613eSGovind Singh } 6885762613eSGovind Singh 6895762613eSGovind Singh pci_set_master(pdev); 6905762613eSGovind Singh 6915762613eSGovind Singh ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); 6925762613eSGovind Singh ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); 6935762613eSGovind Singh if (!ab->mem) { 6945762613eSGovind Singh ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); 6955762613eSGovind Singh ret = -EIO; 6965762613eSGovind Singh goto clear_master; 6975762613eSGovind Singh } 6985762613eSGovind Singh 6995762613eSGovind Singh ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); 7005762613eSGovind Singh return 0; 7015762613eSGovind Singh 7025762613eSGovind Singh clear_master: 7035762613eSGovind Singh pci_clear_master(pdev); 7045762613eSGovind Singh release_region: 7055762613eSGovind Singh pci_release_region(pdev, ATH11K_PCI_BAR_NUM); 7065762613eSGovind Singh disable_device: 7075762613eSGovind Singh pci_disable_device(pdev); 7085762613eSGovind Singh out: 7095762613eSGovind Singh return ret; 7105762613eSGovind Singh } 7115762613eSGovind Singh 7125762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) 7135762613eSGovind Singh { 7145762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 7155762613eSGovind Singh struct pci_dev *pci_dev = ab_pci->pdev; 7165762613eSGovind Singh 7175762613eSGovind Singh pci_iounmap(pci_dev, ab->mem); 7185762613eSGovind Singh ab->mem = NULL; 7195762613eSGovind Singh pci_clear_master(pci_dev); 7205762613eSGovind Singh pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); 7215762613eSGovind Singh if (pci_is_enabled(pci_dev)) 7225762613eSGovind Singh pci_disable_device(pci_dev); 7235762613eSGovind Singh } 7245762613eSGovind Singh 7251399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab) 7261399fb87SGovind Singh { 7271399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 7281399fb87SGovind Singh int ret; 7291399fb87SGovind Singh 730f3c603d4SCarl Huang ath11k_pci_sw_reset(ab_pci->ab); 731f3c603d4SCarl Huang 7321399fb87SGovind Singh ret = ath11k_mhi_start(ab_pci); 7331399fb87SGovind Singh if (ret) { 7341399fb87SGovind Singh ath11k_err(ab, "failed to start mhi: %d\n", ret); 7351399fb87SGovind Singh return ret; 7361399fb87SGovind Singh } 7371399fb87SGovind Singh 7381399fb87SGovind Singh return 0; 7391399fb87SGovind Singh } 7401399fb87SGovind Singh 7411399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab) 7421399fb87SGovind Singh { 7431399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 7441399fb87SGovind Singh 7451399fb87SGovind Singh ath11k_mhi_stop(ab_pci); 746f3c603d4SCarl Huang ath11k_pci_force_wake(ab_pci->ab); 747f3c603d4SCarl Huang ath11k_pci_sw_reset(ab_pci->ab); 7481399fb87SGovind Singh } 7491399fb87SGovind Singh 7502c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) 7512c3960c2SGovind Singh { 7522c3960c2SGovind Singh int i; 7532c3960c2SGovind Singh 754d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 7552c3960c2SGovind Singh struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; 7562c3960c2SGovind Singh 757e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 7582c3960c2SGovind Singh continue; 7592c3960c2SGovind Singh 7602c3960c2SGovind Singh tasklet_kill(&ce_pipe->intr_tq); 7612c3960c2SGovind Singh } 7622c3960c2SGovind Singh } 7632c3960c2SGovind Singh 7647f4beda2SGovind Singh static void ath11k_pci_stop(struct ath11k_base *ab) 7657f4beda2SGovind Singh { 7662c3960c2SGovind Singh ath11k_pci_ce_irqs_disable(ab); 7672c3960c2SGovind Singh ath11k_pci_sync_ce_irqs(ab); 7682c3960c2SGovind Singh ath11k_pci_kill_tasklets(ab); 7697f4beda2SGovind Singh ath11k_ce_cleanup_pipes(ab); 7707f4beda2SGovind Singh } 7717f4beda2SGovind Singh 7727f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab) 7737f4beda2SGovind Singh { 7747f4beda2SGovind Singh ath11k_pci_ce_irqs_enable(ab); 7752c3960c2SGovind Singh ath11k_ce_rx_post_buf(ab); 7762c3960c2SGovind Singh 7772c3960c2SGovind Singh return 0; 7782c3960c2SGovind Singh } 7792c3960c2SGovind Singh 7802c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, 7812c3960c2SGovind Singh u8 *ul_pipe, u8 *dl_pipe) 7822c3960c2SGovind Singh { 7832c3960c2SGovind Singh const struct service_to_pipe *entry; 7842c3960c2SGovind Singh bool ul_set = false, dl_set = false; 7852c3960c2SGovind Singh int i; 7862c3960c2SGovind Singh 787*967c1d11SAnilkumar Kolli for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) { 788*967c1d11SAnilkumar Kolli entry = &ab->hw_params.svc_to_ce_map[i]; 7892c3960c2SGovind Singh 7902c3960c2SGovind Singh if (__le32_to_cpu(entry->service_id) != service_id) 7912c3960c2SGovind Singh continue; 7922c3960c2SGovind Singh 7932c3960c2SGovind Singh switch (__le32_to_cpu(entry->pipedir)) { 7942c3960c2SGovind Singh case PIPEDIR_NONE: 7952c3960c2SGovind Singh break; 7962c3960c2SGovind Singh case PIPEDIR_IN: 7972c3960c2SGovind Singh WARN_ON(dl_set); 7982c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 7992c3960c2SGovind Singh dl_set = true; 8002c3960c2SGovind Singh break; 8012c3960c2SGovind Singh case PIPEDIR_OUT: 8022c3960c2SGovind Singh WARN_ON(ul_set); 8032c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 8042c3960c2SGovind Singh ul_set = true; 8052c3960c2SGovind Singh break; 8062c3960c2SGovind Singh case PIPEDIR_INOUT: 8072c3960c2SGovind Singh WARN_ON(dl_set); 8082c3960c2SGovind Singh WARN_ON(ul_set); 8092c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 8102c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 8112c3960c2SGovind Singh dl_set = true; 8122c3960c2SGovind Singh ul_set = true; 8132c3960c2SGovind Singh break; 8142c3960c2SGovind Singh } 8152c3960c2SGovind Singh } 8162c3960c2SGovind Singh 8172c3960c2SGovind Singh if (WARN_ON(!ul_set || !dl_set)) 8182c3960c2SGovind Singh return -ENOENT; 8197f4beda2SGovind Singh 8207f4beda2SGovind Singh return 0; 8217f4beda2SGovind Singh } 8227f4beda2SGovind Singh 8237f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = { 8247f4beda2SGovind Singh .start = ath11k_pci_start, 8257f4beda2SGovind Singh .stop = ath11k_pci_stop, 826654e959aSGovind Singh .read32 = ath11k_pci_read32, 827654e959aSGovind Singh .write32 = ath11k_pci_write32, 8281399fb87SGovind Singh .power_down = ath11k_pci_power_down, 8291399fb87SGovind Singh .power_up = ath11k_pci_power_up, 830d4ecb90bSCarl Huang .irq_enable = ath11k_pci_ext_irq_enable, 831d4ecb90bSCarl Huang .irq_disable = ath11k_pci_ext_irq_disable, 832c4eacabeSGovind Singh .get_msi_address = ath11k_pci_get_msi_address, 833c4eacabeSGovind Singh .get_user_msi_vector = ath11k_get_user_msi_assignment, 8342c3960c2SGovind Singh .map_service_to_pipe = ath11k_pci_map_service_to_pipe, 8351399fb87SGovind Singh }; 8361399fb87SGovind Singh 8376e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev, 8386e0355afSGovind Singh const struct pci_device_id *pci_dev) 8396e0355afSGovind Singh { 8406e0355afSGovind Singh struct ath11k_base *ab; 8415762613eSGovind Singh struct ath11k_pci *ab_pci; 8426e0355afSGovind Singh enum ath11k_hw_rev hw_rev; 8435762613eSGovind Singh int ret; 8446e0355afSGovind Singh 8456e0355afSGovind Singh dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n"); 8466e0355afSGovind Singh 8476e0355afSGovind Singh switch (pci_dev->device) { 8486e0355afSGovind Singh case QCA6390_DEVICE_ID: 8496e0355afSGovind Singh hw_rev = ATH11K_HW_QCA6390_HW20; 8506e0355afSGovind Singh break; 8516e0355afSGovind Singh default: 8526e0355afSGovind Singh dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", 8536e0355afSGovind Singh pci_dev->device); 8546e0355afSGovind Singh return -ENOTSUPP; 8556e0355afSGovind Singh } 8566e0355afSGovind Singh 8571ff8ed78SGovind Singh ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, 8581ff8ed78SGovind Singh &ath11k_pci_bus_params); 8596e0355afSGovind Singh if (!ab) { 8606e0355afSGovind Singh dev_err(&pdev->dev, "failed to allocate ath11k base\n"); 8616e0355afSGovind Singh return -ENOMEM; 8626e0355afSGovind Singh } 8636e0355afSGovind Singh 8646e0355afSGovind Singh ab->dev = &pdev->dev; 8656e0355afSGovind Singh ab->hw_rev = hw_rev; 8666e0355afSGovind Singh pci_set_drvdata(pdev, ab); 8675762613eSGovind Singh ab_pci = ath11k_pci_priv(ab); 8685762613eSGovind Singh ab_pci->dev_id = pci_dev->device; 8695762613eSGovind Singh ab_pci->ab = ab; 8705697a564SGovind Singh ab_pci->pdev = pdev; 8717f4beda2SGovind Singh ab->hif.ops = &ath11k_pci_hif_ops; 8725762613eSGovind Singh pci_set_drvdata(pdev, ab); 873654e959aSGovind Singh spin_lock_init(&ab_pci->window_lock); 8745762613eSGovind Singh 8755762613eSGovind Singh ret = ath11k_pci_claim(ab_pci, pdev); 8765762613eSGovind Singh if (ret) { 8775762613eSGovind Singh ath11k_err(ab, "failed to claim device: %d\n", ret); 8785762613eSGovind Singh goto err_free_core; 8795762613eSGovind Singh } 8806e0355afSGovind Singh 8815697a564SGovind Singh ret = ath11k_pci_enable_msi(ab_pci); 8825697a564SGovind Singh if (ret) { 8835697a564SGovind Singh ath11k_err(ab, "failed to enable msi: %d\n", ret); 8845697a564SGovind Singh goto err_pci_free_region; 8855697a564SGovind Singh } 8865697a564SGovind Singh 887b8246f88SKalle Valo ret = ath11k_core_pre_init(ab); 888b8246f88SKalle Valo if (ret) 889b8246f88SKalle Valo goto err_pci_disable_msi; 890b8246f88SKalle Valo 8911399fb87SGovind Singh ret = ath11k_mhi_register(ab_pci); 8921399fb87SGovind Singh if (ret) { 8931399fb87SGovind Singh ath11k_err(ab, "failed to register mhi: %d\n", ret); 8941399fb87SGovind Singh goto err_pci_disable_msi; 8951399fb87SGovind Singh } 8961399fb87SGovind Singh 8977f4beda2SGovind Singh ret = ath11k_hal_srng_init(ab); 8987f4beda2SGovind Singh if (ret) 8997f4beda2SGovind Singh goto err_mhi_unregister; 9007f4beda2SGovind Singh 9017f4beda2SGovind Singh ret = ath11k_ce_alloc_pipes(ab); 9027f4beda2SGovind Singh if (ret) { 9037f4beda2SGovind Singh ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret); 9047f4beda2SGovind Singh goto err_hal_srng_deinit; 9057f4beda2SGovind Singh } 9067f4beda2SGovind Singh 9077f4beda2SGovind Singh ath11k_pci_init_qmi_ce_config(ab); 9087f4beda2SGovind Singh 9097f4beda2SGovind Singh ret = ath11k_pci_config_irq(ab); 9107f4beda2SGovind Singh if (ret) { 9117f4beda2SGovind Singh ath11k_err(ab, "failed to config irq: %d\n", ret); 9127f4beda2SGovind Singh goto err_ce_free; 9137f4beda2SGovind Singh } 9147f4beda2SGovind Singh 9157f4beda2SGovind Singh ret = ath11k_core_init(ab); 9167f4beda2SGovind Singh if (ret) { 9177f4beda2SGovind Singh ath11k_err(ab, "failed to init core: %d\n", ret); 9187f4beda2SGovind Singh goto err_free_irq; 9197f4beda2SGovind Singh } 9206e0355afSGovind Singh return 0; 9215762613eSGovind Singh 9227f4beda2SGovind Singh err_free_irq: 9237f4beda2SGovind Singh ath11k_pci_free_irq(ab); 9247f4beda2SGovind Singh 9257f4beda2SGovind Singh err_ce_free: 9267f4beda2SGovind Singh ath11k_ce_free_pipes(ab); 9277f4beda2SGovind Singh 9287f4beda2SGovind Singh err_hal_srng_deinit: 9297f4beda2SGovind Singh ath11k_hal_srng_deinit(ab); 9307f4beda2SGovind Singh 9317f4beda2SGovind Singh err_mhi_unregister: 9327f4beda2SGovind Singh ath11k_mhi_unregister(ab_pci); 9337f4beda2SGovind Singh 934b8246f88SKalle Valo err_pci_disable_msi: 935b8246f88SKalle Valo ath11k_pci_disable_msi(ab_pci); 936b8246f88SKalle Valo 9375697a564SGovind Singh err_pci_free_region: 9385697a564SGovind Singh ath11k_pci_free_region(ab_pci); 9395697a564SGovind Singh 9405762613eSGovind Singh err_free_core: 9415762613eSGovind Singh ath11k_core_free(ab); 9425697a564SGovind Singh 9435762613eSGovind Singh return ret; 9446e0355afSGovind Singh } 9456e0355afSGovind Singh 9466e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev) 9476e0355afSGovind Singh { 9486e0355afSGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 9495762613eSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 9506e0355afSGovind Singh 9516e0355afSGovind Singh set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); 9521399fb87SGovind Singh ath11k_mhi_unregister(ab_pci); 9535697a564SGovind Singh ath11k_pci_disable_msi(ab_pci); 9545762613eSGovind Singh ath11k_pci_free_region(ab_pci); 9557f4beda2SGovind Singh ath11k_pci_free_irq(ab); 9566e0355afSGovind Singh ath11k_core_free(ab); 9576e0355afSGovind Singh } 9586e0355afSGovind Singh 9591399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev) 9601399fb87SGovind Singh { 9611399fb87SGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 9621399fb87SGovind Singh 9631399fb87SGovind Singh ath11k_pci_power_down(ab); 9641399fb87SGovind Singh } 9651399fb87SGovind Singh 9666e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = { 9676e0355afSGovind Singh .name = "ath11k_pci", 9686e0355afSGovind Singh .id_table = ath11k_pci_id_table, 9696e0355afSGovind Singh .probe = ath11k_pci_probe, 9706e0355afSGovind Singh .remove = ath11k_pci_remove, 9711399fb87SGovind Singh .shutdown = ath11k_pci_shutdown, 9726e0355afSGovind Singh }; 9736e0355afSGovind Singh 9746e0355afSGovind Singh static int ath11k_pci_init(void) 9756e0355afSGovind Singh { 9766e0355afSGovind Singh int ret; 9776e0355afSGovind Singh 9786e0355afSGovind Singh ret = pci_register_driver(&ath11k_pci_driver); 9796e0355afSGovind Singh if (ret) 9806e0355afSGovind Singh pr_err("failed to register ath11k pci driver: %d\n", 9816e0355afSGovind Singh ret); 9826e0355afSGovind Singh 9836e0355afSGovind Singh return ret; 9846e0355afSGovind Singh } 9856e0355afSGovind Singh module_init(ath11k_pci_init); 9866e0355afSGovind Singh 9876e0355afSGovind Singh static void ath11k_pci_exit(void) 9886e0355afSGovind Singh { 9896e0355afSGovind Singh pci_unregister_driver(&ath11k_pci_driver); 9906e0355afSGovind Singh } 9916e0355afSGovind Singh 9926e0355afSGovind Singh module_exit(ath11k_pci_exit); 9936e0355afSGovind Singh 9946e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); 9956e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL"); 996