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 204ab4693fSCarl Huang #define ATH11K_PCI_IRQ_DP_OFFSET 14 217f4beda2SGovind Singh 22654e959aSGovind Singh #define WINDOW_ENABLE_BIT 0x40000000 23654e959aSGovind Singh #define WINDOW_REG_ADDRESS 0x310c 24654e959aSGovind Singh #define WINDOW_VALUE_MASK GENMASK(24, 19) 25654e959aSGovind Singh #define WINDOW_START 0x80000 26654e959aSGovind Singh #define WINDOW_RANGE_MASK GENMASK(18, 0) 27654e959aSGovind Singh 2818ac1665SKalle Valo #define TCSR_SOC_HW_VERSION 0x0224 2918ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(16, 8) 3018ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0) 3118ac1665SKalle Valo 32a05bd851SCarl Huang /* BAR0 + 4k is always accessible, and no 33a05bd851SCarl Huang * need to force wakeup. 34a05bd851SCarl Huang * 4K - 32 = 0xFE0 35a05bd851SCarl Huang */ 36a05bd851SCarl Huang #define ACCESS_ALWAYS_OFF 0xFE0 37a05bd851SCarl Huang 386e0355afSGovind Singh #define QCA6390_DEVICE_ID 0x1101 394e809461SAnilkumar Kolli #define QCN9074_DEVICE_ID 0x1104 400fbf1957SBaochen Qiang #define WCN6855_DEVICE_ID 0x1103 416e0355afSGovind Singh 426e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = { 436e0355afSGovind Singh { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, 440fbf1957SBaochen Qiang { PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) }, 4549f5b114SAnilkumar Kolli { PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) }, 466e0355afSGovind Singh {0} 476e0355afSGovind Singh }; 486e0355afSGovind Singh 496e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); 506e0355afSGovind Singh 511ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = { 521ff8ed78SGovind Singh .mhi_support = true, 5356970454SGovind Singh .m3_fw_support = true, 546eb6ea51SGovind Singh .fixed_bdf_addr = false, 556eb6ea51SGovind Singh .fixed_mem_region = false, 561ff8ed78SGovind Singh }; 571ff8ed78SGovind Singh 587a3aed0cSAnilkumar Kolli static const struct ath11k_msi_config ath11k_msi_config[] = { 597a3aed0cSAnilkumar Kolli { 605697a564SGovind Singh .total_vectors = 32, 615697a564SGovind Singh .total_users = 4, 625697a564SGovind Singh .users = (struct ath11k_msi_user[]) { 635697a564SGovind Singh { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 645697a564SGovind Singh { .name = "CE", .num_vectors = 10, .base_vector = 3 }, 655697a564SGovind Singh { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, 665697a564SGovind Singh { .name = "DP", .num_vectors = 18, .base_vector = 14 }, 675697a564SGovind Singh }, 687a3aed0cSAnilkumar Kolli }, 694e809461SAnilkumar Kolli { 704e809461SAnilkumar Kolli .total_vectors = 16, 714e809461SAnilkumar Kolli .total_users = 3, 724e809461SAnilkumar Kolli .users = (struct ath11k_msi_user[]) { 734e809461SAnilkumar Kolli { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 744e809461SAnilkumar Kolli { .name = "CE", .num_vectors = 5, .base_vector = 3 }, 754e809461SAnilkumar Kolli { .name = "DP", .num_vectors = 8, .base_vector = 8 }, 764e809461SAnilkumar Kolli }, 774e809461SAnilkumar Kolli }, 785697a564SGovind Singh }; 795697a564SGovind Singh 80ac6e7348SCarl Huang static const struct ath11k_msi_config msi_config_one_msi = { 81ac6e7348SCarl Huang .total_vectors = 1, 82ac6e7348SCarl Huang .total_users = 4, 83ac6e7348SCarl Huang .users = (struct ath11k_msi_user[]) { 84ac6e7348SCarl Huang { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 85ac6e7348SCarl Huang { .name = "CE", .num_vectors = 1, .base_vector = 0 }, 86ac6e7348SCarl Huang { .name = "WAKE", .num_vectors = 1, .base_vector = 0 }, 87ac6e7348SCarl Huang { .name = "DP", .num_vectors = 1, .base_vector = 0 }, 88ac6e7348SCarl Huang }, 89ac6e7348SCarl Huang }; 90ac6e7348SCarl Huang 917f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { 927f4beda2SGovind Singh "bhi", 937f4beda2SGovind Singh "mhi-er0", 947f4beda2SGovind Singh "mhi-er1", 957f4beda2SGovind Singh "ce0", 967f4beda2SGovind Singh "ce1", 977f4beda2SGovind Singh "ce2", 987f4beda2SGovind Singh "ce3", 997f4beda2SGovind Singh "ce4", 1007f4beda2SGovind Singh "ce5", 1017f4beda2SGovind Singh "ce6", 1027f4beda2SGovind Singh "ce7", 1037f4beda2SGovind Singh "ce8", 1047f4beda2SGovind Singh "ce9", 1057f4beda2SGovind Singh "ce10", 1067f4beda2SGovind Singh "ce11", 1077f4beda2SGovind Singh "host2wbm-desc-feed", 1087f4beda2SGovind Singh "host2reo-re-injection", 1097f4beda2SGovind Singh "host2reo-command", 1107f4beda2SGovind Singh "host2rxdma-monitor-ring3", 1117f4beda2SGovind Singh "host2rxdma-monitor-ring2", 1127f4beda2SGovind Singh "host2rxdma-monitor-ring1", 1137f4beda2SGovind Singh "reo2ost-exception", 1147f4beda2SGovind Singh "wbm2host-rx-release", 1157f4beda2SGovind Singh "reo2host-status", 1167f4beda2SGovind Singh "reo2host-destination-ring4", 1177f4beda2SGovind Singh "reo2host-destination-ring3", 1187f4beda2SGovind Singh "reo2host-destination-ring2", 1197f4beda2SGovind Singh "reo2host-destination-ring1", 1207f4beda2SGovind Singh "rxdma2host-monitor-destination-mac3", 1217f4beda2SGovind Singh "rxdma2host-monitor-destination-mac2", 1227f4beda2SGovind Singh "rxdma2host-monitor-destination-mac1", 1237f4beda2SGovind Singh "ppdu-end-interrupts-mac3", 1247f4beda2SGovind Singh "ppdu-end-interrupts-mac2", 1257f4beda2SGovind Singh "ppdu-end-interrupts-mac1", 1267f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac3", 1277f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac2", 1287f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac1", 1297f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac3", 1307f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac2", 1317f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac1", 1327f4beda2SGovind Singh "rxdma2host-destination-ring-mac3", 1337f4beda2SGovind Singh "rxdma2host-destination-ring-mac2", 1347f4beda2SGovind Singh "rxdma2host-destination-ring-mac1", 1357f4beda2SGovind Singh "host2tcl-input-ring4", 1367f4beda2SGovind Singh "host2tcl-input-ring3", 1377f4beda2SGovind Singh "host2tcl-input-ring2", 1387f4beda2SGovind Singh "host2tcl-input-ring1", 1397f4beda2SGovind Singh "wbm2host-tx-completions-ring3", 1407f4beda2SGovind Singh "wbm2host-tx-completions-ring2", 1417f4beda2SGovind Singh "wbm2host-tx-completions-ring1", 1427f4beda2SGovind Singh "tcl2host-status-ring", 1437f4beda2SGovind Singh }; 1447f4beda2SGovind Singh 145654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset) 146654e959aSGovind Singh { 147654e959aSGovind Singh struct ath11k_base *ab = ab_pci->ab; 148654e959aSGovind Singh 149654e959aSGovind Singh u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset); 150654e959aSGovind Singh 151654e959aSGovind Singh lockdep_assert_held(&ab_pci->window_lock); 152654e959aSGovind Singh 153654e959aSGovind Singh if (window != ab_pci->register_window) { 154654e959aSGovind Singh iowrite32(WINDOW_ENABLE_BIT | window, 155654e959aSGovind Singh ab->mem + WINDOW_REG_ADDRESS); 156f6fa37a4SCarl Huang ioread32(ab->mem + WINDOW_REG_ADDRESS); 157654e959aSGovind Singh ab_pci->register_window = window; 158654e959aSGovind Singh } 159654e959aSGovind Singh } 160654e959aSGovind Singh 161480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci) 162480a7361SKarthikeyan Periyasamy { 163480a7361SKarthikeyan Periyasamy u32 umac_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET); 164480a7361SKarthikeyan Periyasamy u32 ce_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE); 165480a7361SKarthikeyan Periyasamy u32 window; 166480a7361SKarthikeyan Periyasamy 167480a7361SKarthikeyan Periyasamy window = (umac_window << 12) | (ce_window << 6); 168480a7361SKarthikeyan Periyasamy 169480a7361SKarthikeyan Periyasamy iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + WINDOW_REG_ADDRESS); 170480a7361SKarthikeyan Periyasamy } 171480a7361SKarthikeyan Periyasamy 172480a7361SKarthikeyan Periyasamy static inline u32 ath11k_pci_get_window_start(struct ath11k_base *ab, 173480a7361SKarthikeyan Periyasamy u32 offset) 174480a7361SKarthikeyan Periyasamy { 175480a7361SKarthikeyan Periyasamy u32 window_start; 176480a7361SKarthikeyan Periyasamy 177480a7361SKarthikeyan Periyasamy /* If offset lies within DP register range, use 3rd window */ 178480a7361SKarthikeyan Periyasamy if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < WINDOW_RANGE_MASK) 179480a7361SKarthikeyan Periyasamy window_start = 3 * WINDOW_START; 180480a7361SKarthikeyan Periyasamy /* If offset lies within CE register range, use 2nd window */ 181480a7361SKarthikeyan Periyasamy else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK) 182480a7361SKarthikeyan Periyasamy window_start = 2 * WINDOW_START; 183480a7361SKarthikeyan Periyasamy else 184480a7361SKarthikeyan Periyasamy window_start = WINDOW_START; 185480a7361SKarthikeyan Periyasamy 186480a7361SKarthikeyan Periyasamy return window_start; 187480a7361SKarthikeyan Periyasamy } 188480a7361SKarthikeyan Periyasamy 189f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) 190654e959aSGovind Singh { 191654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 192480a7361SKarthikeyan Periyasamy u32 window_start; 193654e959aSGovind Singh 194a05bd851SCarl Huang /* for offset beyond BAR + 4K - 32, may 195a05bd851SCarl Huang * need to wakeup MHI to access. 196a05bd851SCarl Huang */ 197081e2d64SSeevalamuthu Mariappan if (ab->hw_params.wakeup_mhi && 198081e2d64SSeevalamuthu Mariappan test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 199a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 200a05bd851SCarl Huang mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); 201a05bd851SCarl Huang 202654e959aSGovind Singh if (offset < WINDOW_START) { 203654e959aSGovind Singh iowrite32(value, ab->mem + offset); 204654e959aSGovind Singh } else { 205480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 206480a7361SKarthikeyan Periyasamy window_start = ath11k_pci_get_window_start(ab, offset); 207480a7361SKarthikeyan Periyasamy else 208480a7361SKarthikeyan Periyasamy window_start = WINDOW_START; 209480a7361SKarthikeyan Periyasamy 210480a7361SKarthikeyan Periyasamy if (window_start == WINDOW_START) { 211654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 212654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 213480a7361SKarthikeyan Periyasamy iowrite32(value, ab->mem + window_start + 214480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 215654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 216480a7361SKarthikeyan Periyasamy } else { 217480a7361SKarthikeyan Periyasamy iowrite32(value, ab->mem + window_start + 218480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 219480a7361SKarthikeyan Periyasamy } 220654e959aSGovind Singh } 221a05bd851SCarl Huang 222081e2d64SSeevalamuthu Mariappan if (ab->hw_params.wakeup_mhi && 223081e2d64SSeevalamuthu Mariappan test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 224a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 225a05bd851SCarl Huang mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); 226654e959aSGovind Singh } 227654e959aSGovind Singh 228f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) 229654e959aSGovind Singh { 230654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 231480a7361SKarthikeyan Periyasamy u32 val, window_start; 232654e959aSGovind Singh 233a05bd851SCarl Huang /* for offset beyond BAR + 4K - 32, may 234a05bd851SCarl Huang * need to wakeup MHI to access. 235a05bd851SCarl Huang */ 236081e2d64SSeevalamuthu Mariappan if (ab->hw_params.wakeup_mhi && 237081e2d64SSeevalamuthu Mariappan test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 238a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 239a05bd851SCarl Huang mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); 240a05bd851SCarl Huang 241654e959aSGovind Singh if (offset < WINDOW_START) { 242654e959aSGovind Singh val = ioread32(ab->mem + offset); 243654e959aSGovind Singh } else { 244480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 245480a7361SKarthikeyan Periyasamy window_start = ath11k_pci_get_window_start(ab, offset); 246480a7361SKarthikeyan Periyasamy else 247480a7361SKarthikeyan Periyasamy window_start = WINDOW_START; 248480a7361SKarthikeyan Periyasamy 249480a7361SKarthikeyan Periyasamy if (window_start == WINDOW_START) { 250654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 251654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 252480a7361SKarthikeyan Periyasamy val = ioread32(ab->mem + window_start + 253480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 254654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 255480a7361SKarthikeyan Periyasamy } else { 256480a7361SKarthikeyan Periyasamy val = ioread32(ab->mem + window_start + 257480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 258480a7361SKarthikeyan Periyasamy } 259654e959aSGovind Singh } 260654e959aSGovind Singh 261081e2d64SSeevalamuthu Mariappan if (ab->hw_params.wakeup_mhi && 262081e2d64SSeevalamuthu Mariappan test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 263a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 264a05bd851SCarl Huang mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); 265a05bd851SCarl Huang 266654e959aSGovind Singh return val; 267654e959aSGovind Singh } 268654e959aSGovind Singh 269f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) 270f3c603d4SCarl Huang { 271f3c603d4SCarl Huang u32 val, delay; 272f3c603d4SCarl Huang 273f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 274f3c603d4SCarl Huang 275f3c603d4SCarl Huang val |= PCIE_SOC_GLOBAL_RESET_V; 276f3c603d4SCarl Huang 277f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 278f3c603d4SCarl Huang 279f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 280f3c603d4SCarl Huang delay = 10; 281f3c603d4SCarl Huang mdelay(delay); 282f3c603d4SCarl Huang 283f3c603d4SCarl Huang /* Need to toggle V bit back otherwise stuck in reset status */ 284f3c603d4SCarl Huang val &= ~PCIE_SOC_GLOBAL_RESET_V; 285f3c603d4SCarl Huang 286f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 287f3c603d4SCarl Huang 288f3c603d4SCarl Huang mdelay(delay); 289f3c603d4SCarl Huang 290f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 291f3c603d4SCarl Huang if (val == 0xffffffff) 292f3c603d4SCarl Huang ath11k_warn(ab, "link down error during global reset\n"); 293f3c603d4SCarl Huang } 294f3c603d4SCarl Huang 295f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) 296f3c603d4SCarl Huang { 297f3c603d4SCarl Huang u32 val; 298f3c603d4SCarl Huang 299f3c603d4SCarl Huang /* read cookie */ 300f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR); 301f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val); 302f3c603d4SCarl Huang 303f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 304f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 305f3c603d4SCarl Huang 306f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 307f3c603d4SCarl Huang mdelay(10); 308f3c603d4SCarl Huang 309f3c603d4SCarl Huang /* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from 310f3c603d4SCarl Huang * continuing warm path and entering dead loop. 311f3c603d4SCarl Huang */ 312f3c603d4SCarl Huang ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0); 313f3c603d4SCarl Huang mdelay(10); 314f3c603d4SCarl Huang 315f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 316f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 317f3c603d4SCarl Huang 318f3c603d4SCarl Huang /* A read clear register. clear the register to prevent 319f3c603d4SCarl Huang * Q6 from entering wrong code path. 320f3c603d4SCarl Huang */ 321f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG); 322f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val); 323f3c603d4SCarl Huang } 324f3c603d4SCarl Huang 32506999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab, 32606999407SCarl Huang u32 offset, u32 value, u32 mask) 32706999407SCarl Huang { 32806999407SCarl Huang u32 v; 32906999407SCarl Huang int i; 33006999407SCarl Huang 33106999407SCarl Huang v = ath11k_pci_read32(ab, offset); 33206999407SCarl Huang if ((v & mask) == value) 33306999407SCarl Huang return 0; 33406999407SCarl Huang 33506999407SCarl Huang for (i = 0; i < 10; i++) { 33606999407SCarl Huang ath11k_pci_write32(ab, offset, (v & ~mask) | value); 33706999407SCarl Huang 33806999407SCarl Huang v = ath11k_pci_read32(ab, offset); 33906999407SCarl Huang if ((v & mask) == value) 34006999407SCarl Huang return 0; 34106999407SCarl Huang 34206999407SCarl Huang mdelay(2); 34306999407SCarl Huang } 34406999407SCarl Huang 34506999407SCarl Huang ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n", 34606999407SCarl Huang offset, v & mask, value); 34706999407SCarl Huang 34806999407SCarl Huang return -ETIMEDOUT; 34906999407SCarl Huang } 35006999407SCarl Huang 35106999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab) 35206999407SCarl Huang { 35306999407SCarl Huang int ret; 35406999407SCarl Huang 35506999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3566fe6f68fSKarthikeyan Periyasamy PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab), 35706999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL, 35806999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK); 35930d08503SDan Carpenter if (ret) { 36006999407SCarl Huang ath11k_warn(ab, "failed to set sysclk: %d\n", ret); 36106999407SCarl Huang return ret; 36206999407SCarl Huang } 36306999407SCarl Huang 36406999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3656fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab), 3666fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG1_VAL, 3676fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 36830d08503SDan Carpenter if (ret) { 36906999407SCarl Huang ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret); 37006999407SCarl Huang return ret; 37106999407SCarl Huang } 37206999407SCarl Huang 37306999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3746fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab), 3756fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG2_VAL, 3766fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 37730d08503SDan Carpenter if (ret) { 37806999407SCarl Huang ath11k_warn(ab, "failed to set dtct config2: %d\n", ret); 37906999407SCarl Huang return ret; 38006999407SCarl Huang } 38106999407SCarl Huang 38206999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3836fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab), 3846fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG4_VAL, 3856fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 38630d08503SDan Carpenter if (ret) { 38706999407SCarl Huang ath11k_warn(ab, "failed to set dtct config4: %d\n", ret); 38806999407SCarl Huang return ret; 38906999407SCarl Huang } 39006999407SCarl Huang 39106999407SCarl Huang return 0; 39206999407SCarl Huang } 39306999407SCarl Huang 394babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab) 395babb0cedSCarl Huang { 396babb0cedSCarl Huang u32 val; 397babb0cedSCarl Huang int i; 398babb0cedSCarl Huang 399babb0cedSCarl Huang val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); 400babb0cedSCarl Huang 401babb0cedSCarl Huang /* PCIE link seems very unstable after the Hot Reset*/ 402babb0cedSCarl Huang for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) { 403babb0cedSCarl Huang if (val == 0xffffffff) 404babb0cedSCarl Huang mdelay(5); 405babb0cedSCarl Huang 406babb0cedSCarl Huang ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE); 407babb0cedSCarl Huang val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); 408babb0cedSCarl Huang } 409babb0cedSCarl Huang 410babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val); 411babb0cedSCarl Huang 412babb0cedSCarl Huang val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); 413562934adSKalle Valo val |= GCC_GCC_PCIE_HOT_RST_VAL; 414babb0cedSCarl Huang ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val); 415babb0cedSCarl Huang val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); 416babb0cedSCarl Huang 417babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val); 418babb0cedSCarl Huang 419babb0cedSCarl Huang mdelay(5); 420babb0cedSCarl Huang } 421babb0cedSCarl Huang 422babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab) 423babb0cedSCarl Huang { 424babb0cedSCarl Huang /* This is a WAR for PCIE Hotreset. 425babb0cedSCarl Huang * When target receive Hotreset, but will set the interrupt. 426babb0cedSCarl Huang * So when download SBL again, SBL will open Interrupt and 427babb0cedSCarl Huang * receive it, and crash immediately. 428babb0cedSCarl Huang */ 429babb0cedSCarl Huang ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL); 430babb0cedSCarl Huang } 431babb0cedSCarl Huang 4320ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab) 4330ccdf439SCarl Huang { 4340ccdf439SCarl Huang u32 val; 4350ccdf439SCarl Huang 4360ccdf439SCarl Huang val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG); 4370ccdf439SCarl Huang val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK; 4380ccdf439SCarl Huang ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val); 4390ccdf439SCarl Huang } 4400ccdf439SCarl Huang 441f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab) 442f3c603d4SCarl Huang { 443f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1); 444f3c603d4SCarl Huang mdelay(5); 445f3c603d4SCarl Huang } 446f3c603d4SCarl Huang 447babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on) 448f3c603d4SCarl Huang { 4498a0b899fSBaochen Qiang mdelay(100); 4508a0b899fSBaochen Qiang 451babb0cedSCarl Huang if (power_on) { 452babb0cedSCarl Huang ath11k_pci_enable_ltssm(ab); 453babb0cedSCarl Huang ath11k_pci_clear_all_intrs(ab); 4540ccdf439SCarl Huang ath11k_pci_set_wlaon_pwr_ctrl(ab); 4555088df05SBaochen Qiang if (ab->hw_params.fix_l1ss) 45606999407SCarl Huang ath11k_pci_fix_l1ss(ab); 457babb0cedSCarl Huang } 458babb0cedSCarl Huang 459f3c603d4SCarl Huang ath11k_mhi_clear_vector(ab); 4608a0b899fSBaochen Qiang ath11k_pci_clear_dbg_registers(ab); 461f3c603d4SCarl Huang ath11k_pci_soc_global_reset(ab); 462f3c603d4SCarl Huang ath11k_mhi_set_mhictrl_reset(ab); 463f3c603d4SCarl Huang } 464f3c603d4SCarl Huang 4651399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) 4661399fb87SGovind Singh { 4671399fb87SGovind Singh struct pci_dev *pci_dev = to_pci_dev(dev); 4681399fb87SGovind Singh 4691399fb87SGovind Singh return pci_irq_vector(pci_dev, vector); 4701399fb87SGovind Singh } 4711399fb87SGovind Singh 472c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, 473c4eacabeSGovind Singh u32 *msi_addr_hi) 474c4eacabeSGovind Singh { 475e8e55d89SAnilkumar Kolli struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 476c4eacabeSGovind Singh struct pci_dev *pci_dev = to_pci_dev(ab->dev); 477c4eacabeSGovind Singh 478c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, 479c4eacabeSGovind Singh msi_addr_lo); 480c4eacabeSGovind Singh 481e8e55d89SAnilkumar Kolli if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) { 482c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, 483c4eacabeSGovind Singh msi_addr_hi); 484e8e55d89SAnilkumar Kolli } else { 485e8e55d89SAnilkumar Kolli *msi_addr_hi = 0; 486e8e55d89SAnilkumar Kolli } 487c4eacabeSGovind Singh } 488c4eacabeSGovind Singh 4891399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, 4901399fb87SGovind Singh int *num_vectors, u32 *user_base_data, 4911399fb87SGovind Singh u32 *base_vector) 4921399fb87SGovind Singh { 4931399fb87SGovind Singh struct ath11k_base *ab = ab_pci->ab; 4947a3aed0cSAnilkumar Kolli const struct ath11k_msi_config *msi_config = ab_pci->msi_config; 4951399fb87SGovind Singh int idx; 4961399fb87SGovind Singh 4977a3aed0cSAnilkumar Kolli for (idx = 0; idx < msi_config->total_users; idx++) { 4987a3aed0cSAnilkumar Kolli if (strcmp(user_name, msi_config->users[idx].name) == 0) { 4997a3aed0cSAnilkumar Kolli *num_vectors = msi_config->users[idx].num_vectors; 5007a3aed0cSAnilkumar Kolli *base_vector = msi_config->users[idx].base_vector; 501c41a6700SCarl Huang *user_base_data = *base_vector + ab_pci->msi_ep_base_data; 5021399fb87SGovind Singh 503c41a6700SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, 504c41a6700SCarl Huang "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", 5051399fb87SGovind Singh user_name, *num_vectors, *user_base_data, 5061399fb87SGovind Singh *base_vector); 5071399fb87SGovind Singh 5081399fb87SGovind Singh return 0; 5091399fb87SGovind Singh } 5101399fb87SGovind Singh } 5111399fb87SGovind Singh 5121399fb87SGovind Singh ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name); 5131399fb87SGovind Singh 5141399fb87SGovind Singh return -EINVAL; 5151399fb87SGovind Singh } 5161399fb87SGovind Singh 5176289ac2bSKarthikeyan Periyasamy static void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, 5186289ac2bSKarthikeyan Periyasamy u32 *msi_idx) 5196289ac2bSKarthikeyan Periyasamy { 5206289ac2bSKarthikeyan Periyasamy u32 i, msi_data_idx; 5216289ac2bSKarthikeyan Periyasamy 5226289ac2bSKarthikeyan Periyasamy for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { 5236289ac2bSKarthikeyan Periyasamy if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5246289ac2bSKarthikeyan Periyasamy continue; 5256289ac2bSKarthikeyan Periyasamy 5266289ac2bSKarthikeyan Periyasamy if (ce_id == i) 5276289ac2bSKarthikeyan Periyasamy break; 5286289ac2bSKarthikeyan Periyasamy 5296289ac2bSKarthikeyan Periyasamy msi_data_idx++; 5306289ac2bSKarthikeyan Periyasamy } 5316289ac2bSKarthikeyan Periyasamy *msi_idx = msi_data_idx; 5326289ac2bSKarthikeyan Periyasamy } 5336289ac2bSKarthikeyan Periyasamy 534c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, 535c4eacabeSGovind Singh int *num_vectors, u32 *user_base_data, 536c4eacabeSGovind Singh u32 *base_vector) 537c4eacabeSGovind Singh { 538c4eacabeSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 539c4eacabeSGovind Singh 540c4eacabeSGovind Singh return ath11k_pci_get_user_msi_assignment(ab_pci, user_name, 541c4eacabeSGovind Singh num_vectors, user_base_data, 542c4eacabeSGovind Singh base_vector); 543c4eacabeSGovind Singh } 544c4eacabeSGovind Singh 545d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab) 546d4ecb90bSCarl Huang { 547d4ecb90bSCarl Huang int i, j; 548d4ecb90bSCarl Huang 549d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 550d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 551d4ecb90bSCarl Huang 552d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) 553d4ecb90bSCarl Huang free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); 554d4ecb90bSCarl Huang 555d4ecb90bSCarl Huang netif_napi_del(&irq_grp->napi); 556d4ecb90bSCarl Huang } 557d4ecb90bSCarl Huang } 558d4ecb90bSCarl Huang 5597f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab) 5607f4beda2SGovind Singh { 5617f4beda2SGovind Singh int i, irq_idx; 5627f4beda2SGovind Singh 563d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 564e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5657f4beda2SGovind Singh continue; 5667f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 5677f4beda2SGovind Singh free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); 5687f4beda2SGovind Singh } 569d4ecb90bSCarl Huang 570d4ecb90bSCarl Huang ath11k_pci_free_ext_irq(ab); 5717f4beda2SGovind Singh } 5727f4beda2SGovind Singh 5732c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) 5742c3960c2SGovind Singh { 575c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 5762c3960c2SGovind Singh u32 irq_idx; 5772c3960c2SGovind Singh 578c41a6700SCarl Huang /* In case of one MSI vector, we handle irq enable/disable in a 579c41a6700SCarl Huang * uniform way since we only have one irq 580c41a6700SCarl Huang */ 581c41a6700SCarl Huang if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 582c41a6700SCarl Huang return; 583c41a6700SCarl Huang 5842c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 5852c3960c2SGovind Singh enable_irq(ab->irq_num[irq_idx]); 5862c3960c2SGovind Singh } 5872c3960c2SGovind Singh 5887f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) 5897f4beda2SGovind Singh { 590c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 5917f4beda2SGovind Singh u32 irq_idx; 5927f4beda2SGovind Singh 593c41a6700SCarl Huang /* In case of one MSI vector, we handle irq enable/disable in a 594c41a6700SCarl Huang * uniform way since we only have one irq 595c41a6700SCarl Huang */ 596c41a6700SCarl Huang if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 597c41a6700SCarl Huang return; 598c41a6700SCarl Huang 5997f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 6007f4beda2SGovind Singh disable_irq_nosync(ab->irq_num[irq_idx]); 6017f4beda2SGovind Singh } 6027f4beda2SGovind Singh 6032c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab) 6042c3960c2SGovind Singh { 6052c3960c2SGovind Singh int i; 6062c3960c2SGovind Singh 60701279bcdSCarl Huang clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); 60801279bcdSCarl Huang 609d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 610e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 6112c3960c2SGovind Singh continue; 6122c3960c2SGovind Singh ath11k_pci_ce_irq_disable(ab, i); 6132c3960c2SGovind Singh } 6142c3960c2SGovind Singh } 6152c3960c2SGovind Singh 6162c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) 6172c3960c2SGovind Singh { 6182c3960c2SGovind Singh int i; 6192c3960c2SGovind Singh int irq_idx; 6202c3960c2SGovind Singh 621d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 622e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 6232c3960c2SGovind Singh continue; 6242c3960c2SGovind Singh 6252c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 6262c3960c2SGovind Singh synchronize_irq(ab->irq_num[irq_idx]); 6272c3960c2SGovind Singh } 6282c3960c2SGovind Singh } 6292c3960c2SGovind Singh 6300f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t) 6312c3960c2SGovind Singh { 6320f01dcb8SAllen Pais struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); 633ac6e7348SCarl Huang int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; 6342c3960c2SGovind Singh 6352c3960c2SGovind Singh ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); 6362c3960c2SGovind Singh 637ac6e7348SCarl Huang enable_irq(ce_pipe->ab->irq_num[irq_idx]); 6382c3960c2SGovind Singh } 6392c3960c2SGovind Singh 6407f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) 6417f4beda2SGovind Singh { 6427f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe = arg; 64301279bcdSCarl Huang struct ath11k_base *ab = ce_pipe->ab; 644ac6e7348SCarl Huang int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; 64501279bcdSCarl Huang 64601279bcdSCarl Huang if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags)) 64701279bcdSCarl Huang return IRQ_HANDLED; 6487f4beda2SGovind Singh 6497dc67af0SKarthikeyan Periyasamy /* last interrupt received for this CE */ 6507dc67af0SKarthikeyan Periyasamy ce_pipe->timestamp = jiffies; 6517dc67af0SKarthikeyan Periyasamy 652ac6e7348SCarl Huang disable_irq_nosync(ab->irq_num[irq_idx]); 653ac6e7348SCarl Huang 6542c3960c2SGovind Singh tasklet_schedule(&ce_pipe->intr_tq); 6557f4beda2SGovind Singh 6567f4beda2SGovind Singh return IRQ_HANDLED; 6577f4beda2SGovind Singh } 6587f4beda2SGovind Singh 659d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) 660d4ecb90bSCarl Huang { 661c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); 662d4ecb90bSCarl Huang int i; 663d4ecb90bSCarl Huang 664c41a6700SCarl Huang /* In case of one MSI vector, we handle irq enable/disable 665c41a6700SCarl Huang * in a uniform way since we only have one irq 666c41a6700SCarl Huang */ 667c41a6700SCarl Huang if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 668c41a6700SCarl Huang return; 669c41a6700SCarl Huang 670d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 671d4ecb90bSCarl Huang disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 672d4ecb90bSCarl Huang } 673d4ecb90bSCarl Huang 674d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc) 675d4ecb90bSCarl Huang { 676d4ecb90bSCarl Huang int i; 677d4ecb90bSCarl Huang 67801279bcdSCarl Huang clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags); 67901279bcdSCarl Huang 680d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 681d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; 682d4ecb90bSCarl Huang 683d4ecb90bSCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 684d4ecb90bSCarl Huang 685d4ecb90bSCarl Huang napi_synchronize(&irq_grp->napi); 686d4ecb90bSCarl Huang napi_disable(&irq_grp->napi); 687d4ecb90bSCarl Huang } 688d4ecb90bSCarl Huang } 689d4ecb90bSCarl Huang 690d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) 691d4ecb90bSCarl Huang { 692c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); 693d4ecb90bSCarl Huang int i; 694d4ecb90bSCarl Huang 695c41a6700SCarl Huang /* In case of one MSI vector, we handle irq enable/disable in a 696c41a6700SCarl Huang * uniform way since we only have one irq 697c41a6700SCarl Huang */ 698c41a6700SCarl Huang if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 699c41a6700SCarl Huang return; 700c41a6700SCarl Huang 701d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 702d4ecb90bSCarl Huang enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 703d4ecb90bSCarl Huang } 704d4ecb90bSCarl Huang 705d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab) 706d4ecb90bSCarl Huang { 707d4ecb90bSCarl Huang int i; 708d4ecb90bSCarl Huang 70901279bcdSCarl Huang set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); 71001279bcdSCarl Huang 711d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 712d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 713d4ecb90bSCarl Huang 714d4ecb90bSCarl Huang napi_enable(&irq_grp->napi); 715d4ecb90bSCarl Huang ath11k_pci_ext_grp_enable(irq_grp); 716d4ecb90bSCarl Huang } 717d4ecb90bSCarl Huang } 718d4ecb90bSCarl Huang 719d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab) 720d4ecb90bSCarl Huang { 721d4ecb90bSCarl Huang int i, j, irq_idx; 722d4ecb90bSCarl Huang 723d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 724d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 725d4ecb90bSCarl Huang 726d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 727d4ecb90bSCarl Huang irq_idx = irq_grp->irqs[j]; 728d4ecb90bSCarl Huang synchronize_irq(ab->irq_num[irq_idx]); 729d4ecb90bSCarl Huang } 730d4ecb90bSCarl Huang } 731d4ecb90bSCarl Huang } 732d4ecb90bSCarl Huang 733d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab) 734d4ecb90bSCarl Huang { 735d4ecb90bSCarl Huang __ath11k_pci_ext_irq_disable(ab); 736d4ecb90bSCarl Huang ath11k_pci_sync_ext_irqs(ab); 737d4ecb90bSCarl Huang } 738d4ecb90bSCarl Huang 739d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) 740d4ecb90bSCarl Huang { 741d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = container_of(napi, 742d4ecb90bSCarl Huang struct ath11k_ext_irq_grp, 743d4ecb90bSCarl Huang napi); 744d4ecb90bSCarl Huang struct ath11k_base *ab = irq_grp->ab; 745d4ecb90bSCarl Huang int work_done; 746ac6e7348SCarl Huang int i; 747d4ecb90bSCarl Huang 748d4ecb90bSCarl Huang work_done = ath11k_dp_service_srng(ab, irq_grp, budget); 749d4ecb90bSCarl Huang if (work_done < budget) { 750d4ecb90bSCarl Huang napi_complete_done(napi, work_done); 751ac6e7348SCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 752ac6e7348SCarl Huang enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 753d4ecb90bSCarl Huang } 754d4ecb90bSCarl Huang 755d4ecb90bSCarl Huang if (work_done > budget) 756d4ecb90bSCarl Huang work_done = budget; 757d4ecb90bSCarl Huang 758d4ecb90bSCarl Huang return work_done; 759d4ecb90bSCarl Huang } 760d4ecb90bSCarl Huang 761d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) 762d4ecb90bSCarl Huang { 763d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = arg; 76401279bcdSCarl Huang struct ath11k_base *ab = irq_grp->ab; 765ac6e7348SCarl Huang int i; 76601279bcdSCarl Huang 76701279bcdSCarl Huang if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) 76801279bcdSCarl Huang return IRQ_HANDLED; 769d4ecb90bSCarl Huang 770d4ecb90bSCarl Huang ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); 771d4ecb90bSCarl Huang 7727dc67af0SKarthikeyan Periyasamy /* last interrupt received for this group */ 7737dc67af0SKarthikeyan Periyasamy irq_grp->timestamp = jiffies; 7747dc67af0SKarthikeyan Periyasamy 775ac6e7348SCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 776ac6e7348SCarl Huang disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 777d4ecb90bSCarl Huang 778d4ecb90bSCarl Huang napi_schedule(&irq_grp->napi); 779d4ecb90bSCarl Huang 780d4ecb90bSCarl Huang return IRQ_HANDLED; 781d4ecb90bSCarl Huang } 782d4ecb90bSCarl Huang 783d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) 784d4ecb90bSCarl Huang { 785c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 786d4ecb90bSCarl Huang int i, j, ret, num_vectors = 0; 7874ab4693fSCarl Huang u32 user_base_data = 0, base_vector = 0; 788d4ecb90bSCarl Huang 789b2c09458SColin Ian King ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", 790b2c09458SColin Ian King &num_vectors, 791b2c09458SColin Ian King &user_base_data, 792d4ecb90bSCarl Huang &base_vector); 793b2c09458SColin Ian King if (ret < 0) 794b2c09458SColin Ian King return ret; 795d4ecb90bSCarl Huang 796d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 797d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 798d4ecb90bSCarl Huang u32 num_irq = 0; 799d4ecb90bSCarl Huang 800d4ecb90bSCarl Huang irq_grp->ab = ab; 801d4ecb90bSCarl Huang irq_grp->grp_id = i; 802d4ecb90bSCarl Huang init_dummy_netdev(&irq_grp->napi_ndev); 803d4ecb90bSCarl Huang netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, 804d4ecb90bSCarl Huang ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT); 805d4ecb90bSCarl Huang 806d4ecb90bSCarl Huang if (ab->hw_params.ring_mask->tx[i] || 807d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx[i] || 808d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_err[i] || 809d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_wbm_rel[i] || 810d4ecb90bSCarl Huang ab->hw_params.ring_mask->reo_status[i] || 811d4ecb90bSCarl Huang ab->hw_params.ring_mask->rxdma2host[i] || 812d4ecb90bSCarl Huang ab->hw_params.ring_mask->host2rxdma[i] || 813d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_mon_status[i]) { 814d4ecb90bSCarl Huang num_irq = 1; 815d4ecb90bSCarl Huang } 816d4ecb90bSCarl Huang 817d4ecb90bSCarl Huang irq_grp->num_irq = num_irq; 8184ab4693fSCarl Huang irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i; 819d4ecb90bSCarl Huang 820d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 821d4ecb90bSCarl Huang int irq_idx = irq_grp->irqs[j]; 822d4ecb90bSCarl Huang int vector = (i % num_vectors) + base_vector; 823d4ecb90bSCarl Huang int irq = ath11k_pci_get_msi_irq(ab->dev, vector); 824d4ecb90bSCarl Huang 825d4ecb90bSCarl Huang ab->irq_num[irq_idx] = irq; 826d4ecb90bSCarl Huang 827d4ecb90bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, 828d4ecb90bSCarl Huang "irq:%d group:%d\n", irq, i); 8297dc67af0SKarthikeyan Periyasamy 8307dc67af0SKarthikeyan Periyasamy irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); 831d4ecb90bSCarl Huang ret = request_irq(irq, ath11k_pci_ext_interrupt_handler, 832c41a6700SCarl Huang ab_pci->irq_flags, 833d4ecb90bSCarl Huang "DP_EXT_IRQ", irq_grp); 834d4ecb90bSCarl Huang if (ret) { 835d4ecb90bSCarl Huang ath11k_err(ab, "failed request irq %d: %d\n", 836d4ecb90bSCarl Huang vector, ret); 837d4ecb90bSCarl Huang return ret; 838d4ecb90bSCarl Huang } 839d4ecb90bSCarl Huang } 840c41a6700SCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 841d4ecb90bSCarl Huang } 842d4ecb90bSCarl Huang 843d4ecb90bSCarl Huang return 0; 844d4ecb90bSCarl Huang } 845d4ecb90bSCarl Huang 8467f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab) 8477f4beda2SGovind Singh { 848c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 8497f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe; 8507f4beda2SGovind Singh u32 msi_data_start; 8516289ac2bSKarthikeyan Periyasamy u32 msi_data_count, msi_data_idx; 8527f4beda2SGovind Singh u32 msi_irq_start; 8537f4beda2SGovind Singh unsigned int msi_data; 8547f4beda2SGovind Singh int irq, i, ret, irq_idx; 8557f4beda2SGovind Singh 8567f4beda2SGovind Singh ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), 8577f4beda2SGovind Singh "CE", &msi_data_count, 8587f4beda2SGovind Singh &msi_data_start, &msi_irq_start); 8597f4beda2SGovind Singh if (ret) 8607f4beda2SGovind Singh return ret; 8617f4beda2SGovind Singh 8627f4beda2SGovind Singh /* Configure CE irqs */ 8636289ac2bSKarthikeyan Periyasamy for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { 864e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 8657f4beda2SGovind Singh continue; 8667f4beda2SGovind Singh 8676289ac2bSKarthikeyan Periyasamy msi_data = (msi_data_idx % msi_data_count) + msi_irq_start; 8686289ac2bSKarthikeyan Periyasamy irq = ath11k_pci_get_msi_irq(ab->dev, msi_data); 8696289ac2bSKarthikeyan Periyasamy ce_pipe = &ab->ce.ce_pipe[i]; 8706289ac2bSKarthikeyan Periyasamy 8717f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 8727f4beda2SGovind Singh 8730f01dcb8SAllen Pais tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet); 8742c3960c2SGovind Singh 8757f4beda2SGovind Singh ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, 876c41a6700SCarl Huang ab_pci->irq_flags, irq_name[irq_idx], 8777f4beda2SGovind Singh ce_pipe); 8787f4beda2SGovind Singh if (ret) { 8797f4beda2SGovind Singh ath11k_err(ab, "failed to request irq %d: %d\n", 8807f4beda2SGovind Singh irq_idx, ret); 8817f4beda2SGovind Singh return ret; 8827f4beda2SGovind Singh } 8837f4beda2SGovind Singh 8847f4beda2SGovind Singh ab->irq_num[irq_idx] = irq; 8856289ac2bSKarthikeyan Periyasamy msi_data_idx++; 886e678fbd4SKarthikeyan Periyasamy 887e5c860e1SCarl Huang ath11k_pci_ce_irq_disable(ab, i); 8887f4beda2SGovind Singh } 8897f4beda2SGovind Singh 890d4ecb90bSCarl Huang ret = ath11k_pci_ext_irq_config(ab); 891d4ecb90bSCarl Huang if (ret) 892d4ecb90bSCarl Huang return ret; 893d4ecb90bSCarl Huang 8947f4beda2SGovind Singh return 0; 8957f4beda2SGovind Singh } 8967f4beda2SGovind Singh 8977f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) 8987f4beda2SGovind Singh { 8997f4beda2SGovind Singh struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; 9007f4beda2SGovind Singh 901967c1d11SAnilkumar Kolli cfg->tgt_ce = ab->hw_params.target_ce_config; 902967c1d11SAnilkumar Kolli cfg->tgt_ce_len = ab->hw_params.target_ce_count; 9037f4beda2SGovind Singh 904967c1d11SAnilkumar Kolli cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map; 905967c1d11SAnilkumar Kolli cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len; 90616001e4bSAnilkumar Kolli ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id; 907e838c14aSCarl Huang 908e838c14aSCarl Huang ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2, 909e838c14aSCarl Huang &cfg->shadow_reg_v2_len); 9107f4beda2SGovind Singh } 9117f4beda2SGovind Singh 9127f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) 9137f4beda2SGovind Singh { 9147f4beda2SGovind Singh int i; 9157f4beda2SGovind Singh 91601279bcdSCarl Huang set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); 91701279bcdSCarl Huang 918d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 919e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 9207f4beda2SGovind Singh continue; 9217f4beda2SGovind Singh ath11k_pci_ce_irq_enable(ab, i); 9227f4beda2SGovind Singh } 9237f4beda2SGovind Singh } 9247f4beda2SGovind Singh 92596527d52SBaochen Qiang static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable) 92696527d52SBaochen Qiang { 92796527d52SBaochen Qiang struct pci_dev *dev = ab_pci->pdev; 92896527d52SBaochen Qiang u16 control; 92996527d52SBaochen Qiang 93096527d52SBaochen Qiang pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control); 93196527d52SBaochen Qiang 93296527d52SBaochen Qiang if (enable) 93396527d52SBaochen Qiang control |= PCI_MSI_FLAGS_ENABLE; 93496527d52SBaochen Qiang else 93596527d52SBaochen Qiang control &= ~PCI_MSI_FLAGS_ENABLE; 93696527d52SBaochen Qiang 93796527d52SBaochen Qiang pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control); 93896527d52SBaochen Qiang } 93996527d52SBaochen Qiang 94096527d52SBaochen Qiang static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci) 94196527d52SBaochen Qiang { 94296527d52SBaochen Qiang ath11k_pci_msi_config(ab_pci, true); 94396527d52SBaochen Qiang } 94496527d52SBaochen Qiang 94596527d52SBaochen Qiang static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci) 94696527d52SBaochen Qiang { 94796527d52SBaochen Qiang ath11k_pci_msi_config(ab_pci, false); 94896527d52SBaochen Qiang } 94996527d52SBaochen Qiang 95096527d52SBaochen Qiang static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci) 9515697a564SGovind Singh { 9525697a564SGovind Singh struct ath11k_base *ab = ab_pci->ab; 9537a3aed0cSAnilkumar Kolli const struct ath11k_msi_config *msi_config = ab_pci->msi_config; 9545697a564SGovind Singh struct msi_desc *msi_desc; 9555697a564SGovind Singh int num_vectors; 9565697a564SGovind Singh int ret; 9575697a564SGovind Singh 9585697a564SGovind Singh num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 9597a3aed0cSAnilkumar Kolli msi_config->total_vectors, 9607a3aed0cSAnilkumar Kolli msi_config->total_vectors, 9615697a564SGovind Singh PCI_IRQ_MSI); 962ac6e7348SCarl Huang if (num_vectors == msi_config->total_vectors) { 963c41a6700SCarl Huang set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); 964c41a6700SCarl Huang ab_pci->irq_flags = IRQF_SHARED; 965ac6e7348SCarl Huang } else { 966ac6e7348SCarl Huang num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 967ac6e7348SCarl Huang 1, 968ac6e7348SCarl Huang 1, 969ac6e7348SCarl Huang PCI_IRQ_MSI); 970ac6e7348SCarl Huang if (num_vectors < 0) { 971ac6e7348SCarl Huang ret = -EINVAL; 972ac6e7348SCarl Huang goto reset_msi_config; 9735697a564SGovind Singh } 974ac6e7348SCarl Huang clear_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); 975ac6e7348SCarl Huang ab_pci->msi_config = &msi_config_one_msi; 976ac6e7348SCarl Huang ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; 977ac6e7348SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n"); 978ac6e7348SCarl Huang } 979ac6e7348SCarl Huang ath11k_info(ab, "MSI vectors: %d\n", num_vectors); 980ac6e7348SCarl Huang 98196527d52SBaochen Qiang ath11k_pci_msi_disable(ab_pci); 9825697a564SGovind Singh 9835697a564SGovind Singh msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 9845697a564SGovind Singh if (!msi_desc) { 9855697a564SGovind Singh ath11k_err(ab, "msi_desc is NULL!\n"); 9865697a564SGovind Singh ret = -EINVAL; 9875697a564SGovind Singh goto free_msi_vector; 9885697a564SGovind Singh } 9895697a564SGovind Singh 9905697a564SGovind Singh ab_pci->msi_ep_base_data = msi_desc->msg.data; 991e8e55d89SAnilkumar Kolli if (msi_desc->msi_attrib.is_64) 992e8e55d89SAnilkumar Kolli set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags); 9935697a564SGovind Singh 9945697a564SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); 9955697a564SGovind Singh 9965697a564SGovind Singh return 0; 9975697a564SGovind Singh 9985697a564SGovind Singh free_msi_vector: 9995697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 10005697a564SGovind Singh 1001ac6e7348SCarl Huang reset_msi_config: 10025697a564SGovind Singh return ret; 10035697a564SGovind Singh } 10045697a564SGovind Singh 100596527d52SBaochen Qiang static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci) 10065697a564SGovind Singh { 10075697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 10085697a564SGovind Singh } 10095697a564SGovind Singh 101087b4072dSCarl Huang static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci) 101187b4072dSCarl Huang { 101287b4072dSCarl Huang struct msi_desc *msi_desc; 101387b4072dSCarl Huang 101487b4072dSCarl Huang msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 101587b4072dSCarl Huang if (!msi_desc) { 101687b4072dSCarl Huang ath11k_err(ab_pci->ab, "msi_desc is NULL!\n"); 101787b4072dSCarl Huang pci_free_irq_vectors(ab_pci->pdev); 101887b4072dSCarl Huang return -EINVAL; 101987b4072dSCarl Huang } 102087b4072dSCarl Huang 102187b4072dSCarl Huang ab_pci->msi_ep_base_data = msi_desc->msg.data; 102287b4072dSCarl Huang 102387b4072dSCarl Huang ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n", 102487b4072dSCarl Huang ab_pci->msi_ep_base_data); 102587b4072dSCarl Huang 102687b4072dSCarl Huang return 0; 102787b4072dSCarl Huang } 102887b4072dSCarl Huang 10295762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) 10305762613eSGovind Singh { 10315762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 10325762613eSGovind Singh u16 device_id; 10335762613eSGovind Singh int ret = 0; 10345762613eSGovind Singh 10355762613eSGovind Singh pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 10365762613eSGovind Singh if (device_id != ab_pci->dev_id) { 10375762613eSGovind Singh ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", 10385762613eSGovind Singh device_id, ab_pci->dev_id); 10395762613eSGovind Singh ret = -EIO; 10405762613eSGovind Singh goto out; 10415762613eSGovind Singh } 10425762613eSGovind Singh 10435762613eSGovind Singh ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); 10445762613eSGovind Singh if (ret) { 10455762613eSGovind Singh ath11k_err(ab, "failed to assign pci resource: %d\n", ret); 10465762613eSGovind Singh goto out; 10475762613eSGovind Singh } 10485762613eSGovind Singh 10495762613eSGovind Singh ret = pci_enable_device(pdev); 10505762613eSGovind Singh if (ret) { 10515762613eSGovind Singh ath11k_err(ab, "failed to enable pci device: %d\n", ret); 10525762613eSGovind Singh goto out; 10535762613eSGovind Singh } 10545762613eSGovind Singh 10555762613eSGovind Singh ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); 10565762613eSGovind Singh if (ret) { 10575762613eSGovind Singh ath11k_err(ab, "failed to request pci region: %d\n", ret); 10585762613eSGovind Singh goto disable_device; 10595762613eSGovind Singh } 10605762613eSGovind Singh 1061923a1346SChristophe JAILLET ret = dma_set_mask_and_coherent(&pdev->dev, 1062923a1346SChristophe JAILLET DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 10635762613eSGovind Singh if (ret) { 10645762613eSGovind Singh ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", 10655762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 10665762613eSGovind Singh goto release_region; 10675762613eSGovind Singh } 10685762613eSGovind Singh 10695762613eSGovind Singh pci_set_master(pdev); 10705762613eSGovind Singh 10715762613eSGovind Singh ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); 10725762613eSGovind Singh ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); 10735762613eSGovind Singh if (!ab->mem) { 10745762613eSGovind Singh ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); 10755762613eSGovind Singh ret = -EIO; 10765762613eSGovind Singh goto clear_master; 10775762613eSGovind Singh } 10785762613eSGovind Singh 10795762613eSGovind Singh ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); 10805762613eSGovind Singh return 0; 10815762613eSGovind Singh 10825762613eSGovind Singh clear_master: 10835762613eSGovind Singh pci_clear_master(pdev); 10845762613eSGovind Singh release_region: 10855762613eSGovind Singh pci_release_region(pdev, ATH11K_PCI_BAR_NUM); 10865762613eSGovind Singh disable_device: 10875762613eSGovind Singh pci_disable_device(pdev); 10885762613eSGovind Singh out: 10895762613eSGovind Singh return ret; 10905762613eSGovind Singh } 10915762613eSGovind Singh 10925762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) 10935762613eSGovind Singh { 10945762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 10955762613eSGovind Singh struct pci_dev *pci_dev = ab_pci->pdev; 10965762613eSGovind Singh 10975762613eSGovind Singh pci_iounmap(pci_dev, ab->mem); 10985762613eSGovind Singh ab->mem = NULL; 10995762613eSGovind Singh pci_clear_master(pci_dev); 11005762613eSGovind Singh pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); 11015762613eSGovind Singh if (pci_is_enabled(pci_dev)) 11025762613eSGovind Singh pci_disable_device(pci_dev); 11035762613eSGovind Singh } 11045762613eSGovind Singh 1105e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci) 1106e9603f4bSCarl Huang { 1107e9603f4bSCarl Huang struct ath11k_base *ab = ab_pci->ab; 1108e9603f4bSCarl Huang 1109e9603f4bSCarl Huang pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL, 1110e9603f4bSCarl Huang &ab_pci->link_ctl); 1111e9603f4bSCarl Huang 1112e9603f4bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n", 1113e9603f4bSCarl Huang ab_pci->link_ctl, 1114e9603f4bSCarl Huang u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S), 1115e9603f4bSCarl Huang u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1)); 1116e9603f4bSCarl Huang 1117e9603f4bSCarl Huang /* disable L0s and L1 */ 1118e9603f4bSCarl Huang pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, 1119e9603f4bSCarl Huang ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC); 1120e9603f4bSCarl Huang 1121e9603f4bSCarl Huang set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags); 1122e9603f4bSCarl Huang } 1123e9603f4bSCarl Huang 1124e9603f4bSCarl Huang static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci) 1125e9603f4bSCarl Huang { 1126e9603f4bSCarl Huang if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags)) 1127e9603f4bSCarl Huang pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, 1128e9603f4bSCarl Huang ab_pci->link_ctl); 1129e9603f4bSCarl Huang } 1130e9603f4bSCarl Huang 11311399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab) 11321399fb87SGovind Singh { 11331399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 11341399fb87SGovind Singh int ret; 11351399fb87SGovind Singh 1136a05bd851SCarl Huang ab_pci->register_window = 0; 1137a05bd851SCarl Huang clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 1138babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, true); 1139f3c603d4SCarl Huang 1140e9603f4bSCarl Huang /* Disable ASPM during firmware download due to problems switching 1141e9603f4bSCarl Huang * to AMSS state. 1142e9603f4bSCarl Huang */ 1143e9603f4bSCarl Huang ath11k_pci_aspm_disable(ab_pci); 1144e9603f4bSCarl Huang 114596527d52SBaochen Qiang ath11k_pci_msi_enable(ab_pci); 114696527d52SBaochen Qiang 11471399fb87SGovind Singh ret = ath11k_mhi_start(ab_pci); 11481399fb87SGovind Singh if (ret) { 11491399fb87SGovind Singh ath11k_err(ab, "failed to start mhi: %d\n", ret); 11501399fb87SGovind Singh return ret; 11511399fb87SGovind Singh } 11521399fb87SGovind Singh 1153480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 1154480a7361SKarthikeyan Periyasamy ath11k_pci_select_static_window(ab_pci); 1155480a7361SKarthikeyan Periyasamy 11561399fb87SGovind Singh return 0; 11571399fb87SGovind Singh } 11581399fb87SGovind Singh 11591399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab) 11601399fb87SGovind Singh { 11611399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 11621399fb87SGovind Singh 1163e9603f4bSCarl Huang /* restore aspm in case firmware bootup fails */ 1164e9603f4bSCarl Huang ath11k_pci_aspm_restore(ab_pci); 1165e9603f4bSCarl Huang 1166babb0cedSCarl Huang ath11k_pci_force_wake(ab_pci->ab); 116796527d52SBaochen Qiang 116896527d52SBaochen Qiang ath11k_pci_msi_disable(ab_pci); 116996527d52SBaochen Qiang 11701399fb87SGovind Singh ath11k_mhi_stop(ab_pci); 1171a05bd851SCarl Huang clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 1172babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, false); 11731399fb87SGovind Singh } 11741399fb87SGovind Singh 1175fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab) 1176fa5917e4SCarl Huang { 1177fa5917e4SCarl Huang struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); 1178fa5917e4SCarl Huang 1179fa5917e4SCarl Huang ath11k_mhi_suspend(ar_pci); 1180fa5917e4SCarl Huang 1181fa5917e4SCarl Huang return 0; 1182fa5917e4SCarl Huang } 1183fa5917e4SCarl Huang 1184fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab) 1185fa5917e4SCarl Huang { 1186fa5917e4SCarl Huang struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); 1187fa5917e4SCarl Huang 1188fa5917e4SCarl Huang ath11k_mhi_resume(ar_pci); 1189fa5917e4SCarl Huang 1190fa5917e4SCarl Huang return 0; 1191fa5917e4SCarl Huang } 1192fa5917e4SCarl Huang 11932c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) 11942c3960c2SGovind Singh { 11952c3960c2SGovind Singh int i; 11962c3960c2SGovind Singh 1197d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 11982c3960c2SGovind Singh struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; 11992c3960c2SGovind Singh 1200e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 12012c3960c2SGovind Singh continue; 12022c3960c2SGovind Singh 12032c3960c2SGovind Singh tasklet_kill(&ce_pipe->intr_tq); 12042c3960c2SGovind Singh } 12052c3960c2SGovind Singh } 12062c3960c2SGovind Singh 1207d578ec2aSCarl Huang static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab) 12087f4beda2SGovind Singh { 12092c3960c2SGovind Singh ath11k_pci_ce_irqs_disable(ab); 12102c3960c2SGovind Singh ath11k_pci_sync_ce_irqs(ab); 12112c3960c2SGovind Singh ath11k_pci_kill_tasklets(ab); 1212d578ec2aSCarl Huang } 1213d578ec2aSCarl Huang 1214d578ec2aSCarl Huang static void ath11k_pci_stop(struct ath11k_base *ab) 1215d578ec2aSCarl Huang { 1216d578ec2aSCarl Huang ath11k_pci_ce_irq_disable_sync(ab); 12177f4beda2SGovind Singh ath11k_ce_cleanup_pipes(ab); 12187f4beda2SGovind Singh } 12197f4beda2SGovind Singh 12207f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab) 12217f4beda2SGovind Singh { 1222a05bd851SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 1223a05bd851SCarl Huang 1224a05bd851SCarl Huang set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 1225a05bd851SCarl Huang 1226*915a081fSCarl Huang /* TODO: for now don't restore ASPM in case of single MSI 1227*915a081fSCarl Huang * vector as MHI register reading in M2 causes system hang. 1228*915a081fSCarl Huang */ 1229*915a081fSCarl Huang if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 1230e9603f4bSCarl Huang ath11k_pci_aspm_restore(ab_pci); 1231*915a081fSCarl Huang else 1232*915a081fSCarl Huang ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n"); 1233e9603f4bSCarl Huang 12347f4beda2SGovind Singh ath11k_pci_ce_irqs_enable(ab); 12352c3960c2SGovind Singh ath11k_ce_rx_post_buf(ab); 12362c3960c2SGovind Singh 12372c3960c2SGovind Singh return 0; 12382c3960c2SGovind Singh } 12392c3960c2SGovind Singh 1240d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab) 1241d578ec2aSCarl Huang { 1242d578ec2aSCarl Huang ath11k_pci_ce_irqs_enable(ab); 1243d578ec2aSCarl Huang } 1244d578ec2aSCarl Huang 1245d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab) 1246d578ec2aSCarl Huang { 1247d578ec2aSCarl Huang ath11k_pci_ce_irq_disable_sync(ab); 1248d578ec2aSCarl Huang } 1249d578ec2aSCarl Huang 12502c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, 12512c3960c2SGovind Singh u8 *ul_pipe, u8 *dl_pipe) 12522c3960c2SGovind Singh { 12532c3960c2SGovind Singh const struct service_to_pipe *entry; 12542c3960c2SGovind Singh bool ul_set = false, dl_set = false; 12552c3960c2SGovind Singh int i; 12562c3960c2SGovind Singh 1257967c1d11SAnilkumar Kolli for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) { 1258967c1d11SAnilkumar Kolli entry = &ab->hw_params.svc_to_ce_map[i]; 12592c3960c2SGovind Singh 12602c3960c2SGovind Singh if (__le32_to_cpu(entry->service_id) != service_id) 12612c3960c2SGovind Singh continue; 12622c3960c2SGovind Singh 12632c3960c2SGovind Singh switch (__le32_to_cpu(entry->pipedir)) { 12642c3960c2SGovind Singh case PIPEDIR_NONE: 12652c3960c2SGovind Singh break; 12662c3960c2SGovind Singh case PIPEDIR_IN: 12672c3960c2SGovind Singh WARN_ON(dl_set); 12682c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 12692c3960c2SGovind Singh dl_set = true; 12702c3960c2SGovind Singh break; 12712c3960c2SGovind Singh case PIPEDIR_OUT: 12722c3960c2SGovind Singh WARN_ON(ul_set); 12732c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 12742c3960c2SGovind Singh ul_set = true; 12752c3960c2SGovind Singh break; 12762c3960c2SGovind Singh case PIPEDIR_INOUT: 12772c3960c2SGovind Singh WARN_ON(dl_set); 12782c3960c2SGovind Singh WARN_ON(ul_set); 12792c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 12802c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 12812c3960c2SGovind Singh dl_set = true; 12822c3960c2SGovind Singh ul_set = true; 12832c3960c2SGovind Singh break; 12842c3960c2SGovind Singh } 12852c3960c2SGovind Singh } 12862c3960c2SGovind Singh 12872c3960c2SGovind Singh if (WARN_ON(!ul_set || !dl_set)) 12882c3960c2SGovind Singh return -ENOENT; 12897f4beda2SGovind Singh 12907f4beda2SGovind Singh return 0; 12917f4beda2SGovind Singh } 12927f4beda2SGovind Singh 12937f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = { 12947f4beda2SGovind Singh .start = ath11k_pci_start, 12957f4beda2SGovind Singh .stop = ath11k_pci_stop, 1296654e959aSGovind Singh .read32 = ath11k_pci_read32, 1297654e959aSGovind Singh .write32 = ath11k_pci_write32, 12981399fb87SGovind Singh .power_down = ath11k_pci_power_down, 12991399fb87SGovind Singh .power_up = ath11k_pci_power_up, 1300fa5917e4SCarl Huang .suspend = ath11k_pci_hif_suspend, 1301fa5917e4SCarl Huang .resume = ath11k_pci_hif_resume, 1302d4ecb90bSCarl Huang .irq_enable = ath11k_pci_ext_irq_enable, 1303d4ecb90bSCarl Huang .irq_disable = ath11k_pci_ext_irq_disable, 1304c4eacabeSGovind Singh .get_msi_address = ath11k_pci_get_msi_address, 1305c4eacabeSGovind Singh .get_user_msi_vector = ath11k_get_user_msi_assignment, 13062c3960c2SGovind Singh .map_service_to_pipe = ath11k_pci_map_service_to_pipe, 1307d578ec2aSCarl Huang .ce_irq_enable = ath11k_pci_hif_ce_irq_enable, 1308d578ec2aSCarl Huang .ce_irq_disable = ath11k_pci_hif_ce_irq_disable, 13096289ac2bSKarthikeyan Periyasamy .get_ce_msi_idx = ath11k_pci_get_ce_msi_idx, 13101399fb87SGovind Singh }; 13111399fb87SGovind Singh 13120fbf1957SBaochen Qiang static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor) 13130fbf1957SBaochen Qiang { 13140fbf1957SBaochen Qiang u32 soc_hw_version; 13150fbf1957SBaochen Qiang 13160fbf1957SBaochen Qiang soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION); 13170fbf1957SBaochen Qiang *major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK, 13180fbf1957SBaochen Qiang soc_hw_version); 13190fbf1957SBaochen Qiang *minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK, 13200fbf1957SBaochen Qiang soc_hw_version); 13210fbf1957SBaochen Qiang 13220fbf1957SBaochen Qiang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n", 13230fbf1957SBaochen Qiang *major, *minor); 13240fbf1957SBaochen Qiang } 13250fbf1957SBaochen Qiang 13266e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev, 13276e0355afSGovind Singh const struct pci_device_id *pci_dev) 13286e0355afSGovind Singh { 13296e0355afSGovind Singh struct ath11k_base *ab; 13305762613eSGovind Singh struct ath11k_pci *ab_pci; 13310fbf1957SBaochen Qiang u32 soc_hw_version_major, soc_hw_version_minor; 13325762613eSGovind Singh int ret; 13336e0355afSGovind Singh 13341ff8ed78SGovind Singh ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, 13351ff8ed78SGovind Singh &ath11k_pci_bus_params); 13366e0355afSGovind Singh if (!ab) { 13376e0355afSGovind Singh dev_err(&pdev->dev, "failed to allocate ath11k base\n"); 13386e0355afSGovind Singh return -ENOMEM; 13396e0355afSGovind Singh } 13406e0355afSGovind Singh 13416e0355afSGovind Singh ab->dev = &pdev->dev; 13426e0355afSGovind Singh pci_set_drvdata(pdev, ab); 13435762613eSGovind Singh ab_pci = ath11k_pci_priv(ab); 13445762613eSGovind Singh ab_pci->dev_id = pci_dev->device; 13455762613eSGovind Singh ab_pci->ab = ab; 13465697a564SGovind Singh ab_pci->pdev = pdev; 13477f4beda2SGovind Singh ab->hif.ops = &ath11k_pci_hif_ops; 13485762613eSGovind Singh pci_set_drvdata(pdev, ab); 1349654e959aSGovind Singh spin_lock_init(&ab_pci->window_lock); 13505762613eSGovind Singh 13515762613eSGovind Singh ret = ath11k_pci_claim(ab_pci, pdev); 13525762613eSGovind Singh if (ret) { 13535762613eSGovind Singh ath11k_err(ab, "failed to claim device: %d\n", ret); 13545762613eSGovind Singh goto err_free_core; 13555762613eSGovind Singh } 13566e0355afSGovind Singh 1357fc95d10aSWen Gong ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n", 1358fc95d10aSWen Gong pdev->vendor, pdev->device, 1359fc95d10aSWen Gong pdev->subsystem_vendor, pdev->subsystem_device); 1360fc95d10aSWen Gong 1361fc95d10aSWen Gong ab->id.vendor = pdev->vendor; 1362fc95d10aSWen Gong ab->id.device = pdev->device; 1363fc95d10aSWen Gong ab->id.subsystem_vendor = pdev->subsystem_vendor; 1364fc95d10aSWen Gong ab->id.subsystem_device = pdev->subsystem_device; 1365fc95d10aSWen Gong 136618ac1665SKalle Valo switch (pci_dev->device) { 136718ac1665SKalle Valo case QCA6390_DEVICE_ID: 13680fbf1957SBaochen Qiang ath11k_pci_read_hw_version(ab, &soc_hw_version_major, 13690fbf1957SBaochen Qiang &soc_hw_version_minor); 137018ac1665SKalle Valo switch (soc_hw_version_major) { 137118ac1665SKalle Valo case 2: 137218ac1665SKalle Valo ab->hw_rev = ATH11K_HW_QCA6390_HW20; 137318ac1665SKalle Valo break; 137418ac1665SKalle Valo default: 137518ac1665SKalle Valo dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n", 137618ac1665SKalle Valo soc_hw_version_major, soc_hw_version_minor); 137718ac1665SKalle Valo ret = -EOPNOTSUPP; 137818ac1665SKalle Valo goto err_pci_free_region; 137918ac1665SKalle Valo } 13804e809461SAnilkumar Kolli ab_pci->msi_config = &ath11k_msi_config[0]; 13814e809461SAnilkumar Kolli break; 13824e809461SAnilkumar Kolli case QCN9074_DEVICE_ID: 13834e809461SAnilkumar Kolli ab_pci->msi_config = &ath11k_msi_config[1]; 13844e809461SAnilkumar Kolli ab->bus_params.static_window_map = true; 13854e809461SAnilkumar Kolli ab->hw_rev = ATH11K_HW_QCN9074_HW10; 138618ac1665SKalle Valo break; 13870fbf1957SBaochen Qiang case WCN6855_DEVICE_ID: 1388fc95d10aSWen Gong ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD; 13890fbf1957SBaochen Qiang ath11k_pci_read_hw_version(ab, &soc_hw_version_major, 13900fbf1957SBaochen Qiang &soc_hw_version_minor); 13910fbf1957SBaochen Qiang switch (soc_hw_version_major) { 13920fbf1957SBaochen Qiang case 2: 13930fbf1957SBaochen Qiang ab->hw_rev = ATH11K_HW_WCN6855_HW20; 13940fbf1957SBaochen Qiang break; 13950fbf1957SBaochen Qiang default: 13960fbf1957SBaochen Qiang dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n", 13970fbf1957SBaochen Qiang soc_hw_version_major, soc_hw_version_minor); 13980fbf1957SBaochen Qiang ret = -EOPNOTSUPP; 13990fbf1957SBaochen Qiang goto err_pci_free_region; 14000fbf1957SBaochen Qiang } 14010fbf1957SBaochen Qiang ab_pci->msi_config = &ath11k_msi_config[0]; 14020fbf1957SBaochen Qiang break; 140318ac1665SKalle Valo default: 140418ac1665SKalle Valo dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", 140518ac1665SKalle Valo pci_dev->device); 140618ac1665SKalle Valo ret = -EOPNOTSUPP; 140718ac1665SKalle Valo goto err_pci_free_region; 140818ac1665SKalle Valo } 140918ac1665SKalle Valo 141096527d52SBaochen Qiang ret = ath11k_pci_alloc_msi(ab_pci); 14115697a564SGovind Singh if (ret) { 14125697a564SGovind Singh ath11k_err(ab, "failed to enable msi: %d\n", ret); 14135697a564SGovind Singh goto err_pci_free_region; 14145697a564SGovind Singh } 14155697a564SGovind Singh 1416b8246f88SKalle Valo ret = ath11k_core_pre_init(ab); 1417b8246f88SKalle Valo if (ret) 1418b8246f88SKalle Valo goto err_pci_disable_msi; 1419b8246f88SKalle Valo 14201399fb87SGovind Singh ret = ath11k_mhi_register(ab_pci); 14211399fb87SGovind Singh if (ret) { 14221399fb87SGovind Singh ath11k_err(ab, "failed to register mhi: %d\n", ret); 14231399fb87SGovind Singh goto err_pci_disable_msi; 14241399fb87SGovind Singh } 14251399fb87SGovind Singh 14267f4beda2SGovind Singh ret = ath11k_hal_srng_init(ab); 14277f4beda2SGovind Singh if (ret) 14287f4beda2SGovind Singh goto err_mhi_unregister; 14297f4beda2SGovind Singh 14307f4beda2SGovind Singh ret = ath11k_ce_alloc_pipes(ab); 14317f4beda2SGovind Singh if (ret) { 14327f4beda2SGovind Singh ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret); 14337f4beda2SGovind Singh goto err_hal_srng_deinit; 14347f4beda2SGovind Singh } 14357f4beda2SGovind Singh 14367f4beda2SGovind Singh ath11k_pci_init_qmi_ce_config(ab); 14377f4beda2SGovind Singh 14387f4beda2SGovind Singh ret = ath11k_pci_config_irq(ab); 14397f4beda2SGovind Singh if (ret) { 14407f4beda2SGovind Singh ath11k_err(ab, "failed to config irq: %d\n", ret); 14417f4beda2SGovind Singh goto err_ce_free; 14427f4beda2SGovind Singh } 14437f4beda2SGovind Singh 144487b4072dSCarl Huang /* kernel may allocate a dummy vector before request_irq and 144587b4072dSCarl Huang * then allocate a real vector when request_irq is called. 144687b4072dSCarl Huang * So get msi_data here again to avoid spurious interrupt 144787b4072dSCarl Huang * as msi_data will configured to srngs. 144887b4072dSCarl Huang */ 144987b4072dSCarl Huang ret = ath11k_pci_config_msi_data(ab_pci); 145087b4072dSCarl Huang if (ret) { 145187b4072dSCarl Huang ath11k_err(ab, "failed to config msi_data: %d\n", ret); 145287b4072dSCarl Huang goto err_free_irq; 145387b4072dSCarl Huang } 145487b4072dSCarl Huang 14557f4beda2SGovind Singh ret = ath11k_core_init(ab); 14567f4beda2SGovind Singh if (ret) { 14577f4beda2SGovind Singh ath11k_err(ab, "failed to init core: %d\n", ret); 14587f4beda2SGovind Singh goto err_free_irq; 14597f4beda2SGovind Singh } 14606e0355afSGovind Singh return 0; 14615762613eSGovind Singh 14627f4beda2SGovind Singh err_free_irq: 14637f4beda2SGovind Singh ath11k_pci_free_irq(ab); 14647f4beda2SGovind Singh 14657f4beda2SGovind Singh err_ce_free: 14667f4beda2SGovind Singh ath11k_ce_free_pipes(ab); 14677f4beda2SGovind Singh 14687f4beda2SGovind Singh err_hal_srng_deinit: 14697f4beda2SGovind Singh ath11k_hal_srng_deinit(ab); 14707f4beda2SGovind Singh 14717f4beda2SGovind Singh err_mhi_unregister: 14727f4beda2SGovind Singh ath11k_mhi_unregister(ab_pci); 14737f4beda2SGovind Singh 1474b8246f88SKalle Valo err_pci_disable_msi: 147596527d52SBaochen Qiang ath11k_pci_free_msi(ab_pci); 1476b8246f88SKalle Valo 14775697a564SGovind Singh err_pci_free_region: 14785697a564SGovind Singh ath11k_pci_free_region(ab_pci); 14795697a564SGovind Singh 14805762613eSGovind Singh err_free_core: 14815762613eSGovind Singh ath11k_core_free(ab); 14825697a564SGovind Singh 14835762613eSGovind Singh return ret; 14846e0355afSGovind Singh } 14856e0355afSGovind Singh 14866e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev) 14876e0355afSGovind Singh { 14886e0355afSGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 14895762613eSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 14906e0355afSGovind Singh 149161a57e51SAnilkumar Kolli if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { 149261a57e51SAnilkumar Kolli ath11k_pci_power_down(ab); 149361a57e51SAnilkumar Kolli ath11k_debugfs_soc_destroy(ab); 149461a57e51SAnilkumar Kolli ath11k_qmi_deinit_service(ab); 149561a57e51SAnilkumar Kolli goto qmi_fail; 149661a57e51SAnilkumar Kolli } 149761a57e51SAnilkumar Kolli 14986e0355afSGovind Singh set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); 14996fbd8898SCarl Huang 15006fbd8898SCarl Huang ath11k_core_deinit(ab); 15016fbd8898SCarl Huang 150261a57e51SAnilkumar Kolli qmi_fail: 15031399fb87SGovind Singh ath11k_mhi_unregister(ab_pci); 15046fbd8898SCarl Huang 15056fbd8898SCarl Huang ath11k_pci_free_irq(ab); 150696527d52SBaochen Qiang ath11k_pci_free_msi(ab_pci); 15075762613eSGovind Singh ath11k_pci_free_region(ab_pci); 15086fbd8898SCarl Huang 15096fbd8898SCarl Huang ath11k_hal_srng_deinit(ab); 15106fbd8898SCarl Huang ath11k_ce_free_pipes(ab); 15116e0355afSGovind Singh ath11k_core_free(ab); 15126e0355afSGovind Singh } 15136e0355afSGovind Singh 15141399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev) 15151399fb87SGovind Singh { 15161399fb87SGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 15171399fb87SGovind Singh 15181399fb87SGovind Singh ath11k_pci_power_down(ab); 15191399fb87SGovind Singh } 15201399fb87SGovind Singh 1521d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev) 1522d1b0c338SCarl Huang { 1523d1b0c338SCarl Huang struct ath11k_base *ab = dev_get_drvdata(dev); 1524d1b0c338SCarl Huang int ret; 1525d1b0c338SCarl Huang 1526d1b0c338SCarl Huang ret = ath11k_core_suspend(ab); 1527d1b0c338SCarl Huang if (ret) 1528d1b0c338SCarl Huang ath11k_warn(ab, "failed to suspend core: %d\n", ret); 1529d1b0c338SCarl Huang 1530d1b0c338SCarl Huang return ret; 1531d1b0c338SCarl Huang } 1532d1b0c338SCarl Huang 1533d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev) 1534d1b0c338SCarl Huang { 1535d1b0c338SCarl Huang struct ath11k_base *ab = dev_get_drvdata(dev); 1536d1b0c338SCarl Huang int ret; 1537d1b0c338SCarl Huang 1538d1b0c338SCarl Huang ret = ath11k_core_resume(ab); 1539d1b0c338SCarl Huang if (ret) 1540d1b0c338SCarl Huang ath11k_warn(ab, "failed to resume core: %d\n", ret); 1541d1b0c338SCarl Huang 1542d1b0c338SCarl Huang return ret; 1543d1b0c338SCarl Huang } 1544d1b0c338SCarl Huang 1545d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops, 1546d1b0c338SCarl Huang ath11k_pci_pm_suspend, 1547d1b0c338SCarl Huang ath11k_pci_pm_resume); 1548d1b0c338SCarl Huang 15496e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = { 15506e0355afSGovind Singh .name = "ath11k_pci", 15516e0355afSGovind Singh .id_table = ath11k_pci_id_table, 15526e0355afSGovind Singh .probe = ath11k_pci_probe, 15536e0355afSGovind Singh .remove = ath11k_pci_remove, 15541399fb87SGovind Singh .shutdown = ath11k_pci_shutdown, 1555d1b0c338SCarl Huang #ifdef CONFIG_PM 1556d1b0c338SCarl Huang .driver.pm = &ath11k_pci_pm_ops, 1557d1b0c338SCarl Huang #endif 15586e0355afSGovind Singh }; 15596e0355afSGovind Singh 15606e0355afSGovind Singh static int ath11k_pci_init(void) 15616e0355afSGovind Singh { 15626e0355afSGovind Singh int ret; 15636e0355afSGovind Singh 15646e0355afSGovind Singh ret = pci_register_driver(&ath11k_pci_driver); 15656e0355afSGovind Singh if (ret) 15666e0355afSGovind Singh pr_err("failed to register ath11k pci driver: %d\n", 15676e0355afSGovind Singh ret); 15686e0355afSGovind Singh 15696e0355afSGovind Singh return ret; 15706e0355afSGovind Singh } 15716e0355afSGovind Singh module_init(ath11k_pci_init); 15726e0355afSGovind Singh 15736e0355afSGovind Singh static void ath11k_pci_exit(void) 15746e0355afSGovind Singh { 15756e0355afSGovind Singh pci_unregister_driver(&ath11k_pci_driver); 15766e0355afSGovind Singh } 15776e0355afSGovind Singh 15786e0355afSGovind Singh module_exit(ath11k_pci_exit); 15796e0355afSGovind Singh 15806e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); 15816e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL"); 15823dbd7fe7SDevin Bayer 15833dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */ 15843dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE); 15853dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE); 15863dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE); 1587