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> 9*6ac04bdcSAnilkumar Kolli #include <linux/of.h> 106e0355afSGovind Singh 115762613eSGovind Singh #include "pci.h" 126e0355afSGovind Singh #include "core.h" 131399fb87SGovind Singh #include "hif.h" 141399fb87SGovind Singh #include "mhi.h" 156e0355afSGovind Singh #include "debug.h" 166e0355afSGovind Singh 175762613eSGovind Singh #define ATH11K_PCI_BAR_NUM 0 185762613eSGovind Singh #define ATH11K_PCI_DMA_MASK 32 195762613eSGovind Singh 207f4beda2SGovind Singh #define ATH11K_PCI_IRQ_CE0_OFFSET 3 214ab4693fSCarl Huang #define ATH11K_PCI_IRQ_DP_OFFSET 14 227f4beda2SGovind Singh 23654e959aSGovind Singh #define WINDOW_ENABLE_BIT 0x40000000 24654e959aSGovind Singh #define WINDOW_REG_ADDRESS 0x310c 25654e959aSGovind Singh #define WINDOW_VALUE_MASK GENMASK(24, 19) 26654e959aSGovind Singh #define WINDOW_START 0x80000 27654e959aSGovind Singh #define WINDOW_RANGE_MASK GENMASK(18, 0) 28654e959aSGovind Singh 2918ac1665SKalle Valo #define TCSR_SOC_HW_VERSION 0x0224 30d1147a31SBaochen Qiang #define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8) 3118ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0) 3218ac1665SKalle Valo 33a05bd851SCarl Huang /* BAR0 + 4k is always accessible, and no 34a05bd851SCarl Huang * need to force wakeup. 35a05bd851SCarl Huang * 4K - 32 = 0xFE0 36a05bd851SCarl Huang */ 37a05bd851SCarl Huang #define ACCESS_ALWAYS_OFF 0xFE0 38a05bd851SCarl Huang 396e0355afSGovind Singh #define QCA6390_DEVICE_ID 0x1101 404e809461SAnilkumar Kolli #define QCN9074_DEVICE_ID 0x1104 410fbf1957SBaochen Qiang #define WCN6855_DEVICE_ID 0x1103 426e0355afSGovind Singh 436e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = { 446e0355afSGovind Singh { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, 450fbf1957SBaochen Qiang { PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) }, 4649f5b114SAnilkumar Kolli { PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) }, 476e0355afSGovind Singh {0} 486e0355afSGovind Singh }; 496e0355afSGovind Singh 506e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); 516e0355afSGovind Singh 521ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = { 531ff8ed78SGovind Singh .mhi_support = true, 5456970454SGovind Singh .m3_fw_support = true, 556eb6ea51SGovind Singh .fixed_bdf_addr = false, 566eb6ea51SGovind Singh .fixed_mem_region = false, 571ff8ed78SGovind Singh }; 581ff8ed78SGovind Singh 597a3aed0cSAnilkumar Kolli static const struct ath11k_msi_config ath11k_msi_config[] = { 607a3aed0cSAnilkumar Kolli { 615697a564SGovind Singh .total_vectors = 32, 625697a564SGovind Singh .total_users = 4, 635697a564SGovind Singh .users = (struct ath11k_msi_user[]) { 645697a564SGovind Singh { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 655697a564SGovind Singh { .name = "CE", .num_vectors = 10, .base_vector = 3 }, 665697a564SGovind Singh { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, 675697a564SGovind Singh { .name = "DP", .num_vectors = 18, .base_vector = 14 }, 685697a564SGovind Singh }, 697a3aed0cSAnilkumar Kolli }, 704e809461SAnilkumar Kolli { 714e809461SAnilkumar Kolli .total_vectors = 16, 724e809461SAnilkumar Kolli .total_users = 3, 734e809461SAnilkumar Kolli .users = (struct ath11k_msi_user[]) { 744e809461SAnilkumar Kolli { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 754e809461SAnilkumar Kolli { .name = "CE", .num_vectors = 5, .base_vector = 3 }, 764e809461SAnilkumar Kolli { .name = "DP", .num_vectors = 8, .base_vector = 8 }, 774e809461SAnilkumar Kolli }, 784e809461SAnilkumar Kolli }, 795697a564SGovind Singh }; 805697a564SGovind Singh 81ac6e7348SCarl Huang static const struct ath11k_msi_config msi_config_one_msi = { 82ac6e7348SCarl Huang .total_vectors = 1, 83ac6e7348SCarl Huang .total_users = 4, 84ac6e7348SCarl Huang .users = (struct ath11k_msi_user[]) { 85ac6e7348SCarl Huang { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 86ac6e7348SCarl Huang { .name = "CE", .num_vectors = 1, .base_vector = 0 }, 87ac6e7348SCarl Huang { .name = "WAKE", .num_vectors = 1, .base_vector = 0 }, 88ac6e7348SCarl Huang { .name = "DP", .num_vectors = 1, .base_vector = 0 }, 89ac6e7348SCarl Huang }, 90ac6e7348SCarl Huang }; 91ac6e7348SCarl Huang 927f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { 937f4beda2SGovind Singh "bhi", 947f4beda2SGovind Singh "mhi-er0", 957f4beda2SGovind Singh "mhi-er1", 967f4beda2SGovind Singh "ce0", 977f4beda2SGovind Singh "ce1", 987f4beda2SGovind Singh "ce2", 997f4beda2SGovind Singh "ce3", 1007f4beda2SGovind Singh "ce4", 1017f4beda2SGovind Singh "ce5", 1027f4beda2SGovind Singh "ce6", 1037f4beda2SGovind Singh "ce7", 1047f4beda2SGovind Singh "ce8", 1057f4beda2SGovind Singh "ce9", 1067f4beda2SGovind Singh "ce10", 1077f4beda2SGovind Singh "ce11", 1087f4beda2SGovind Singh "host2wbm-desc-feed", 1097f4beda2SGovind Singh "host2reo-re-injection", 1107f4beda2SGovind Singh "host2reo-command", 1117f4beda2SGovind Singh "host2rxdma-monitor-ring3", 1127f4beda2SGovind Singh "host2rxdma-monitor-ring2", 1137f4beda2SGovind Singh "host2rxdma-monitor-ring1", 1147f4beda2SGovind Singh "reo2ost-exception", 1157f4beda2SGovind Singh "wbm2host-rx-release", 1167f4beda2SGovind Singh "reo2host-status", 1177f4beda2SGovind Singh "reo2host-destination-ring4", 1187f4beda2SGovind Singh "reo2host-destination-ring3", 1197f4beda2SGovind Singh "reo2host-destination-ring2", 1207f4beda2SGovind Singh "reo2host-destination-ring1", 1217f4beda2SGovind Singh "rxdma2host-monitor-destination-mac3", 1227f4beda2SGovind Singh "rxdma2host-monitor-destination-mac2", 1237f4beda2SGovind Singh "rxdma2host-monitor-destination-mac1", 1247f4beda2SGovind Singh "ppdu-end-interrupts-mac3", 1257f4beda2SGovind Singh "ppdu-end-interrupts-mac2", 1267f4beda2SGovind Singh "ppdu-end-interrupts-mac1", 1277f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac3", 1287f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac2", 1297f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac1", 1307f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac3", 1317f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac2", 1327f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac1", 1337f4beda2SGovind Singh "rxdma2host-destination-ring-mac3", 1347f4beda2SGovind Singh "rxdma2host-destination-ring-mac2", 1357f4beda2SGovind Singh "rxdma2host-destination-ring-mac1", 1367f4beda2SGovind Singh "host2tcl-input-ring4", 1377f4beda2SGovind Singh "host2tcl-input-ring3", 1387f4beda2SGovind Singh "host2tcl-input-ring2", 1397f4beda2SGovind Singh "host2tcl-input-ring1", 1407f4beda2SGovind Singh "wbm2host-tx-completions-ring3", 1417f4beda2SGovind Singh "wbm2host-tx-completions-ring2", 1427f4beda2SGovind Singh "wbm2host-tx-completions-ring1", 1437f4beda2SGovind Singh "tcl2host-status-ring", 1447f4beda2SGovind Singh }; 1457f4beda2SGovind Singh 146654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset) 147654e959aSGovind Singh { 148654e959aSGovind Singh struct ath11k_base *ab = ab_pci->ab; 149654e959aSGovind Singh 150654e959aSGovind Singh u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset); 151654e959aSGovind Singh 152654e959aSGovind Singh lockdep_assert_held(&ab_pci->window_lock); 153654e959aSGovind Singh 154654e959aSGovind Singh if (window != ab_pci->register_window) { 155654e959aSGovind Singh iowrite32(WINDOW_ENABLE_BIT | window, 156654e959aSGovind Singh ab->mem + WINDOW_REG_ADDRESS); 157f6fa37a4SCarl Huang ioread32(ab->mem + WINDOW_REG_ADDRESS); 158654e959aSGovind Singh ab_pci->register_window = window; 159654e959aSGovind Singh } 160654e959aSGovind Singh } 161654e959aSGovind Singh 162480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci) 163480a7361SKarthikeyan Periyasamy { 164480a7361SKarthikeyan Periyasamy u32 umac_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET); 165480a7361SKarthikeyan Periyasamy u32 ce_window = FIELD_GET(WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE); 166480a7361SKarthikeyan Periyasamy u32 window; 167480a7361SKarthikeyan Periyasamy 168480a7361SKarthikeyan Periyasamy window = (umac_window << 12) | (ce_window << 6); 169480a7361SKarthikeyan Periyasamy 170480a7361SKarthikeyan Periyasamy iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + WINDOW_REG_ADDRESS); 171480a7361SKarthikeyan Periyasamy } 172480a7361SKarthikeyan Periyasamy 173480a7361SKarthikeyan Periyasamy static inline u32 ath11k_pci_get_window_start(struct ath11k_base *ab, 174480a7361SKarthikeyan Periyasamy u32 offset) 175480a7361SKarthikeyan Periyasamy { 176480a7361SKarthikeyan Periyasamy u32 window_start; 177480a7361SKarthikeyan Periyasamy 178480a7361SKarthikeyan Periyasamy /* If offset lies within DP register range, use 3rd window */ 179480a7361SKarthikeyan Periyasamy if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < WINDOW_RANGE_MASK) 180480a7361SKarthikeyan Periyasamy window_start = 3 * WINDOW_START; 181480a7361SKarthikeyan Periyasamy /* If offset lies within CE register range, use 2nd window */ 182480a7361SKarthikeyan Periyasamy else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK) 183480a7361SKarthikeyan Periyasamy window_start = 2 * WINDOW_START; 184480a7361SKarthikeyan Periyasamy else 185480a7361SKarthikeyan Periyasamy window_start = WINDOW_START; 186480a7361SKarthikeyan Periyasamy 187480a7361SKarthikeyan Periyasamy return window_start; 188480a7361SKarthikeyan Periyasamy } 189480a7361SKarthikeyan Periyasamy 190f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) 191654e959aSGovind Singh { 192654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 193480a7361SKarthikeyan Periyasamy u32 window_start; 194654e959aSGovind Singh 195a05bd851SCarl Huang /* for offset beyond BAR + 4K - 32, may 196a05bd851SCarl Huang * need to wakeup MHI to access. 197a05bd851SCarl Huang */ 198081e2d64SSeevalamuthu Mariappan if (ab->hw_params.wakeup_mhi && 199081e2d64SSeevalamuthu Mariappan test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 200a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 201a05bd851SCarl Huang mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); 202a05bd851SCarl Huang 203654e959aSGovind Singh if (offset < WINDOW_START) { 204654e959aSGovind Singh iowrite32(value, ab->mem + offset); 205654e959aSGovind Singh } else { 206480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 207480a7361SKarthikeyan Periyasamy window_start = ath11k_pci_get_window_start(ab, offset); 208480a7361SKarthikeyan Periyasamy else 209480a7361SKarthikeyan Periyasamy window_start = WINDOW_START; 210480a7361SKarthikeyan Periyasamy 211480a7361SKarthikeyan Periyasamy if (window_start == WINDOW_START) { 212654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 213654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 214480a7361SKarthikeyan Periyasamy iowrite32(value, ab->mem + window_start + 215480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 216654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 217480a7361SKarthikeyan Periyasamy } else { 218480a7361SKarthikeyan Periyasamy iowrite32(value, ab->mem + window_start + 219480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 220480a7361SKarthikeyan Periyasamy } 221654e959aSGovind Singh } 222a05bd851SCarl Huang 223081e2d64SSeevalamuthu Mariappan if (ab->hw_params.wakeup_mhi && 224081e2d64SSeevalamuthu Mariappan test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 225a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 226a05bd851SCarl Huang mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); 227654e959aSGovind Singh } 228654e959aSGovind Singh 229f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) 230654e959aSGovind Singh { 231654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 232480a7361SKarthikeyan Periyasamy u32 val, window_start; 233654e959aSGovind Singh 234a05bd851SCarl Huang /* for offset beyond BAR + 4K - 32, may 235a05bd851SCarl Huang * need to wakeup MHI to access. 236a05bd851SCarl Huang */ 237081e2d64SSeevalamuthu Mariappan if (ab->hw_params.wakeup_mhi && 238081e2d64SSeevalamuthu Mariappan test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 239a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 240a05bd851SCarl Huang mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); 241a05bd851SCarl Huang 242654e959aSGovind Singh if (offset < WINDOW_START) { 243654e959aSGovind Singh val = ioread32(ab->mem + offset); 244654e959aSGovind Singh } else { 245480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 246480a7361SKarthikeyan Periyasamy window_start = ath11k_pci_get_window_start(ab, offset); 247480a7361SKarthikeyan Periyasamy else 248480a7361SKarthikeyan Periyasamy window_start = WINDOW_START; 249480a7361SKarthikeyan Periyasamy 250480a7361SKarthikeyan Periyasamy if (window_start == WINDOW_START) { 251654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 252654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 253480a7361SKarthikeyan Periyasamy val = ioread32(ab->mem + window_start + 254480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 255654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 256480a7361SKarthikeyan Periyasamy } else { 257480a7361SKarthikeyan Periyasamy val = ioread32(ab->mem + window_start + 258480a7361SKarthikeyan Periyasamy (offset & WINDOW_RANGE_MASK)); 259480a7361SKarthikeyan Periyasamy } 260654e959aSGovind Singh } 261654e959aSGovind Singh 262081e2d64SSeevalamuthu Mariappan if (ab->hw_params.wakeup_mhi && 263081e2d64SSeevalamuthu Mariappan test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 264a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 265a05bd851SCarl Huang mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); 266a05bd851SCarl Huang 267654e959aSGovind Singh return val; 268654e959aSGovind Singh } 269654e959aSGovind Singh 270f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) 271f3c603d4SCarl Huang { 272f3c603d4SCarl Huang u32 val, delay; 273f3c603d4SCarl Huang 274f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 275f3c603d4SCarl Huang 276f3c603d4SCarl Huang val |= PCIE_SOC_GLOBAL_RESET_V; 277f3c603d4SCarl Huang 278f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 279f3c603d4SCarl Huang 280f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 281f3c603d4SCarl Huang delay = 10; 282f3c603d4SCarl Huang mdelay(delay); 283f3c603d4SCarl Huang 284f3c603d4SCarl Huang /* Need to toggle V bit back otherwise stuck in reset status */ 285f3c603d4SCarl Huang val &= ~PCIE_SOC_GLOBAL_RESET_V; 286f3c603d4SCarl Huang 287f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 288f3c603d4SCarl Huang 289f3c603d4SCarl Huang mdelay(delay); 290f3c603d4SCarl Huang 291f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 292f3c603d4SCarl Huang if (val == 0xffffffff) 293f3c603d4SCarl Huang ath11k_warn(ab, "link down error during global reset\n"); 294f3c603d4SCarl Huang } 295f3c603d4SCarl Huang 296f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) 297f3c603d4SCarl Huang { 298f3c603d4SCarl Huang u32 val; 299f3c603d4SCarl Huang 300f3c603d4SCarl Huang /* read cookie */ 301f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR); 302f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val); 303f3c603d4SCarl Huang 304f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 305f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 306f3c603d4SCarl Huang 307f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 308f3c603d4SCarl Huang mdelay(10); 309f3c603d4SCarl Huang 310f3c603d4SCarl Huang /* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from 311f3c603d4SCarl Huang * continuing warm path and entering dead loop. 312f3c603d4SCarl Huang */ 313f3c603d4SCarl Huang ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0); 314f3c603d4SCarl Huang mdelay(10); 315f3c603d4SCarl Huang 316f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 317f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 318f3c603d4SCarl Huang 319f3c603d4SCarl Huang /* A read clear register. clear the register to prevent 320f3c603d4SCarl Huang * Q6 from entering wrong code path. 321f3c603d4SCarl Huang */ 322f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG); 323f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val); 324f3c603d4SCarl Huang } 325f3c603d4SCarl Huang 32606999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab, 32706999407SCarl Huang u32 offset, u32 value, u32 mask) 32806999407SCarl Huang { 32906999407SCarl Huang u32 v; 33006999407SCarl Huang int i; 33106999407SCarl Huang 33206999407SCarl Huang v = ath11k_pci_read32(ab, offset); 33306999407SCarl Huang if ((v & mask) == value) 33406999407SCarl Huang return 0; 33506999407SCarl Huang 33606999407SCarl Huang for (i = 0; i < 10; i++) { 33706999407SCarl Huang ath11k_pci_write32(ab, offset, (v & ~mask) | value); 33806999407SCarl Huang 33906999407SCarl Huang v = ath11k_pci_read32(ab, offset); 34006999407SCarl Huang if ((v & mask) == value) 34106999407SCarl Huang return 0; 34206999407SCarl Huang 34306999407SCarl Huang mdelay(2); 34406999407SCarl Huang } 34506999407SCarl Huang 34606999407SCarl Huang ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n", 34706999407SCarl Huang offset, v & mask, value); 34806999407SCarl Huang 34906999407SCarl Huang return -ETIMEDOUT; 35006999407SCarl Huang } 35106999407SCarl Huang 35206999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab) 35306999407SCarl Huang { 35406999407SCarl Huang int ret; 35506999407SCarl Huang 35606999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3576fe6f68fSKarthikeyan Periyasamy PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab), 35806999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL, 35906999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK); 36030d08503SDan Carpenter if (ret) { 36106999407SCarl Huang ath11k_warn(ab, "failed to set sysclk: %d\n", ret); 36206999407SCarl Huang return ret; 36306999407SCarl Huang } 36406999407SCarl Huang 36506999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3666fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab), 3676fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG1_VAL, 3686fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 36930d08503SDan Carpenter if (ret) { 37006999407SCarl Huang ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret); 37106999407SCarl Huang return ret; 37206999407SCarl Huang } 37306999407SCarl Huang 37406999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3756fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab), 3766fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG2_VAL, 3776fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 37830d08503SDan Carpenter if (ret) { 37906999407SCarl Huang ath11k_warn(ab, "failed to set dtct config2: %d\n", ret); 38006999407SCarl Huang return ret; 38106999407SCarl Huang } 38206999407SCarl Huang 38306999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3846fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab), 3856fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG4_VAL, 3866fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 38730d08503SDan Carpenter if (ret) { 38806999407SCarl Huang ath11k_warn(ab, "failed to set dtct config4: %d\n", ret); 38906999407SCarl Huang return ret; 39006999407SCarl Huang } 39106999407SCarl Huang 39206999407SCarl Huang return 0; 39306999407SCarl Huang } 39406999407SCarl Huang 395babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab) 396babb0cedSCarl Huang { 397babb0cedSCarl Huang u32 val; 398babb0cedSCarl Huang int i; 399babb0cedSCarl Huang 400babb0cedSCarl Huang val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); 401babb0cedSCarl Huang 402babb0cedSCarl Huang /* PCIE link seems very unstable after the Hot Reset*/ 403babb0cedSCarl Huang for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) { 404babb0cedSCarl Huang if (val == 0xffffffff) 405babb0cedSCarl Huang mdelay(5); 406babb0cedSCarl Huang 407babb0cedSCarl Huang ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE); 408babb0cedSCarl Huang val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); 409babb0cedSCarl Huang } 410babb0cedSCarl Huang 411babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val); 412babb0cedSCarl Huang 413babb0cedSCarl Huang val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); 414562934adSKalle Valo val |= GCC_GCC_PCIE_HOT_RST_VAL; 415babb0cedSCarl Huang ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val); 416babb0cedSCarl Huang val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); 417babb0cedSCarl Huang 418babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val); 419babb0cedSCarl Huang 420babb0cedSCarl Huang mdelay(5); 421babb0cedSCarl Huang } 422babb0cedSCarl Huang 423babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab) 424babb0cedSCarl Huang { 425babb0cedSCarl Huang /* This is a WAR for PCIE Hotreset. 426babb0cedSCarl Huang * When target receive Hotreset, but will set the interrupt. 427babb0cedSCarl Huang * So when download SBL again, SBL will open Interrupt and 428babb0cedSCarl Huang * receive it, and crash immediately. 429babb0cedSCarl Huang */ 430babb0cedSCarl Huang ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL); 431babb0cedSCarl Huang } 432babb0cedSCarl Huang 4330ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab) 4340ccdf439SCarl Huang { 4350ccdf439SCarl Huang u32 val; 4360ccdf439SCarl Huang 4370ccdf439SCarl Huang val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG); 4380ccdf439SCarl Huang val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK; 4390ccdf439SCarl Huang ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val); 4400ccdf439SCarl Huang } 4410ccdf439SCarl Huang 442f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab) 443f3c603d4SCarl Huang { 444f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1); 445f3c603d4SCarl Huang mdelay(5); 446f3c603d4SCarl Huang } 447f3c603d4SCarl Huang 448babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on) 449f3c603d4SCarl Huang { 4508a0b899fSBaochen Qiang mdelay(100); 4518a0b899fSBaochen Qiang 452babb0cedSCarl Huang if (power_on) { 453babb0cedSCarl Huang ath11k_pci_enable_ltssm(ab); 454babb0cedSCarl Huang ath11k_pci_clear_all_intrs(ab); 4550ccdf439SCarl Huang ath11k_pci_set_wlaon_pwr_ctrl(ab); 4565088df05SBaochen Qiang if (ab->hw_params.fix_l1ss) 45706999407SCarl Huang ath11k_pci_fix_l1ss(ab); 458babb0cedSCarl Huang } 459babb0cedSCarl Huang 460f3c603d4SCarl Huang ath11k_mhi_clear_vector(ab); 4618a0b899fSBaochen Qiang ath11k_pci_clear_dbg_registers(ab); 462f3c603d4SCarl Huang ath11k_pci_soc_global_reset(ab); 463f3c603d4SCarl Huang ath11k_mhi_set_mhictrl_reset(ab); 464f3c603d4SCarl Huang } 465f3c603d4SCarl Huang 4661399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) 4671399fb87SGovind Singh { 4681399fb87SGovind Singh struct pci_dev *pci_dev = to_pci_dev(dev); 4691399fb87SGovind Singh 4701399fb87SGovind Singh return pci_irq_vector(pci_dev, vector); 4711399fb87SGovind Singh } 4721399fb87SGovind Singh 473c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, 474c4eacabeSGovind Singh u32 *msi_addr_hi) 475c4eacabeSGovind Singh { 476e8e55d89SAnilkumar Kolli struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 477c4eacabeSGovind Singh struct pci_dev *pci_dev = to_pci_dev(ab->dev); 478c4eacabeSGovind Singh 479c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, 480c4eacabeSGovind Singh msi_addr_lo); 481c4eacabeSGovind Singh 482e8e55d89SAnilkumar Kolli if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) { 483c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, 484c4eacabeSGovind Singh msi_addr_hi); 485e8e55d89SAnilkumar Kolli } else { 486e8e55d89SAnilkumar Kolli *msi_addr_hi = 0; 487e8e55d89SAnilkumar Kolli } 488c4eacabeSGovind Singh } 489c4eacabeSGovind Singh 4901399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, 4911399fb87SGovind Singh int *num_vectors, u32 *user_base_data, 4921399fb87SGovind Singh u32 *base_vector) 4931399fb87SGovind Singh { 4941399fb87SGovind Singh struct ath11k_base *ab = ab_pci->ab; 4957a3aed0cSAnilkumar Kolli const struct ath11k_msi_config *msi_config = ab_pci->msi_config; 4961399fb87SGovind Singh int idx; 4971399fb87SGovind Singh 4987a3aed0cSAnilkumar Kolli for (idx = 0; idx < msi_config->total_users; idx++) { 4997a3aed0cSAnilkumar Kolli if (strcmp(user_name, msi_config->users[idx].name) == 0) { 5007a3aed0cSAnilkumar Kolli *num_vectors = msi_config->users[idx].num_vectors; 5017a3aed0cSAnilkumar Kolli *base_vector = msi_config->users[idx].base_vector; 502c41a6700SCarl Huang *user_base_data = *base_vector + ab_pci->msi_ep_base_data; 5031399fb87SGovind Singh 504c41a6700SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, 505c41a6700SCarl Huang "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", 5061399fb87SGovind Singh user_name, *num_vectors, *user_base_data, 5071399fb87SGovind Singh *base_vector); 5081399fb87SGovind Singh 5091399fb87SGovind Singh return 0; 5101399fb87SGovind Singh } 5111399fb87SGovind Singh } 5121399fb87SGovind Singh 5131399fb87SGovind Singh ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name); 5141399fb87SGovind Singh 5151399fb87SGovind Singh return -EINVAL; 5161399fb87SGovind Singh } 5171399fb87SGovind Singh 5186289ac2bSKarthikeyan Periyasamy static void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, 5196289ac2bSKarthikeyan Periyasamy u32 *msi_idx) 5206289ac2bSKarthikeyan Periyasamy { 5216289ac2bSKarthikeyan Periyasamy u32 i, msi_data_idx; 5226289ac2bSKarthikeyan Periyasamy 5236289ac2bSKarthikeyan Periyasamy for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { 5246289ac2bSKarthikeyan Periyasamy if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5256289ac2bSKarthikeyan Periyasamy continue; 5266289ac2bSKarthikeyan Periyasamy 5276289ac2bSKarthikeyan Periyasamy if (ce_id == i) 5286289ac2bSKarthikeyan Periyasamy break; 5296289ac2bSKarthikeyan Periyasamy 5306289ac2bSKarthikeyan Periyasamy msi_data_idx++; 5316289ac2bSKarthikeyan Periyasamy } 5326289ac2bSKarthikeyan Periyasamy *msi_idx = msi_data_idx; 5336289ac2bSKarthikeyan Periyasamy } 5346289ac2bSKarthikeyan Periyasamy 535c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, 536c4eacabeSGovind Singh int *num_vectors, u32 *user_base_data, 537c4eacabeSGovind Singh u32 *base_vector) 538c4eacabeSGovind Singh { 539c4eacabeSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 540c4eacabeSGovind Singh 541c4eacabeSGovind Singh return ath11k_pci_get_user_msi_assignment(ab_pci, user_name, 542c4eacabeSGovind Singh num_vectors, user_base_data, 543c4eacabeSGovind Singh base_vector); 544c4eacabeSGovind Singh } 545c4eacabeSGovind Singh 546d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab) 547d4ecb90bSCarl Huang { 548d4ecb90bSCarl Huang int i, j; 549d4ecb90bSCarl Huang 550d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 551d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 552d4ecb90bSCarl Huang 553d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) 554d4ecb90bSCarl Huang free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); 555d4ecb90bSCarl Huang 556d4ecb90bSCarl Huang netif_napi_del(&irq_grp->napi); 557d4ecb90bSCarl Huang } 558d4ecb90bSCarl Huang } 559d4ecb90bSCarl Huang 5607f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab) 5617f4beda2SGovind Singh { 5627f4beda2SGovind Singh int i, irq_idx; 5637f4beda2SGovind Singh 564d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 565e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5667f4beda2SGovind Singh continue; 5677f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 5687f4beda2SGovind Singh free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); 5697f4beda2SGovind Singh } 570d4ecb90bSCarl Huang 571d4ecb90bSCarl Huang ath11k_pci_free_ext_irq(ab); 5727f4beda2SGovind Singh } 5737f4beda2SGovind Singh 5742c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) 5752c3960c2SGovind Singh { 576c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 5772c3960c2SGovind Singh u32 irq_idx; 5782c3960c2SGovind Singh 579c41a6700SCarl Huang /* In case of one MSI vector, we handle irq enable/disable in a 580c41a6700SCarl Huang * uniform way since we only have one irq 581c41a6700SCarl Huang */ 582c41a6700SCarl Huang if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 583c41a6700SCarl Huang return; 584c41a6700SCarl Huang 5852c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 5862c3960c2SGovind Singh enable_irq(ab->irq_num[irq_idx]); 5872c3960c2SGovind Singh } 5882c3960c2SGovind Singh 5897f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) 5907f4beda2SGovind Singh { 591c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 5927f4beda2SGovind Singh u32 irq_idx; 5937f4beda2SGovind Singh 594c41a6700SCarl Huang /* In case of one MSI vector, we handle irq enable/disable in a 595c41a6700SCarl Huang * uniform way since we only have one irq 596c41a6700SCarl Huang */ 597c41a6700SCarl Huang if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 598c41a6700SCarl Huang return; 599c41a6700SCarl Huang 6007f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 6017f4beda2SGovind Singh disable_irq_nosync(ab->irq_num[irq_idx]); 6027f4beda2SGovind Singh } 6037f4beda2SGovind Singh 6042c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab) 6052c3960c2SGovind Singh { 6062c3960c2SGovind Singh int i; 6072c3960c2SGovind Singh 60801279bcdSCarl Huang clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); 60901279bcdSCarl Huang 610d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 611e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 6122c3960c2SGovind Singh continue; 6132c3960c2SGovind Singh ath11k_pci_ce_irq_disable(ab, i); 6142c3960c2SGovind Singh } 6152c3960c2SGovind Singh } 6162c3960c2SGovind Singh 6172c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) 6182c3960c2SGovind Singh { 6192c3960c2SGovind Singh int i; 6202c3960c2SGovind Singh int irq_idx; 6212c3960c2SGovind Singh 622d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 623e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 6242c3960c2SGovind Singh continue; 6252c3960c2SGovind Singh 6262c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 6272c3960c2SGovind Singh synchronize_irq(ab->irq_num[irq_idx]); 6282c3960c2SGovind Singh } 6292c3960c2SGovind Singh } 6302c3960c2SGovind Singh 6310f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t) 6322c3960c2SGovind Singh { 6330f01dcb8SAllen Pais struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); 634ac6e7348SCarl Huang int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; 6352c3960c2SGovind Singh 6362c3960c2SGovind Singh ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); 6372c3960c2SGovind Singh 638ac6e7348SCarl Huang enable_irq(ce_pipe->ab->irq_num[irq_idx]); 6392c3960c2SGovind Singh } 6402c3960c2SGovind Singh 6417f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) 6427f4beda2SGovind Singh { 6437f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe = arg; 64401279bcdSCarl Huang struct ath11k_base *ab = ce_pipe->ab; 645ac6e7348SCarl Huang int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; 64601279bcdSCarl Huang 64701279bcdSCarl Huang if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags)) 64801279bcdSCarl Huang return IRQ_HANDLED; 6497f4beda2SGovind Singh 6507dc67af0SKarthikeyan Periyasamy /* last interrupt received for this CE */ 6517dc67af0SKarthikeyan Periyasamy ce_pipe->timestamp = jiffies; 6527dc67af0SKarthikeyan Periyasamy 653ac6e7348SCarl Huang disable_irq_nosync(ab->irq_num[irq_idx]); 654ac6e7348SCarl Huang 6552c3960c2SGovind Singh tasklet_schedule(&ce_pipe->intr_tq); 6567f4beda2SGovind Singh 6577f4beda2SGovind Singh return IRQ_HANDLED; 6587f4beda2SGovind Singh } 6597f4beda2SGovind Singh 660d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) 661d4ecb90bSCarl Huang { 662c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); 663d4ecb90bSCarl Huang int i; 664d4ecb90bSCarl Huang 665c41a6700SCarl Huang /* In case of one MSI vector, we handle irq enable/disable 666c41a6700SCarl Huang * in a uniform way since we only have one irq 667c41a6700SCarl Huang */ 668c41a6700SCarl Huang if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 669c41a6700SCarl Huang return; 670c41a6700SCarl Huang 671d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 672d4ecb90bSCarl Huang disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 673d4ecb90bSCarl Huang } 674d4ecb90bSCarl Huang 675d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc) 676d4ecb90bSCarl Huang { 677d4ecb90bSCarl Huang int i; 678d4ecb90bSCarl Huang 67901279bcdSCarl Huang clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags); 68001279bcdSCarl Huang 681d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 682d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; 683d4ecb90bSCarl Huang 684d4ecb90bSCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 685d4ecb90bSCarl Huang 686d4ecb90bSCarl Huang napi_synchronize(&irq_grp->napi); 687d4ecb90bSCarl Huang napi_disable(&irq_grp->napi); 688d4ecb90bSCarl Huang } 689d4ecb90bSCarl Huang } 690d4ecb90bSCarl Huang 691d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) 692d4ecb90bSCarl Huang { 693c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); 694d4ecb90bSCarl Huang int i; 695d4ecb90bSCarl Huang 696c41a6700SCarl Huang /* In case of one MSI vector, we handle irq enable/disable in a 697c41a6700SCarl Huang * uniform way since we only have one irq 698c41a6700SCarl Huang */ 699c41a6700SCarl Huang if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 700c41a6700SCarl Huang return; 701c41a6700SCarl Huang 702d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 703d4ecb90bSCarl Huang enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 704d4ecb90bSCarl Huang } 705d4ecb90bSCarl Huang 706d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab) 707d4ecb90bSCarl Huang { 708d4ecb90bSCarl Huang int i; 709d4ecb90bSCarl Huang 71001279bcdSCarl Huang set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); 71101279bcdSCarl Huang 712d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 713d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 714d4ecb90bSCarl Huang 715d4ecb90bSCarl Huang napi_enable(&irq_grp->napi); 716d4ecb90bSCarl Huang ath11k_pci_ext_grp_enable(irq_grp); 717d4ecb90bSCarl Huang } 718d4ecb90bSCarl Huang } 719d4ecb90bSCarl Huang 720d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab) 721d4ecb90bSCarl Huang { 722d4ecb90bSCarl Huang int i, j, irq_idx; 723d4ecb90bSCarl Huang 724d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 725d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 726d4ecb90bSCarl Huang 727d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 728d4ecb90bSCarl Huang irq_idx = irq_grp->irqs[j]; 729d4ecb90bSCarl Huang synchronize_irq(ab->irq_num[irq_idx]); 730d4ecb90bSCarl Huang } 731d4ecb90bSCarl Huang } 732d4ecb90bSCarl Huang } 733d4ecb90bSCarl Huang 734d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab) 735d4ecb90bSCarl Huang { 736d4ecb90bSCarl Huang __ath11k_pci_ext_irq_disable(ab); 737d4ecb90bSCarl Huang ath11k_pci_sync_ext_irqs(ab); 738d4ecb90bSCarl Huang } 739d4ecb90bSCarl Huang 740d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) 741d4ecb90bSCarl Huang { 742d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = container_of(napi, 743d4ecb90bSCarl Huang struct ath11k_ext_irq_grp, 744d4ecb90bSCarl Huang napi); 745d4ecb90bSCarl Huang struct ath11k_base *ab = irq_grp->ab; 746d4ecb90bSCarl Huang int work_done; 747ac6e7348SCarl Huang int i; 748d4ecb90bSCarl Huang 749d4ecb90bSCarl Huang work_done = ath11k_dp_service_srng(ab, irq_grp, budget); 750d4ecb90bSCarl Huang if (work_done < budget) { 751d4ecb90bSCarl Huang napi_complete_done(napi, work_done); 752ac6e7348SCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 753ac6e7348SCarl Huang enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 754d4ecb90bSCarl Huang } 755d4ecb90bSCarl Huang 756d4ecb90bSCarl Huang if (work_done > budget) 757d4ecb90bSCarl Huang work_done = budget; 758d4ecb90bSCarl Huang 759d4ecb90bSCarl Huang return work_done; 760d4ecb90bSCarl Huang } 761d4ecb90bSCarl Huang 762d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) 763d4ecb90bSCarl Huang { 764d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = arg; 76501279bcdSCarl Huang struct ath11k_base *ab = irq_grp->ab; 766ac6e7348SCarl Huang int i; 76701279bcdSCarl Huang 76801279bcdSCarl Huang if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) 76901279bcdSCarl Huang return IRQ_HANDLED; 770d4ecb90bSCarl Huang 771d4ecb90bSCarl Huang ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); 772d4ecb90bSCarl Huang 7737dc67af0SKarthikeyan Periyasamy /* last interrupt received for this group */ 7747dc67af0SKarthikeyan Periyasamy irq_grp->timestamp = jiffies; 7757dc67af0SKarthikeyan Periyasamy 776ac6e7348SCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 777ac6e7348SCarl Huang disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 778d4ecb90bSCarl Huang 779d4ecb90bSCarl Huang napi_schedule(&irq_grp->napi); 780d4ecb90bSCarl Huang 781d4ecb90bSCarl Huang return IRQ_HANDLED; 782d4ecb90bSCarl Huang } 783d4ecb90bSCarl Huang 784d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) 785d4ecb90bSCarl Huang { 786c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 787d4ecb90bSCarl Huang int i, j, ret, num_vectors = 0; 7884ab4693fSCarl Huang u32 user_base_data = 0, base_vector = 0; 789d4ecb90bSCarl Huang 790b2c09458SColin Ian King ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", 791b2c09458SColin Ian King &num_vectors, 792b2c09458SColin Ian King &user_base_data, 793d4ecb90bSCarl Huang &base_vector); 794b2c09458SColin Ian King if (ret < 0) 795b2c09458SColin Ian King return ret; 796d4ecb90bSCarl Huang 797d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 798d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 799d4ecb90bSCarl Huang u32 num_irq = 0; 800d4ecb90bSCarl Huang 801d4ecb90bSCarl Huang irq_grp->ab = ab; 802d4ecb90bSCarl Huang irq_grp->grp_id = i; 803d4ecb90bSCarl Huang init_dummy_netdev(&irq_grp->napi_ndev); 804d4ecb90bSCarl Huang netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, 805d4ecb90bSCarl Huang ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT); 806d4ecb90bSCarl Huang 807d4ecb90bSCarl Huang if (ab->hw_params.ring_mask->tx[i] || 808d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx[i] || 809d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_err[i] || 810d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_wbm_rel[i] || 811d4ecb90bSCarl Huang ab->hw_params.ring_mask->reo_status[i] || 812d4ecb90bSCarl Huang ab->hw_params.ring_mask->rxdma2host[i] || 813d4ecb90bSCarl Huang ab->hw_params.ring_mask->host2rxdma[i] || 814d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_mon_status[i]) { 815d4ecb90bSCarl Huang num_irq = 1; 816d4ecb90bSCarl Huang } 817d4ecb90bSCarl Huang 818d4ecb90bSCarl Huang irq_grp->num_irq = num_irq; 8194ab4693fSCarl Huang irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i; 820d4ecb90bSCarl Huang 821d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 822d4ecb90bSCarl Huang int irq_idx = irq_grp->irqs[j]; 823d4ecb90bSCarl Huang int vector = (i % num_vectors) + base_vector; 824d4ecb90bSCarl Huang int irq = ath11k_pci_get_msi_irq(ab->dev, vector); 825d4ecb90bSCarl Huang 826d4ecb90bSCarl Huang ab->irq_num[irq_idx] = irq; 827d4ecb90bSCarl Huang 828d4ecb90bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, 829d4ecb90bSCarl Huang "irq:%d group:%d\n", irq, i); 8307dc67af0SKarthikeyan Periyasamy 8317dc67af0SKarthikeyan Periyasamy irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); 832d4ecb90bSCarl Huang ret = request_irq(irq, ath11k_pci_ext_interrupt_handler, 833c41a6700SCarl Huang ab_pci->irq_flags, 834d4ecb90bSCarl Huang "DP_EXT_IRQ", irq_grp); 835d4ecb90bSCarl Huang if (ret) { 836d4ecb90bSCarl Huang ath11k_err(ab, "failed request irq %d: %d\n", 837d4ecb90bSCarl Huang vector, ret); 838d4ecb90bSCarl Huang return ret; 839d4ecb90bSCarl Huang } 840d4ecb90bSCarl Huang } 841c41a6700SCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 842d4ecb90bSCarl Huang } 843d4ecb90bSCarl Huang 844d4ecb90bSCarl Huang return 0; 845d4ecb90bSCarl Huang } 846d4ecb90bSCarl Huang 847e94b0749SBaochen Qiang static int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci, 848e94b0749SBaochen Qiang const struct cpumask *m) 849e94b0749SBaochen Qiang { 850e94b0749SBaochen Qiang if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 851e94b0749SBaochen Qiang return 0; 852e94b0749SBaochen Qiang 853e94b0749SBaochen Qiang return irq_set_affinity_hint(ab_pci->pdev->irq, m); 854e94b0749SBaochen Qiang } 855e94b0749SBaochen Qiang 8567f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab) 8577f4beda2SGovind Singh { 858c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 8597f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe; 8607f4beda2SGovind Singh u32 msi_data_start; 8616289ac2bSKarthikeyan Periyasamy u32 msi_data_count, msi_data_idx; 8627f4beda2SGovind Singh u32 msi_irq_start; 8637f4beda2SGovind Singh unsigned int msi_data; 8647f4beda2SGovind Singh int irq, i, ret, irq_idx; 8657f4beda2SGovind Singh 8667f4beda2SGovind Singh ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), 8677f4beda2SGovind Singh "CE", &msi_data_count, 8687f4beda2SGovind Singh &msi_data_start, &msi_irq_start); 8697f4beda2SGovind Singh if (ret) 8707f4beda2SGovind Singh return ret; 8717f4beda2SGovind Singh 872e94b0749SBaochen Qiang ret = ath11k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0)); 873e94b0749SBaochen Qiang if (ret) { 874e94b0749SBaochen Qiang ath11k_err(ab, "failed to set irq affinity %d\n", ret); 875e94b0749SBaochen Qiang return ret; 876e94b0749SBaochen Qiang } 877e94b0749SBaochen Qiang 8787f4beda2SGovind Singh /* Configure CE irqs */ 8796289ac2bSKarthikeyan Periyasamy for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { 880e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 8817f4beda2SGovind Singh continue; 8827f4beda2SGovind Singh 8836289ac2bSKarthikeyan Periyasamy msi_data = (msi_data_idx % msi_data_count) + msi_irq_start; 8846289ac2bSKarthikeyan Periyasamy irq = ath11k_pci_get_msi_irq(ab->dev, msi_data); 8856289ac2bSKarthikeyan Periyasamy ce_pipe = &ab->ce.ce_pipe[i]; 8866289ac2bSKarthikeyan Periyasamy 8877f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 8887f4beda2SGovind Singh 8890f01dcb8SAllen Pais tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet); 8902c3960c2SGovind Singh 8917f4beda2SGovind Singh ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, 892c41a6700SCarl Huang ab_pci->irq_flags, irq_name[irq_idx], 8937f4beda2SGovind Singh ce_pipe); 8947f4beda2SGovind Singh if (ret) { 8957f4beda2SGovind Singh ath11k_err(ab, "failed to request irq %d: %d\n", 8967f4beda2SGovind Singh irq_idx, ret); 897e94b0749SBaochen Qiang goto err_irq_affinity_cleanup; 8987f4beda2SGovind Singh } 8997f4beda2SGovind Singh 9007f4beda2SGovind Singh ab->irq_num[irq_idx] = irq; 9016289ac2bSKarthikeyan Periyasamy msi_data_idx++; 902e678fbd4SKarthikeyan Periyasamy 903e5c860e1SCarl Huang ath11k_pci_ce_irq_disable(ab, i); 9047f4beda2SGovind Singh } 9057f4beda2SGovind Singh 906d4ecb90bSCarl Huang ret = ath11k_pci_ext_irq_config(ab); 907d4ecb90bSCarl Huang if (ret) 908e94b0749SBaochen Qiang goto err_irq_affinity_cleanup; 909d4ecb90bSCarl Huang 9107f4beda2SGovind Singh return 0; 911e94b0749SBaochen Qiang 912e94b0749SBaochen Qiang err_irq_affinity_cleanup: 913e94b0749SBaochen Qiang ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); 914e94b0749SBaochen Qiang return ret; 9157f4beda2SGovind Singh } 9167f4beda2SGovind Singh 9177f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) 9187f4beda2SGovind Singh { 9197f4beda2SGovind Singh struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; 9207f4beda2SGovind Singh 921967c1d11SAnilkumar Kolli cfg->tgt_ce = ab->hw_params.target_ce_config; 922967c1d11SAnilkumar Kolli cfg->tgt_ce_len = ab->hw_params.target_ce_count; 9237f4beda2SGovind Singh 924967c1d11SAnilkumar Kolli cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map; 925967c1d11SAnilkumar Kolli cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len; 92616001e4bSAnilkumar Kolli ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id; 927e838c14aSCarl Huang 928e838c14aSCarl Huang ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2, 929e838c14aSCarl Huang &cfg->shadow_reg_v2_len); 9307f4beda2SGovind Singh } 9317f4beda2SGovind Singh 9327f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) 9337f4beda2SGovind Singh { 9347f4beda2SGovind Singh int i; 9357f4beda2SGovind Singh 93601279bcdSCarl Huang set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); 93701279bcdSCarl Huang 938d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 939e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 9407f4beda2SGovind Singh continue; 9417f4beda2SGovind Singh ath11k_pci_ce_irq_enable(ab, i); 9427f4beda2SGovind Singh } 9437f4beda2SGovind Singh } 9447f4beda2SGovind Singh 94596527d52SBaochen Qiang static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable) 94696527d52SBaochen Qiang { 94796527d52SBaochen Qiang struct pci_dev *dev = ab_pci->pdev; 94896527d52SBaochen Qiang u16 control; 94996527d52SBaochen Qiang 95096527d52SBaochen Qiang pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control); 95196527d52SBaochen Qiang 95296527d52SBaochen Qiang if (enable) 95396527d52SBaochen Qiang control |= PCI_MSI_FLAGS_ENABLE; 95496527d52SBaochen Qiang else 95596527d52SBaochen Qiang control &= ~PCI_MSI_FLAGS_ENABLE; 95696527d52SBaochen Qiang 95796527d52SBaochen Qiang pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control); 95896527d52SBaochen Qiang } 95996527d52SBaochen Qiang 96096527d52SBaochen Qiang static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci) 96196527d52SBaochen Qiang { 96296527d52SBaochen Qiang ath11k_pci_msi_config(ab_pci, true); 96396527d52SBaochen Qiang } 96496527d52SBaochen Qiang 96596527d52SBaochen Qiang static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci) 96696527d52SBaochen Qiang { 96796527d52SBaochen Qiang ath11k_pci_msi_config(ab_pci, false); 96896527d52SBaochen Qiang } 96996527d52SBaochen Qiang 97096527d52SBaochen Qiang static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci) 9715697a564SGovind Singh { 9725697a564SGovind Singh struct ath11k_base *ab = ab_pci->ab; 9737a3aed0cSAnilkumar Kolli const struct ath11k_msi_config *msi_config = ab_pci->msi_config; 9745697a564SGovind Singh struct msi_desc *msi_desc; 9755697a564SGovind Singh int num_vectors; 9765697a564SGovind Singh int ret; 9775697a564SGovind Singh 9785697a564SGovind Singh num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 9797a3aed0cSAnilkumar Kolli msi_config->total_vectors, 9807a3aed0cSAnilkumar Kolli msi_config->total_vectors, 9815697a564SGovind Singh PCI_IRQ_MSI); 982ac6e7348SCarl Huang if (num_vectors == msi_config->total_vectors) { 983c41a6700SCarl Huang set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); 984c41a6700SCarl Huang ab_pci->irq_flags = IRQF_SHARED; 985ac6e7348SCarl Huang } else { 986ac6e7348SCarl Huang num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 987ac6e7348SCarl Huang 1, 988ac6e7348SCarl Huang 1, 989ac6e7348SCarl Huang PCI_IRQ_MSI); 990ac6e7348SCarl Huang if (num_vectors < 0) { 991ac6e7348SCarl Huang ret = -EINVAL; 992ac6e7348SCarl Huang goto reset_msi_config; 9935697a564SGovind Singh } 994ac6e7348SCarl Huang clear_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); 995ac6e7348SCarl Huang ab_pci->msi_config = &msi_config_one_msi; 996ac6e7348SCarl Huang ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; 997ac6e7348SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n"); 998ac6e7348SCarl Huang } 999ac6e7348SCarl Huang ath11k_info(ab, "MSI vectors: %d\n", num_vectors); 1000ac6e7348SCarl Huang 100196527d52SBaochen Qiang ath11k_pci_msi_disable(ab_pci); 10025697a564SGovind Singh 10035697a564SGovind Singh msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 10045697a564SGovind Singh if (!msi_desc) { 10055697a564SGovind Singh ath11k_err(ab, "msi_desc is NULL!\n"); 10065697a564SGovind Singh ret = -EINVAL; 10075697a564SGovind Singh goto free_msi_vector; 10085697a564SGovind Singh } 10095697a564SGovind Singh 10105697a564SGovind Singh ab_pci->msi_ep_base_data = msi_desc->msg.data; 1011e8e55d89SAnilkumar Kolli if (msi_desc->msi_attrib.is_64) 1012e8e55d89SAnilkumar Kolli set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags); 10135697a564SGovind Singh 10145697a564SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); 10155697a564SGovind Singh 10165697a564SGovind Singh return 0; 10175697a564SGovind Singh 10185697a564SGovind Singh free_msi_vector: 10195697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 10205697a564SGovind Singh 1021ac6e7348SCarl Huang reset_msi_config: 10225697a564SGovind Singh return ret; 10235697a564SGovind Singh } 10245697a564SGovind Singh 102596527d52SBaochen Qiang static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci) 10265697a564SGovind Singh { 10275697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 10285697a564SGovind Singh } 10295697a564SGovind Singh 103087b4072dSCarl Huang static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci) 103187b4072dSCarl Huang { 103287b4072dSCarl Huang struct msi_desc *msi_desc; 103387b4072dSCarl Huang 103487b4072dSCarl Huang msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 103587b4072dSCarl Huang if (!msi_desc) { 103687b4072dSCarl Huang ath11k_err(ab_pci->ab, "msi_desc is NULL!\n"); 103787b4072dSCarl Huang pci_free_irq_vectors(ab_pci->pdev); 103887b4072dSCarl Huang return -EINVAL; 103987b4072dSCarl Huang } 104087b4072dSCarl Huang 104187b4072dSCarl Huang ab_pci->msi_ep_base_data = msi_desc->msg.data; 104287b4072dSCarl Huang 104387b4072dSCarl Huang ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n", 104487b4072dSCarl Huang ab_pci->msi_ep_base_data); 104587b4072dSCarl Huang 104687b4072dSCarl Huang return 0; 104787b4072dSCarl Huang } 104887b4072dSCarl Huang 10495762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) 10505762613eSGovind Singh { 10515762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 10525762613eSGovind Singh u16 device_id; 10535762613eSGovind Singh int ret = 0; 10545762613eSGovind Singh 10555762613eSGovind Singh pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 10565762613eSGovind Singh if (device_id != ab_pci->dev_id) { 10575762613eSGovind Singh ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", 10585762613eSGovind Singh device_id, ab_pci->dev_id); 10595762613eSGovind Singh ret = -EIO; 10605762613eSGovind Singh goto out; 10615762613eSGovind Singh } 10625762613eSGovind Singh 10635762613eSGovind Singh ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); 10645762613eSGovind Singh if (ret) { 10655762613eSGovind Singh ath11k_err(ab, "failed to assign pci resource: %d\n", ret); 10665762613eSGovind Singh goto out; 10675762613eSGovind Singh } 10685762613eSGovind Singh 10695762613eSGovind Singh ret = pci_enable_device(pdev); 10705762613eSGovind Singh if (ret) { 10715762613eSGovind Singh ath11k_err(ab, "failed to enable pci device: %d\n", ret); 10725762613eSGovind Singh goto out; 10735762613eSGovind Singh } 10745762613eSGovind Singh 10755762613eSGovind Singh ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); 10765762613eSGovind Singh if (ret) { 10775762613eSGovind Singh ath11k_err(ab, "failed to request pci region: %d\n", ret); 10785762613eSGovind Singh goto disable_device; 10795762613eSGovind Singh } 10805762613eSGovind Singh 1081923a1346SChristophe JAILLET ret = dma_set_mask_and_coherent(&pdev->dev, 1082923a1346SChristophe JAILLET DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 10835762613eSGovind Singh if (ret) { 10845762613eSGovind Singh ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", 10855762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 10865762613eSGovind Singh goto release_region; 10875762613eSGovind Singh } 10885762613eSGovind Singh 10895762613eSGovind Singh pci_set_master(pdev); 10905762613eSGovind Singh 10915762613eSGovind Singh ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); 10925762613eSGovind Singh ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); 10935762613eSGovind Singh if (!ab->mem) { 10945762613eSGovind Singh ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); 10955762613eSGovind Singh ret = -EIO; 10965762613eSGovind Singh goto clear_master; 10975762613eSGovind Singh } 10985762613eSGovind Singh 10995762613eSGovind Singh ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); 11005762613eSGovind Singh return 0; 11015762613eSGovind Singh 11025762613eSGovind Singh clear_master: 11035762613eSGovind Singh pci_clear_master(pdev); 11045762613eSGovind Singh release_region: 11055762613eSGovind Singh pci_release_region(pdev, ATH11K_PCI_BAR_NUM); 11065762613eSGovind Singh disable_device: 11075762613eSGovind Singh pci_disable_device(pdev); 11085762613eSGovind Singh out: 11095762613eSGovind Singh return ret; 11105762613eSGovind Singh } 11115762613eSGovind Singh 11125762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) 11135762613eSGovind Singh { 11145762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 11155762613eSGovind Singh struct pci_dev *pci_dev = ab_pci->pdev; 11165762613eSGovind Singh 11175762613eSGovind Singh pci_iounmap(pci_dev, ab->mem); 11185762613eSGovind Singh ab->mem = NULL; 11195762613eSGovind Singh pci_clear_master(pci_dev); 11205762613eSGovind Singh pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); 11215762613eSGovind Singh if (pci_is_enabled(pci_dev)) 11225762613eSGovind Singh pci_disable_device(pci_dev); 11235762613eSGovind Singh } 11245762613eSGovind Singh 1125e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci) 1126e9603f4bSCarl Huang { 1127e9603f4bSCarl Huang struct ath11k_base *ab = ab_pci->ab; 1128e9603f4bSCarl Huang 1129e9603f4bSCarl Huang pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL, 1130e9603f4bSCarl Huang &ab_pci->link_ctl); 1131e9603f4bSCarl Huang 1132e9603f4bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n", 1133e9603f4bSCarl Huang ab_pci->link_ctl, 1134e9603f4bSCarl Huang u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S), 1135e9603f4bSCarl Huang u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1)); 1136e9603f4bSCarl Huang 1137e9603f4bSCarl Huang /* disable L0s and L1 */ 1138e9603f4bSCarl Huang pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, 1139e9603f4bSCarl Huang ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC); 1140e9603f4bSCarl Huang 1141e9603f4bSCarl Huang set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags); 1142e9603f4bSCarl Huang } 1143e9603f4bSCarl Huang 1144e9603f4bSCarl Huang static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci) 1145e9603f4bSCarl Huang { 1146e9603f4bSCarl Huang if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags)) 1147e9603f4bSCarl Huang pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, 1148e9603f4bSCarl Huang ab_pci->link_ctl); 1149e9603f4bSCarl Huang } 1150e9603f4bSCarl Huang 11511399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab) 11521399fb87SGovind Singh { 11531399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 11541399fb87SGovind Singh int ret; 11551399fb87SGovind Singh 1156a05bd851SCarl Huang ab_pci->register_window = 0; 1157a05bd851SCarl Huang clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 1158babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, true); 1159f3c603d4SCarl Huang 1160e9603f4bSCarl Huang /* Disable ASPM during firmware download due to problems switching 1161e9603f4bSCarl Huang * to AMSS state. 1162e9603f4bSCarl Huang */ 1163e9603f4bSCarl Huang ath11k_pci_aspm_disable(ab_pci); 1164e9603f4bSCarl Huang 116596527d52SBaochen Qiang ath11k_pci_msi_enable(ab_pci); 116696527d52SBaochen Qiang 11671399fb87SGovind Singh ret = ath11k_mhi_start(ab_pci); 11681399fb87SGovind Singh if (ret) { 11691399fb87SGovind Singh ath11k_err(ab, "failed to start mhi: %d\n", ret); 11701399fb87SGovind Singh return ret; 11711399fb87SGovind Singh } 11721399fb87SGovind Singh 1173480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 1174480a7361SKarthikeyan Periyasamy ath11k_pci_select_static_window(ab_pci); 1175480a7361SKarthikeyan Periyasamy 11761399fb87SGovind Singh return 0; 11771399fb87SGovind Singh } 11781399fb87SGovind Singh 11791399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab) 11801399fb87SGovind Singh { 11811399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 11821399fb87SGovind Singh 1183e9603f4bSCarl Huang /* restore aspm in case firmware bootup fails */ 1184e9603f4bSCarl Huang ath11k_pci_aspm_restore(ab_pci); 1185e9603f4bSCarl Huang 1186babb0cedSCarl Huang ath11k_pci_force_wake(ab_pci->ab); 118796527d52SBaochen Qiang 118896527d52SBaochen Qiang ath11k_pci_msi_disable(ab_pci); 118996527d52SBaochen Qiang 11901399fb87SGovind Singh ath11k_mhi_stop(ab_pci); 1191a05bd851SCarl Huang clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 1192babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, false); 11931399fb87SGovind Singh } 11941399fb87SGovind Singh 1195fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab) 1196fa5917e4SCarl Huang { 1197fa5917e4SCarl Huang struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); 1198fa5917e4SCarl Huang 1199fa5917e4SCarl Huang ath11k_mhi_suspend(ar_pci); 1200fa5917e4SCarl Huang 1201fa5917e4SCarl Huang return 0; 1202fa5917e4SCarl Huang } 1203fa5917e4SCarl Huang 1204fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab) 1205fa5917e4SCarl Huang { 1206fa5917e4SCarl Huang struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); 1207fa5917e4SCarl Huang 1208fa5917e4SCarl Huang ath11k_mhi_resume(ar_pci); 1209fa5917e4SCarl Huang 1210fa5917e4SCarl Huang return 0; 1211fa5917e4SCarl Huang } 1212fa5917e4SCarl Huang 12132c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) 12142c3960c2SGovind Singh { 12152c3960c2SGovind Singh int i; 12162c3960c2SGovind Singh 1217d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 12182c3960c2SGovind Singh struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; 12192c3960c2SGovind Singh 1220e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 12212c3960c2SGovind Singh continue; 12222c3960c2SGovind Singh 12232c3960c2SGovind Singh tasklet_kill(&ce_pipe->intr_tq); 12242c3960c2SGovind Singh } 12252c3960c2SGovind Singh } 12262c3960c2SGovind Singh 1227d578ec2aSCarl Huang static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab) 12287f4beda2SGovind Singh { 12292c3960c2SGovind Singh ath11k_pci_ce_irqs_disable(ab); 12302c3960c2SGovind Singh ath11k_pci_sync_ce_irqs(ab); 12312c3960c2SGovind Singh ath11k_pci_kill_tasklets(ab); 1232d578ec2aSCarl Huang } 1233d578ec2aSCarl Huang 1234d578ec2aSCarl Huang static void ath11k_pci_stop(struct ath11k_base *ab) 1235d578ec2aSCarl Huang { 1236d578ec2aSCarl Huang ath11k_pci_ce_irq_disable_sync(ab); 12377f4beda2SGovind Singh ath11k_ce_cleanup_pipes(ab); 12387f4beda2SGovind Singh } 12397f4beda2SGovind Singh 12407f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab) 12417f4beda2SGovind Singh { 1242a05bd851SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 1243a05bd851SCarl Huang 1244a05bd851SCarl Huang set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 1245a05bd851SCarl Huang 1246915a081fSCarl Huang /* TODO: for now don't restore ASPM in case of single MSI 1247915a081fSCarl Huang * vector as MHI register reading in M2 causes system hang. 1248915a081fSCarl Huang */ 1249915a081fSCarl Huang if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 1250e9603f4bSCarl Huang ath11k_pci_aspm_restore(ab_pci); 1251915a081fSCarl Huang else 1252915a081fSCarl Huang ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n"); 1253e9603f4bSCarl Huang 12547f4beda2SGovind Singh ath11k_pci_ce_irqs_enable(ab); 12552c3960c2SGovind Singh ath11k_ce_rx_post_buf(ab); 12562c3960c2SGovind Singh 12572c3960c2SGovind Singh return 0; 12582c3960c2SGovind Singh } 12592c3960c2SGovind Singh 1260d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab) 1261d578ec2aSCarl Huang { 1262d578ec2aSCarl Huang ath11k_pci_ce_irqs_enable(ab); 1263d578ec2aSCarl Huang } 1264d578ec2aSCarl Huang 1265d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab) 1266d578ec2aSCarl Huang { 1267d578ec2aSCarl Huang ath11k_pci_ce_irq_disable_sync(ab); 1268d578ec2aSCarl Huang } 1269d578ec2aSCarl Huang 12702c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, 12712c3960c2SGovind Singh u8 *ul_pipe, u8 *dl_pipe) 12722c3960c2SGovind Singh { 12732c3960c2SGovind Singh const struct service_to_pipe *entry; 12742c3960c2SGovind Singh bool ul_set = false, dl_set = false; 12752c3960c2SGovind Singh int i; 12762c3960c2SGovind Singh 1277967c1d11SAnilkumar Kolli for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) { 1278967c1d11SAnilkumar Kolli entry = &ab->hw_params.svc_to_ce_map[i]; 12792c3960c2SGovind Singh 12802c3960c2SGovind Singh if (__le32_to_cpu(entry->service_id) != service_id) 12812c3960c2SGovind Singh continue; 12822c3960c2SGovind Singh 12832c3960c2SGovind Singh switch (__le32_to_cpu(entry->pipedir)) { 12842c3960c2SGovind Singh case PIPEDIR_NONE: 12852c3960c2SGovind Singh break; 12862c3960c2SGovind Singh case PIPEDIR_IN: 12872c3960c2SGovind Singh WARN_ON(dl_set); 12882c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 12892c3960c2SGovind Singh dl_set = true; 12902c3960c2SGovind Singh break; 12912c3960c2SGovind Singh case PIPEDIR_OUT: 12922c3960c2SGovind Singh WARN_ON(ul_set); 12932c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 12942c3960c2SGovind Singh ul_set = true; 12952c3960c2SGovind Singh break; 12962c3960c2SGovind Singh case PIPEDIR_INOUT: 12972c3960c2SGovind Singh WARN_ON(dl_set); 12982c3960c2SGovind Singh WARN_ON(ul_set); 12992c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 13002c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 13012c3960c2SGovind Singh dl_set = true; 13022c3960c2SGovind Singh ul_set = true; 13032c3960c2SGovind Singh break; 13042c3960c2SGovind Singh } 13052c3960c2SGovind Singh } 13062c3960c2SGovind Singh 13072c3960c2SGovind Singh if (WARN_ON(!ul_set || !dl_set)) 13082c3960c2SGovind Singh return -ENOENT; 13097f4beda2SGovind Singh 13107f4beda2SGovind Singh return 0; 13117f4beda2SGovind Singh } 13127f4beda2SGovind Singh 13137f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = { 13147f4beda2SGovind Singh .start = ath11k_pci_start, 13157f4beda2SGovind Singh .stop = ath11k_pci_stop, 1316654e959aSGovind Singh .read32 = ath11k_pci_read32, 1317654e959aSGovind Singh .write32 = ath11k_pci_write32, 13181399fb87SGovind Singh .power_down = ath11k_pci_power_down, 13191399fb87SGovind Singh .power_up = ath11k_pci_power_up, 1320fa5917e4SCarl Huang .suspend = ath11k_pci_hif_suspend, 1321fa5917e4SCarl Huang .resume = ath11k_pci_hif_resume, 1322d4ecb90bSCarl Huang .irq_enable = ath11k_pci_ext_irq_enable, 1323d4ecb90bSCarl Huang .irq_disable = ath11k_pci_ext_irq_disable, 1324c4eacabeSGovind Singh .get_msi_address = ath11k_pci_get_msi_address, 1325c4eacabeSGovind Singh .get_user_msi_vector = ath11k_get_user_msi_assignment, 13262c3960c2SGovind Singh .map_service_to_pipe = ath11k_pci_map_service_to_pipe, 1327d578ec2aSCarl Huang .ce_irq_enable = ath11k_pci_hif_ce_irq_enable, 1328d578ec2aSCarl Huang .ce_irq_disable = ath11k_pci_hif_ce_irq_disable, 13296289ac2bSKarthikeyan Periyasamy .get_ce_msi_idx = ath11k_pci_get_ce_msi_idx, 13301399fb87SGovind Singh }; 13311399fb87SGovind Singh 13320fbf1957SBaochen Qiang static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor) 13330fbf1957SBaochen Qiang { 13340fbf1957SBaochen Qiang u32 soc_hw_version; 13350fbf1957SBaochen Qiang 13360fbf1957SBaochen Qiang soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION); 13370fbf1957SBaochen Qiang *major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK, 13380fbf1957SBaochen Qiang soc_hw_version); 13390fbf1957SBaochen Qiang *minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK, 13400fbf1957SBaochen Qiang soc_hw_version); 13410fbf1957SBaochen Qiang 13420fbf1957SBaochen Qiang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n", 13430fbf1957SBaochen Qiang *major, *minor); 13440fbf1957SBaochen Qiang } 13450fbf1957SBaochen Qiang 13466e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev, 13476e0355afSGovind Singh const struct pci_device_id *pci_dev) 13486e0355afSGovind Singh { 13496e0355afSGovind Singh struct ath11k_base *ab; 13505762613eSGovind Singh struct ath11k_pci *ab_pci; 1351*6ac04bdcSAnilkumar Kolli u32 soc_hw_version_major, soc_hw_version_minor, addr; 13525762613eSGovind Singh int ret; 13536e0355afSGovind Singh 13541ff8ed78SGovind Singh ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, 13551ff8ed78SGovind Singh &ath11k_pci_bus_params); 13566e0355afSGovind Singh if (!ab) { 13576e0355afSGovind Singh dev_err(&pdev->dev, "failed to allocate ath11k base\n"); 13586e0355afSGovind Singh return -ENOMEM; 13596e0355afSGovind Singh } 13606e0355afSGovind Singh 13616e0355afSGovind Singh ab->dev = &pdev->dev; 13626e0355afSGovind Singh pci_set_drvdata(pdev, ab); 13635762613eSGovind Singh ab_pci = ath11k_pci_priv(ab); 13645762613eSGovind Singh ab_pci->dev_id = pci_dev->device; 13655762613eSGovind Singh ab_pci->ab = ab; 13665697a564SGovind Singh ab_pci->pdev = pdev; 13677f4beda2SGovind Singh ab->hif.ops = &ath11k_pci_hif_ops; 13685762613eSGovind Singh pci_set_drvdata(pdev, ab); 1369654e959aSGovind Singh spin_lock_init(&ab_pci->window_lock); 13705762613eSGovind Singh 1371*6ac04bdcSAnilkumar Kolli /* Set fixed_mem_region to true for platforms support reserved memory 1372*6ac04bdcSAnilkumar Kolli * from DT. If memory is reserved from DT for FW, ath11k driver need not 1373*6ac04bdcSAnilkumar Kolli * allocate memory. 1374*6ac04bdcSAnilkumar Kolli */ 1375*6ac04bdcSAnilkumar Kolli ret = of_property_read_u32(ab->dev->of_node, "memory-region", &addr); 1376*6ac04bdcSAnilkumar Kolli if (!ret) 1377*6ac04bdcSAnilkumar Kolli set_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags); 1378*6ac04bdcSAnilkumar Kolli 13795762613eSGovind Singh ret = ath11k_pci_claim(ab_pci, pdev); 13805762613eSGovind Singh if (ret) { 13815762613eSGovind Singh ath11k_err(ab, "failed to claim device: %d\n", ret); 13825762613eSGovind Singh goto err_free_core; 13835762613eSGovind Singh } 13846e0355afSGovind Singh 1385fc95d10aSWen Gong ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n", 1386fc95d10aSWen Gong pdev->vendor, pdev->device, 1387fc95d10aSWen Gong pdev->subsystem_vendor, pdev->subsystem_device); 1388fc95d10aSWen Gong 1389fc95d10aSWen Gong ab->id.vendor = pdev->vendor; 1390fc95d10aSWen Gong ab->id.device = pdev->device; 1391fc95d10aSWen Gong ab->id.subsystem_vendor = pdev->subsystem_vendor; 1392fc95d10aSWen Gong ab->id.subsystem_device = pdev->subsystem_device; 1393fc95d10aSWen Gong 139418ac1665SKalle Valo switch (pci_dev->device) { 139518ac1665SKalle Valo case QCA6390_DEVICE_ID: 13960fbf1957SBaochen Qiang ath11k_pci_read_hw_version(ab, &soc_hw_version_major, 13970fbf1957SBaochen Qiang &soc_hw_version_minor); 139818ac1665SKalle Valo switch (soc_hw_version_major) { 139918ac1665SKalle Valo case 2: 140018ac1665SKalle Valo ab->hw_rev = ATH11K_HW_QCA6390_HW20; 140118ac1665SKalle Valo break; 140218ac1665SKalle Valo default: 140318ac1665SKalle Valo dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n", 140418ac1665SKalle Valo soc_hw_version_major, soc_hw_version_minor); 140518ac1665SKalle Valo ret = -EOPNOTSUPP; 140618ac1665SKalle Valo goto err_pci_free_region; 140718ac1665SKalle Valo } 14084e809461SAnilkumar Kolli ab_pci->msi_config = &ath11k_msi_config[0]; 14094e809461SAnilkumar Kolli break; 14104e809461SAnilkumar Kolli case QCN9074_DEVICE_ID: 14114e809461SAnilkumar Kolli ab_pci->msi_config = &ath11k_msi_config[1]; 14124e809461SAnilkumar Kolli ab->bus_params.static_window_map = true; 14134e809461SAnilkumar Kolli ab->hw_rev = ATH11K_HW_QCN9074_HW10; 141418ac1665SKalle Valo break; 14150fbf1957SBaochen Qiang case WCN6855_DEVICE_ID: 1416fc95d10aSWen Gong ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD; 14170fbf1957SBaochen Qiang ath11k_pci_read_hw_version(ab, &soc_hw_version_major, 14180fbf1957SBaochen Qiang &soc_hw_version_minor); 14190fbf1957SBaochen Qiang switch (soc_hw_version_major) { 14200fbf1957SBaochen Qiang case 2: 1421d1147a31SBaochen Qiang switch (soc_hw_version_minor) { 1422d1147a31SBaochen Qiang case 0x00: 1423d1147a31SBaochen Qiang case 0x01: 14240fbf1957SBaochen Qiang ab->hw_rev = ATH11K_HW_WCN6855_HW20; 14250fbf1957SBaochen Qiang break; 1426d1147a31SBaochen Qiang case 0x10: 1427d1147a31SBaochen Qiang case 0x11: 1428d1147a31SBaochen Qiang ab->hw_rev = ATH11K_HW_WCN6855_HW21; 1429d1147a31SBaochen Qiang break; 14300fbf1957SBaochen Qiang default: 1431d1147a31SBaochen Qiang goto unsupported_wcn6855_soc; 1432d1147a31SBaochen Qiang } 1433d1147a31SBaochen Qiang break; 1434d1147a31SBaochen Qiang default: 1435d1147a31SBaochen Qiang unsupported_wcn6855_soc: 14360fbf1957SBaochen Qiang dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n", 14370fbf1957SBaochen Qiang soc_hw_version_major, soc_hw_version_minor); 14380fbf1957SBaochen Qiang ret = -EOPNOTSUPP; 14390fbf1957SBaochen Qiang goto err_pci_free_region; 14400fbf1957SBaochen Qiang } 14410fbf1957SBaochen Qiang ab_pci->msi_config = &ath11k_msi_config[0]; 14420fbf1957SBaochen Qiang break; 144318ac1665SKalle Valo default: 144418ac1665SKalle Valo dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", 144518ac1665SKalle Valo pci_dev->device); 144618ac1665SKalle Valo ret = -EOPNOTSUPP; 144718ac1665SKalle Valo goto err_pci_free_region; 144818ac1665SKalle Valo } 144918ac1665SKalle Valo 145096527d52SBaochen Qiang ret = ath11k_pci_alloc_msi(ab_pci); 14515697a564SGovind Singh if (ret) { 14525697a564SGovind Singh ath11k_err(ab, "failed to enable msi: %d\n", ret); 14535697a564SGovind Singh goto err_pci_free_region; 14545697a564SGovind Singh } 14555697a564SGovind Singh 1456b8246f88SKalle Valo ret = ath11k_core_pre_init(ab); 1457b8246f88SKalle Valo if (ret) 1458b8246f88SKalle Valo goto err_pci_disable_msi; 1459b8246f88SKalle Valo 14601399fb87SGovind Singh ret = ath11k_mhi_register(ab_pci); 14611399fb87SGovind Singh if (ret) { 14621399fb87SGovind Singh ath11k_err(ab, "failed to register mhi: %d\n", ret); 14631399fb87SGovind Singh goto err_pci_disable_msi; 14641399fb87SGovind Singh } 14651399fb87SGovind Singh 14667f4beda2SGovind Singh ret = ath11k_hal_srng_init(ab); 14677f4beda2SGovind Singh if (ret) 14687f4beda2SGovind Singh goto err_mhi_unregister; 14697f4beda2SGovind Singh 14707f4beda2SGovind Singh ret = ath11k_ce_alloc_pipes(ab); 14717f4beda2SGovind Singh if (ret) { 14727f4beda2SGovind Singh ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret); 14737f4beda2SGovind Singh goto err_hal_srng_deinit; 14747f4beda2SGovind Singh } 14757f4beda2SGovind Singh 14767f4beda2SGovind Singh ath11k_pci_init_qmi_ce_config(ab); 14777f4beda2SGovind Singh 14787f4beda2SGovind Singh ret = ath11k_pci_config_irq(ab); 14797f4beda2SGovind Singh if (ret) { 14807f4beda2SGovind Singh ath11k_err(ab, "failed to config irq: %d\n", ret); 14817f4beda2SGovind Singh goto err_ce_free; 14827f4beda2SGovind Singh } 14837f4beda2SGovind Singh 148487b4072dSCarl Huang /* kernel may allocate a dummy vector before request_irq and 148587b4072dSCarl Huang * then allocate a real vector when request_irq is called. 148687b4072dSCarl Huang * So get msi_data here again to avoid spurious interrupt 148787b4072dSCarl Huang * as msi_data will configured to srngs. 148887b4072dSCarl Huang */ 148987b4072dSCarl Huang ret = ath11k_pci_config_msi_data(ab_pci); 149087b4072dSCarl Huang if (ret) { 149187b4072dSCarl Huang ath11k_err(ab, "failed to config msi_data: %d\n", ret); 149287b4072dSCarl Huang goto err_free_irq; 149387b4072dSCarl Huang } 149487b4072dSCarl Huang 14957f4beda2SGovind Singh ret = ath11k_core_init(ab); 14967f4beda2SGovind Singh if (ret) { 14977f4beda2SGovind Singh ath11k_err(ab, "failed to init core: %d\n", ret); 14987f4beda2SGovind Singh goto err_free_irq; 14997f4beda2SGovind Singh } 15006e0355afSGovind Singh return 0; 15015762613eSGovind Singh 15027f4beda2SGovind Singh err_free_irq: 15037f4beda2SGovind Singh ath11k_pci_free_irq(ab); 15047f4beda2SGovind Singh 15057f4beda2SGovind Singh err_ce_free: 15067f4beda2SGovind Singh ath11k_ce_free_pipes(ab); 15077f4beda2SGovind Singh 15087f4beda2SGovind Singh err_hal_srng_deinit: 15097f4beda2SGovind Singh ath11k_hal_srng_deinit(ab); 15107f4beda2SGovind Singh 15117f4beda2SGovind Singh err_mhi_unregister: 15127f4beda2SGovind Singh ath11k_mhi_unregister(ab_pci); 15137f4beda2SGovind Singh 1514b8246f88SKalle Valo err_pci_disable_msi: 151596527d52SBaochen Qiang ath11k_pci_free_msi(ab_pci); 1516b8246f88SKalle Valo 15175697a564SGovind Singh err_pci_free_region: 15185697a564SGovind Singh ath11k_pci_free_region(ab_pci); 15195697a564SGovind Singh 15205762613eSGovind Singh err_free_core: 15215762613eSGovind Singh ath11k_core_free(ab); 15225697a564SGovind Singh 15235762613eSGovind Singh return ret; 15246e0355afSGovind Singh } 15256e0355afSGovind Singh 15266e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev) 15276e0355afSGovind Singh { 15286e0355afSGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 15295762613eSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 15306e0355afSGovind Singh 1531e94b0749SBaochen Qiang ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); 1532e94b0749SBaochen Qiang 153361a57e51SAnilkumar Kolli if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { 153461a57e51SAnilkumar Kolli ath11k_pci_power_down(ab); 153561a57e51SAnilkumar Kolli ath11k_debugfs_soc_destroy(ab); 153661a57e51SAnilkumar Kolli ath11k_qmi_deinit_service(ab); 153761a57e51SAnilkumar Kolli goto qmi_fail; 153861a57e51SAnilkumar Kolli } 153961a57e51SAnilkumar Kolli 15406e0355afSGovind Singh set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); 15416fbd8898SCarl Huang 15426fbd8898SCarl Huang ath11k_core_deinit(ab); 15436fbd8898SCarl Huang 154461a57e51SAnilkumar Kolli qmi_fail: 15451399fb87SGovind Singh ath11k_mhi_unregister(ab_pci); 15466fbd8898SCarl Huang 15476fbd8898SCarl Huang ath11k_pci_free_irq(ab); 154896527d52SBaochen Qiang ath11k_pci_free_msi(ab_pci); 15495762613eSGovind Singh ath11k_pci_free_region(ab_pci); 15506fbd8898SCarl Huang 15516fbd8898SCarl Huang ath11k_hal_srng_deinit(ab); 15526fbd8898SCarl Huang ath11k_ce_free_pipes(ab); 15536e0355afSGovind Singh ath11k_core_free(ab); 15546e0355afSGovind Singh } 15556e0355afSGovind Singh 15561399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev) 15571399fb87SGovind Singh { 15581399fb87SGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 15591399fb87SGovind Singh 15601399fb87SGovind Singh ath11k_pci_power_down(ab); 15611399fb87SGovind Singh } 15621399fb87SGovind Singh 1563d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev) 1564d1b0c338SCarl Huang { 1565d1b0c338SCarl Huang struct ath11k_base *ab = dev_get_drvdata(dev); 1566d1b0c338SCarl Huang int ret; 1567d1b0c338SCarl Huang 1568d1b0c338SCarl Huang ret = ath11k_core_suspend(ab); 1569d1b0c338SCarl Huang if (ret) 1570d1b0c338SCarl Huang ath11k_warn(ab, "failed to suspend core: %d\n", ret); 1571d1b0c338SCarl Huang 1572d1b0c338SCarl Huang return ret; 1573d1b0c338SCarl Huang } 1574d1b0c338SCarl Huang 1575d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev) 1576d1b0c338SCarl Huang { 1577d1b0c338SCarl Huang struct ath11k_base *ab = dev_get_drvdata(dev); 1578d1b0c338SCarl Huang int ret; 1579d1b0c338SCarl Huang 1580d1b0c338SCarl Huang ret = ath11k_core_resume(ab); 1581d1b0c338SCarl Huang if (ret) 1582d1b0c338SCarl Huang ath11k_warn(ab, "failed to resume core: %d\n", ret); 1583d1b0c338SCarl Huang 1584d1b0c338SCarl Huang return ret; 1585d1b0c338SCarl Huang } 1586d1b0c338SCarl Huang 1587d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops, 1588d1b0c338SCarl Huang ath11k_pci_pm_suspend, 1589d1b0c338SCarl Huang ath11k_pci_pm_resume); 1590d1b0c338SCarl Huang 15916e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = { 15926e0355afSGovind Singh .name = "ath11k_pci", 15936e0355afSGovind Singh .id_table = ath11k_pci_id_table, 15946e0355afSGovind Singh .probe = ath11k_pci_probe, 15956e0355afSGovind Singh .remove = ath11k_pci_remove, 15961399fb87SGovind Singh .shutdown = ath11k_pci_shutdown, 1597d1b0c338SCarl Huang #ifdef CONFIG_PM 1598d1b0c338SCarl Huang .driver.pm = &ath11k_pci_pm_ops, 1599d1b0c338SCarl Huang #endif 16006e0355afSGovind Singh }; 16016e0355afSGovind Singh 16026e0355afSGovind Singh static int ath11k_pci_init(void) 16036e0355afSGovind Singh { 16046e0355afSGovind Singh int ret; 16056e0355afSGovind Singh 16066e0355afSGovind Singh ret = pci_register_driver(&ath11k_pci_driver); 16076e0355afSGovind Singh if (ret) 16086e0355afSGovind Singh pr_err("failed to register ath11k pci driver: %d\n", 16096e0355afSGovind Singh ret); 16106e0355afSGovind Singh 16116e0355afSGovind Singh return ret; 16126e0355afSGovind Singh } 16136e0355afSGovind Singh module_init(ath11k_pci_init); 16146e0355afSGovind Singh 16156e0355afSGovind Singh static void ath11k_pci_exit(void) 16166e0355afSGovind Singh { 16176e0355afSGovind Singh pci_unregister_driver(&ath11k_pci_driver); 16186e0355afSGovind Singh } 16196e0355afSGovind Singh 16206e0355afSGovind Singh module_exit(ath11k_pci_exit); 16216e0355afSGovind Singh 16226e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); 16236e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL"); 16243dbd7fe7SDevin Bayer 16253dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */ 16263dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE); 16273dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE); 16283dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE); 1629