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 384e809461SAnilkumar Kolli #define QCN9074_DEVICE_ID 0x1104 390fbf1957SBaochen Qiang #define WCN6855_DEVICE_ID 0x1103 406e0355afSGovind Singh 416e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = { 426e0355afSGovind Singh { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, 430fbf1957SBaochen Qiang { PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) }, 4449f5b114SAnilkumar Kolli { PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) }, 456e0355afSGovind Singh {0} 466e0355afSGovind Singh }; 476e0355afSGovind Singh 486e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); 496e0355afSGovind Singh 501ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = { 511ff8ed78SGovind Singh .mhi_support = true, 5256970454SGovind Singh .m3_fw_support = true, 536eb6ea51SGovind Singh .fixed_bdf_addr = false, 546eb6ea51SGovind Singh .fixed_mem_region = false, 551ff8ed78SGovind Singh }; 561ff8ed78SGovind Singh 577a3aed0cSAnilkumar Kolli static const struct ath11k_msi_config ath11k_msi_config[] = { 587a3aed0cSAnilkumar Kolli { 595697a564SGovind Singh .total_vectors = 32, 605697a564SGovind Singh .total_users = 4, 615697a564SGovind Singh .users = (struct ath11k_msi_user[]) { 625697a564SGovind Singh { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 635697a564SGovind Singh { .name = "CE", .num_vectors = 10, .base_vector = 3 }, 645697a564SGovind Singh { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, 655697a564SGovind Singh { .name = "DP", .num_vectors = 18, .base_vector = 14 }, 665697a564SGovind Singh }, 677a3aed0cSAnilkumar Kolli }, 684e809461SAnilkumar Kolli { 694e809461SAnilkumar Kolli .total_vectors = 16, 704e809461SAnilkumar Kolli .total_users = 3, 714e809461SAnilkumar Kolli .users = (struct ath11k_msi_user[]) { 724e809461SAnilkumar Kolli { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 734e809461SAnilkumar Kolli { .name = "CE", .num_vectors = 5, .base_vector = 3 }, 744e809461SAnilkumar Kolli { .name = "DP", .num_vectors = 8, .base_vector = 8 }, 754e809461SAnilkumar Kolli }, 764e809461SAnilkumar Kolli }, 775697a564SGovind Singh }; 785697a564SGovind Singh 797f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { 807f4beda2SGovind Singh "bhi", 817f4beda2SGovind Singh "mhi-er0", 827f4beda2SGovind Singh "mhi-er1", 837f4beda2SGovind Singh "ce0", 847f4beda2SGovind Singh "ce1", 857f4beda2SGovind Singh "ce2", 867f4beda2SGovind Singh "ce3", 877f4beda2SGovind Singh "ce4", 887f4beda2SGovind Singh "ce5", 897f4beda2SGovind Singh "ce6", 907f4beda2SGovind Singh "ce7", 917f4beda2SGovind Singh "ce8", 927f4beda2SGovind Singh "ce9", 937f4beda2SGovind Singh "ce10", 947f4beda2SGovind Singh "ce11", 957f4beda2SGovind Singh "host2wbm-desc-feed", 967f4beda2SGovind Singh "host2reo-re-injection", 977f4beda2SGovind Singh "host2reo-command", 987f4beda2SGovind Singh "host2rxdma-monitor-ring3", 997f4beda2SGovind Singh "host2rxdma-monitor-ring2", 1007f4beda2SGovind Singh "host2rxdma-monitor-ring1", 1017f4beda2SGovind Singh "reo2ost-exception", 1027f4beda2SGovind Singh "wbm2host-rx-release", 1037f4beda2SGovind Singh "reo2host-status", 1047f4beda2SGovind Singh "reo2host-destination-ring4", 1057f4beda2SGovind Singh "reo2host-destination-ring3", 1067f4beda2SGovind Singh "reo2host-destination-ring2", 1077f4beda2SGovind Singh "reo2host-destination-ring1", 1087f4beda2SGovind Singh "rxdma2host-monitor-destination-mac3", 1097f4beda2SGovind Singh "rxdma2host-monitor-destination-mac2", 1107f4beda2SGovind Singh "rxdma2host-monitor-destination-mac1", 1117f4beda2SGovind Singh "ppdu-end-interrupts-mac3", 1127f4beda2SGovind Singh "ppdu-end-interrupts-mac2", 1137f4beda2SGovind Singh "ppdu-end-interrupts-mac1", 1147f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac3", 1157f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac2", 1167f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac1", 1177f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac3", 1187f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac2", 1197f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac1", 1207f4beda2SGovind Singh "rxdma2host-destination-ring-mac3", 1217f4beda2SGovind Singh "rxdma2host-destination-ring-mac2", 1227f4beda2SGovind Singh "rxdma2host-destination-ring-mac1", 1237f4beda2SGovind Singh "host2tcl-input-ring4", 1247f4beda2SGovind Singh "host2tcl-input-ring3", 1257f4beda2SGovind Singh "host2tcl-input-ring2", 1267f4beda2SGovind Singh "host2tcl-input-ring1", 1277f4beda2SGovind Singh "wbm2host-tx-completions-ring3", 1287f4beda2SGovind Singh "wbm2host-tx-completions-ring2", 1297f4beda2SGovind Singh "wbm2host-tx-completions-ring1", 1307f4beda2SGovind Singh "tcl2host-status-ring", 1317f4beda2SGovind Singh }; 1327f4beda2SGovind Singh 133654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset) 134654e959aSGovind Singh { 135654e959aSGovind Singh struct ath11k_base *ab = ab_pci->ab; 136654e959aSGovind Singh 137654e959aSGovind Singh u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset); 138654e959aSGovind Singh 139654e959aSGovind Singh lockdep_assert_held(&ab_pci->window_lock); 140654e959aSGovind Singh 141654e959aSGovind Singh if (window != ab_pci->register_window) { 142654e959aSGovind Singh iowrite32(WINDOW_ENABLE_BIT | window, 143654e959aSGovind Singh ab->mem + WINDOW_REG_ADDRESS); 144f6fa37a4SCarl Huang ioread32(ab->mem + WINDOW_REG_ADDRESS); 145654e959aSGovind Singh ab_pci->register_window = window; 146654e959aSGovind Singh } 147654e959aSGovind Singh } 148654e959aSGovind Singh 149480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci) 150480a7361SKarthikeyan Periyasamy { 151480a7361SKarthikeyan Periyasamy u32 umac_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET); 152480a7361SKarthikeyan Periyasamy u32 ce_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE); 153480a7361SKarthikeyan Periyasamy u32 window; 154480a7361SKarthikeyan Periyasamy 155480a7361SKarthikeyan Periyasamy window = (umac_window << 12) | (ce_window << 6); 156480a7361SKarthikeyan Periyasamy 157480a7361SKarthikeyan Periyasamy iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + WINDOW_REG_ADDRESS); 158480a7361SKarthikeyan Periyasamy } 159480a7361SKarthikeyan Periyasamy 160480a7361SKarthikeyan Periyasamy static inline u32 ath11k_pci_get_window_start(struct ath11k_base *ab, 161480a7361SKarthikeyan Periyasamy u32 offset) 162480a7361SKarthikeyan Periyasamy { 163480a7361SKarthikeyan Periyasamy u32 window_start; 164480a7361SKarthikeyan Periyasamy 165480a7361SKarthikeyan Periyasamy /* If offset lies within DP register range, use 3rd window */ 166480a7361SKarthikeyan Periyasamy if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < WINDOW_RANGE_MASK) 167480a7361SKarthikeyan Periyasamy window_start = 3 * WINDOW_START; 168480a7361SKarthikeyan Periyasamy /* If offset lies within CE register range, use 2nd window */ 169480a7361SKarthikeyan Periyasamy else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK) 170480a7361SKarthikeyan Periyasamy window_start = 2 * WINDOW_START; 171480a7361SKarthikeyan Periyasamy else 172480a7361SKarthikeyan Periyasamy window_start = WINDOW_START; 173480a7361SKarthikeyan Periyasamy 174480a7361SKarthikeyan Periyasamy return window_start; 175480a7361SKarthikeyan Periyasamy } 176480a7361SKarthikeyan Periyasamy 177f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) 178654e959aSGovind Singh { 179654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 180480a7361SKarthikeyan Periyasamy u32 window_start; 181654e959aSGovind Singh 182a05bd851SCarl Huang /* for offset beyond BAR + 4K - 32, may 183a05bd851SCarl Huang * need to wakeup MHI to access. 184a05bd851SCarl Huang */ 185a05bd851SCarl Huang if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 186a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 187a05bd851SCarl Huang mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); 188a05bd851SCarl Huang 189654e959aSGovind Singh if (offset < WINDOW_START) { 190654e959aSGovind Singh iowrite32(value, ab->mem + offset); 191654e959aSGovind Singh } else { 192480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 193480a7361SKarthikeyan Periyasamy window_start = ath11k_pci_get_window_start(ab, offset); 194480a7361SKarthikeyan Periyasamy else 195480a7361SKarthikeyan Periyasamy window_start = WINDOW_START; 196480a7361SKarthikeyan Periyasamy 197480a7361SKarthikeyan Periyasamy if (window_start == WINDOW_START) { 198654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 199654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 200480a7361SKarthikeyan Periyasamy iowrite32(value, ab->mem + window_start + 201480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 202654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 203480a7361SKarthikeyan Periyasamy } else { 204480a7361SKarthikeyan Periyasamy iowrite32(value, ab->mem + window_start + 205480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 206480a7361SKarthikeyan Periyasamy } 207654e959aSGovind Singh } 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_put(ab_pci->mhi_ctrl->mhi_dev); 212654e959aSGovind Singh } 213654e959aSGovind Singh 214f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) 215654e959aSGovind Singh { 216654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 217480a7361SKarthikeyan Periyasamy u32 val, window_start; 218654e959aSGovind Singh 219a05bd851SCarl Huang /* for offset beyond BAR + 4K - 32, may 220a05bd851SCarl Huang * need to wakeup MHI to access. 221a05bd851SCarl Huang */ 222a05bd851SCarl Huang if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 223a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 224a05bd851SCarl Huang mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); 225a05bd851SCarl Huang 226654e959aSGovind Singh if (offset < WINDOW_START) { 227654e959aSGovind Singh val = ioread32(ab->mem + offset); 228654e959aSGovind Singh } else { 229480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 230480a7361SKarthikeyan Periyasamy window_start = ath11k_pci_get_window_start(ab, offset); 231480a7361SKarthikeyan Periyasamy else 232480a7361SKarthikeyan Periyasamy window_start = WINDOW_START; 233480a7361SKarthikeyan Periyasamy 234480a7361SKarthikeyan Periyasamy if (window_start == WINDOW_START) { 235654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 236654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 237480a7361SKarthikeyan Periyasamy val = ioread32(ab->mem + window_start + 238480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 239654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 240480a7361SKarthikeyan Periyasamy } else { 241480a7361SKarthikeyan Periyasamy val = ioread32(ab->mem + window_start + 242480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 243480a7361SKarthikeyan Periyasamy } 244654e959aSGovind Singh } 245654e959aSGovind Singh 246a05bd851SCarl Huang if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 247a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 248a05bd851SCarl Huang mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); 249a05bd851SCarl Huang 250654e959aSGovind Singh return val; 251654e959aSGovind Singh } 252654e959aSGovind Singh 253f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) 254f3c603d4SCarl Huang { 255f3c603d4SCarl Huang u32 val, delay; 256f3c603d4SCarl Huang 257f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 258f3c603d4SCarl Huang 259f3c603d4SCarl Huang val |= PCIE_SOC_GLOBAL_RESET_V; 260f3c603d4SCarl Huang 261f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 262f3c603d4SCarl Huang 263f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 264f3c603d4SCarl Huang delay = 10; 265f3c603d4SCarl Huang mdelay(delay); 266f3c603d4SCarl Huang 267f3c603d4SCarl Huang /* Need to toggle V bit back otherwise stuck in reset status */ 268f3c603d4SCarl Huang val &= ~PCIE_SOC_GLOBAL_RESET_V; 269f3c603d4SCarl Huang 270f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 271f3c603d4SCarl Huang 272f3c603d4SCarl Huang mdelay(delay); 273f3c603d4SCarl Huang 274f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 275f3c603d4SCarl Huang if (val == 0xffffffff) 276f3c603d4SCarl Huang ath11k_warn(ab, "link down error during global reset\n"); 277f3c603d4SCarl Huang } 278f3c603d4SCarl Huang 279f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) 280f3c603d4SCarl Huang { 281f3c603d4SCarl Huang u32 val; 282f3c603d4SCarl Huang 283f3c603d4SCarl Huang /* read cookie */ 284f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR); 285f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val); 286f3c603d4SCarl Huang 287f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 288f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 289f3c603d4SCarl Huang 290f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 291f3c603d4SCarl Huang mdelay(10); 292f3c603d4SCarl Huang 293f3c603d4SCarl Huang /* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from 294f3c603d4SCarl Huang * continuing warm path and entering dead loop. 295f3c603d4SCarl Huang */ 296f3c603d4SCarl Huang ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0); 297f3c603d4SCarl Huang mdelay(10); 298f3c603d4SCarl Huang 299f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 300f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 301f3c603d4SCarl Huang 302f3c603d4SCarl Huang /* A read clear register. clear the register to prevent 303f3c603d4SCarl Huang * Q6 from entering wrong code path. 304f3c603d4SCarl Huang */ 305f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG); 306f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val); 307f3c603d4SCarl Huang } 308f3c603d4SCarl Huang 30906999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab, 31006999407SCarl Huang u32 offset, u32 value, u32 mask) 31106999407SCarl Huang { 31206999407SCarl Huang u32 v; 31306999407SCarl Huang int i; 31406999407SCarl Huang 31506999407SCarl Huang v = ath11k_pci_read32(ab, offset); 31606999407SCarl Huang if ((v & mask) == value) 31706999407SCarl Huang return 0; 31806999407SCarl Huang 31906999407SCarl Huang for (i = 0; i < 10; i++) { 32006999407SCarl Huang ath11k_pci_write32(ab, offset, (v & ~mask) | value); 32106999407SCarl Huang 32206999407SCarl Huang v = ath11k_pci_read32(ab, offset); 32306999407SCarl Huang if ((v & mask) == value) 32406999407SCarl Huang return 0; 32506999407SCarl Huang 32606999407SCarl Huang mdelay(2); 32706999407SCarl Huang } 32806999407SCarl Huang 32906999407SCarl Huang ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n", 33006999407SCarl Huang offset, v & mask, value); 33106999407SCarl Huang 33206999407SCarl Huang return -ETIMEDOUT; 33306999407SCarl Huang } 33406999407SCarl Huang 33506999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab) 33606999407SCarl Huang { 33706999407SCarl Huang int ret; 33806999407SCarl Huang 33906999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3406fe6f68fSKarthikeyan Periyasamy PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab), 34106999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL, 34206999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK); 34330d08503SDan Carpenter if (ret) { 34406999407SCarl Huang ath11k_warn(ab, "failed to set sysclk: %d\n", ret); 34506999407SCarl Huang return ret; 34606999407SCarl Huang } 34706999407SCarl Huang 34806999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3496fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab), 3506fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG1_VAL, 3516fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 35230d08503SDan Carpenter if (ret) { 35306999407SCarl Huang ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret); 35406999407SCarl Huang return ret; 35506999407SCarl Huang } 35606999407SCarl Huang 35706999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3586fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab), 3596fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG2_VAL, 3606fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 36130d08503SDan Carpenter if (ret) { 36206999407SCarl Huang ath11k_warn(ab, "failed to set dtct config2: %d\n", ret); 36306999407SCarl Huang return ret; 36406999407SCarl Huang } 36506999407SCarl Huang 36606999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3676fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab), 3686fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG4_VAL, 3696fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 37030d08503SDan Carpenter if (ret) { 37106999407SCarl Huang ath11k_warn(ab, "failed to set dtct config4: %d\n", ret); 37206999407SCarl Huang return ret; 37306999407SCarl Huang } 37406999407SCarl Huang 37506999407SCarl Huang return 0; 37606999407SCarl Huang } 37706999407SCarl Huang 378babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab) 379babb0cedSCarl Huang { 380babb0cedSCarl Huang u32 val; 381babb0cedSCarl Huang int i; 382babb0cedSCarl Huang 383babb0cedSCarl Huang val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); 384babb0cedSCarl Huang 385babb0cedSCarl Huang /* PCIE link seems very unstable after the Hot Reset*/ 386babb0cedSCarl Huang for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) { 387babb0cedSCarl Huang if (val == 0xffffffff) 388babb0cedSCarl Huang mdelay(5); 389babb0cedSCarl Huang 390babb0cedSCarl Huang ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE); 391babb0cedSCarl Huang val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); 392babb0cedSCarl Huang } 393babb0cedSCarl Huang 394babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val); 395babb0cedSCarl Huang 396babb0cedSCarl Huang val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); 397562934adSKalle Valo val |= GCC_GCC_PCIE_HOT_RST_VAL; 398babb0cedSCarl Huang ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val); 399babb0cedSCarl Huang val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); 400babb0cedSCarl Huang 401babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val); 402babb0cedSCarl Huang 403babb0cedSCarl Huang mdelay(5); 404babb0cedSCarl Huang } 405babb0cedSCarl Huang 406babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab) 407babb0cedSCarl Huang { 408babb0cedSCarl Huang /* This is a WAR for PCIE Hotreset. 409babb0cedSCarl Huang * When target receive Hotreset, but will set the interrupt. 410babb0cedSCarl Huang * So when download SBL again, SBL will open Interrupt and 411babb0cedSCarl Huang * receive it, and crash immediately. 412babb0cedSCarl Huang */ 413babb0cedSCarl Huang ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL); 414babb0cedSCarl Huang } 415babb0cedSCarl Huang 4160ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab) 4170ccdf439SCarl Huang { 4180ccdf439SCarl Huang u32 val; 4190ccdf439SCarl Huang 4200ccdf439SCarl Huang val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG); 4210ccdf439SCarl Huang val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK; 4220ccdf439SCarl Huang ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val); 4230ccdf439SCarl Huang } 4240ccdf439SCarl Huang 425f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab) 426f3c603d4SCarl Huang { 427f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1); 428f3c603d4SCarl Huang mdelay(5); 429f3c603d4SCarl Huang } 430f3c603d4SCarl Huang 431babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on) 432f3c603d4SCarl Huang { 4338a0b899fSBaochen Qiang mdelay(100); 4348a0b899fSBaochen Qiang 435babb0cedSCarl Huang if (power_on) { 436babb0cedSCarl Huang ath11k_pci_enable_ltssm(ab); 437babb0cedSCarl Huang ath11k_pci_clear_all_intrs(ab); 4380ccdf439SCarl Huang ath11k_pci_set_wlaon_pwr_ctrl(ab); 4395088df05SBaochen Qiang if (ab->hw_params.fix_l1ss) 44006999407SCarl Huang ath11k_pci_fix_l1ss(ab); 441babb0cedSCarl Huang } 442babb0cedSCarl Huang 443f3c603d4SCarl Huang ath11k_mhi_clear_vector(ab); 4448a0b899fSBaochen Qiang ath11k_pci_clear_dbg_registers(ab); 445f3c603d4SCarl Huang ath11k_pci_soc_global_reset(ab); 446f3c603d4SCarl Huang ath11k_mhi_set_mhictrl_reset(ab); 447f3c603d4SCarl Huang } 448f3c603d4SCarl Huang 4491399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) 4501399fb87SGovind Singh { 4511399fb87SGovind Singh struct pci_dev *pci_dev = to_pci_dev(dev); 4521399fb87SGovind Singh 4531399fb87SGovind Singh return pci_irq_vector(pci_dev, vector); 4541399fb87SGovind Singh } 4551399fb87SGovind Singh 456c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, 457c4eacabeSGovind Singh u32 *msi_addr_hi) 458c4eacabeSGovind Singh { 459e8e55d89SAnilkumar Kolli struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 460c4eacabeSGovind Singh struct pci_dev *pci_dev = to_pci_dev(ab->dev); 461c4eacabeSGovind Singh 462c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, 463c4eacabeSGovind Singh msi_addr_lo); 464c4eacabeSGovind Singh 465e8e55d89SAnilkumar Kolli if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) { 466c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, 467c4eacabeSGovind Singh msi_addr_hi); 468e8e55d89SAnilkumar Kolli } else { 469e8e55d89SAnilkumar Kolli *msi_addr_hi = 0; 470e8e55d89SAnilkumar Kolli } 471c4eacabeSGovind Singh } 472c4eacabeSGovind Singh 4731399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, 4741399fb87SGovind Singh int *num_vectors, u32 *user_base_data, 4751399fb87SGovind Singh u32 *base_vector) 4761399fb87SGovind Singh { 4771399fb87SGovind Singh struct ath11k_base *ab = ab_pci->ab; 4787a3aed0cSAnilkumar Kolli const struct ath11k_msi_config *msi_config = ab_pci->msi_config; 4791399fb87SGovind Singh int idx; 4801399fb87SGovind Singh 4817a3aed0cSAnilkumar Kolli for (idx = 0; idx < msi_config->total_users; idx++) { 4827a3aed0cSAnilkumar Kolli if (strcmp(user_name, msi_config->users[idx].name) == 0) { 4837a3aed0cSAnilkumar Kolli *num_vectors = msi_config->users[idx].num_vectors; 4847a3aed0cSAnilkumar Kolli *user_base_data = msi_config->users[idx].base_vector 4851399fb87SGovind Singh + ab_pci->msi_ep_base_data; 4867a3aed0cSAnilkumar Kolli *base_vector = msi_config->users[idx].base_vector; 4871399fb87SGovind Singh 4881399fb87SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", 4891399fb87SGovind Singh user_name, *num_vectors, *user_base_data, 4901399fb87SGovind Singh *base_vector); 4911399fb87SGovind Singh 4921399fb87SGovind Singh return 0; 4931399fb87SGovind Singh } 4941399fb87SGovind Singh } 4951399fb87SGovind Singh 4961399fb87SGovind Singh ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name); 4971399fb87SGovind Singh 4981399fb87SGovind Singh return -EINVAL; 4991399fb87SGovind Singh } 5001399fb87SGovind Singh 5016289ac2bSKarthikeyan Periyasamy static void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, 5026289ac2bSKarthikeyan Periyasamy u32 *msi_idx) 5036289ac2bSKarthikeyan Periyasamy { 5046289ac2bSKarthikeyan Periyasamy u32 i, msi_data_idx; 5056289ac2bSKarthikeyan Periyasamy 5066289ac2bSKarthikeyan Periyasamy for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { 5076289ac2bSKarthikeyan Periyasamy if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5086289ac2bSKarthikeyan Periyasamy continue; 5096289ac2bSKarthikeyan Periyasamy 5106289ac2bSKarthikeyan Periyasamy if (ce_id == i) 5116289ac2bSKarthikeyan Periyasamy break; 5126289ac2bSKarthikeyan Periyasamy 5136289ac2bSKarthikeyan Periyasamy msi_data_idx++; 5146289ac2bSKarthikeyan Periyasamy } 5156289ac2bSKarthikeyan Periyasamy *msi_idx = msi_data_idx; 5166289ac2bSKarthikeyan Periyasamy } 5176289ac2bSKarthikeyan Periyasamy 518c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, 519c4eacabeSGovind Singh int *num_vectors, u32 *user_base_data, 520c4eacabeSGovind Singh u32 *base_vector) 521c4eacabeSGovind Singh { 522c4eacabeSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 523c4eacabeSGovind Singh 524c4eacabeSGovind Singh return ath11k_pci_get_user_msi_assignment(ab_pci, user_name, 525c4eacabeSGovind Singh num_vectors, user_base_data, 526c4eacabeSGovind Singh base_vector); 527c4eacabeSGovind Singh } 528c4eacabeSGovind Singh 529d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab) 530d4ecb90bSCarl Huang { 531d4ecb90bSCarl Huang int i, j; 532d4ecb90bSCarl Huang 533d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 534d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 535d4ecb90bSCarl Huang 536d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) 537d4ecb90bSCarl Huang free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); 538d4ecb90bSCarl Huang 539d4ecb90bSCarl Huang netif_napi_del(&irq_grp->napi); 540d4ecb90bSCarl Huang } 541d4ecb90bSCarl Huang } 542d4ecb90bSCarl Huang 5437f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab) 5447f4beda2SGovind Singh { 5457f4beda2SGovind Singh int i, irq_idx; 5467f4beda2SGovind Singh 547d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 548e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5497f4beda2SGovind Singh continue; 5507f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 5517f4beda2SGovind Singh free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); 5527f4beda2SGovind Singh } 553d4ecb90bSCarl Huang 554d4ecb90bSCarl Huang ath11k_pci_free_ext_irq(ab); 5557f4beda2SGovind Singh } 5567f4beda2SGovind Singh 5572c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) 5582c3960c2SGovind Singh { 5592c3960c2SGovind Singh u32 irq_idx; 5602c3960c2SGovind Singh 5612c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 5622c3960c2SGovind Singh enable_irq(ab->irq_num[irq_idx]); 5632c3960c2SGovind Singh } 5642c3960c2SGovind Singh 5657f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) 5667f4beda2SGovind Singh { 5677f4beda2SGovind Singh u32 irq_idx; 5687f4beda2SGovind Singh 5697f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 5707f4beda2SGovind Singh disable_irq_nosync(ab->irq_num[irq_idx]); 5717f4beda2SGovind Singh } 5727f4beda2SGovind Singh 5732c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab) 5742c3960c2SGovind Singh { 5752c3960c2SGovind Singh int i; 5762c3960c2SGovind Singh 577d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 578e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5792c3960c2SGovind Singh continue; 5802c3960c2SGovind Singh ath11k_pci_ce_irq_disable(ab, i); 5812c3960c2SGovind Singh } 5822c3960c2SGovind Singh } 5832c3960c2SGovind Singh 5842c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) 5852c3960c2SGovind Singh { 5862c3960c2SGovind Singh int i; 5872c3960c2SGovind Singh int irq_idx; 5882c3960c2SGovind Singh 589d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 590e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5912c3960c2SGovind Singh continue; 5922c3960c2SGovind Singh 5932c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 5942c3960c2SGovind Singh synchronize_irq(ab->irq_num[irq_idx]); 5952c3960c2SGovind Singh } 5962c3960c2SGovind Singh } 5972c3960c2SGovind Singh 5980f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t) 5992c3960c2SGovind Singh { 6000f01dcb8SAllen Pais struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); 6012c3960c2SGovind Singh 6022c3960c2SGovind Singh ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); 6032c3960c2SGovind Singh 6042c3960c2SGovind Singh ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num); 6052c3960c2SGovind Singh } 6062c3960c2SGovind Singh 6077f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) 6087f4beda2SGovind Singh { 6097f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe = arg; 6107f4beda2SGovind Singh 6117dc67af0SKarthikeyan Periyasamy /* last interrupt received for this CE */ 6127dc67af0SKarthikeyan Periyasamy ce_pipe->timestamp = jiffies; 6137dc67af0SKarthikeyan Periyasamy 6147f4beda2SGovind Singh ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num); 6152c3960c2SGovind Singh tasklet_schedule(&ce_pipe->intr_tq); 6167f4beda2SGovind Singh 6177f4beda2SGovind Singh return IRQ_HANDLED; 6187f4beda2SGovind Singh } 6197f4beda2SGovind Singh 620d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) 621d4ecb90bSCarl Huang { 622d4ecb90bSCarl Huang int i; 623d4ecb90bSCarl Huang 624d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 625d4ecb90bSCarl Huang disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 626d4ecb90bSCarl Huang } 627d4ecb90bSCarl Huang 628d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc) 629d4ecb90bSCarl Huang { 630d4ecb90bSCarl Huang int i; 631d4ecb90bSCarl Huang 632d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 633d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; 634d4ecb90bSCarl Huang 635d4ecb90bSCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 636d4ecb90bSCarl Huang 637d4ecb90bSCarl Huang napi_synchronize(&irq_grp->napi); 638d4ecb90bSCarl Huang napi_disable(&irq_grp->napi); 639d4ecb90bSCarl Huang } 640d4ecb90bSCarl Huang } 641d4ecb90bSCarl Huang 642d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) 643d4ecb90bSCarl Huang { 644d4ecb90bSCarl Huang int i; 645d4ecb90bSCarl Huang 646d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 647d4ecb90bSCarl Huang enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 648d4ecb90bSCarl Huang } 649d4ecb90bSCarl Huang 650d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab) 651d4ecb90bSCarl Huang { 652d4ecb90bSCarl Huang int i; 653d4ecb90bSCarl Huang 654d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 655d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 656d4ecb90bSCarl Huang 657d4ecb90bSCarl Huang napi_enable(&irq_grp->napi); 658d4ecb90bSCarl Huang ath11k_pci_ext_grp_enable(irq_grp); 659d4ecb90bSCarl Huang } 660d4ecb90bSCarl Huang } 661d4ecb90bSCarl Huang 662d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab) 663d4ecb90bSCarl Huang { 664d4ecb90bSCarl Huang int i, j, irq_idx; 665d4ecb90bSCarl Huang 666d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 667d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 668d4ecb90bSCarl Huang 669d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 670d4ecb90bSCarl Huang irq_idx = irq_grp->irqs[j]; 671d4ecb90bSCarl Huang synchronize_irq(ab->irq_num[irq_idx]); 672d4ecb90bSCarl Huang } 673d4ecb90bSCarl Huang } 674d4ecb90bSCarl Huang } 675d4ecb90bSCarl Huang 676d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab) 677d4ecb90bSCarl Huang { 678d4ecb90bSCarl Huang __ath11k_pci_ext_irq_disable(ab); 679d4ecb90bSCarl Huang ath11k_pci_sync_ext_irqs(ab); 680d4ecb90bSCarl Huang } 681d4ecb90bSCarl Huang 682d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) 683d4ecb90bSCarl Huang { 684d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = container_of(napi, 685d4ecb90bSCarl Huang struct ath11k_ext_irq_grp, 686d4ecb90bSCarl Huang napi); 687d4ecb90bSCarl Huang struct ath11k_base *ab = irq_grp->ab; 688d4ecb90bSCarl Huang int work_done; 689d4ecb90bSCarl Huang 690d4ecb90bSCarl Huang work_done = ath11k_dp_service_srng(ab, irq_grp, budget); 691d4ecb90bSCarl Huang if (work_done < budget) { 692d4ecb90bSCarl Huang napi_complete_done(napi, work_done); 693d4ecb90bSCarl Huang ath11k_pci_ext_grp_enable(irq_grp); 694d4ecb90bSCarl Huang } 695d4ecb90bSCarl Huang 696d4ecb90bSCarl Huang if (work_done > budget) 697d4ecb90bSCarl Huang work_done = budget; 698d4ecb90bSCarl Huang 699d4ecb90bSCarl Huang return work_done; 700d4ecb90bSCarl Huang } 701d4ecb90bSCarl Huang 702d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) 703d4ecb90bSCarl Huang { 704d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = arg; 705d4ecb90bSCarl Huang 706d4ecb90bSCarl Huang ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); 707d4ecb90bSCarl Huang 7087dc67af0SKarthikeyan Periyasamy /* last interrupt received for this group */ 7097dc67af0SKarthikeyan Periyasamy irq_grp->timestamp = jiffies; 7107dc67af0SKarthikeyan Periyasamy 711d4ecb90bSCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 712d4ecb90bSCarl Huang 713d4ecb90bSCarl Huang napi_schedule(&irq_grp->napi); 714d4ecb90bSCarl Huang 715d4ecb90bSCarl Huang return IRQ_HANDLED; 716d4ecb90bSCarl Huang } 717d4ecb90bSCarl Huang 718d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) 719d4ecb90bSCarl Huang { 720d4ecb90bSCarl Huang int i, j, ret, num_vectors = 0; 7217dc67af0SKarthikeyan Periyasamy u32 user_base_data = 0, base_vector = 0, base_idx; 722d4ecb90bSCarl Huang 7237dc67af0SKarthikeyan Periyasamy base_idx = ATH11K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX; 724b2c09458SColin Ian King ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", 725b2c09458SColin Ian King &num_vectors, 726b2c09458SColin Ian King &user_base_data, 727d4ecb90bSCarl Huang &base_vector); 728b2c09458SColin Ian King if (ret < 0) 729b2c09458SColin Ian King return ret; 730d4ecb90bSCarl Huang 731d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 732d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 733d4ecb90bSCarl Huang u32 num_irq = 0; 734d4ecb90bSCarl Huang 735d4ecb90bSCarl Huang irq_grp->ab = ab; 736d4ecb90bSCarl Huang irq_grp->grp_id = i; 737d4ecb90bSCarl Huang init_dummy_netdev(&irq_grp->napi_ndev); 738d4ecb90bSCarl Huang netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, 739d4ecb90bSCarl Huang ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT); 740d4ecb90bSCarl Huang 741d4ecb90bSCarl Huang if (ab->hw_params.ring_mask->tx[i] || 742d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx[i] || 743d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_err[i] || 744d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_wbm_rel[i] || 745d4ecb90bSCarl Huang ab->hw_params.ring_mask->reo_status[i] || 746d4ecb90bSCarl Huang ab->hw_params.ring_mask->rxdma2host[i] || 747d4ecb90bSCarl Huang ab->hw_params.ring_mask->host2rxdma[i] || 748d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_mon_status[i]) { 749d4ecb90bSCarl Huang num_irq = 1; 750d4ecb90bSCarl Huang } 751d4ecb90bSCarl Huang 752d4ecb90bSCarl Huang irq_grp->num_irq = num_irq; 7537dc67af0SKarthikeyan Periyasamy irq_grp->irqs[0] = base_idx + i; 754d4ecb90bSCarl Huang 755d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 756d4ecb90bSCarl Huang int irq_idx = irq_grp->irqs[j]; 757d4ecb90bSCarl Huang int vector = (i % num_vectors) + base_vector; 758d4ecb90bSCarl Huang int irq = ath11k_pci_get_msi_irq(ab->dev, vector); 759d4ecb90bSCarl Huang 760d4ecb90bSCarl Huang ab->irq_num[irq_idx] = irq; 761d4ecb90bSCarl Huang 762d4ecb90bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, 763d4ecb90bSCarl Huang "irq:%d group:%d\n", irq, i); 7647dc67af0SKarthikeyan Periyasamy 7657dc67af0SKarthikeyan Periyasamy irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); 766d4ecb90bSCarl Huang ret = request_irq(irq, ath11k_pci_ext_interrupt_handler, 767d4ecb90bSCarl Huang IRQF_SHARED, 768d4ecb90bSCarl Huang "DP_EXT_IRQ", irq_grp); 769d4ecb90bSCarl Huang if (ret) { 770d4ecb90bSCarl Huang ath11k_err(ab, "failed request irq %d: %d\n", 771d4ecb90bSCarl Huang vector, ret); 772d4ecb90bSCarl Huang return ret; 773d4ecb90bSCarl Huang } 774d4ecb90bSCarl Huang 775d4ecb90bSCarl Huang disable_irq_nosync(ab->irq_num[irq_idx]); 776d4ecb90bSCarl Huang } 777d4ecb90bSCarl Huang } 778d4ecb90bSCarl Huang 779d4ecb90bSCarl Huang return 0; 780d4ecb90bSCarl Huang } 781d4ecb90bSCarl Huang 7827f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab) 7837f4beda2SGovind Singh { 7847f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe; 7857f4beda2SGovind Singh u32 msi_data_start; 7866289ac2bSKarthikeyan Periyasamy u32 msi_data_count, msi_data_idx; 7877f4beda2SGovind Singh u32 msi_irq_start; 7887f4beda2SGovind Singh unsigned int msi_data; 7897f4beda2SGovind Singh int irq, i, ret, irq_idx; 7907f4beda2SGovind Singh 7917f4beda2SGovind Singh ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), 7927f4beda2SGovind Singh "CE", &msi_data_count, 7937f4beda2SGovind Singh &msi_data_start, &msi_irq_start); 7947f4beda2SGovind Singh if (ret) 7957f4beda2SGovind Singh return ret; 7967f4beda2SGovind Singh 7977f4beda2SGovind Singh /* Configure CE irqs */ 7986289ac2bSKarthikeyan Periyasamy for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { 799e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 8007f4beda2SGovind Singh continue; 8017f4beda2SGovind Singh 8026289ac2bSKarthikeyan Periyasamy msi_data = (msi_data_idx % msi_data_count) + msi_irq_start; 8036289ac2bSKarthikeyan Periyasamy irq = ath11k_pci_get_msi_irq(ab->dev, msi_data); 8046289ac2bSKarthikeyan Periyasamy ce_pipe = &ab->ce.ce_pipe[i]; 8056289ac2bSKarthikeyan Periyasamy 8067f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 8077f4beda2SGovind Singh 8080f01dcb8SAllen Pais tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet); 8092c3960c2SGovind Singh 8107f4beda2SGovind Singh ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, 8117f4beda2SGovind Singh IRQF_SHARED, irq_name[irq_idx], 8127f4beda2SGovind Singh ce_pipe); 8137f4beda2SGovind Singh if (ret) { 8147f4beda2SGovind Singh ath11k_err(ab, "failed to request irq %d: %d\n", 8157f4beda2SGovind Singh irq_idx, ret); 8167f4beda2SGovind Singh return ret; 8177f4beda2SGovind Singh } 8187f4beda2SGovind Singh 8197f4beda2SGovind Singh ab->irq_num[irq_idx] = irq; 8206289ac2bSKarthikeyan Periyasamy msi_data_idx++; 821e678fbd4SKarthikeyan Periyasamy 822e5c860e1SCarl Huang ath11k_pci_ce_irq_disable(ab, i); 8237f4beda2SGovind Singh } 8247f4beda2SGovind Singh 825d4ecb90bSCarl Huang ret = ath11k_pci_ext_irq_config(ab); 826d4ecb90bSCarl Huang if (ret) 827d4ecb90bSCarl Huang return ret; 828d4ecb90bSCarl Huang 8297f4beda2SGovind Singh return 0; 8307f4beda2SGovind Singh } 8317f4beda2SGovind Singh 8327f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) 8337f4beda2SGovind Singh { 8347f4beda2SGovind Singh struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; 8357f4beda2SGovind Singh 836967c1d11SAnilkumar Kolli cfg->tgt_ce = ab->hw_params.target_ce_config; 837967c1d11SAnilkumar Kolli cfg->tgt_ce_len = ab->hw_params.target_ce_count; 8387f4beda2SGovind Singh 839967c1d11SAnilkumar Kolli cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map; 840967c1d11SAnilkumar Kolli cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len; 84116001e4bSAnilkumar Kolli ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id; 842e838c14aSCarl Huang 843e838c14aSCarl Huang ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2, 844e838c14aSCarl Huang &cfg->shadow_reg_v2_len); 8457f4beda2SGovind Singh } 8467f4beda2SGovind Singh 8477f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) 8487f4beda2SGovind Singh { 8497f4beda2SGovind Singh int i; 8507f4beda2SGovind Singh 851d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 852e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 8537f4beda2SGovind Singh continue; 8547f4beda2SGovind Singh ath11k_pci_ce_irq_enable(ab, i); 8557f4beda2SGovind Singh } 8567f4beda2SGovind Singh } 8577f4beda2SGovind Singh 858*96527d52SBaochen Qiang static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable) 859*96527d52SBaochen Qiang { 860*96527d52SBaochen Qiang struct pci_dev *dev = ab_pci->pdev; 861*96527d52SBaochen Qiang u16 control; 862*96527d52SBaochen Qiang 863*96527d52SBaochen Qiang pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control); 864*96527d52SBaochen Qiang 865*96527d52SBaochen Qiang if (enable) 866*96527d52SBaochen Qiang control |= PCI_MSI_FLAGS_ENABLE; 867*96527d52SBaochen Qiang else 868*96527d52SBaochen Qiang control &= ~PCI_MSI_FLAGS_ENABLE; 869*96527d52SBaochen Qiang 870*96527d52SBaochen Qiang pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control); 871*96527d52SBaochen Qiang } 872*96527d52SBaochen Qiang 873*96527d52SBaochen Qiang static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci) 874*96527d52SBaochen Qiang { 875*96527d52SBaochen Qiang ath11k_pci_msi_config(ab_pci, true); 876*96527d52SBaochen Qiang } 877*96527d52SBaochen Qiang 878*96527d52SBaochen Qiang static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci) 879*96527d52SBaochen Qiang { 880*96527d52SBaochen Qiang ath11k_pci_msi_config(ab_pci, false); 881*96527d52SBaochen Qiang } 882*96527d52SBaochen Qiang 883*96527d52SBaochen Qiang static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci) 8845697a564SGovind Singh { 8855697a564SGovind Singh struct ath11k_base *ab = ab_pci->ab; 8867a3aed0cSAnilkumar Kolli const struct ath11k_msi_config *msi_config = ab_pci->msi_config; 8875697a564SGovind Singh struct msi_desc *msi_desc; 8885697a564SGovind Singh int num_vectors; 8895697a564SGovind Singh int ret; 8905697a564SGovind Singh 8915697a564SGovind Singh num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 8927a3aed0cSAnilkumar Kolli msi_config->total_vectors, 8937a3aed0cSAnilkumar Kolli msi_config->total_vectors, 8945697a564SGovind Singh PCI_IRQ_MSI); 8957a3aed0cSAnilkumar Kolli if (num_vectors != msi_config->total_vectors) { 8965697a564SGovind Singh ath11k_err(ab, "failed to get %d MSI vectors, only %d available", 8977a3aed0cSAnilkumar Kolli msi_config->total_vectors, num_vectors); 8985697a564SGovind Singh 8995697a564SGovind Singh if (num_vectors >= 0) 9005697a564SGovind Singh return -EINVAL; 9015697a564SGovind Singh else 9025697a564SGovind Singh return num_vectors; 9035697a564SGovind Singh } 904*96527d52SBaochen Qiang ath11k_pci_msi_disable(ab_pci); 9055697a564SGovind Singh 9065697a564SGovind Singh msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 9075697a564SGovind Singh if (!msi_desc) { 9085697a564SGovind Singh ath11k_err(ab, "msi_desc is NULL!\n"); 9095697a564SGovind Singh ret = -EINVAL; 9105697a564SGovind Singh goto free_msi_vector; 9115697a564SGovind Singh } 9125697a564SGovind Singh 9135697a564SGovind Singh ab_pci->msi_ep_base_data = msi_desc->msg.data; 914e8e55d89SAnilkumar Kolli if (msi_desc->msi_attrib.is_64) 915e8e55d89SAnilkumar Kolli set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags); 9165697a564SGovind Singh 9175697a564SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); 9185697a564SGovind Singh 9195697a564SGovind Singh return 0; 9205697a564SGovind Singh 9215697a564SGovind Singh free_msi_vector: 9225697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 9235697a564SGovind Singh 9245697a564SGovind Singh return ret; 9255697a564SGovind Singh } 9265697a564SGovind Singh 927*96527d52SBaochen Qiang static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci) 9285697a564SGovind Singh { 9295697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 9305697a564SGovind Singh } 9315697a564SGovind Singh 9325762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) 9335762613eSGovind Singh { 9345762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 9355762613eSGovind Singh u16 device_id; 9365762613eSGovind Singh int ret = 0; 9375762613eSGovind Singh 9385762613eSGovind Singh pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 9395762613eSGovind Singh if (device_id != ab_pci->dev_id) { 9405762613eSGovind Singh ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", 9415762613eSGovind Singh device_id, ab_pci->dev_id); 9425762613eSGovind Singh ret = -EIO; 9435762613eSGovind Singh goto out; 9445762613eSGovind Singh } 9455762613eSGovind Singh 9465762613eSGovind Singh ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); 9475762613eSGovind Singh if (ret) { 9485762613eSGovind Singh ath11k_err(ab, "failed to assign pci resource: %d\n", ret); 9495762613eSGovind Singh goto out; 9505762613eSGovind Singh } 9515762613eSGovind Singh 9525762613eSGovind Singh ret = pci_enable_device(pdev); 9535762613eSGovind Singh if (ret) { 9545762613eSGovind Singh ath11k_err(ab, "failed to enable pci device: %d\n", ret); 9555762613eSGovind Singh goto out; 9565762613eSGovind Singh } 9575762613eSGovind Singh 9585762613eSGovind Singh ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); 9595762613eSGovind Singh if (ret) { 9605762613eSGovind Singh ath11k_err(ab, "failed to request pci region: %d\n", ret); 9615762613eSGovind Singh goto disable_device; 9625762613eSGovind Singh } 9635762613eSGovind Singh 964923a1346SChristophe JAILLET ret = dma_set_mask_and_coherent(&pdev->dev, 965923a1346SChristophe JAILLET DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 9665762613eSGovind Singh if (ret) { 9675762613eSGovind Singh ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", 9685762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 9695762613eSGovind Singh goto release_region; 9705762613eSGovind Singh } 9715762613eSGovind Singh 9725762613eSGovind Singh pci_set_master(pdev); 9735762613eSGovind Singh 9745762613eSGovind Singh ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); 9755762613eSGovind Singh ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); 9765762613eSGovind Singh if (!ab->mem) { 9775762613eSGovind Singh ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); 9785762613eSGovind Singh ret = -EIO; 9795762613eSGovind Singh goto clear_master; 9805762613eSGovind Singh } 9815762613eSGovind Singh 9825762613eSGovind Singh ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); 9835762613eSGovind Singh return 0; 9845762613eSGovind Singh 9855762613eSGovind Singh clear_master: 9865762613eSGovind Singh pci_clear_master(pdev); 9875762613eSGovind Singh release_region: 9885762613eSGovind Singh pci_release_region(pdev, ATH11K_PCI_BAR_NUM); 9895762613eSGovind Singh disable_device: 9905762613eSGovind Singh pci_disable_device(pdev); 9915762613eSGovind Singh out: 9925762613eSGovind Singh return ret; 9935762613eSGovind Singh } 9945762613eSGovind Singh 9955762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) 9965762613eSGovind Singh { 9975762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 9985762613eSGovind Singh struct pci_dev *pci_dev = ab_pci->pdev; 9995762613eSGovind Singh 10005762613eSGovind Singh pci_iounmap(pci_dev, ab->mem); 10015762613eSGovind Singh ab->mem = NULL; 10025762613eSGovind Singh pci_clear_master(pci_dev); 10035762613eSGovind Singh pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); 10045762613eSGovind Singh if (pci_is_enabled(pci_dev)) 10055762613eSGovind Singh pci_disable_device(pci_dev); 10065762613eSGovind Singh } 10075762613eSGovind Singh 1008e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci) 1009e9603f4bSCarl Huang { 1010e9603f4bSCarl Huang struct ath11k_base *ab = ab_pci->ab; 1011e9603f4bSCarl Huang 1012e9603f4bSCarl Huang pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL, 1013e9603f4bSCarl Huang &ab_pci->link_ctl); 1014e9603f4bSCarl Huang 1015e9603f4bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n", 1016e9603f4bSCarl Huang ab_pci->link_ctl, 1017e9603f4bSCarl Huang u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S), 1018e9603f4bSCarl Huang u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1)); 1019e9603f4bSCarl Huang 1020e9603f4bSCarl Huang /* disable L0s and L1 */ 1021e9603f4bSCarl Huang pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, 1022e9603f4bSCarl Huang ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC); 1023e9603f4bSCarl Huang 1024e9603f4bSCarl Huang set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags); 1025e9603f4bSCarl Huang } 1026e9603f4bSCarl Huang 1027e9603f4bSCarl Huang static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci) 1028e9603f4bSCarl Huang { 1029e9603f4bSCarl Huang if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags)) 1030e9603f4bSCarl Huang pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, 1031e9603f4bSCarl Huang ab_pci->link_ctl); 1032e9603f4bSCarl Huang } 1033e9603f4bSCarl Huang 10341399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab) 10351399fb87SGovind Singh { 10361399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 10371399fb87SGovind Singh int ret; 10381399fb87SGovind Singh 1039a05bd851SCarl Huang ab_pci->register_window = 0; 1040a05bd851SCarl Huang clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 1041babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, true); 1042f3c603d4SCarl Huang 1043e9603f4bSCarl Huang /* Disable ASPM during firmware download due to problems switching 1044e9603f4bSCarl Huang * to AMSS state. 1045e9603f4bSCarl Huang */ 1046e9603f4bSCarl Huang ath11k_pci_aspm_disable(ab_pci); 1047e9603f4bSCarl Huang 1048*96527d52SBaochen Qiang ath11k_pci_msi_enable(ab_pci); 1049*96527d52SBaochen Qiang 10501399fb87SGovind Singh ret = ath11k_mhi_start(ab_pci); 10511399fb87SGovind Singh if (ret) { 10521399fb87SGovind Singh ath11k_err(ab, "failed to start mhi: %d\n", ret); 10531399fb87SGovind Singh return ret; 10541399fb87SGovind Singh } 10551399fb87SGovind Singh 1056480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 1057480a7361SKarthikeyan Periyasamy ath11k_pci_select_static_window(ab_pci); 1058480a7361SKarthikeyan Periyasamy 10591399fb87SGovind Singh return 0; 10601399fb87SGovind Singh } 10611399fb87SGovind Singh 10621399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab) 10631399fb87SGovind Singh { 10641399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 10651399fb87SGovind Singh 1066e9603f4bSCarl Huang /* restore aspm in case firmware bootup fails */ 1067e9603f4bSCarl Huang ath11k_pci_aspm_restore(ab_pci); 1068e9603f4bSCarl Huang 1069babb0cedSCarl Huang ath11k_pci_force_wake(ab_pci->ab); 1070*96527d52SBaochen Qiang 1071*96527d52SBaochen Qiang ath11k_pci_msi_disable(ab_pci); 1072*96527d52SBaochen Qiang 10731399fb87SGovind Singh ath11k_mhi_stop(ab_pci); 1074a05bd851SCarl Huang clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 1075babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, false); 10761399fb87SGovind Singh } 10771399fb87SGovind Singh 1078fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab) 1079fa5917e4SCarl Huang { 1080fa5917e4SCarl Huang struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); 1081fa5917e4SCarl Huang 1082fa5917e4SCarl Huang ath11k_mhi_suspend(ar_pci); 1083fa5917e4SCarl Huang 1084fa5917e4SCarl Huang return 0; 1085fa5917e4SCarl Huang } 1086fa5917e4SCarl Huang 1087fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab) 1088fa5917e4SCarl Huang { 1089fa5917e4SCarl Huang struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); 1090fa5917e4SCarl Huang 1091fa5917e4SCarl Huang ath11k_mhi_resume(ar_pci); 1092fa5917e4SCarl Huang 1093fa5917e4SCarl Huang return 0; 1094fa5917e4SCarl Huang } 1095fa5917e4SCarl Huang 10962c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) 10972c3960c2SGovind Singh { 10982c3960c2SGovind Singh int i; 10992c3960c2SGovind Singh 1100d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 11012c3960c2SGovind Singh struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; 11022c3960c2SGovind Singh 1103e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 11042c3960c2SGovind Singh continue; 11052c3960c2SGovind Singh 11062c3960c2SGovind Singh tasklet_kill(&ce_pipe->intr_tq); 11072c3960c2SGovind Singh } 11082c3960c2SGovind Singh } 11092c3960c2SGovind Singh 1110d578ec2aSCarl Huang static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab) 11117f4beda2SGovind Singh { 11122c3960c2SGovind Singh ath11k_pci_ce_irqs_disable(ab); 11132c3960c2SGovind Singh ath11k_pci_sync_ce_irqs(ab); 11142c3960c2SGovind Singh ath11k_pci_kill_tasklets(ab); 1115d578ec2aSCarl Huang } 1116d578ec2aSCarl Huang 1117d578ec2aSCarl Huang static void ath11k_pci_stop(struct ath11k_base *ab) 1118d578ec2aSCarl Huang { 1119d578ec2aSCarl Huang ath11k_pci_ce_irq_disable_sync(ab); 11207f4beda2SGovind Singh ath11k_ce_cleanup_pipes(ab); 11217f4beda2SGovind Singh } 11227f4beda2SGovind Singh 11237f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab) 11247f4beda2SGovind Singh { 1125a05bd851SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 1126a05bd851SCarl Huang 1127a05bd851SCarl Huang set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 1128a05bd851SCarl Huang 1129e9603f4bSCarl Huang ath11k_pci_aspm_restore(ab_pci); 1130e9603f4bSCarl Huang 11317f4beda2SGovind Singh ath11k_pci_ce_irqs_enable(ab); 11322c3960c2SGovind Singh ath11k_ce_rx_post_buf(ab); 11332c3960c2SGovind Singh 11342c3960c2SGovind Singh return 0; 11352c3960c2SGovind Singh } 11362c3960c2SGovind Singh 1137d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab) 1138d578ec2aSCarl Huang { 1139d578ec2aSCarl Huang ath11k_pci_ce_irqs_enable(ab); 1140d578ec2aSCarl Huang } 1141d578ec2aSCarl Huang 1142d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab) 1143d578ec2aSCarl Huang { 1144d578ec2aSCarl Huang ath11k_pci_ce_irq_disable_sync(ab); 1145d578ec2aSCarl Huang } 1146d578ec2aSCarl Huang 11472c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, 11482c3960c2SGovind Singh u8 *ul_pipe, u8 *dl_pipe) 11492c3960c2SGovind Singh { 11502c3960c2SGovind Singh const struct service_to_pipe *entry; 11512c3960c2SGovind Singh bool ul_set = false, dl_set = false; 11522c3960c2SGovind Singh int i; 11532c3960c2SGovind Singh 1154967c1d11SAnilkumar Kolli for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) { 1155967c1d11SAnilkumar Kolli entry = &ab->hw_params.svc_to_ce_map[i]; 11562c3960c2SGovind Singh 11572c3960c2SGovind Singh if (__le32_to_cpu(entry->service_id) != service_id) 11582c3960c2SGovind Singh continue; 11592c3960c2SGovind Singh 11602c3960c2SGovind Singh switch (__le32_to_cpu(entry->pipedir)) { 11612c3960c2SGovind Singh case PIPEDIR_NONE: 11622c3960c2SGovind Singh break; 11632c3960c2SGovind Singh case PIPEDIR_IN: 11642c3960c2SGovind Singh WARN_ON(dl_set); 11652c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 11662c3960c2SGovind Singh dl_set = true; 11672c3960c2SGovind Singh break; 11682c3960c2SGovind Singh case PIPEDIR_OUT: 11692c3960c2SGovind Singh WARN_ON(ul_set); 11702c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 11712c3960c2SGovind Singh ul_set = true; 11722c3960c2SGovind Singh break; 11732c3960c2SGovind Singh case PIPEDIR_INOUT: 11742c3960c2SGovind Singh WARN_ON(dl_set); 11752c3960c2SGovind Singh WARN_ON(ul_set); 11762c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 11772c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 11782c3960c2SGovind Singh dl_set = true; 11792c3960c2SGovind Singh ul_set = true; 11802c3960c2SGovind Singh break; 11812c3960c2SGovind Singh } 11822c3960c2SGovind Singh } 11832c3960c2SGovind Singh 11842c3960c2SGovind Singh if (WARN_ON(!ul_set || !dl_set)) 11852c3960c2SGovind Singh return -ENOENT; 11867f4beda2SGovind Singh 11877f4beda2SGovind Singh return 0; 11887f4beda2SGovind Singh } 11897f4beda2SGovind Singh 11907f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = { 11917f4beda2SGovind Singh .start = ath11k_pci_start, 11927f4beda2SGovind Singh .stop = ath11k_pci_stop, 1193654e959aSGovind Singh .read32 = ath11k_pci_read32, 1194654e959aSGovind Singh .write32 = ath11k_pci_write32, 11951399fb87SGovind Singh .power_down = ath11k_pci_power_down, 11961399fb87SGovind Singh .power_up = ath11k_pci_power_up, 1197fa5917e4SCarl Huang .suspend = ath11k_pci_hif_suspend, 1198fa5917e4SCarl Huang .resume = ath11k_pci_hif_resume, 1199d4ecb90bSCarl Huang .irq_enable = ath11k_pci_ext_irq_enable, 1200d4ecb90bSCarl Huang .irq_disable = ath11k_pci_ext_irq_disable, 1201c4eacabeSGovind Singh .get_msi_address = ath11k_pci_get_msi_address, 1202c4eacabeSGovind Singh .get_user_msi_vector = ath11k_get_user_msi_assignment, 12032c3960c2SGovind Singh .map_service_to_pipe = ath11k_pci_map_service_to_pipe, 1204d578ec2aSCarl Huang .ce_irq_enable = ath11k_pci_hif_ce_irq_enable, 1205d578ec2aSCarl Huang .ce_irq_disable = ath11k_pci_hif_ce_irq_disable, 12066289ac2bSKarthikeyan Periyasamy .get_ce_msi_idx = ath11k_pci_get_ce_msi_idx, 12071399fb87SGovind Singh }; 12081399fb87SGovind Singh 12090fbf1957SBaochen Qiang static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor) 12100fbf1957SBaochen Qiang { 12110fbf1957SBaochen Qiang u32 soc_hw_version; 12120fbf1957SBaochen Qiang 12130fbf1957SBaochen Qiang soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION); 12140fbf1957SBaochen Qiang *major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK, 12150fbf1957SBaochen Qiang soc_hw_version); 12160fbf1957SBaochen Qiang *minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK, 12170fbf1957SBaochen Qiang soc_hw_version); 12180fbf1957SBaochen Qiang 12190fbf1957SBaochen Qiang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n", 12200fbf1957SBaochen Qiang *major, *minor); 12210fbf1957SBaochen Qiang } 12220fbf1957SBaochen Qiang 12236e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev, 12246e0355afSGovind Singh const struct pci_device_id *pci_dev) 12256e0355afSGovind Singh { 12266e0355afSGovind Singh struct ath11k_base *ab; 12275762613eSGovind Singh struct ath11k_pci *ab_pci; 12280fbf1957SBaochen Qiang u32 soc_hw_version_major, soc_hw_version_minor; 12295762613eSGovind Singh int ret; 12306e0355afSGovind Singh 12311ff8ed78SGovind Singh ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, 12321ff8ed78SGovind Singh &ath11k_pci_bus_params); 12336e0355afSGovind Singh if (!ab) { 12346e0355afSGovind Singh dev_err(&pdev->dev, "failed to allocate ath11k base\n"); 12356e0355afSGovind Singh return -ENOMEM; 12366e0355afSGovind Singh } 12376e0355afSGovind Singh 12386e0355afSGovind Singh ab->dev = &pdev->dev; 12396e0355afSGovind Singh pci_set_drvdata(pdev, ab); 12405762613eSGovind Singh ab_pci = ath11k_pci_priv(ab); 12415762613eSGovind Singh ab_pci->dev_id = pci_dev->device; 12425762613eSGovind Singh ab_pci->ab = ab; 12435697a564SGovind Singh ab_pci->pdev = pdev; 12447f4beda2SGovind Singh ab->hif.ops = &ath11k_pci_hif_ops; 12455762613eSGovind Singh pci_set_drvdata(pdev, ab); 1246654e959aSGovind Singh spin_lock_init(&ab_pci->window_lock); 12475762613eSGovind Singh 12485762613eSGovind Singh ret = ath11k_pci_claim(ab_pci, pdev); 12495762613eSGovind Singh if (ret) { 12505762613eSGovind Singh ath11k_err(ab, "failed to claim device: %d\n", ret); 12515762613eSGovind Singh goto err_free_core; 12525762613eSGovind Singh } 12536e0355afSGovind Singh 125418ac1665SKalle Valo switch (pci_dev->device) { 125518ac1665SKalle Valo case QCA6390_DEVICE_ID: 12560fbf1957SBaochen Qiang ath11k_pci_read_hw_version(ab, &soc_hw_version_major, 12570fbf1957SBaochen Qiang &soc_hw_version_minor); 125818ac1665SKalle Valo switch (soc_hw_version_major) { 125918ac1665SKalle Valo case 2: 126018ac1665SKalle Valo ab->hw_rev = ATH11K_HW_QCA6390_HW20; 126118ac1665SKalle Valo break; 126218ac1665SKalle Valo default: 126318ac1665SKalle Valo dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n", 126418ac1665SKalle Valo soc_hw_version_major, soc_hw_version_minor); 126518ac1665SKalle Valo ret = -EOPNOTSUPP; 126618ac1665SKalle Valo goto err_pci_free_region; 126718ac1665SKalle Valo } 12684e809461SAnilkumar Kolli ab_pci->msi_config = &ath11k_msi_config[0]; 12694e809461SAnilkumar Kolli break; 12704e809461SAnilkumar Kolli case QCN9074_DEVICE_ID: 12714e809461SAnilkumar Kolli ab_pci->msi_config = &ath11k_msi_config[1]; 12724e809461SAnilkumar Kolli ab->bus_params.static_window_map = true; 12734e809461SAnilkumar Kolli ab->hw_rev = ATH11K_HW_QCN9074_HW10; 127418ac1665SKalle Valo break; 12750fbf1957SBaochen Qiang case WCN6855_DEVICE_ID: 12760fbf1957SBaochen Qiang ath11k_pci_read_hw_version(ab, &soc_hw_version_major, 12770fbf1957SBaochen Qiang &soc_hw_version_minor); 12780fbf1957SBaochen Qiang switch (soc_hw_version_major) { 12790fbf1957SBaochen Qiang case 2: 12800fbf1957SBaochen Qiang ab->hw_rev = ATH11K_HW_WCN6855_HW20; 12810fbf1957SBaochen Qiang break; 12820fbf1957SBaochen Qiang default: 12830fbf1957SBaochen Qiang dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n", 12840fbf1957SBaochen Qiang soc_hw_version_major, soc_hw_version_minor); 12850fbf1957SBaochen Qiang ret = -EOPNOTSUPP; 12860fbf1957SBaochen Qiang goto err_pci_free_region; 12870fbf1957SBaochen Qiang } 12880fbf1957SBaochen Qiang ab_pci->msi_config = &ath11k_msi_config[0]; 12890fbf1957SBaochen Qiang break; 129018ac1665SKalle Valo default: 129118ac1665SKalle Valo dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", 129218ac1665SKalle Valo pci_dev->device); 129318ac1665SKalle Valo ret = -EOPNOTSUPP; 129418ac1665SKalle Valo goto err_pci_free_region; 129518ac1665SKalle Valo } 129618ac1665SKalle Valo 1297*96527d52SBaochen Qiang ret = ath11k_pci_alloc_msi(ab_pci); 12985697a564SGovind Singh if (ret) { 12995697a564SGovind Singh ath11k_err(ab, "failed to enable msi: %d\n", ret); 13005697a564SGovind Singh goto err_pci_free_region; 13015697a564SGovind Singh } 13025697a564SGovind Singh 1303b8246f88SKalle Valo ret = ath11k_core_pre_init(ab); 1304b8246f88SKalle Valo if (ret) 1305b8246f88SKalle Valo goto err_pci_disable_msi; 1306b8246f88SKalle Valo 13071399fb87SGovind Singh ret = ath11k_mhi_register(ab_pci); 13081399fb87SGovind Singh if (ret) { 13091399fb87SGovind Singh ath11k_err(ab, "failed to register mhi: %d\n", ret); 13101399fb87SGovind Singh goto err_pci_disable_msi; 13111399fb87SGovind Singh } 13121399fb87SGovind Singh 13137f4beda2SGovind Singh ret = ath11k_hal_srng_init(ab); 13147f4beda2SGovind Singh if (ret) 13157f4beda2SGovind Singh goto err_mhi_unregister; 13167f4beda2SGovind Singh 13177f4beda2SGovind Singh ret = ath11k_ce_alloc_pipes(ab); 13187f4beda2SGovind Singh if (ret) { 13197f4beda2SGovind Singh ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret); 13207f4beda2SGovind Singh goto err_hal_srng_deinit; 13217f4beda2SGovind Singh } 13227f4beda2SGovind Singh 13237f4beda2SGovind Singh ath11k_pci_init_qmi_ce_config(ab); 13247f4beda2SGovind Singh 13257f4beda2SGovind Singh ret = ath11k_pci_config_irq(ab); 13267f4beda2SGovind Singh if (ret) { 13277f4beda2SGovind Singh ath11k_err(ab, "failed to config irq: %d\n", ret); 13287f4beda2SGovind Singh goto err_ce_free; 13297f4beda2SGovind Singh } 13307f4beda2SGovind Singh 13317f4beda2SGovind Singh ret = ath11k_core_init(ab); 13327f4beda2SGovind Singh if (ret) { 13337f4beda2SGovind Singh ath11k_err(ab, "failed to init core: %d\n", ret); 13347f4beda2SGovind Singh goto err_free_irq; 13357f4beda2SGovind Singh } 13366e0355afSGovind Singh return 0; 13375762613eSGovind Singh 13387f4beda2SGovind Singh err_free_irq: 13397f4beda2SGovind Singh ath11k_pci_free_irq(ab); 13407f4beda2SGovind Singh 13417f4beda2SGovind Singh err_ce_free: 13427f4beda2SGovind Singh ath11k_ce_free_pipes(ab); 13437f4beda2SGovind Singh 13447f4beda2SGovind Singh err_hal_srng_deinit: 13457f4beda2SGovind Singh ath11k_hal_srng_deinit(ab); 13467f4beda2SGovind Singh 13477f4beda2SGovind Singh err_mhi_unregister: 13487f4beda2SGovind Singh ath11k_mhi_unregister(ab_pci); 13497f4beda2SGovind Singh 1350b8246f88SKalle Valo err_pci_disable_msi: 1351*96527d52SBaochen Qiang ath11k_pci_free_msi(ab_pci); 1352b8246f88SKalle Valo 13535697a564SGovind Singh err_pci_free_region: 13545697a564SGovind Singh ath11k_pci_free_region(ab_pci); 13555697a564SGovind Singh 13565762613eSGovind Singh err_free_core: 13575762613eSGovind Singh ath11k_core_free(ab); 13585697a564SGovind Singh 13595762613eSGovind Singh return ret; 13606e0355afSGovind Singh } 13616e0355afSGovind Singh 13626e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev) 13636e0355afSGovind Singh { 13646e0355afSGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 13655762613eSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 13666e0355afSGovind Singh 136761a57e51SAnilkumar Kolli if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { 136861a57e51SAnilkumar Kolli ath11k_pci_power_down(ab); 136961a57e51SAnilkumar Kolli ath11k_debugfs_soc_destroy(ab); 137061a57e51SAnilkumar Kolli ath11k_qmi_deinit_service(ab); 137161a57e51SAnilkumar Kolli goto qmi_fail; 137261a57e51SAnilkumar Kolli } 137361a57e51SAnilkumar Kolli 13746e0355afSGovind Singh set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); 13756fbd8898SCarl Huang 13766fbd8898SCarl Huang ath11k_core_deinit(ab); 13776fbd8898SCarl Huang 137861a57e51SAnilkumar Kolli qmi_fail: 13791399fb87SGovind Singh ath11k_mhi_unregister(ab_pci); 13806fbd8898SCarl Huang 13816fbd8898SCarl Huang ath11k_pci_free_irq(ab); 1382*96527d52SBaochen Qiang ath11k_pci_free_msi(ab_pci); 13835762613eSGovind Singh ath11k_pci_free_region(ab_pci); 13846fbd8898SCarl Huang 13856fbd8898SCarl Huang ath11k_hal_srng_deinit(ab); 13866fbd8898SCarl Huang ath11k_ce_free_pipes(ab); 13876e0355afSGovind Singh ath11k_core_free(ab); 13886e0355afSGovind Singh } 13896e0355afSGovind Singh 13901399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev) 13911399fb87SGovind Singh { 13921399fb87SGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 13931399fb87SGovind Singh 13941399fb87SGovind Singh ath11k_pci_power_down(ab); 13951399fb87SGovind Singh } 13961399fb87SGovind Singh 1397d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev) 1398d1b0c338SCarl Huang { 1399d1b0c338SCarl Huang struct ath11k_base *ab = dev_get_drvdata(dev); 1400d1b0c338SCarl Huang int ret; 1401d1b0c338SCarl Huang 1402d1b0c338SCarl Huang ret = ath11k_core_suspend(ab); 1403d1b0c338SCarl Huang if (ret) 1404d1b0c338SCarl Huang ath11k_warn(ab, "failed to suspend core: %d\n", ret); 1405d1b0c338SCarl Huang 1406d1b0c338SCarl Huang return ret; 1407d1b0c338SCarl Huang } 1408d1b0c338SCarl Huang 1409d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev) 1410d1b0c338SCarl Huang { 1411d1b0c338SCarl Huang struct ath11k_base *ab = dev_get_drvdata(dev); 1412d1b0c338SCarl Huang int ret; 1413d1b0c338SCarl Huang 1414d1b0c338SCarl Huang ret = ath11k_core_resume(ab); 1415d1b0c338SCarl Huang if (ret) 1416d1b0c338SCarl Huang ath11k_warn(ab, "failed to resume core: %d\n", ret); 1417d1b0c338SCarl Huang 1418d1b0c338SCarl Huang return ret; 1419d1b0c338SCarl Huang } 1420d1b0c338SCarl Huang 1421d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops, 1422d1b0c338SCarl Huang ath11k_pci_pm_suspend, 1423d1b0c338SCarl Huang ath11k_pci_pm_resume); 1424d1b0c338SCarl Huang 14256e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = { 14266e0355afSGovind Singh .name = "ath11k_pci", 14276e0355afSGovind Singh .id_table = ath11k_pci_id_table, 14286e0355afSGovind Singh .probe = ath11k_pci_probe, 14296e0355afSGovind Singh .remove = ath11k_pci_remove, 14301399fb87SGovind Singh .shutdown = ath11k_pci_shutdown, 1431d1b0c338SCarl Huang #ifdef CONFIG_PM 1432d1b0c338SCarl Huang .driver.pm = &ath11k_pci_pm_ops, 1433d1b0c338SCarl Huang #endif 14346e0355afSGovind Singh }; 14356e0355afSGovind Singh 14366e0355afSGovind Singh static int ath11k_pci_init(void) 14376e0355afSGovind Singh { 14386e0355afSGovind Singh int ret; 14396e0355afSGovind Singh 14406e0355afSGovind Singh ret = pci_register_driver(&ath11k_pci_driver); 14416e0355afSGovind Singh if (ret) 14426e0355afSGovind Singh pr_err("failed to register ath11k pci driver: %d\n", 14436e0355afSGovind Singh ret); 14446e0355afSGovind Singh 14456e0355afSGovind Singh return ret; 14466e0355afSGovind Singh } 14476e0355afSGovind Singh module_init(ath11k_pci_init); 14486e0355afSGovind Singh 14496e0355afSGovind Singh static void ath11k_pci_exit(void) 14506e0355afSGovind Singh { 14516e0355afSGovind Singh pci_unregister_driver(&ath11k_pci_driver); 14526e0355afSGovind Singh } 14536e0355afSGovind Singh 14546e0355afSGovind Singh module_exit(ath11k_pci_exit); 14556e0355afSGovind Singh 14566e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); 14576e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL"); 14583dbd7fe7SDevin Bayer 14593dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */ 14603dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE); 14613dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE); 14623dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE); 1463