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 27*18ac1665SKalle Valo #define TCSR_SOC_HW_VERSION 0x0224 28*18ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(16, 8) 29*18ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0) 30*18ac1665SKalle Valo 316e0355afSGovind Singh #define QCA6390_DEVICE_ID 0x1101 326e0355afSGovind Singh 336e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = { 346e0355afSGovind Singh { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, 356e0355afSGovind Singh {0} 366e0355afSGovind Singh }; 376e0355afSGovind Singh 386e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); 396e0355afSGovind Singh 401ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = { 411ff8ed78SGovind Singh .mhi_support = true, 4256970454SGovind Singh .m3_fw_support = true, 436eb6ea51SGovind Singh .fixed_bdf_addr = false, 446eb6ea51SGovind Singh .fixed_mem_region = false, 451ff8ed78SGovind Singh }; 461ff8ed78SGovind Singh 475697a564SGovind Singh static const struct ath11k_msi_config msi_config = { 485697a564SGovind Singh .total_vectors = 32, 495697a564SGovind Singh .total_users = 4, 505697a564SGovind Singh .users = (struct ath11k_msi_user[]) { 515697a564SGovind Singh { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 525697a564SGovind Singh { .name = "CE", .num_vectors = 10, .base_vector = 3 }, 535697a564SGovind Singh { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, 545697a564SGovind Singh { .name = "DP", .num_vectors = 18, .base_vector = 14 }, 555697a564SGovind Singh }, 565697a564SGovind Singh }; 575697a564SGovind Singh 587f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { 597f4beda2SGovind Singh "bhi", 607f4beda2SGovind Singh "mhi-er0", 617f4beda2SGovind Singh "mhi-er1", 627f4beda2SGovind Singh "ce0", 637f4beda2SGovind Singh "ce1", 647f4beda2SGovind Singh "ce2", 657f4beda2SGovind Singh "ce3", 667f4beda2SGovind Singh "ce4", 677f4beda2SGovind Singh "ce5", 687f4beda2SGovind Singh "ce6", 697f4beda2SGovind Singh "ce7", 707f4beda2SGovind Singh "ce8", 717f4beda2SGovind Singh "ce9", 727f4beda2SGovind Singh "ce10", 737f4beda2SGovind Singh "ce11", 747f4beda2SGovind Singh "host2wbm-desc-feed", 757f4beda2SGovind Singh "host2reo-re-injection", 767f4beda2SGovind Singh "host2reo-command", 777f4beda2SGovind Singh "host2rxdma-monitor-ring3", 787f4beda2SGovind Singh "host2rxdma-monitor-ring2", 797f4beda2SGovind Singh "host2rxdma-monitor-ring1", 807f4beda2SGovind Singh "reo2ost-exception", 817f4beda2SGovind Singh "wbm2host-rx-release", 827f4beda2SGovind Singh "reo2host-status", 837f4beda2SGovind Singh "reo2host-destination-ring4", 847f4beda2SGovind Singh "reo2host-destination-ring3", 857f4beda2SGovind Singh "reo2host-destination-ring2", 867f4beda2SGovind Singh "reo2host-destination-ring1", 877f4beda2SGovind Singh "rxdma2host-monitor-destination-mac3", 887f4beda2SGovind Singh "rxdma2host-monitor-destination-mac2", 897f4beda2SGovind Singh "rxdma2host-monitor-destination-mac1", 907f4beda2SGovind Singh "ppdu-end-interrupts-mac3", 917f4beda2SGovind Singh "ppdu-end-interrupts-mac2", 927f4beda2SGovind Singh "ppdu-end-interrupts-mac1", 937f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac3", 947f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac2", 957f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac1", 967f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac3", 977f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac2", 987f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac1", 997f4beda2SGovind Singh "rxdma2host-destination-ring-mac3", 1007f4beda2SGovind Singh "rxdma2host-destination-ring-mac2", 1017f4beda2SGovind Singh "rxdma2host-destination-ring-mac1", 1027f4beda2SGovind Singh "host2tcl-input-ring4", 1037f4beda2SGovind Singh "host2tcl-input-ring3", 1047f4beda2SGovind Singh "host2tcl-input-ring2", 1057f4beda2SGovind Singh "host2tcl-input-ring1", 1067f4beda2SGovind Singh "wbm2host-tx-completions-ring3", 1077f4beda2SGovind Singh "wbm2host-tx-completions-ring2", 1087f4beda2SGovind Singh "wbm2host-tx-completions-ring1", 1097f4beda2SGovind Singh "tcl2host-status-ring", 1107f4beda2SGovind Singh }; 1117f4beda2SGovind Singh 112654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset) 113654e959aSGovind Singh { 114654e959aSGovind Singh struct ath11k_base *ab = ab_pci->ab; 115654e959aSGovind Singh 116654e959aSGovind Singh u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset); 117654e959aSGovind Singh 118654e959aSGovind Singh lockdep_assert_held(&ab_pci->window_lock); 119654e959aSGovind Singh 120654e959aSGovind Singh if (window != ab_pci->register_window) { 121654e959aSGovind Singh iowrite32(WINDOW_ENABLE_BIT | window, 122654e959aSGovind Singh ab->mem + WINDOW_REG_ADDRESS); 123654e959aSGovind Singh ab_pci->register_window = window; 124654e959aSGovind Singh } 125654e959aSGovind Singh } 126654e959aSGovind Singh 127f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) 128654e959aSGovind Singh { 129654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 130654e959aSGovind Singh 131654e959aSGovind Singh if (offset < WINDOW_START) { 132654e959aSGovind Singh iowrite32(value, ab->mem + offset); 133654e959aSGovind Singh } else { 134654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 135654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 136654e959aSGovind Singh iowrite32(value, ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK)); 137654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 138654e959aSGovind Singh } 139654e959aSGovind Singh } 140654e959aSGovind Singh 141f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) 142654e959aSGovind Singh { 143654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 144654e959aSGovind Singh u32 val; 145654e959aSGovind Singh 146654e959aSGovind Singh if (offset < WINDOW_START) { 147654e959aSGovind Singh val = ioread32(ab->mem + offset); 148654e959aSGovind Singh } else { 149654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 150654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 151654e959aSGovind Singh val = ioread32(ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK)); 152654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 153654e959aSGovind Singh } 154654e959aSGovind Singh 155654e959aSGovind Singh return val; 156654e959aSGovind Singh } 157654e959aSGovind Singh 158f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) 159f3c603d4SCarl Huang { 160f3c603d4SCarl Huang u32 val, delay; 161f3c603d4SCarl Huang 162f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 163f3c603d4SCarl Huang 164f3c603d4SCarl Huang val |= PCIE_SOC_GLOBAL_RESET_V; 165f3c603d4SCarl Huang 166f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 167f3c603d4SCarl Huang 168f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 169f3c603d4SCarl Huang delay = 10; 170f3c603d4SCarl Huang mdelay(delay); 171f3c603d4SCarl Huang 172f3c603d4SCarl Huang /* Need to toggle V bit back otherwise stuck in reset status */ 173f3c603d4SCarl Huang val &= ~PCIE_SOC_GLOBAL_RESET_V; 174f3c603d4SCarl Huang 175f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 176f3c603d4SCarl Huang 177f3c603d4SCarl Huang mdelay(delay); 178f3c603d4SCarl Huang 179f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 180f3c603d4SCarl Huang if (val == 0xffffffff) 181f3c603d4SCarl Huang ath11k_warn(ab, "link down error during global reset\n"); 182f3c603d4SCarl Huang } 183f3c603d4SCarl Huang 184f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) 185f3c603d4SCarl Huang { 186f3c603d4SCarl Huang u32 val; 187f3c603d4SCarl Huang 188f3c603d4SCarl Huang /* read cookie */ 189f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR); 190f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val); 191f3c603d4SCarl Huang 192f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 193f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 194f3c603d4SCarl Huang 195f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 196f3c603d4SCarl Huang mdelay(10); 197f3c603d4SCarl Huang 198f3c603d4SCarl Huang /* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from 199f3c603d4SCarl Huang * continuing warm path and entering dead loop. 200f3c603d4SCarl Huang */ 201f3c603d4SCarl Huang ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0); 202f3c603d4SCarl Huang mdelay(10); 203f3c603d4SCarl Huang 204f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 205f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 206f3c603d4SCarl Huang 207f3c603d4SCarl Huang /* A read clear register. clear the register to prevent 208f3c603d4SCarl Huang * Q6 from entering wrong code path. 209f3c603d4SCarl Huang */ 210f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG); 211f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val); 212f3c603d4SCarl Huang } 213f3c603d4SCarl Huang 214f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab) 215f3c603d4SCarl Huang { 216f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1); 217f3c603d4SCarl Huang mdelay(5); 218f3c603d4SCarl Huang } 219f3c603d4SCarl Huang 220f3c603d4SCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab) 221f3c603d4SCarl Huang { 222f3c603d4SCarl Huang ath11k_pci_soc_global_reset(ab); 223f3c603d4SCarl Huang ath11k_mhi_clear_vector(ab); 224f3c603d4SCarl Huang ath11k_pci_soc_global_reset(ab); 225f3c603d4SCarl Huang ath11k_mhi_set_mhictrl_reset(ab); 226f3c603d4SCarl Huang ath11k_pci_clear_dbg_registers(ab); 227f3c603d4SCarl Huang } 228f3c603d4SCarl Huang 2291399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) 2301399fb87SGovind Singh { 2311399fb87SGovind Singh struct pci_dev *pci_dev = to_pci_dev(dev); 2321399fb87SGovind Singh 2331399fb87SGovind Singh return pci_irq_vector(pci_dev, vector); 2341399fb87SGovind Singh } 2351399fb87SGovind Singh 236c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, 237c4eacabeSGovind Singh u32 *msi_addr_hi) 238c4eacabeSGovind Singh { 239c4eacabeSGovind Singh struct pci_dev *pci_dev = to_pci_dev(ab->dev); 240c4eacabeSGovind Singh 241c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, 242c4eacabeSGovind Singh msi_addr_lo); 243c4eacabeSGovind Singh 244c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, 245c4eacabeSGovind Singh msi_addr_hi); 246c4eacabeSGovind Singh } 247c4eacabeSGovind Singh 2481399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, 2491399fb87SGovind Singh int *num_vectors, u32 *user_base_data, 2501399fb87SGovind Singh u32 *base_vector) 2511399fb87SGovind Singh { 2521399fb87SGovind Singh struct ath11k_base *ab = ab_pci->ab; 2531399fb87SGovind Singh int idx; 2541399fb87SGovind Singh 2551399fb87SGovind Singh for (idx = 0; idx < msi_config.total_users; idx++) { 2561399fb87SGovind Singh if (strcmp(user_name, msi_config.users[idx].name) == 0) { 2571399fb87SGovind Singh *num_vectors = msi_config.users[idx].num_vectors; 2581399fb87SGovind Singh *user_base_data = msi_config.users[idx].base_vector 2591399fb87SGovind Singh + ab_pci->msi_ep_base_data; 2601399fb87SGovind Singh *base_vector = msi_config.users[idx].base_vector; 2611399fb87SGovind Singh 2621399fb87SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", 2631399fb87SGovind Singh user_name, *num_vectors, *user_base_data, 2641399fb87SGovind Singh *base_vector); 2651399fb87SGovind Singh 2661399fb87SGovind Singh return 0; 2671399fb87SGovind Singh } 2681399fb87SGovind Singh } 2691399fb87SGovind Singh 2701399fb87SGovind Singh ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name); 2711399fb87SGovind Singh 2721399fb87SGovind Singh return -EINVAL; 2731399fb87SGovind Singh } 2741399fb87SGovind Singh 275c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, 276c4eacabeSGovind Singh int *num_vectors, u32 *user_base_data, 277c4eacabeSGovind Singh u32 *base_vector) 278c4eacabeSGovind Singh { 279c4eacabeSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 280c4eacabeSGovind Singh 281c4eacabeSGovind Singh return ath11k_pci_get_user_msi_assignment(ab_pci, user_name, 282c4eacabeSGovind Singh num_vectors, user_base_data, 283c4eacabeSGovind Singh base_vector); 284c4eacabeSGovind Singh } 285c4eacabeSGovind Singh 286d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab) 287d4ecb90bSCarl Huang { 288d4ecb90bSCarl Huang int i, j; 289d4ecb90bSCarl Huang 290d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 291d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 292d4ecb90bSCarl Huang 293d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) 294d4ecb90bSCarl Huang free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); 295d4ecb90bSCarl Huang 296d4ecb90bSCarl Huang netif_napi_del(&irq_grp->napi); 297d4ecb90bSCarl Huang } 298d4ecb90bSCarl Huang } 299d4ecb90bSCarl Huang 3007f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab) 3017f4beda2SGovind Singh { 3027f4beda2SGovind Singh int i, irq_idx; 3037f4beda2SGovind Singh 304d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 305e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 3067f4beda2SGovind Singh continue; 3077f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 3087f4beda2SGovind Singh free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); 3097f4beda2SGovind Singh } 310d4ecb90bSCarl Huang 311d4ecb90bSCarl Huang ath11k_pci_free_ext_irq(ab); 3127f4beda2SGovind Singh } 3137f4beda2SGovind Singh 3142c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) 3152c3960c2SGovind Singh { 3162c3960c2SGovind Singh u32 irq_idx; 3172c3960c2SGovind Singh 3182c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 3192c3960c2SGovind Singh enable_irq(ab->irq_num[irq_idx]); 3202c3960c2SGovind Singh } 3212c3960c2SGovind Singh 3227f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) 3237f4beda2SGovind Singh { 3247f4beda2SGovind Singh u32 irq_idx; 3257f4beda2SGovind Singh 3267f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 3277f4beda2SGovind Singh disable_irq_nosync(ab->irq_num[irq_idx]); 3287f4beda2SGovind Singh } 3297f4beda2SGovind Singh 3302c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab) 3312c3960c2SGovind Singh { 3322c3960c2SGovind Singh int i; 3332c3960c2SGovind Singh 334d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 335e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 3362c3960c2SGovind Singh continue; 3372c3960c2SGovind Singh ath11k_pci_ce_irq_disable(ab, i); 3382c3960c2SGovind Singh } 3392c3960c2SGovind Singh } 3402c3960c2SGovind Singh 3412c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) 3422c3960c2SGovind Singh { 3432c3960c2SGovind Singh int i; 3442c3960c2SGovind Singh int irq_idx; 3452c3960c2SGovind Singh 346d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 347e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 3482c3960c2SGovind Singh continue; 3492c3960c2SGovind Singh 3502c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 3512c3960c2SGovind Singh synchronize_irq(ab->irq_num[irq_idx]); 3522c3960c2SGovind Singh } 3532c3960c2SGovind Singh } 3542c3960c2SGovind Singh 3552c3960c2SGovind Singh static void ath11k_pci_ce_tasklet(unsigned long data) 3562c3960c2SGovind Singh { 3572c3960c2SGovind Singh struct ath11k_ce_pipe *ce_pipe = (struct ath11k_ce_pipe *)data; 3582c3960c2SGovind Singh 3592c3960c2SGovind Singh ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); 3602c3960c2SGovind Singh 3612c3960c2SGovind Singh ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num); 3622c3960c2SGovind Singh } 3632c3960c2SGovind Singh 3647f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) 3657f4beda2SGovind Singh { 3667f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe = arg; 3677f4beda2SGovind Singh 3687f4beda2SGovind Singh ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num); 3692c3960c2SGovind Singh tasklet_schedule(&ce_pipe->intr_tq); 3707f4beda2SGovind Singh 3717f4beda2SGovind Singh return IRQ_HANDLED; 3727f4beda2SGovind Singh } 3737f4beda2SGovind Singh 374d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) 375d4ecb90bSCarl Huang { 376d4ecb90bSCarl Huang int i; 377d4ecb90bSCarl Huang 378d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 379d4ecb90bSCarl Huang disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 380d4ecb90bSCarl Huang } 381d4ecb90bSCarl Huang 382d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc) 383d4ecb90bSCarl Huang { 384d4ecb90bSCarl Huang int i; 385d4ecb90bSCarl Huang 386d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 387d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; 388d4ecb90bSCarl Huang 389d4ecb90bSCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 390d4ecb90bSCarl Huang 391d4ecb90bSCarl Huang napi_synchronize(&irq_grp->napi); 392d4ecb90bSCarl Huang napi_disable(&irq_grp->napi); 393d4ecb90bSCarl Huang } 394d4ecb90bSCarl Huang } 395d4ecb90bSCarl Huang 396d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) 397d4ecb90bSCarl Huang { 398d4ecb90bSCarl Huang int i; 399d4ecb90bSCarl Huang 400d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 401d4ecb90bSCarl Huang enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 402d4ecb90bSCarl Huang } 403d4ecb90bSCarl Huang 404d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab) 405d4ecb90bSCarl Huang { 406d4ecb90bSCarl Huang int i; 407d4ecb90bSCarl Huang 408d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 409d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 410d4ecb90bSCarl Huang 411d4ecb90bSCarl Huang napi_enable(&irq_grp->napi); 412d4ecb90bSCarl Huang ath11k_pci_ext_grp_enable(irq_grp); 413d4ecb90bSCarl Huang } 414d4ecb90bSCarl Huang } 415d4ecb90bSCarl Huang 416d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab) 417d4ecb90bSCarl Huang { 418d4ecb90bSCarl Huang int i, j, irq_idx; 419d4ecb90bSCarl Huang 420d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 421d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 422d4ecb90bSCarl Huang 423d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 424d4ecb90bSCarl Huang irq_idx = irq_grp->irqs[j]; 425d4ecb90bSCarl Huang synchronize_irq(ab->irq_num[irq_idx]); 426d4ecb90bSCarl Huang } 427d4ecb90bSCarl Huang } 428d4ecb90bSCarl Huang } 429d4ecb90bSCarl Huang 430d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab) 431d4ecb90bSCarl Huang { 432d4ecb90bSCarl Huang __ath11k_pci_ext_irq_disable(ab); 433d4ecb90bSCarl Huang ath11k_pci_sync_ext_irqs(ab); 434d4ecb90bSCarl Huang } 435d4ecb90bSCarl Huang 436d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) 437d4ecb90bSCarl Huang { 438d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = container_of(napi, 439d4ecb90bSCarl Huang struct ath11k_ext_irq_grp, 440d4ecb90bSCarl Huang napi); 441d4ecb90bSCarl Huang struct ath11k_base *ab = irq_grp->ab; 442d4ecb90bSCarl Huang int work_done; 443d4ecb90bSCarl Huang 444d4ecb90bSCarl Huang work_done = ath11k_dp_service_srng(ab, irq_grp, budget); 445d4ecb90bSCarl Huang if (work_done < budget) { 446d4ecb90bSCarl Huang napi_complete_done(napi, work_done); 447d4ecb90bSCarl Huang ath11k_pci_ext_grp_enable(irq_grp); 448d4ecb90bSCarl Huang } 449d4ecb90bSCarl Huang 450d4ecb90bSCarl Huang if (work_done > budget) 451d4ecb90bSCarl Huang work_done = budget; 452d4ecb90bSCarl Huang 453d4ecb90bSCarl Huang return work_done; 454d4ecb90bSCarl Huang } 455d4ecb90bSCarl Huang 456d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) 457d4ecb90bSCarl Huang { 458d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = arg; 459d4ecb90bSCarl Huang 460d4ecb90bSCarl Huang ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); 461d4ecb90bSCarl Huang 462d4ecb90bSCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 463d4ecb90bSCarl Huang 464d4ecb90bSCarl Huang napi_schedule(&irq_grp->napi); 465d4ecb90bSCarl Huang 466d4ecb90bSCarl Huang return IRQ_HANDLED; 467d4ecb90bSCarl Huang } 468d4ecb90bSCarl Huang 469d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) 470d4ecb90bSCarl Huang { 471d4ecb90bSCarl Huang int i, j, ret, num_vectors = 0; 472d4ecb90bSCarl Huang u32 user_base_data = 0, base_vector = 0; 473d4ecb90bSCarl Huang 474b2c09458SColin Ian King ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", 475b2c09458SColin Ian King &num_vectors, 476b2c09458SColin Ian King &user_base_data, 477d4ecb90bSCarl Huang &base_vector); 478b2c09458SColin Ian King if (ret < 0) 479b2c09458SColin Ian King return ret; 480d4ecb90bSCarl Huang 481d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 482d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 483d4ecb90bSCarl Huang u32 num_irq = 0; 484d4ecb90bSCarl Huang 485d4ecb90bSCarl Huang irq_grp->ab = ab; 486d4ecb90bSCarl Huang irq_grp->grp_id = i; 487d4ecb90bSCarl Huang init_dummy_netdev(&irq_grp->napi_ndev); 488d4ecb90bSCarl Huang netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, 489d4ecb90bSCarl Huang ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT); 490d4ecb90bSCarl Huang 491d4ecb90bSCarl Huang if (ab->hw_params.ring_mask->tx[i] || 492d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx[i] || 493d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_err[i] || 494d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_wbm_rel[i] || 495d4ecb90bSCarl Huang ab->hw_params.ring_mask->reo_status[i] || 496d4ecb90bSCarl Huang ab->hw_params.ring_mask->rxdma2host[i] || 497d4ecb90bSCarl Huang ab->hw_params.ring_mask->host2rxdma[i] || 498d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_mon_status[i]) { 499d4ecb90bSCarl Huang num_irq = 1; 500d4ecb90bSCarl Huang } 501d4ecb90bSCarl Huang 502d4ecb90bSCarl Huang irq_grp->num_irq = num_irq; 503d4ecb90bSCarl Huang irq_grp->irqs[0] = base_vector + i; 504d4ecb90bSCarl Huang 505d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 506d4ecb90bSCarl Huang int irq_idx = irq_grp->irqs[j]; 507d4ecb90bSCarl Huang int vector = (i % num_vectors) + base_vector; 508d4ecb90bSCarl Huang int irq = ath11k_pci_get_msi_irq(ab->dev, vector); 509d4ecb90bSCarl Huang 510d4ecb90bSCarl Huang ab->irq_num[irq_idx] = irq; 511d4ecb90bSCarl Huang 512d4ecb90bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, 513d4ecb90bSCarl Huang "irq:%d group:%d\n", irq, i); 514d4ecb90bSCarl Huang ret = request_irq(irq, ath11k_pci_ext_interrupt_handler, 515d4ecb90bSCarl Huang IRQF_SHARED, 516d4ecb90bSCarl Huang "DP_EXT_IRQ", irq_grp); 517d4ecb90bSCarl Huang if (ret) { 518d4ecb90bSCarl Huang ath11k_err(ab, "failed request irq %d: %d\n", 519d4ecb90bSCarl Huang vector, ret); 520d4ecb90bSCarl Huang return ret; 521d4ecb90bSCarl Huang } 522d4ecb90bSCarl Huang 523d4ecb90bSCarl Huang disable_irq_nosync(ab->irq_num[irq_idx]); 524d4ecb90bSCarl Huang } 525d4ecb90bSCarl Huang } 526d4ecb90bSCarl Huang 527d4ecb90bSCarl Huang return 0; 528d4ecb90bSCarl Huang } 529d4ecb90bSCarl Huang 5307f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab) 5317f4beda2SGovind Singh { 5327f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe; 5337f4beda2SGovind Singh u32 msi_data_start; 5347f4beda2SGovind Singh u32 msi_data_count; 5357f4beda2SGovind Singh u32 msi_irq_start; 5367f4beda2SGovind Singh unsigned int msi_data; 5377f4beda2SGovind Singh int irq, i, ret, irq_idx; 5387f4beda2SGovind Singh 5397f4beda2SGovind Singh ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), 5407f4beda2SGovind Singh "CE", &msi_data_count, 5417f4beda2SGovind Singh &msi_data_start, &msi_irq_start); 5427f4beda2SGovind Singh if (ret) 5437f4beda2SGovind Singh return ret; 5447f4beda2SGovind Singh 5457f4beda2SGovind Singh /* Configure CE irqs */ 546d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 5477f4beda2SGovind Singh msi_data = (i % msi_data_count) + msi_irq_start; 5487f4beda2SGovind Singh irq = ath11k_pci_get_msi_irq(ab->dev, msi_data); 5497f4beda2SGovind Singh ce_pipe = &ab->ce.ce_pipe[i]; 5507f4beda2SGovind Singh 551e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5527f4beda2SGovind Singh continue; 5537f4beda2SGovind Singh 5547f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 5557f4beda2SGovind Singh 5562c3960c2SGovind Singh tasklet_init(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet, 5572c3960c2SGovind Singh (unsigned long)ce_pipe); 5582c3960c2SGovind Singh 5597f4beda2SGovind Singh ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, 5607f4beda2SGovind Singh IRQF_SHARED, irq_name[irq_idx], 5617f4beda2SGovind Singh ce_pipe); 5627f4beda2SGovind Singh if (ret) { 5637f4beda2SGovind Singh ath11k_err(ab, "failed to request irq %d: %d\n", 5647f4beda2SGovind Singh irq_idx, ret); 5657f4beda2SGovind Singh return ret; 5667f4beda2SGovind Singh } 5677f4beda2SGovind Singh 5687f4beda2SGovind Singh ab->irq_num[irq_idx] = irq; 569e5c860e1SCarl Huang ath11k_pci_ce_irq_disable(ab, i); 5707f4beda2SGovind Singh } 5717f4beda2SGovind Singh 572d4ecb90bSCarl Huang ret = ath11k_pci_ext_irq_config(ab); 573d4ecb90bSCarl Huang if (ret) 574d4ecb90bSCarl Huang return ret; 575d4ecb90bSCarl Huang 5767f4beda2SGovind Singh return 0; 5777f4beda2SGovind Singh } 5787f4beda2SGovind Singh 5797f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) 5807f4beda2SGovind Singh { 5817f4beda2SGovind Singh struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; 5827f4beda2SGovind Singh 583967c1d11SAnilkumar Kolli cfg->tgt_ce = ab->hw_params.target_ce_config; 584967c1d11SAnilkumar Kolli cfg->tgt_ce_len = ab->hw_params.target_ce_count; 5857f4beda2SGovind Singh 586967c1d11SAnilkumar Kolli cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map; 587967c1d11SAnilkumar Kolli cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len; 588eb8de049SGovind Singh ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390; 5897f4beda2SGovind Singh } 5907f4beda2SGovind Singh 5917f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) 5927f4beda2SGovind Singh { 5937f4beda2SGovind Singh int i; 5947f4beda2SGovind Singh 595d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 596e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5977f4beda2SGovind Singh continue; 5987f4beda2SGovind Singh ath11k_pci_ce_irq_enable(ab, i); 5997f4beda2SGovind Singh } 6007f4beda2SGovind Singh } 6017f4beda2SGovind Singh 6025697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci) 6035697a564SGovind Singh { 6045697a564SGovind Singh struct ath11k_base *ab = ab_pci->ab; 6055697a564SGovind Singh struct msi_desc *msi_desc; 6065697a564SGovind Singh int num_vectors; 6075697a564SGovind Singh int ret; 6085697a564SGovind Singh 6095697a564SGovind Singh num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 6105697a564SGovind Singh msi_config.total_vectors, 6115697a564SGovind Singh msi_config.total_vectors, 6125697a564SGovind Singh PCI_IRQ_MSI); 6135697a564SGovind Singh if (num_vectors != msi_config.total_vectors) { 6145697a564SGovind Singh ath11k_err(ab, "failed to get %d MSI vectors, only %d available", 6155697a564SGovind Singh msi_config.total_vectors, num_vectors); 6165697a564SGovind Singh 6175697a564SGovind Singh if (num_vectors >= 0) 6185697a564SGovind Singh return -EINVAL; 6195697a564SGovind Singh else 6205697a564SGovind Singh return num_vectors; 6215697a564SGovind Singh } 6225697a564SGovind Singh 6235697a564SGovind Singh msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 6245697a564SGovind Singh if (!msi_desc) { 6255697a564SGovind Singh ath11k_err(ab, "msi_desc is NULL!\n"); 6265697a564SGovind Singh ret = -EINVAL; 6275697a564SGovind Singh goto free_msi_vector; 6285697a564SGovind Singh } 6295697a564SGovind Singh 6305697a564SGovind Singh ab_pci->msi_ep_base_data = msi_desc->msg.data; 6315697a564SGovind Singh 6325697a564SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); 6335697a564SGovind Singh 6345697a564SGovind Singh return 0; 6355697a564SGovind Singh 6365697a564SGovind Singh free_msi_vector: 6375697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 6385697a564SGovind Singh 6395697a564SGovind Singh return ret; 6405697a564SGovind Singh } 6415697a564SGovind Singh 6425697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci) 6435697a564SGovind Singh { 6445697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 6455697a564SGovind Singh } 6465697a564SGovind Singh 6475762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) 6485762613eSGovind Singh { 6495762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 6505762613eSGovind Singh u16 device_id; 6515762613eSGovind Singh int ret = 0; 6525762613eSGovind Singh 6535762613eSGovind Singh pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 6545762613eSGovind Singh if (device_id != ab_pci->dev_id) { 6555762613eSGovind Singh ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", 6565762613eSGovind Singh device_id, ab_pci->dev_id); 6575762613eSGovind Singh ret = -EIO; 6585762613eSGovind Singh goto out; 6595762613eSGovind Singh } 6605762613eSGovind Singh 6615762613eSGovind Singh ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); 6625762613eSGovind Singh if (ret) { 6635762613eSGovind Singh ath11k_err(ab, "failed to assign pci resource: %d\n", ret); 6645762613eSGovind Singh goto out; 6655762613eSGovind Singh } 6665762613eSGovind Singh 6675762613eSGovind Singh ret = pci_enable_device(pdev); 6685762613eSGovind Singh if (ret) { 6695762613eSGovind Singh ath11k_err(ab, "failed to enable pci device: %d\n", ret); 6705762613eSGovind Singh goto out; 6715762613eSGovind Singh } 6725762613eSGovind Singh 6735762613eSGovind Singh ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); 6745762613eSGovind Singh if (ret) { 6755762613eSGovind Singh ath11k_err(ab, "failed to request pci region: %d\n", ret); 6765762613eSGovind Singh goto disable_device; 6775762613eSGovind Singh } 6785762613eSGovind Singh 6795762613eSGovind Singh ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 6805762613eSGovind Singh if (ret) { 6815762613eSGovind Singh ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", 6825762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 6835762613eSGovind Singh goto release_region; 6845762613eSGovind Singh } 6855762613eSGovind Singh 6865762613eSGovind Singh ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 6875762613eSGovind Singh if (ret) { 6885762613eSGovind Singh ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n", 6895762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 6905762613eSGovind Singh goto release_region; 6915762613eSGovind Singh } 6925762613eSGovind Singh 6935762613eSGovind Singh pci_set_master(pdev); 6945762613eSGovind Singh 6955762613eSGovind Singh ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); 6965762613eSGovind Singh ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); 6975762613eSGovind Singh if (!ab->mem) { 6985762613eSGovind Singh ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); 6995762613eSGovind Singh ret = -EIO; 7005762613eSGovind Singh goto clear_master; 7015762613eSGovind Singh } 7025762613eSGovind Singh 7035762613eSGovind Singh ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); 7045762613eSGovind Singh return 0; 7055762613eSGovind Singh 7065762613eSGovind Singh clear_master: 7075762613eSGovind Singh pci_clear_master(pdev); 7085762613eSGovind Singh release_region: 7095762613eSGovind Singh pci_release_region(pdev, ATH11K_PCI_BAR_NUM); 7105762613eSGovind Singh disable_device: 7115762613eSGovind Singh pci_disable_device(pdev); 7125762613eSGovind Singh out: 7135762613eSGovind Singh return ret; 7145762613eSGovind Singh } 7155762613eSGovind Singh 7165762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) 7175762613eSGovind Singh { 7185762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 7195762613eSGovind Singh struct pci_dev *pci_dev = ab_pci->pdev; 7205762613eSGovind Singh 7215762613eSGovind Singh pci_iounmap(pci_dev, ab->mem); 7225762613eSGovind Singh ab->mem = NULL; 7235762613eSGovind Singh pci_clear_master(pci_dev); 7245762613eSGovind Singh pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); 7255762613eSGovind Singh if (pci_is_enabled(pci_dev)) 7265762613eSGovind Singh pci_disable_device(pci_dev); 7275762613eSGovind Singh } 7285762613eSGovind Singh 7291399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab) 7301399fb87SGovind Singh { 7311399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 7321399fb87SGovind Singh int ret; 7331399fb87SGovind Singh 734f3c603d4SCarl Huang ath11k_pci_sw_reset(ab_pci->ab); 735f3c603d4SCarl Huang 7361399fb87SGovind Singh ret = ath11k_mhi_start(ab_pci); 7371399fb87SGovind Singh if (ret) { 7381399fb87SGovind Singh ath11k_err(ab, "failed to start mhi: %d\n", ret); 7391399fb87SGovind Singh return ret; 7401399fb87SGovind Singh } 7411399fb87SGovind Singh 7421399fb87SGovind Singh return 0; 7431399fb87SGovind Singh } 7441399fb87SGovind Singh 7451399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab) 7461399fb87SGovind Singh { 7471399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 7481399fb87SGovind Singh 7491399fb87SGovind Singh ath11k_mhi_stop(ab_pci); 750f3c603d4SCarl Huang ath11k_pci_force_wake(ab_pci->ab); 751f3c603d4SCarl Huang ath11k_pci_sw_reset(ab_pci->ab); 7521399fb87SGovind Singh } 7531399fb87SGovind Singh 7542c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) 7552c3960c2SGovind Singh { 7562c3960c2SGovind Singh int i; 7572c3960c2SGovind Singh 758d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 7592c3960c2SGovind Singh struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; 7602c3960c2SGovind Singh 761e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 7622c3960c2SGovind Singh continue; 7632c3960c2SGovind Singh 7642c3960c2SGovind Singh tasklet_kill(&ce_pipe->intr_tq); 7652c3960c2SGovind Singh } 7662c3960c2SGovind Singh } 7672c3960c2SGovind Singh 7687f4beda2SGovind Singh static void ath11k_pci_stop(struct ath11k_base *ab) 7697f4beda2SGovind Singh { 7702c3960c2SGovind Singh ath11k_pci_ce_irqs_disable(ab); 7712c3960c2SGovind Singh ath11k_pci_sync_ce_irqs(ab); 7722c3960c2SGovind Singh ath11k_pci_kill_tasklets(ab); 7737f4beda2SGovind Singh ath11k_ce_cleanup_pipes(ab); 7747f4beda2SGovind Singh } 7757f4beda2SGovind Singh 7767f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab) 7777f4beda2SGovind Singh { 7787f4beda2SGovind Singh ath11k_pci_ce_irqs_enable(ab); 7792c3960c2SGovind Singh ath11k_ce_rx_post_buf(ab); 7802c3960c2SGovind Singh 7812c3960c2SGovind Singh return 0; 7822c3960c2SGovind Singh } 7832c3960c2SGovind Singh 7842c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, 7852c3960c2SGovind Singh u8 *ul_pipe, u8 *dl_pipe) 7862c3960c2SGovind Singh { 7872c3960c2SGovind Singh const struct service_to_pipe *entry; 7882c3960c2SGovind Singh bool ul_set = false, dl_set = false; 7892c3960c2SGovind Singh int i; 7902c3960c2SGovind Singh 791967c1d11SAnilkumar Kolli for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) { 792967c1d11SAnilkumar Kolli entry = &ab->hw_params.svc_to_ce_map[i]; 7932c3960c2SGovind Singh 7942c3960c2SGovind Singh if (__le32_to_cpu(entry->service_id) != service_id) 7952c3960c2SGovind Singh continue; 7962c3960c2SGovind Singh 7972c3960c2SGovind Singh switch (__le32_to_cpu(entry->pipedir)) { 7982c3960c2SGovind Singh case PIPEDIR_NONE: 7992c3960c2SGovind Singh break; 8002c3960c2SGovind Singh case PIPEDIR_IN: 8012c3960c2SGovind Singh WARN_ON(dl_set); 8022c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 8032c3960c2SGovind Singh dl_set = true; 8042c3960c2SGovind Singh break; 8052c3960c2SGovind Singh case PIPEDIR_OUT: 8062c3960c2SGovind Singh WARN_ON(ul_set); 8072c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 8082c3960c2SGovind Singh ul_set = true; 8092c3960c2SGovind Singh break; 8102c3960c2SGovind Singh case PIPEDIR_INOUT: 8112c3960c2SGovind Singh WARN_ON(dl_set); 8122c3960c2SGovind Singh WARN_ON(ul_set); 8132c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 8142c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 8152c3960c2SGovind Singh dl_set = true; 8162c3960c2SGovind Singh ul_set = true; 8172c3960c2SGovind Singh break; 8182c3960c2SGovind Singh } 8192c3960c2SGovind Singh } 8202c3960c2SGovind Singh 8212c3960c2SGovind Singh if (WARN_ON(!ul_set || !dl_set)) 8222c3960c2SGovind Singh return -ENOENT; 8237f4beda2SGovind Singh 8247f4beda2SGovind Singh return 0; 8257f4beda2SGovind Singh } 8267f4beda2SGovind Singh 8277f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = { 8287f4beda2SGovind Singh .start = ath11k_pci_start, 8297f4beda2SGovind Singh .stop = ath11k_pci_stop, 830654e959aSGovind Singh .read32 = ath11k_pci_read32, 831654e959aSGovind Singh .write32 = ath11k_pci_write32, 8321399fb87SGovind Singh .power_down = ath11k_pci_power_down, 8331399fb87SGovind Singh .power_up = ath11k_pci_power_up, 834d4ecb90bSCarl Huang .irq_enable = ath11k_pci_ext_irq_enable, 835d4ecb90bSCarl Huang .irq_disable = ath11k_pci_ext_irq_disable, 836c4eacabeSGovind Singh .get_msi_address = ath11k_pci_get_msi_address, 837c4eacabeSGovind Singh .get_user_msi_vector = ath11k_get_user_msi_assignment, 8382c3960c2SGovind Singh .map_service_to_pipe = ath11k_pci_map_service_to_pipe, 8391399fb87SGovind Singh }; 8401399fb87SGovind Singh 8416e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev, 8426e0355afSGovind Singh const struct pci_device_id *pci_dev) 8436e0355afSGovind Singh { 8446e0355afSGovind Singh struct ath11k_base *ab; 8455762613eSGovind Singh struct ath11k_pci *ab_pci; 846*18ac1665SKalle Valo u32 soc_hw_version, soc_hw_version_major, soc_hw_version_minor; 8475762613eSGovind Singh int ret; 8486e0355afSGovind Singh 8496e0355afSGovind Singh dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n"); 8506e0355afSGovind Singh 8511ff8ed78SGovind Singh ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, 8521ff8ed78SGovind Singh &ath11k_pci_bus_params); 8536e0355afSGovind Singh if (!ab) { 8546e0355afSGovind Singh dev_err(&pdev->dev, "failed to allocate ath11k base\n"); 8556e0355afSGovind Singh return -ENOMEM; 8566e0355afSGovind Singh } 8576e0355afSGovind Singh 8586e0355afSGovind Singh ab->dev = &pdev->dev; 8596e0355afSGovind Singh pci_set_drvdata(pdev, ab); 8605762613eSGovind Singh ab_pci = ath11k_pci_priv(ab); 8615762613eSGovind Singh ab_pci->dev_id = pci_dev->device; 8625762613eSGovind Singh ab_pci->ab = ab; 8635697a564SGovind Singh ab_pci->pdev = pdev; 8647f4beda2SGovind Singh ab->hif.ops = &ath11k_pci_hif_ops; 8655762613eSGovind Singh pci_set_drvdata(pdev, ab); 866654e959aSGovind Singh spin_lock_init(&ab_pci->window_lock); 8675762613eSGovind Singh 8685762613eSGovind Singh ret = ath11k_pci_claim(ab_pci, pdev); 8695762613eSGovind Singh if (ret) { 8705762613eSGovind Singh ath11k_err(ab, "failed to claim device: %d\n", ret); 8715762613eSGovind Singh goto err_free_core; 8725762613eSGovind Singh } 8736e0355afSGovind Singh 874*18ac1665SKalle Valo switch (pci_dev->device) { 875*18ac1665SKalle Valo case QCA6390_DEVICE_ID: 876*18ac1665SKalle Valo soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION); 877*18ac1665SKalle Valo soc_hw_version_major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK, 878*18ac1665SKalle Valo soc_hw_version); 879*18ac1665SKalle Valo soc_hw_version_minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK, 880*18ac1665SKalle Valo soc_hw_version); 881*18ac1665SKalle Valo 882*18ac1665SKalle Valo ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n", 883*18ac1665SKalle Valo soc_hw_version_major, soc_hw_version_minor); 884*18ac1665SKalle Valo 885*18ac1665SKalle Valo switch (soc_hw_version_major) { 886*18ac1665SKalle Valo case 2: 887*18ac1665SKalle Valo ab->hw_rev = ATH11K_HW_QCA6390_HW20; 888*18ac1665SKalle Valo break; 889*18ac1665SKalle Valo default: 890*18ac1665SKalle Valo dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n", 891*18ac1665SKalle Valo soc_hw_version_major, soc_hw_version_minor); 892*18ac1665SKalle Valo ret = -EOPNOTSUPP; 893*18ac1665SKalle Valo goto err_pci_free_region; 894*18ac1665SKalle Valo } 895*18ac1665SKalle Valo break; 896*18ac1665SKalle Valo default: 897*18ac1665SKalle Valo dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", 898*18ac1665SKalle Valo pci_dev->device); 899*18ac1665SKalle Valo ret = -EOPNOTSUPP; 900*18ac1665SKalle Valo goto err_pci_free_region; 901*18ac1665SKalle Valo } 902*18ac1665SKalle Valo 9035697a564SGovind Singh ret = ath11k_pci_enable_msi(ab_pci); 9045697a564SGovind Singh if (ret) { 9055697a564SGovind Singh ath11k_err(ab, "failed to enable msi: %d\n", ret); 9065697a564SGovind Singh goto err_pci_free_region; 9075697a564SGovind Singh } 9085697a564SGovind Singh 909b8246f88SKalle Valo ret = ath11k_core_pre_init(ab); 910b8246f88SKalle Valo if (ret) 911b8246f88SKalle Valo goto err_pci_disable_msi; 912b8246f88SKalle Valo 9131399fb87SGovind Singh ret = ath11k_mhi_register(ab_pci); 9141399fb87SGovind Singh if (ret) { 9151399fb87SGovind Singh ath11k_err(ab, "failed to register mhi: %d\n", ret); 9161399fb87SGovind Singh goto err_pci_disable_msi; 9171399fb87SGovind Singh } 9181399fb87SGovind Singh 9197f4beda2SGovind Singh ret = ath11k_hal_srng_init(ab); 9207f4beda2SGovind Singh if (ret) 9217f4beda2SGovind Singh goto err_mhi_unregister; 9227f4beda2SGovind Singh 9237f4beda2SGovind Singh ret = ath11k_ce_alloc_pipes(ab); 9247f4beda2SGovind Singh if (ret) { 9257f4beda2SGovind Singh ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret); 9267f4beda2SGovind Singh goto err_hal_srng_deinit; 9277f4beda2SGovind Singh } 9287f4beda2SGovind Singh 9297f4beda2SGovind Singh ath11k_pci_init_qmi_ce_config(ab); 9307f4beda2SGovind Singh 9317f4beda2SGovind Singh ret = ath11k_pci_config_irq(ab); 9327f4beda2SGovind Singh if (ret) { 9337f4beda2SGovind Singh ath11k_err(ab, "failed to config irq: %d\n", ret); 9347f4beda2SGovind Singh goto err_ce_free; 9357f4beda2SGovind Singh } 9367f4beda2SGovind Singh 9377f4beda2SGovind Singh ret = ath11k_core_init(ab); 9387f4beda2SGovind Singh if (ret) { 9397f4beda2SGovind Singh ath11k_err(ab, "failed to init core: %d\n", ret); 9407f4beda2SGovind Singh goto err_free_irq; 9417f4beda2SGovind Singh } 9426e0355afSGovind Singh return 0; 9435762613eSGovind Singh 9447f4beda2SGovind Singh err_free_irq: 9457f4beda2SGovind Singh ath11k_pci_free_irq(ab); 9467f4beda2SGovind Singh 9477f4beda2SGovind Singh err_ce_free: 9487f4beda2SGovind Singh ath11k_ce_free_pipes(ab); 9497f4beda2SGovind Singh 9507f4beda2SGovind Singh err_hal_srng_deinit: 9517f4beda2SGovind Singh ath11k_hal_srng_deinit(ab); 9527f4beda2SGovind Singh 9537f4beda2SGovind Singh err_mhi_unregister: 9547f4beda2SGovind Singh ath11k_mhi_unregister(ab_pci); 9557f4beda2SGovind Singh 956b8246f88SKalle Valo err_pci_disable_msi: 957b8246f88SKalle Valo ath11k_pci_disable_msi(ab_pci); 958b8246f88SKalle Valo 9595697a564SGovind Singh err_pci_free_region: 9605697a564SGovind Singh ath11k_pci_free_region(ab_pci); 9615697a564SGovind Singh 9625762613eSGovind Singh err_free_core: 9635762613eSGovind Singh ath11k_core_free(ab); 9645697a564SGovind Singh 9655762613eSGovind Singh return ret; 9666e0355afSGovind Singh } 9676e0355afSGovind Singh 9686e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev) 9696e0355afSGovind Singh { 9706e0355afSGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 9715762613eSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 9726e0355afSGovind Singh 9736e0355afSGovind Singh set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); 9741399fb87SGovind Singh ath11k_mhi_unregister(ab_pci); 9755697a564SGovind Singh ath11k_pci_disable_msi(ab_pci); 9765762613eSGovind Singh ath11k_pci_free_region(ab_pci); 9777f4beda2SGovind Singh ath11k_pci_free_irq(ab); 9786e0355afSGovind Singh ath11k_core_free(ab); 9796e0355afSGovind Singh } 9806e0355afSGovind Singh 9811399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev) 9821399fb87SGovind Singh { 9831399fb87SGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 9841399fb87SGovind Singh 9851399fb87SGovind Singh ath11k_pci_power_down(ab); 9861399fb87SGovind Singh } 9871399fb87SGovind Singh 9886e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = { 9896e0355afSGovind Singh .name = "ath11k_pci", 9906e0355afSGovind Singh .id_table = ath11k_pci_id_table, 9916e0355afSGovind Singh .probe = ath11k_pci_probe, 9926e0355afSGovind Singh .remove = ath11k_pci_remove, 9931399fb87SGovind Singh .shutdown = ath11k_pci_shutdown, 9946e0355afSGovind Singh }; 9956e0355afSGovind Singh 9966e0355afSGovind Singh static int ath11k_pci_init(void) 9976e0355afSGovind Singh { 9986e0355afSGovind Singh int ret; 9996e0355afSGovind Singh 10006e0355afSGovind Singh ret = pci_register_driver(&ath11k_pci_driver); 10016e0355afSGovind Singh if (ret) 10026e0355afSGovind Singh pr_err("failed to register ath11k pci driver: %d\n", 10036e0355afSGovind Singh ret); 10046e0355afSGovind Singh 10056e0355afSGovind Singh return ret; 10066e0355afSGovind Singh } 10076e0355afSGovind Singh module_init(ath11k_pci_init); 10086e0355afSGovind Singh 10096e0355afSGovind Singh static void ath11k_pci_exit(void) 10106e0355afSGovind Singh { 10116e0355afSGovind Singh pci_unregister_driver(&ath11k_pci_driver); 10126e0355afSGovind Singh } 10136e0355afSGovind Singh 10146e0355afSGovind Singh module_exit(ath11k_pci_exit); 10156e0355afSGovind Singh 10166e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); 10176e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL"); 1018