16e0355afSGovind Singh // SPDX-License-Identifier: BSD-3-Clause-Clear 26e0355afSGovind Singh /* 36e0355afSGovind Singh * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. 46e0355afSGovind Singh */ 56e0355afSGovind Singh 66e0355afSGovind Singh #include <linux/module.h> 75697a564SGovind Singh #include <linux/msi.h> 86e0355afSGovind Singh #include <linux/pci.h> 96e0355afSGovind Singh 105762613eSGovind Singh #include "pci.h" 116e0355afSGovind Singh #include "core.h" 121399fb87SGovind Singh #include "hif.h" 131399fb87SGovind Singh #include "mhi.h" 146e0355afSGovind Singh #include "debug.h" 156e0355afSGovind Singh 165762613eSGovind Singh #define ATH11K_PCI_BAR_NUM 0 175762613eSGovind Singh #define ATH11K_PCI_DMA_MASK 32 185762613eSGovind Singh 197f4beda2SGovind Singh #define ATH11K_PCI_IRQ_CE0_OFFSET 3 207f4beda2SGovind Singh 21654e959aSGovind Singh #define WINDOW_ENABLE_BIT 0x40000000 22654e959aSGovind Singh #define WINDOW_REG_ADDRESS 0x310c 23654e959aSGovind Singh #define WINDOW_VALUE_MASK GENMASK(24, 19) 24654e959aSGovind Singh #define WINDOW_START 0x80000 25654e959aSGovind Singh #define WINDOW_RANGE_MASK GENMASK(18, 0) 26654e959aSGovind Singh 2718ac1665SKalle Valo #define TCSR_SOC_HW_VERSION 0x0224 2818ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(16, 8) 2918ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0) 3018ac1665SKalle Valo 31a05bd851SCarl Huang /* BAR0 + 4k is always accessible, and no 32a05bd851SCarl Huang * need to force wakeup. 33a05bd851SCarl Huang * 4K - 32 = 0xFE0 34a05bd851SCarl Huang */ 35a05bd851SCarl Huang #define ACCESS_ALWAYS_OFF 0xFE0 36a05bd851SCarl Huang 376e0355afSGovind Singh #define QCA6390_DEVICE_ID 0x1101 386e0355afSGovind Singh 396e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = { 406e0355afSGovind Singh { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, 416e0355afSGovind Singh {0} 426e0355afSGovind Singh }; 436e0355afSGovind Singh 446e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); 456e0355afSGovind Singh 461ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = { 471ff8ed78SGovind Singh .mhi_support = true, 4856970454SGovind Singh .m3_fw_support = true, 496eb6ea51SGovind Singh .fixed_bdf_addr = false, 506eb6ea51SGovind Singh .fixed_mem_region = false, 511ff8ed78SGovind Singh }; 521ff8ed78SGovind Singh 537a3aed0cSAnilkumar Kolli static const struct ath11k_msi_config ath11k_msi_config[] = { 547a3aed0cSAnilkumar Kolli { 555697a564SGovind Singh .total_vectors = 32, 565697a564SGovind Singh .total_users = 4, 575697a564SGovind Singh .users = (struct ath11k_msi_user[]) { 585697a564SGovind Singh { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 595697a564SGovind Singh { .name = "CE", .num_vectors = 10, .base_vector = 3 }, 605697a564SGovind Singh { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, 615697a564SGovind Singh { .name = "DP", .num_vectors = 18, .base_vector = 14 }, 625697a564SGovind Singh }, 637a3aed0cSAnilkumar Kolli }, 645697a564SGovind Singh }; 655697a564SGovind Singh 667f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { 677f4beda2SGovind Singh "bhi", 687f4beda2SGovind Singh "mhi-er0", 697f4beda2SGovind Singh "mhi-er1", 707f4beda2SGovind Singh "ce0", 717f4beda2SGovind Singh "ce1", 727f4beda2SGovind Singh "ce2", 737f4beda2SGovind Singh "ce3", 747f4beda2SGovind Singh "ce4", 757f4beda2SGovind Singh "ce5", 767f4beda2SGovind Singh "ce6", 777f4beda2SGovind Singh "ce7", 787f4beda2SGovind Singh "ce8", 797f4beda2SGovind Singh "ce9", 807f4beda2SGovind Singh "ce10", 817f4beda2SGovind Singh "ce11", 827f4beda2SGovind Singh "host2wbm-desc-feed", 837f4beda2SGovind Singh "host2reo-re-injection", 847f4beda2SGovind Singh "host2reo-command", 857f4beda2SGovind Singh "host2rxdma-monitor-ring3", 867f4beda2SGovind Singh "host2rxdma-monitor-ring2", 877f4beda2SGovind Singh "host2rxdma-monitor-ring1", 887f4beda2SGovind Singh "reo2ost-exception", 897f4beda2SGovind Singh "wbm2host-rx-release", 907f4beda2SGovind Singh "reo2host-status", 917f4beda2SGovind Singh "reo2host-destination-ring4", 927f4beda2SGovind Singh "reo2host-destination-ring3", 937f4beda2SGovind Singh "reo2host-destination-ring2", 947f4beda2SGovind Singh "reo2host-destination-ring1", 957f4beda2SGovind Singh "rxdma2host-monitor-destination-mac3", 967f4beda2SGovind Singh "rxdma2host-monitor-destination-mac2", 977f4beda2SGovind Singh "rxdma2host-monitor-destination-mac1", 987f4beda2SGovind Singh "ppdu-end-interrupts-mac3", 997f4beda2SGovind Singh "ppdu-end-interrupts-mac2", 1007f4beda2SGovind Singh "ppdu-end-interrupts-mac1", 1017f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac3", 1027f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac2", 1037f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac1", 1047f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac3", 1057f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac2", 1067f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac1", 1077f4beda2SGovind Singh "rxdma2host-destination-ring-mac3", 1087f4beda2SGovind Singh "rxdma2host-destination-ring-mac2", 1097f4beda2SGovind Singh "rxdma2host-destination-ring-mac1", 1107f4beda2SGovind Singh "host2tcl-input-ring4", 1117f4beda2SGovind Singh "host2tcl-input-ring3", 1127f4beda2SGovind Singh "host2tcl-input-ring2", 1137f4beda2SGovind Singh "host2tcl-input-ring1", 1147f4beda2SGovind Singh "wbm2host-tx-completions-ring3", 1157f4beda2SGovind Singh "wbm2host-tx-completions-ring2", 1167f4beda2SGovind Singh "wbm2host-tx-completions-ring1", 1177f4beda2SGovind Singh "tcl2host-status-ring", 1187f4beda2SGovind Singh }; 1197f4beda2SGovind Singh 120654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset) 121654e959aSGovind Singh { 122654e959aSGovind Singh struct ath11k_base *ab = ab_pci->ab; 123654e959aSGovind Singh 124654e959aSGovind Singh u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset); 125654e959aSGovind Singh 126654e959aSGovind Singh lockdep_assert_held(&ab_pci->window_lock); 127654e959aSGovind Singh 128654e959aSGovind Singh if (window != ab_pci->register_window) { 129654e959aSGovind Singh iowrite32(WINDOW_ENABLE_BIT | window, 130654e959aSGovind Singh ab->mem + WINDOW_REG_ADDRESS); 131f6fa37a4SCarl Huang ioread32(ab->mem + WINDOW_REG_ADDRESS); 132654e959aSGovind Singh ab_pci->register_window = window; 133654e959aSGovind Singh } 134654e959aSGovind Singh } 135654e959aSGovind Singh 136480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci) 137480a7361SKarthikeyan Periyasamy { 138480a7361SKarthikeyan Periyasamy u32 umac_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET); 139480a7361SKarthikeyan Periyasamy u32 ce_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE); 140480a7361SKarthikeyan Periyasamy u32 window; 141480a7361SKarthikeyan Periyasamy 142480a7361SKarthikeyan Periyasamy window = (umac_window << 12) | (ce_window << 6); 143480a7361SKarthikeyan Periyasamy 144480a7361SKarthikeyan Periyasamy iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + WINDOW_REG_ADDRESS); 145480a7361SKarthikeyan Periyasamy } 146480a7361SKarthikeyan Periyasamy 147480a7361SKarthikeyan Periyasamy static inline u32 ath11k_pci_get_window_start(struct ath11k_base *ab, 148480a7361SKarthikeyan Periyasamy u32 offset) 149480a7361SKarthikeyan Periyasamy { 150480a7361SKarthikeyan Periyasamy u32 window_start; 151480a7361SKarthikeyan Periyasamy 152480a7361SKarthikeyan Periyasamy /* If offset lies within DP register range, use 3rd window */ 153480a7361SKarthikeyan Periyasamy if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < WINDOW_RANGE_MASK) 154480a7361SKarthikeyan Periyasamy window_start = 3 * WINDOW_START; 155480a7361SKarthikeyan Periyasamy /* If offset lies within CE register range, use 2nd window */ 156480a7361SKarthikeyan Periyasamy else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK) 157480a7361SKarthikeyan Periyasamy window_start = 2 * WINDOW_START; 158480a7361SKarthikeyan Periyasamy else 159480a7361SKarthikeyan Periyasamy window_start = WINDOW_START; 160480a7361SKarthikeyan Periyasamy 161480a7361SKarthikeyan Periyasamy return window_start; 162480a7361SKarthikeyan Periyasamy } 163480a7361SKarthikeyan Periyasamy 164f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) 165654e959aSGovind Singh { 166654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 167480a7361SKarthikeyan Periyasamy u32 window_start; 168654e959aSGovind Singh 169a05bd851SCarl Huang /* for offset beyond BAR + 4K - 32, may 170a05bd851SCarl Huang * need to wakeup MHI to access. 171a05bd851SCarl Huang */ 172a05bd851SCarl Huang if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 173a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 174a05bd851SCarl Huang mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); 175a05bd851SCarl Huang 176654e959aSGovind Singh if (offset < WINDOW_START) { 177654e959aSGovind Singh iowrite32(value, ab->mem + offset); 178654e959aSGovind Singh } else { 179480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 180480a7361SKarthikeyan Periyasamy window_start = ath11k_pci_get_window_start(ab, offset); 181480a7361SKarthikeyan Periyasamy else 182480a7361SKarthikeyan Periyasamy window_start = WINDOW_START; 183480a7361SKarthikeyan Periyasamy 184480a7361SKarthikeyan Periyasamy if (window_start == WINDOW_START) { 185654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 186654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 187480a7361SKarthikeyan Periyasamy iowrite32(value, ab->mem + window_start + 188480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 189654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 190480a7361SKarthikeyan Periyasamy } else { 191480a7361SKarthikeyan Periyasamy iowrite32(value, ab->mem + window_start + 192480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 193480a7361SKarthikeyan Periyasamy } 194654e959aSGovind Singh } 195a05bd851SCarl Huang 196a05bd851SCarl Huang if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 197a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 198a05bd851SCarl Huang mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); 199654e959aSGovind Singh } 200654e959aSGovind Singh 201f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) 202654e959aSGovind Singh { 203654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 204480a7361SKarthikeyan Periyasamy u32 val, window_start; 205654e959aSGovind Singh 206a05bd851SCarl Huang /* for offset beyond BAR + 4K - 32, may 207a05bd851SCarl Huang * need to wakeup MHI to access. 208a05bd851SCarl Huang */ 209a05bd851SCarl Huang if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 210a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 211a05bd851SCarl Huang mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); 212a05bd851SCarl Huang 213654e959aSGovind Singh if (offset < WINDOW_START) { 214654e959aSGovind Singh val = ioread32(ab->mem + offset); 215654e959aSGovind Singh } else { 216480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 217480a7361SKarthikeyan Periyasamy window_start = ath11k_pci_get_window_start(ab, offset); 218480a7361SKarthikeyan Periyasamy else 219480a7361SKarthikeyan Periyasamy window_start = WINDOW_START; 220480a7361SKarthikeyan Periyasamy 221480a7361SKarthikeyan Periyasamy if (window_start == WINDOW_START) { 222654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 223654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 224480a7361SKarthikeyan Periyasamy val = ioread32(ab->mem + window_start + 225480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 226654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 227480a7361SKarthikeyan Periyasamy } else { 228480a7361SKarthikeyan Periyasamy val = ioread32(ab->mem + window_start + 229480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 230480a7361SKarthikeyan Periyasamy } 231654e959aSGovind Singh } 232654e959aSGovind Singh 233a05bd851SCarl Huang if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 234a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 235a05bd851SCarl Huang mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); 236a05bd851SCarl Huang 237654e959aSGovind Singh return val; 238654e959aSGovind Singh } 239654e959aSGovind Singh 240f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) 241f3c603d4SCarl Huang { 242f3c603d4SCarl Huang u32 val, delay; 243f3c603d4SCarl Huang 244f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 245f3c603d4SCarl Huang 246f3c603d4SCarl Huang val |= PCIE_SOC_GLOBAL_RESET_V; 247f3c603d4SCarl Huang 248f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 249f3c603d4SCarl Huang 250f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 251f3c603d4SCarl Huang delay = 10; 252f3c603d4SCarl Huang mdelay(delay); 253f3c603d4SCarl Huang 254f3c603d4SCarl Huang /* Need to toggle V bit back otherwise stuck in reset status */ 255f3c603d4SCarl Huang val &= ~PCIE_SOC_GLOBAL_RESET_V; 256f3c603d4SCarl Huang 257f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 258f3c603d4SCarl Huang 259f3c603d4SCarl Huang mdelay(delay); 260f3c603d4SCarl Huang 261f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 262f3c603d4SCarl Huang if (val == 0xffffffff) 263f3c603d4SCarl Huang ath11k_warn(ab, "link down error during global reset\n"); 264f3c603d4SCarl Huang } 265f3c603d4SCarl Huang 266f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) 267f3c603d4SCarl Huang { 268f3c603d4SCarl Huang u32 val; 269f3c603d4SCarl Huang 270f3c603d4SCarl Huang /* read cookie */ 271f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR); 272f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val); 273f3c603d4SCarl Huang 274f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 275f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 276f3c603d4SCarl Huang 277f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 278f3c603d4SCarl Huang mdelay(10); 279f3c603d4SCarl Huang 280f3c603d4SCarl Huang /* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from 281f3c603d4SCarl Huang * continuing warm path and entering dead loop. 282f3c603d4SCarl Huang */ 283f3c603d4SCarl Huang ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0); 284f3c603d4SCarl Huang mdelay(10); 285f3c603d4SCarl Huang 286f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 287f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 288f3c603d4SCarl Huang 289f3c603d4SCarl Huang /* A read clear register. clear the register to prevent 290f3c603d4SCarl Huang * Q6 from entering wrong code path. 291f3c603d4SCarl Huang */ 292f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG); 293f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val); 294f3c603d4SCarl Huang } 295f3c603d4SCarl Huang 29606999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab, 29706999407SCarl Huang u32 offset, u32 value, u32 mask) 29806999407SCarl Huang { 29906999407SCarl Huang u32 v; 30006999407SCarl Huang int i; 30106999407SCarl Huang 30206999407SCarl Huang v = ath11k_pci_read32(ab, offset); 30306999407SCarl Huang if ((v & mask) == value) 30406999407SCarl Huang return 0; 30506999407SCarl Huang 30606999407SCarl Huang for (i = 0; i < 10; i++) { 30706999407SCarl Huang ath11k_pci_write32(ab, offset, (v & ~mask) | value); 30806999407SCarl Huang 30906999407SCarl Huang v = ath11k_pci_read32(ab, offset); 31006999407SCarl Huang if ((v & mask) == value) 31106999407SCarl Huang return 0; 31206999407SCarl Huang 31306999407SCarl Huang mdelay(2); 31406999407SCarl Huang } 31506999407SCarl Huang 31606999407SCarl Huang ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n", 31706999407SCarl Huang offset, v & mask, value); 31806999407SCarl Huang 31906999407SCarl Huang return -ETIMEDOUT; 32006999407SCarl Huang } 32106999407SCarl Huang 32206999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab) 32306999407SCarl Huang { 32406999407SCarl Huang int ret; 32506999407SCarl Huang 32606999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3276fe6f68fSKarthikeyan Periyasamy PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab), 32806999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL, 32906999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK); 33030d08503SDan Carpenter if (ret) { 33106999407SCarl Huang ath11k_warn(ab, "failed to set sysclk: %d\n", ret); 33206999407SCarl Huang return ret; 33306999407SCarl Huang } 33406999407SCarl Huang 33506999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3366fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab), 3376fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG1_VAL, 3386fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 33930d08503SDan Carpenter if (ret) { 34006999407SCarl Huang ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret); 34106999407SCarl Huang return ret; 34206999407SCarl Huang } 34306999407SCarl Huang 34406999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3456fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab), 3466fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG2_VAL, 3476fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 34830d08503SDan Carpenter if (ret) { 34906999407SCarl Huang ath11k_warn(ab, "failed to set dtct config2: %d\n", ret); 35006999407SCarl Huang return ret; 35106999407SCarl Huang } 35206999407SCarl Huang 35306999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3546fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab), 3556fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG4_VAL, 3566fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 35730d08503SDan Carpenter if (ret) { 35806999407SCarl Huang ath11k_warn(ab, "failed to set dtct config4: %d\n", ret); 35906999407SCarl Huang return ret; 36006999407SCarl Huang } 36106999407SCarl Huang 36206999407SCarl Huang return 0; 36306999407SCarl Huang } 36406999407SCarl Huang 365babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab) 366babb0cedSCarl Huang { 367babb0cedSCarl Huang u32 val; 368babb0cedSCarl Huang int i; 369babb0cedSCarl Huang 370babb0cedSCarl Huang val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); 371babb0cedSCarl Huang 372babb0cedSCarl Huang /* PCIE link seems very unstable after the Hot Reset*/ 373babb0cedSCarl Huang for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) { 374babb0cedSCarl Huang if (val == 0xffffffff) 375babb0cedSCarl Huang mdelay(5); 376babb0cedSCarl Huang 377babb0cedSCarl Huang ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE); 378babb0cedSCarl Huang val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); 379babb0cedSCarl Huang } 380babb0cedSCarl Huang 381babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val); 382babb0cedSCarl Huang 383babb0cedSCarl Huang val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); 384562934adSKalle Valo val |= GCC_GCC_PCIE_HOT_RST_VAL; 385babb0cedSCarl Huang ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val); 386babb0cedSCarl Huang val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); 387babb0cedSCarl Huang 388babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val); 389babb0cedSCarl Huang 390babb0cedSCarl Huang mdelay(5); 391babb0cedSCarl Huang } 392babb0cedSCarl Huang 393babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab) 394babb0cedSCarl Huang { 395babb0cedSCarl Huang /* This is a WAR for PCIE Hotreset. 396babb0cedSCarl Huang * When target receive Hotreset, but will set the interrupt. 397babb0cedSCarl Huang * So when download SBL again, SBL will open Interrupt and 398babb0cedSCarl Huang * receive it, and crash immediately. 399babb0cedSCarl Huang */ 400babb0cedSCarl Huang ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL); 401babb0cedSCarl Huang } 402babb0cedSCarl Huang 4030ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab) 4040ccdf439SCarl Huang { 4050ccdf439SCarl Huang u32 val; 4060ccdf439SCarl Huang 4070ccdf439SCarl Huang val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG); 4080ccdf439SCarl Huang val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK; 4090ccdf439SCarl Huang ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val); 4100ccdf439SCarl Huang } 4110ccdf439SCarl Huang 412f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab) 413f3c603d4SCarl Huang { 414f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1); 415f3c603d4SCarl Huang mdelay(5); 416f3c603d4SCarl Huang } 417f3c603d4SCarl Huang 418babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on) 419f3c603d4SCarl Huang { 420babb0cedSCarl Huang if (power_on) { 421babb0cedSCarl Huang ath11k_pci_enable_ltssm(ab); 422babb0cedSCarl Huang ath11k_pci_clear_all_intrs(ab); 4230ccdf439SCarl Huang ath11k_pci_set_wlaon_pwr_ctrl(ab); 42406999407SCarl Huang ath11k_pci_fix_l1ss(ab); 425babb0cedSCarl Huang } 426babb0cedSCarl Huang 427f3c603d4SCarl Huang ath11k_mhi_clear_vector(ab); 428f3c603d4SCarl Huang ath11k_pci_soc_global_reset(ab); 429f3c603d4SCarl Huang ath11k_mhi_set_mhictrl_reset(ab); 430f3c603d4SCarl Huang ath11k_pci_clear_dbg_registers(ab); 431f3c603d4SCarl Huang } 432f3c603d4SCarl Huang 4331399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) 4341399fb87SGovind Singh { 4351399fb87SGovind Singh struct pci_dev *pci_dev = to_pci_dev(dev); 4361399fb87SGovind Singh 4371399fb87SGovind Singh return pci_irq_vector(pci_dev, vector); 4381399fb87SGovind Singh } 4391399fb87SGovind Singh 440c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, 441c4eacabeSGovind Singh u32 *msi_addr_hi) 442c4eacabeSGovind Singh { 443e8e55d89SAnilkumar Kolli struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 444c4eacabeSGovind Singh struct pci_dev *pci_dev = to_pci_dev(ab->dev); 445c4eacabeSGovind Singh 446c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, 447c4eacabeSGovind Singh msi_addr_lo); 448c4eacabeSGovind Singh 449e8e55d89SAnilkumar Kolli if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) { 450c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, 451c4eacabeSGovind Singh msi_addr_hi); 452e8e55d89SAnilkumar Kolli } else { 453e8e55d89SAnilkumar Kolli *msi_addr_hi = 0; 454e8e55d89SAnilkumar Kolli } 455c4eacabeSGovind Singh } 456c4eacabeSGovind Singh 4571399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, 4581399fb87SGovind Singh int *num_vectors, u32 *user_base_data, 4591399fb87SGovind Singh u32 *base_vector) 4601399fb87SGovind Singh { 4611399fb87SGovind Singh struct ath11k_base *ab = ab_pci->ab; 4627a3aed0cSAnilkumar Kolli const struct ath11k_msi_config *msi_config = ab_pci->msi_config; 4631399fb87SGovind Singh int idx; 4641399fb87SGovind Singh 4657a3aed0cSAnilkumar Kolli for (idx = 0; idx < msi_config->total_users; idx++) { 4667a3aed0cSAnilkumar Kolli if (strcmp(user_name, msi_config->users[idx].name) == 0) { 4677a3aed0cSAnilkumar Kolli *num_vectors = msi_config->users[idx].num_vectors; 4687a3aed0cSAnilkumar Kolli *user_base_data = msi_config->users[idx].base_vector 4691399fb87SGovind Singh + ab_pci->msi_ep_base_data; 4707a3aed0cSAnilkumar Kolli *base_vector = msi_config->users[idx].base_vector; 4711399fb87SGovind Singh 4721399fb87SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", 4731399fb87SGovind Singh user_name, *num_vectors, *user_base_data, 4741399fb87SGovind Singh *base_vector); 4751399fb87SGovind Singh 4761399fb87SGovind Singh return 0; 4771399fb87SGovind Singh } 4781399fb87SGovind Singh } 4791399fb87SGovind Singh 4801399fb87SGovind Singh ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name); 4811399fb87SGovind Singh 4821399fb87SGovind Singh return -EINVAL; 4831399fb87SGovind Singh } 4841399fb87SGovind Singh 485*6289ac2bSKarthikeyan Periyasamy static void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, 486*6289ac2bSKarthikeyan Periyasamy u32 *msi_idx) 487*6289ac2bSKarthikeyan Periyasamy { 488*6289ac2bSKarthikeyan Periyasamy u32 i, msi_data_idx; 489*6289ac2bSKarthikeyan Periyasamy 490*6289ac2bSKarthikeyan Periyasamy for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { 491*6289ac2bSKarthikeyan Periyasamy if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 492*6289ac2bSKarthikeyan Periyasamy continue; 493*6289ac2bSKarthikeyan Periyasamy 494*6289ac2bSKarthikeyan Periyasamy if (ce_id == i) 495*6289ac2bSKarthikeyan Periyasamy break; 496*6289ac2bSKarthikeyan Periyasamy 497*6289ac2bSKarthikeyan Periyasamy msi_data_idx++; 498*6289ac2bSKarthikeyan Periyasamy } 499*6289ac2bSKarthikeyan Periyasamy *msi_idx = msi_data_idx; 500*6289ac2bSKarthikeyan Periyasamy } 501*6289ac2bSKarthikeyan Periyasamy 502c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, 503c4eacabeSGovind Singh int *num_vectors, u32 *user_base_data, 504c4eacabeSGovind Singh u32 *base_vector) 505c4eacabeSGovind Singh { 506c4eacabeSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 507c4eacabeSGovind Singh 508c4eacabeSGovind Singh return ath11k_pci_get_user_msi_assignment(ab_pci, user_name, 509c4eacabeSGovind Singh num_vectors, user_base_data, 510c4eacabeSGovind Singh base_vector); 511c4eacabeSGovind Singh } 512c4eacabeSGovind Singh 513d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab) 514d4ecb90bSCarl Huang { 515d4ecb90bSCarl Huang int i, j; 516d4ecb90bSCarl Huang 517d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 518d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 519d4ecb90bSCarl Huang 520d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) 521d4ecb90bSCarl Huang free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); 522d4ecb90bSCarl Huang 523d4ecb90bSCarl Huang netif_napi_del(&irq_grp->napi); 524d4ecb90bSCarl Huang } 525d4ecb90bSCarl Huang } 526d4ecb90bSCarl Huang 5277f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab) 5287f4beda2SGovind Singh { 5297f4beda2SGovind Singh int i, irq_idx; 5307f4beda2SGovind Singh 531d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 532e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5337f4beda2SGovind Singh continue; 5347f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 5357f4beda2SGovind Singh free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); 5367f4beda2SGovind Singh } 537d4ecb90bSCarl Huang 538d4ecb90bSCarl Huang ath11k_pci_free_ext_irq(ab); 5397f4beda2SGovind Singh } 5407f4beda2SGovind Singh 5412c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) 5422c3960c2SGovind Singh { 5432c3960c2SGovind Singh u32 irq_idx; 5442c3960c2SGovind Singh 5452c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 5462c3960c2SGovind Singh enable_irq(ab->irq_num[irq_idx]); 5472c3960c2SGovind Singh } 5482c3960c2SGovind Singh 5497f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) 5507f4beda2SGovind Singh { 5517f4beda2SGovind Singh u32 irq_idx; 5527f4beda2SGovind Singh 5537f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 5547f4beda2SGovind Singh disable_irq_nosync(ab->irq_num[irq_idx]); 5557f4beda2SGovind Singh } 5567f4beda2SGovind Singh 5572c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab) 5582c3960c2SGovind Singh { 5592c3960c2SGovind Singh int i; 5602c3960c2SGovind Singh 561d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 562e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5632c3960c2SGovind Singh continue; 5642c3960c2SGovind Singh ath11k_pci_ce_irq_disable(ab, i); 5652c3960c2SGovind Singh } 5662c3960c2SGovind Singh } 5672c3960c2SGovind Singh 5682c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) 5692c3960c2SGovind Singh { 5702c3960c2SGovind Singh int i; 5712c3960c2SGovind Singh int irq_idx; 5722c3960c2SGovind Singh 573d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 574e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5752c3960c2SGovind Singh continue; 5762c3960c2SGovind Singh 5772c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 5782c3960c2SGovind Singh synchronize_irq(ab->irq_num[irq_idx]); 5792c3960c2SGovind Singh } 5802c3960c2SGovind Singh } 5812c3960c2SGovind Singh 5820f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t) 5832c3960c2SGovind Singh { 5840f01dcb8SAllen Pais struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); 5852c3960c2SGovind Singh 5862c3960c2SGovind Singh ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); 5872c3960c2SGovind Singh 5882c3960c2SGovind Singh ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num); 5892c3960c2SGovind Singh } 5902c3960c2SGovind Singh 5917f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) 5927f4beda2SGovind Singh { 5937f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe = arg; 5947f4beda2SGovind Singh 5957f4beda2SGovind Singh ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num); 5962c3960c2SGovind Singh tasklet_schedule(&ce_pipe->intr_tq); 5977f4beda2SGovind Singh 5987f4beda2SGovind Singh return IRQ_HANDLED; 5997f4beda2SGovind Singh } 6007f4beda2SGovind Singh 601d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) 602d4ecb90bSCarl Huang { 603d4ecb90bSCarl Huang int i; 604d4ecb90bSCarl Huang 605d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 606d4ecb90bSCarl Huang disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 607d4ecb90bSCarl Huang } 608d4ecb90bSCarl Huang 609d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc) 610d4ecb90bSCarl Huang { 611d4ecb90bSCarl Huang int i; 612d4ecb90bSCarl Huang 613d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 614d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; 615d4ecb90bSCarl Huang 616d4ecb90bSCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 617d4ecb90bSCarl Huang 618d4ecb90bSCarl Huang napi_synchronize(&irq_grp->napi); 619d4ecb90bSCarl Huang napi_disable(&irq_grp->napi); 620d4ecb90bSCarl Huang } 621d4ecb90bSCarl Huang } 622d4ecb90bSCarl Huang 623d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) 624d4ecb90bSCarl Huang { 625d4ecb90bSCarl Huang int i; 626d4ecb90bSCarl Huang 627d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 628d4ecb90bSCarl Huang enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 629d4ecb90bSCarl Huang } 630d4ecb90bSCarl Huang 631d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab) 632d4ecb90bSCarl Huang { 633d4ecb90bSCarl Huang int i; 634d4ecb90bSCarl Huang 635d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 636d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 637d4ecb90bSCarl Huang 638d4ecb90bSCarl Huang napi_enable(&irq_grp->napi); 639d4ecb90bSCarl Huang ath11k_pci_ext_grp_enable(irq_grp); 640d4ecb90bSCarl Huang } 641d4ecb90bSCarl Huang } 642d4ecb90bSCarl Huang 643d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab) 644d4ecb90bSCarl Huang { 645d4ecb90bSCarl Huang int i, j, irq_idx; 646d4ecb90bSCarl Huang 647d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 648d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 649d4ecb90bSCarl Huang 650d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 651d4ecb90bSCarl Huang irq_idx = irq_grp->irqs[j]; 652d4ecb90bSCarl Huang synchronize_irq(ab->irq_num[irq_idx]); 653d4ecb90bSCarl Huang } 654d4ecb90bSCarl Huang } 655d4ecb90bSCarl Huang } 656d4ecb90bSCarl Huang 657d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab) 658d4ecb90bSCarl Huang { 659d4ecb90bSCarl Huang __ath11k_pci_ext_irq_disable(ab); 660d4ecb90bSCarl Huang ath11k_pci_sync_ext_irqs(ab); 661d4ecb90bSCarl Huang } 662d4ecb90bSCarl Huang 663d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) 664d4ecb90bSCarl Huang { 665d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = container_of(napi, 666d4ecb90bSCarl Huang struct ath11k_ext_irq_grp, 667d4ecb90bSCarl Huang napi); 668d4ecb90bSCarl Huang struct ath11k_base *ab = irq_grp->ab; 669d4ecb90bSCarl Huang int work_done; 670d4ecb90bSCarl Huang 671d4ecb90bSCarl Huang work_done = ath11k_dp_service_srng(ab, irq_grp, budget); 672d4ecb90bSCarl Huang if (work_done < budget) { 673d4ecb90bSCarl Huang napi_complete_done(napi, work_done); 674d4ecb90bSCarl Huang ath11k_pci_ext_grp_enable(irq_grp); 675d4ecb90bSCarl Huang } 676d4ecb90bSCarl Huang 677d4ecb90bSCarl Huang if (work_done > budget) 678d4ecb90bSCarl Huang work_done = budget; 679d4ecb90bSCarl Huang 680d4ecb90bSCarl Huang return work_done; 681d4ecb90bSCarl Huang } 682d4ecb90bSCarl Huang 683d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) 684d4ecb90bSCarl Huang { 685d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = arg; 686d4ecb90bSCarl Huang 687d4ecb90bSCarl Huang ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); 688d4ecb90bSCarl Huang 689d4ecb90bSCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 690d4ecb90bSCarl Huang 691d4ecb90bSCarl Huang napi_schedule(&irq_grp->napi); 692d4ecb90bSCarl Huang 693d4ecb90bSCarl Huang return IRQ_HANDLED; 694d4ecb90bSCarl Huang } 695d4ecb90bSCarl Huang 696d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) 697d4ecb90bSCarl Huang { 698d4ecb90bSCarl Huang int i, j, ret, num_vectors = 0; 699d4ecb90bSCarl Huang u32 user_base_data = 0, base_vector = 0; 700d4ecb90bSCarl Huang 701b2c09458SColin Ian King ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", 702b2c09458SColin Ian King &num_vectors, 703b2c09458SColin Ian King &user_base_data, 704d4ecb90bSCarl Huang &base_vector); 705b2c09458SColin Ian King if (ret < 0) 706b2c09458SColin Ian King return ret; 707d4ecb90bSCarl Huang 708d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 709d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 710d4ecb90bSCarl Huang u32 num_irq = 0; 711d4ecb90bSCarl Huang 712d4ecb90bSCarl Huang irq_grp->ab = ab; 713d4ecb90bSCarl Huang irq_grp->grp_id = i; 714d4ecb90bSCarl Huang init_dummy_netdev(&irq_grp->napi_ndev); 715d4ecb90bSCarl Huang netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, 716d4ecb90bSCarl Huang ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT); 717d4ecb90bSCarl Huang 718d4ecb90bSCarl Huang if (ab->hw_params.ring_mask->tx[i] || 719d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx[i] || 720d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_err[i] || 721d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_wbm_rel[i] || 722d4ecb90bSCarl Huang ab->hw_params.ring_mask->reo_status[i] || 723d4ecb90bSCarl Huang ab->hw_params.ring_mask->rxdma2host[i] || 724d4ecb90bSCarl Huang ab->hw_params.ring_mask->host2rxdma[i] || 725d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_mon_status[i]) { 726d4ecb90bSCarl Huang num_irq = 1; 727d4ecb90bSCarl Huang } 728d4ecb90bSCarl Huang 729d4ecb90bSCarl Huang irq_grp->num_irq = num_irq; 730d4ecb90bSCarl Huang irq_grp->irqs[0] = base_vector + i; 731d4ecb90bSCarl Huang 732d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 733d4ecb90bSCarl Huang int irq_idx = irq_grp->irqs[j]; 734d4ecb90bSCarl Huang int vector = (i % num_vectors) + base_vector; 735d4ecb90bSCarl Huang int irq = ath11k_pci_get_msi_irq(ab->dev, vector); 736d4ecb90bSCarl Huang 737d4ecb90bSCarl Huang ab->irq_num[irq_idx] = irq; 738d4ecb90bSCarl Huang 739d4ecb90bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, 740d4ecb90bSCarl Huang "irq:%d group:%d\n", irq, i); 741d4ecb90bSCarl Huang ret = request_irq(irq, ath11k_pci_ext_interrupt_handler, 742d4ecb90bSCarl Huang IRQF_SHARED, 743d4ecb90bSCarl Huang "DP_EXT_IRQ", irq_grp); 744d4ecb90bSCarl Huang if (ret) { 745d4ecb90bSCarl Huang ath11k_err(ab, "failed request irq %d: %d\n", 746d4ecb90bSCarl Huang vector, ret); 747d4ecb90bSCarl Huang return ret; 748d4ecb90bSCarl Huang } 749d4ecb90bSCarl Huang 750d4ecb90bSCarl Huang disable_irq_nosync(ab->irq_num[irq_idx]); 751d4ecb90bSCarl Huang } 752d4ecb90bSCarl Huang } 753d4ecb90bSCarl Huang 754d4ecb90bSCarl Huang return 0; 755d4ecb90bSCarl Huang } 756d4ecb90bSCarl Huang 7577f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab) 7587f4beda2SGovind Singh { 7597f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe; 7607f4beda2SGovind Singh u32 msi_data_start; 761*6289ac2bSKarthikeyan Periyasamy u32 msi_data_count, msi_data_idx; 7627f4beda2SGovind Singh u32 msi_irq_start; 7637f4beda2SGovind Singh unsigned int msi_data; 7647f4beda2SGovind Singh int irq, i, ret, irq_idx; 7657f4beda2SGovind Singh 7667f4beda2SGovind Singh ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), 7677f4beda2SGovind Singh "CE", &msi_data_count, 7687f4beda2SGovind Singh &msi_data_start, &msi_irq_start); 7697f4beda2SGovind Singh if (ret) 7707f4beda2SGovind Singh return ret; 7717f4beda2SGovind Singh 7727f4beda2SGovind Singh /* Configure CE irqs */ 773*6289ac2bSKarthikeyan Periyasamy for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { 774e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 7757f4beda2SGovind Singh continue; 7767f4beda2SGovind Singh 777*6289ac2bSKarthikeyan Periyasamy msi_data = (msi_data_idx % msi_data_count) + msi_irq_start; 778*6289ac2bSKarthikeyan Periyasamy irq = ath11k_pci_get_msi_irq(ab->dev, msi_data); 779*6289ac2bSKarthikeyan Periyasamy ce_pipe = &ab->ce.ce_pipe[i]; 780*6289ac2bSKarthikeyan Periyasamy 7817f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 7827f4beda2SGovind Singh 7830f01dcb8SAllen Pais tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet); 7842c3960c2SGovind Singh 7857f4beda2SGovind Singh ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, 7867f4beda2SGovind Singh IRQF_SHARED, irq_name[irq_idx], 7877f4beda2SGovind Singh ce_pipe); 7887f4beda2SGovind Singh if (ret) { 7897f4beda2SGovind Singh ath11k_err(ab, "failed to request irq %d: %d\n", 7907f4beda2SGovind Singh irq_idx, ret); 7917f4beda2SGovind Singh return ret; 7927f4beda2SGovind Singh } 7937f4beda2SGovind Singh 7947f4beda2SGovind Singh ab->irq_num[irq_idx] = irq; 795*6289ac2bSKarthikeyan Periyasamy msi_data_idx++; 796e678fbd4SKarthikeyan Periyasamy 797e5c860e1SCarl Huang ath11k_pci_ce_irq_disable(ab, i); 7987f4beda2SGovind Singh } 7997f4beda2SGovind Singh 800d4ecb90bSCarl Huang ret = ath11k_pci_ext_irq_config(ab); 801d4ecb90bSCarl Huang if (ret) 802d4ecb90bSCarl Huang return ret; 803d4ecb90bSCarl Huang 8047f4beda2SGovind Singh return 0; 8057f4beda2SGovind Singh } 8067f4beda2SGovind Singh 8077f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) 8087f4beda2SGovind Singh { 8097f4beda2SGovind Singh struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; 8107f4beda2SGovind Singh 811967c1d11SAnilkumar Kolli cfg->tgt_ce = ab->hw_params.target_ce_config; 812967c1d11SAnilkumar Kolli cfg->tgt_ce_len = ab->hw_params.target_ce_count; 8137f4beda2SGovind Singh 814967c1d11SAnilkumar Kolli cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map; 815967c1d11SAnilkumar Kolli cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len; 81616001e4bSAnilkumar Kolli ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id; 817e838c14aSCarl Huang 818e838c14aSCarl Huang ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2, 819e838c14aSCarl Huang &cfg->shadow_reg_v2_len); 8207f4beda2SGovind Singh } 8217f4beda2SGovind Singh 8227f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) 8237f4beda2SGovind Singh { 8247f4beda2SGovind Singh int i; 8257f4beda2SGovind Singh 826d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 827e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 8287f4beda2SGovind Singh continue; 8297f4beda2SGovind Singh ath11k_pci_ce_irq_enable(ab, i); 8307f4beda2SGovind Singh } 8317f4beda2SGovind Singh } 8327f4beda2SGovind Singh 8335697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci) 8345697a564SGovind Singh { 8355697a564SGovind Singh struct ath11k_base *ab = ab_pci->ab; 8367a3aed0cSAnilkumar Kolli const struct ath11k_msi_config *msi_config = ab_pci->msi_config; 8375697a564SGovind Singh struct msi_desc *msi_desc; 8385697a564SGovind Singh int num_vectors; 8395697a564SGovind Singh int ret; 8405697a564SGovind Singh 8415697a564SGovind Singh num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 8427a3aed0cSAnilkumar Kolli msi_config->total_vectors, 8437a3aed0cSAnilkumar Kolli msi_config->total_vectors, 8445697a564SGovind Singh PCI_IRQ_MSI); 8457a3aed0cSAnilkumar Kolli if (num_vectors != msi_config->total_vectors) { 8465697a564SGovind Singh ath11k_err(ab, "failed to get %d MSI vectors, only %d available", 8477a3aed0cSAnilkumar Kolli msi_config->total_vectors, num_vectors); 8485697a564SGovind Singh 8495697a564SGovind Singh if (num_vectors >= 0) 8505697a564SGovind Singh return -EINVAL; 8515697a564SGovind Singh else 8525697a564SGovind Singh return num_vectors; 8535697a564SGovind Singh } 8545697a564SGovind Singh 8555697a564SGovind Singh msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 8565697a564SGovind Singh if (!msi_desc) { 8575697a564SGovind Singh ath11k_err(ab, "msi_desc is NULL!\n"); 8585697a564SGovind Singh ret = -EINVAL; 8595697a564SGovind Singh goto free_msi_vector; 8605697a564SGovind Singh } 8615697a564SGovind Singh 8625697a564SGovind Singh ab_pci->msi_ep_base_data = msi_desc->msg.data; 863e8e55d89SAnilkumar Kolli if (msi_desc->msi_attrib.is_64) 864e8e55d89SAnilkumar Kolli set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags); 8655697a564SGovind Singh 8665697a564SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); 8675697a564SGovind Singh 8685697a564SGovind Singh return 0; 8695697a564SGovind Singh 8705697a564SGovind Singh free_msi_vector: 8715697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 8725697a564SGovind Singh 8735697a564SGovind Singh return ret; 8745697a564SGovind Singh } 8755697a564SGovind Singh 8765697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci) 8775697a564SGovind Singh { 8785697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 8795697a564SGovind Singh } 8805697a564SGovind Singh 8815762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) 8825762613eSGovind Singh { 8835762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 8845762613eSGovind Singh u16 device_id; 8855762613eSGovind Singh int ret = 0; 8865762613eSGovind Singh 8875762613eSGovind Singh pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 8885762613eSGovind Singh if (device_id != ab_pci->dev_id) { 8895762613eSGovind Singh ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", 8905762613eSGovind Singh device_id, ab_pci->dev_id); 8915762613eSGovind Singh ret = -EIO; 8925762613eSGovind Singh goto out; 8935762613eSGovind Singh } 8945762613eSGovind Singh 8955762613eSGovind Singh ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); 8965762613eSGovind Singh if (ret) { 8975762613eSGovind Singh ath11k_err(ab, "failed to assign pci resource: %d\n", ret); 8985762613eSGovind Singh goto out; 8995762613eSGovind Singh } 9005762613eSGovind Singh 9015762613eSGovind Singh ret = pci_enable_device(pdev); 9025762613eSGovind Singh if (ret) { 9035762613eSGovind Singh ath11k_err(ab, "failed to enable pci device: %d\n", ret); 9045762613eSGovind Singh goto out; 9055762613eSGovind Singh } 9065762613eSGovind Singh 9075762613eSGovind Singh ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); 9085762613eSGovind Singh if (ret) { 9095762613eSGovind Singh ath11k_err(ab, "failed to request pci region: %d\n", ret); 9105762613eSGovind Singh goto disable_device; 9115762613eSGovind Singh } 9125762613eSGovind Singh 9135762613eSGovind Singh ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 9145762613eSGovind Singh if (ret) { 9155762613eSGovind Singh ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", 9165762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 9175762613eSGovind Singh goto release_region; 9185762613eSGovind Singh } 9195762613eSGovind Singh 9205762613eSGovind Singh ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 9215762613eSGovind Singh if (ret) { 9225762613eSGovind Singh ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n", 9235762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 9245762613eSGovind Singh goto release_region; 9255762613eSGovind Singh } 9265762613eSGovind Singh 9275762613eSGovind Singh pci_set_master(pdev); 9285762613eSGovind Singh 9295762613eSGovind Singh ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); 9305762613eSGovind Singh ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); 9315762613eSGovind Singh if (!ab->mem) { 9325762613eSGovind Singh ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); 9335762613eSGovind Singh ret = -EIO; 9345762613eSGovind Singh goto clear_master; 9355762613eSGovind Singh } 9365762613eSGovind Singh 9375762613eSGovind Singh ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); 9385762613eSGovind Singh return 0; 9395762613eSGovind Singh 9405762613eSGovind Singh clear_master: 9415762613eSGovind Singh pci_clear_master(pdev); 9425762613eSGovind Singh release_region: 9435762613eSGovind Singh pci_release_region(pdev, ATH11K_PCI_BAR_NUM); 9445762613eSGovind Singh disable_device: 9455762613eSGovind Singh pci_disable_device(pdev); 9465762613eSGovind Singh out: 9475762613eSGovind Singh return ret; 9485762613eSGovind Singh } 9495762613eSGovind Singh 9505762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) 9515762613eSGovind Singh { 9525762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 9535762613eSGovind Singh struct pci_dev *pci_dev = ab_pci->pdev; 9545762613eSGovind Singh 9555762613eSGovind Singh pci_iounmap(pci_dev, ab->mem); 9565762613eSGovind Singh ab->mem = NULL; 9575762613eSGovind Singh pci_clear_master(pci_dev); 9585762613eSGovind Singh pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); 9595762613eSGovind Singh if (pci_is_enabled(pci_dev)) 9605762613eSGovind Singh pci_disable_device(pci_dev); 9615762613eSGovind Singh } 9625762613eSGovind Singh 963e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci) 964e9603f4bSCarl Huang { 965e9603f4bSCarl Huang struct ath11k_base *ab = ab_pci->ab; 966e9603f4bSCarl Huang 967e9603f4bSCarl Huang pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL, 968e9603f4bSCarl Huang &ab_pci->link_ctl); 969e9603f4bSCarl Huang 970e9603f4bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n", 971e9603f4bSCarl Huang ab_pci->link_ctl, 972e9603f4bSCarl Huang u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S), 973e9603f4bSCarl Huang u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1)); 974e9603f4bSCarl Huang 975e9603f4bSCarl Huang /* disable L0s and L1 */ 976e9603f4bSCarl Huang pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, 977e9603f4bSCarl Huang ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC); 978e9603f4bSCarl Huang 979e9603f4bSCarl Huang set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags); 980e9603f4bSCarl Huang } 981e9603f4bSCarl Huang 982e9603f4bSCarl Huang static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci) 983e9603f4bSCarl Huang { 984e9603f4bSCarl Huang if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags)) 985e9603f4bSCarl Huang pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, 986e9603f4bSCarl Huang ab_pci->link_ctl); 987e9603f4bSCarl Huang } 988e9603f4bSCarl Huang 9891399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab) 9901399fb87SGovind Singh { 9911399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 9921399fb87SGovind Singh int ret; 9931399fb87SGovind Singh 994a05bd851SCarl Huang ab_pci->register_window = 0; 995a05bd851SCarl Huang clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 996babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, true); 997f3c603d4SCarl Huang 998e9603f4bSCarl Huang /* Disable ASPM during firmware download due to problems switching 999e9603f4bSCarl Huang * to AMSS state. 1000e9603f4bSCarl Huang */ 1001e9603f4bSCarl Huang ath11k_pci_aspm_disable(ab_pci); 1002e9603f4bSCarl Huang 10031399fb87SGovind Singh ret = ath11k_mhi_start(ab_pci); 10041399fb87SGovind Singh if (ret) { 10051399fb87SGovind Singh ath11k_err(ab, "failed to start mhi: %d\n", ret); 10061399fb87SGovind Singh return ret; 10071399fb87SGovind Singh } 10081399fb87SGovind Singh 1009480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 1010480a7361SKarthikeyan Periyasamy ath11k_pci_select_static_window(ab_pci); 1011480a7361SKarthikeyan Periyasamy 10121399fb87SGovind Singh return 0; 10131399fb87SGovind Singh } 10141399fb87SGovind Singh 10151399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab) 10161399fb87SGovind Singh { 10171399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 10181399fb87SGovind Singh 1019e9603f4bSCarl Huang /* restore aspm in case firmware bootup fails */ 1020e9603f4bSCarl Huang ath11k_pci_aspm_restore(ab_pci); 1021e9603f4bSCarl Huang 1022babb0cedSCarl Huang ath11k_pci_force_wake(ab_pci->ab); 10231399fb87SGovind Singh ath11k_mhi_stop(ab_pci); 1024a05bd851SCarl Huang clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 1025babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, false); 10261399fb87SGovind Singh } 10271399fb87SGovind Singh 1028fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab) 1029fa5917e4SCarl Huang { 1030fa5917e4SCarl Huang struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); 1031fa5917e4SCarl Huang 1032fa5917e4SCarl Huang ath11k_mhi_suspend(ar_pci); 1033fa5917e4SCarl Huang 1034fa5917e4SCarl Huang return 0; 1035fa5917e4SCarl Huang } 1036fa5917e4SCarl Huang 1037fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab) 1038fa5917e4SCarl Huang { 1039fa5917e4SCarl Huang struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); 1040fa5917e4SCarl Huang 1041fa5917e4SCarl Huang ath11k_mhi_resume(ar_pci); 1042fa5917e4SCarl Huang 1043fa5917e4SCarl Huang return 0; 1044fa5917e4SCarl Huang } 1045fa5917e4SCarl Huang 10462c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) 10472c3960c2SGovind Singh { 10482c3960c2SGovind Singh int i; 10492c3960c2SGovind Singh 1050d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 10512c3960c2SGovind Singh struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; 10522c3960c2SGovind Singh 1053e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 10542c3960c2SGovind Singh continue; 10552c3960c2SGovind Singh 10562c3960c2SGovind Singh tasklet_kill(&ce_pipe->intr_tq); 10572c3960c2SGovind Singh } 10582c3960c2SGovind Singh } 10592c3960c2SGovind Singh 1060d578ec2aSCarl Huang static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab) 10617f4beda2SGovind Singh { 10622c3960c2SGovind Singh ath11k_pci_ce_irqs_disable(ab); 10632c3960c2SGovind Singh ath11k_pci_sync_ce_irqs(ab); 10642c3960c2SGovind Singh ath11k_pci_kill_tasklets(ab); 1065d578ec2aSCarl Huang } 1066d578ec2aSCarl Huang 1067d578ec2aSCarl Huang static void ath11k_pci_stop(struct ath11k_base *ab) 1068d578ec2aSCarl Huang { 1069d578ec2aSCarl Huang ath11k_pci_ce_irq_disable_sync(ab); 10707f4beda2SGovind Singh ath11k_ce_cleanup_pipes(ab); 10717f4beda2SGovind Singh } 10727f4beda2SGovind Singh 10737f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab) 10747f4beda2SGovind Singh { 1075a05bd851SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 1076a05bd851SCarl Huang 1077a05bd851SCarl Huang set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 1078a05bd851SCarl Huang 1079e9603f4bSCarl Huang ath11k_pci_aspm_restore(ab_pci); 1080e9603f4bSCarl Huang 10817f4beda2SGovind Singh ath11k_pci_ce_irqs_enable(ab); 10822c3960c2SGovind Singh ath11k_ce_rx_post_buf(ab); 10832c3960c2SGovind Singh 10842c3960c2SGovind Singh return 0; 10852c3960c2SGovind Singh } 10862c3960c2SGovind Singh 1087d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab) 1088d578ec2aSCarl Huang { 1089d578ec2aSCarl Huang ath11k_pci_ce_irqs_enable(ab); 1090d578ec2aSCarl Huang } 1091d578ec2aSCarl Huang 1092d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab) 1093d578ec2aSCarl Huang { 1094d578ec2aSCarl Huang ath11k_pci_ce_irq_disable_sync(ab); 1095d578ec2aSCarl Huang } 1096d578ec2aSCarl Huang 10972c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, 10982c3960c2SGovind Singh u8 *ul_pipe, u8 *dl_pipe) 10992c3960c2SGovind Singh { 11002c3960c2SGovind Singh const struct service_to_pipe *entry; 11012c3960c2SGovind Singh bool ul_set = false, dl_set = false; 11022c3960c2SGovind Singh int i; 11032c3960c2SGovind Singh 1104967c1d11SAnilkumar Kolli for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) { 1105967c1d11SAnilkumar Kolli entry = &ab->hw_params.svc_to_ce_map[i]; 11062c3960c2SGovind Singh 11072c3960c2SGovind Singh if (__le32_to_cpu(entry->service_id) != service_id) 11082c3960c2SGovind Singh continue; 11092c3960c2SGovind Singh 11102c3960c2SGovind Singh switch (__le32_to_cpu(entry->pipedir)) { 11112c3960c2SGovind Singh case PIPEDIR_NONE: 11122c3960c2SGovind Singh break; 11132c3960c2SGovind Singh case PIPEDIR_IN: 11142c3960c2SGovind Singh WARN_ON(dl_set); 11152c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 11162c3960c2SGovind Singh dl_set = true; 11172c3960c2SGovind Singh break; 11182c3960c2SGovind Singh case PIPEDIR_OUT: 11192c3960c2SGovind Singh WARN_ON(ul_set); 11202c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 11212c3960c2SGovind Singh ul_set = true; 11222c3960c2SGovind Singh break; 11232c3960c2SGovind Singh case PIPEDIR_INOUT: 11242c3960c2SGovind Singh WARN_ON(dl_set); 11252c3960c2SGovind Singh WARN_ON(ul_set); 11262c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 11272c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 11282c3960c2SGovind Singh dl_set = true; 11292c3960c2SGovind Singh ul_set = true; 11302c3960c2SGovind Singh break; 11312c3960c2SGovind Singh } 11322c3960c2SGovind Singh } 11332c3960c2SGovind Singh 11342c3960c2SGovind Singh if (WARN_ON(!ul_set || !dl_set)) 11352c3960c2SGovind Singh return -ENOENT; 11367f4beda2SGovind Singh 11377f4beda2SGovind Singh return 0; 11387f4beda2SGovind Singh } 11397f4beda2SGovind Singh 11407f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = { 11417f4beda2SGovind Singh .start = ath11k_pci_start, 11427f4beda2SGovind Singh .stop = ath11k_pci_stop, 1143654e959aSGovind Singh .read32 = ath11k_pci_read32, 1144654e959aSGovind Singh .write32 = ath11k_pci_write32, 11451399fb87SGovind Singh .power_down = ath11k_pci_power_down, 11461399fb87SGovind Singh .power_up = ath11k_pci_power_up, 1147fa5917e4SCarl Huang .suspend = ath11k_pci_hif_suspend, 1148fa5917e4SCarl Huang .resume = ath11k_pci_hif_resume, 1149d4ecb90bSCarl Huang .irq_enable = ath11k_pci_ext_irq_enable, 1150d4ecb90bSCarl Huang .irq_disable = ath11k_pci_ext_irq_disable, 1151c4eacabeSGovind Singh .get_msi_address = ath11k_pci_get_msi_address, 1152c4eacabeSGovind Singh .get_user_msi_vector = ath11k_get_user_msi_assignment, 11532c3960c2SGovind Singh .map_service_to_pipe = ath11k_pci_map_service_to_pipe, 1154d578ec2aSCarl Huang .ce_irq_enable = ath11k_pci_hif_ce_irq_enable, 1155d578ec2aSCarl Huang .ce_irq_disable = ath11k_pci_hif_ce_irq_disable, 1156*6289ac2bSKarthikeyan Periyasamy .get_ce_msi_idx = ath11k_pci_get_ce_msi_idx, 11571399fb87SGovind Singh }; 11581399fb87SGovind Singh 11596e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev, 11606e0355afSGovind Singh const struct pci_device_id *pci_dev) 11616e0355afSGovind Singh { 11626e0355afSGovind Singh struct ath11k_base *ab; 11635762613eSGovind Singh struct ath11k_pci *ab_pci; 116418ac1665SKalle Valo u32 soc_hw_version, soc_hw_version_major, soc_hw_version_minor; 11655762613eSGovind Singh int ret; 11666e0355afSGovind Singh 11671ff8ed78SGovind Singh ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, 11681ff8ed78SGovind Singh &ath11k_pci_bus_params); 11696e0355afSGovind Singh if (!ab) { 11706e0355afSGovind Singh dev_err(&pdev->dev, "failed to allocate ath11k base\n"); 11716e0355afSGovind Singh return -ENOMEM; 11726e0355afSGovind Singh } 11736e0355afSGovind Singh 11746e0355afSGovind Singh ab->dev = &pdev->dev; 11756e0355afSGovind Singh pci_set_drvdata(pdev, ab); 11765762613eSGovind Singh ab_pci = ath11k_pci_priv(ab); 11775762613eSGovind Singh ab_pci->dev_id = pci_dev->device; 11785762613eSGovind Singh ab_pci->ab = ab; 11795697a564SGovind Singh ab_pci->pdev = pdev; 11807f4beda2SGovind Singh ab->hif.ops = &ath11k_pci_hif_ops; 11815762613eSGovind Singh pci_set_drvdata(pdev, ab); 1182654e959aSGovind Singh spin_lock_init(&ab_pci->window_lock); 11835762613eSGovind Singh 11845762613eSGovind Singh ret = ath11k_pci_claim(ab_pci, pdev); 11855762613eSGovind Singh if (ret) { 11865762613eSGovind Singh ath11k_err(ab, "failed to claim device: %d\n", ret); 11875762613eSGovind Singh goto err_free_core; 11885762613eSGovind Singh } 11896e0355afSGovind Singh 119018ac1665SKalle Valo switch (pci_dev->device) { 119118ac1665SKalle Valo case QCA6390_DEVICE_ID: 119218ac1665SKalle Valo soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION); 119318ac1665SKalle Valo soc_hw_version_major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK, 119418ac1665SKalle Valo soc_hw_version); 119518ac1665SKalle Valo soc_hw_version_minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK, 119618ac1665SKalle Valo soc_hw_version); 119718ac1665SKalle Valo 119818ac1665SKalle Valo ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n", 119918ac1665SKalle Valo soc_hw_version_major, soc_hw_version_minor); 120018ac1665SKalle Valo 120118ac1665SKalle Valo switch (soc_hw_version_major) { 120218ac1665SKalle Valo case 2: 120318ac1665SKalle Valo ab->hw_rev = ATH11K_HW_QCA6390_HW20; 120418ac1665SKalle Valo break; 120518ac1665SKalle Valo default: 120618ac1665SKalle Valo dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n", 120718ac1665SKalle Valo soc_hw_version_major, soc_hw_version_minor); 120818ac1665SKalle Valo ret = -EOPNOTSUPP; 120918ac1665SKalle Valo goto err_pci_free_region; 121018ac1665SKalle Valo } 121118ac1665SKalle Valo break; 121218ac1665SKalle Valo default: 121318ac1665SKalle Valo dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", 121418ac1665SKalle Valo pci_dev->device); 121518ac1665SKalle Valo ret = -EOPNOTSUPP; 121618ac1665SKalle Valo goto err_pci_free_region; 121718ac1665SKalle Valo } 121818ac1665SKalle Valo 12197a3aed0cSAnilkumar Kolli ab_pci->msi_config = &ath11k_msi_config[0]; 12205697a564SGovind Singh ret = ath11k_pci_enable_msi(ab_pci); 12215697a564SGovind Singh if (ret) { 12225697a564SGovind Singh ath11k_err(ab, "failed to enable msi: %d\n", ret); 12235697a564SGovind Singh goto err_pci_free_region; 12245697a564SGovind Singh } 12255697a564SGovind Singh 1226b8246f88SKalle Valo ret = ath11k_core_pre_init(ab); 1227b8246f88SKalle Valo if (ret) 1228b8246f88SKalle Valo goto err_pci_disable_msi; 1229b8246f88SKalle Valo 12301399fb87SGovind Singh ret = ath11k_mhi_register(ab_pci); 12311399fb87SGovind Singh if (ret) { 12321399fb87SGovind Singh ath11k_err(ab, "failed to register mhi: %d\n", ret); 12331399fb87SGovind Singh goto err_pci_disable_msi; 12341399fb87SGovind Singh } 12351399fb87SGovind Singh 12367f4beda2SGovind Singh ret = ath11k_hal_srng_init(ab); 12377f4beda2SGovind Singh if (ret) 12387f4beda2SGovind Singh goto err_mhi_unregister; 12397f4beda2SGovind Singh 12407f4beda2SGovind Singh ret = ath11k_ce_alloc_pipes(ab); 12417f4beda2SGovind Singh if (ret) { 12427f4beda2SGovind Singh ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret); 12437f4beda2SGovind Singh goto err_hal_srng_deinit; 12447f4beda2SGovind Singh } 12457f4beda2SGovind Singh 12467f4beda2SGovind Singh ath11k_pci_init_qmi_ce_config(ab); 12477f4beda2SGovind Singh 12487f4beda2SGovind Singh ret = ath11k_pci_config_irq(ab); 12497f4beda2SGovind Singh if (ret) { 12507f4beda2SGovind Singh ath11k_err(ab, "failed to config irq: %d\n", ret); 12517f4beda2SGovind Singh goto err_ce_free; 12527f4beda2SGovind Singh } 12537f4beda2SGovind Singh 12547f4beda2SGovind Singh ret = ath11k_core_init(ab); 12557f4beda2SGovind Singh if (ret) { 12567f4beda2SGovind Singh ath11k_err(ab, "failed to init core: %d\n", ret); 12577f4beda2SGovind Singh goto err_free_irq; 12587f4beda2SGovind Singh } 12596e0355afSGovind Singh return 0; 12605762613eSGovind Singh 12617f4beda2SGovind Singh err_free_irq: 12627f4beda2SGovind Singh ath11k_pci_free_irq(ab); 12637f4beda2SGovind Singh 12647f4beda2SGovind Singh err_ce_free: 12657f4beda2SGovind Singh ath11k_ce_free_pipes(ab); 12667f4beda2SGovind Singh 12677f4beda2SGovind Singh err_hal_srng_deinit: 12687f4beda2SGovind Singh ath11k_hal_srng_deinit(ab); 12697f4beda2SGovind Singh 12707f4beda2SGovind Singh err_mhi_unregister: 12717f4beda2SGovind Singh ath11k_mhi_unregister(ab_pci); 12727f4beda2SGovind Singh 1273b8246f88SKalle Valo err_pci_disable_msi: 1274b8246f88SKalle Valo ath11k_pci_disable_msi(ab_pci); 1275b8246f88SKalle Valo 12765697a564SGovind Singh err_pci_free_region: 12775697a564SGovind Singh ath11k_pci_free_region(ab_pci); 12785697a564SGovind Singh 12795762613eSGovind Singh err_free_core: 12805762613eSGovind Singh ath11k_core_free(ab); 12815697a564SGovind Singh 12825762613eSGovind Singh return ret; 12836e0355afSGovind Singh } 12846e0355afSGovind Singh 12856e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev) 12866e0355afSGovind Singh { 12876e0355afSGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 12885762613eSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 12896e0355afSGovind Singh 129061a57e51SAnilkumar Kolli if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { 129161a57e51SAnilkumar Kolli ath11k_pci_power_down(ab); 129261a57e51SAnilkumar Kolli ath11k_debugfs_soc_destroy(ab); 129361a57e51SAnilkumar Kolli ath11k_qmi_deinit_service(ab); 129461a57e51SAnilkumar Kolli goto qmi_fail; 129561a57e51SAnilkumar Kolli } 129661a57e51SAnilkumar Kolli 12976e0355afSGovind Singh set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); 12986fbd8898SCarl Huang 12996fbd8898SCarl Huang ath11k_core_deinit(ab); 13006fbd8898SCarl Huang 130161a57e51SAnilkumar Kolli qmi_fail: 13021399fb87SGovind Singh ath11k_mhi_unregister(ab_pci); 13036fbd8898SCarl Huang 13046fbd8898SCarl Huang ath11k_pci_free_irq(ab); 13055697a564SGovind Singh ath11k_pci_disable_msi(ab_pci); 13065762613eSGovind Singh ath11k_pci_free_region(ab_pci); 13076fbd8898SCarl Huang 13086fbd8898SCarl Huang ath11k_hal_srng_deinit(ab); 13096fbd8898SCarl Huang ath11k_ce_free_pipes(ab); 13106e0355afSGovind Singh ath11k_core_free(ab); 13116e0355afSGovind Singh } 13126e0355afSGovind Singh 13131399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev) 13141399fb87SGovind Singh { 13151399fb87SGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 13161399fb87SGovind Singh 13171399fb87SGovind Singh ath11k_pci_power_down(ab); 13181399fb87SGovind Singh } 13191399fb87SGovind Singh 1320d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev) 1321d1b0c338SCarl Huang { 1322d1b0c338SCarl Huang struct ath11k_base *ab = dev_get_drvdata(dev); 1323d1b0c338SCarl Huang int ret; 1324d1b0c338SCarl Huang 1325d1b0c338SCarl Huang ret = ath11k_core_suspend(ab); 1326d1b0c338SCarl Huang if (ret) 1327d1b0c338SCarl Huang ath11k_warn(ab, "failed to suspend core: %d\n", ret); 1328d1b0c338SCarl Huang 1329d1b0c338SCarl Huang return ret; 1330d1b0c338SCarl Huang } 1331d1b0c338SCarl Huang 1332d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev) 1333d1b0c338SCarl Huang { 1334d1b0c338SCarl Huang struct ath11k_base *ab = dev_get_drvdata(dev); 1335d1b0c338SCarl Huang int ret; 1336d1b0c338SCarl Huang 1337d1b0c338SCarl Huang ret = ath11k_core_resume(ab); 1338d1b0c338SCarl Huang if (ret) 1339d1b0c338SCarl Huang ath11k_warn(ab, "failed to resume core: %d\n", ret); 1340d1b0c338SCarl Huang 1341d1b0c338SCarl Huang return ret; 1342d1b0c338SCarl Huang } 1343d1b0c338SCarl Huang 1344d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops, 1345d1b0c338SCarl Huang ath11k_pci_pm_suspend, 1346d1b0c338SCarl Huang ath11k_pci_pm_resume); 1347d1b0c338SCarl Huang 13486e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = { 13496e0355afSGovind Singh .name = "ath11k_pci", 13506e0355afSGovind Singh .id_table = ath11k_pci_id_table, 13516e0355afSGovind Singh .probe = ath11k_pci_probe, 13526e0355afSGovind Singh .remove = ath11k_pci_remove, 13531399fb87SGovind Singh .shutdown = ath11k_pci_shutdown, 1354d1b0c338SCarl Huang #ifdef CONFIG_PM 1355d1b0c338SCarl Huang .driver.pm = &ath11k_pci_pm_ops, 1356d1b0c338SCarl Huang #endif 13576e0355afSGovind Singh }; 13586e0355afSGovind Singh 13596e0355afSGovind Singh static int ath11k_pci_init(void) 13606e0355afSGovind Singh { 13616e0355afSGovind Singh int ret; 13626e0355afSGovind Singh 13636e0355afSGovind Singh ret = pci_register_driver(&ath11k_pci_driver); 13646e0355afSGovind Singh if (ret) 13656e0355afSGovind Singh pr_err("failed to register ath11k pci driver: %d\n", 13666e0355afSGovind Singh ret); 13676e0355afSGovind Singh 13686e0355afSGovind Singh return ret; 13696e0355afSGovind Singh } 13706e0355afSGovind Singh module_init(ath11k_pci_init); 13716e0355afSGovind Singh 13726e0355afSGovind Singh static void ath11k_pci_exit(void) 13736e0355afSGovind Singh { 13746e0355afSGovind Singh pci_unregister_driver(&ath11k_pci_driver); 13756e0355afSGovind Singh } 13766e0355afSGovind Singh 13776e0355afSGovind Singh module_exit(ath11k_pci_exit); 13786e0355afSGovind Singh 13796e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); 13806e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL"); 13813dbd7fe7SDevin Bayer 13823dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */ 13833dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE); 13843dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE); 13853dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE); 1386