16e0355afSGovind Singh // SPDX-License-Identifier: BSD-3-Clause-Clear 26e0355afSGovind Singh /* 36e0355afSGovind Singh * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. 4*948171b5SManikanta Pubbisetty * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. 56e0355afSGovind Singh */ 66e0355afSGovind Singh 76e0355afSGovind Singh #include <linux/module.h> 85697a564SGovind Singh #include <linux/msi.h> 96e0355afSGovind Singh #include <linux/pci.h> 106ac04bdcSAnilkumar Kolli #include <linux/of.h> 116e0355afSGovind Singh 125762613eSGovind Singh #include "pci.h" 136e0355afSGovind Singh #include "core.h" 141399fb87SGovind Singh #include "hif.h" 151399fb87SGovind Singh #include "mhi.h" 166e0355afSGovind Singh #include "debug.h" 176e0355afSGovind Singh 185762613eSGovind Singh #define ATH11K_PCI_BAR_NUM 0 195762613eSGovind Singh #define ATH11K_PCI_DMA_MASK 32 205762613eSGovind Singh 2118ac1665SKalle Valo #define TCSR_SOC_HW_VERSION 0x0224 22d1147a31SBaochen Qiang #define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8) 2318ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0) 2418ac1665SKalle Valo 256e0355afSGovind Singh #define QCA6390_DEVICE_ID 0x1101 264e809461SAnilkumar Kolli #define QCN9074_DEVICE_ID 0x1104 270fbf1957SBaochen Qiang #define WCN6855_DEVICE_ID 0x1103 286e0355afSGovind Singh 296e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = { 306e0355afSGovind Singh { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, 310fbf1957SBaochen Qiang { PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) }, 3249f5b114SAnilkumar Kolli { PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) }, 336e0355afSGovind Singh {0} 346e0355afSGovind Singh }; 356e0355afSGovind Singh 366e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); 376e0355afSGovind Singh 381ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = { 391ff8ed78SGovind Singh .mhi_support = true, 4056970454SGovind Singh .m3_fw_support = true, 416eb6ea51SGovind Singh .fixed_bdf_addr = false, 426eb6ea51SGovind Singh .fixed_mem_region = false, 431ff8ed78SGovind Singh }; 441ff8ed78SGovind Singh 457a3aed0cSAnilkumar Kolli static const struct ath11k_msi_config ath11k_msi_config[] = { 467a3aed0cSAnilkumar Kolli { 475697a564SGovind Singh .total_vectors = 32, 485697a564SGovind Singh .total_users = 4, 495697a564SGovind Singh .users = (struct ath11k_msi_user[]) { 505697a564SGovind Singh { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 515697a564SGovind Singh { .name = "CE", .num_vectors = 10, .base_vector = 3 }, 525697a564SGovind Singh { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, 535697a564SGovind Singh { .name = "DP", .num_vectors = 18, .base_vector = 14 }, 545697a564SGovind Singh }, 557a3aed0cSAnilkumar Kolli }, 564e809461SAnilkumar Kolli { 574e809461SAnilkumar Kolli .total_vectors = 16, 584e809461SAnilkumar Kolli .total_users = 3, 594e809461SAnilkumar Kolli .users = (struct ath11k_msi_user[]) { 604e809461SAnilkumar Kolli { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 614e809461SAnilkumar Kolli { .name = "CE", .num_vectors = 5, .base_vector = 3 }, 624e809461SAnilkumar Kolli { .name = "DP", .num_vectors = 8, .base_vector = 8 }, 634e809461SAnilkumar Kolli }, 644e809461SAnilkumar Kolli }, 655697a564SGovind Singh }; 665697a564SGovind Singh 67ac6e7348SCarl Huang static const struct ath11k_msi_config msi_config_one_msi = { 68ac6e7348SCarl Huang .total_vectors = 1, 69ac6e7348SCarl Huang .total_users = 4, 70ac6e7348SCarl Huang .users = (struct ath11k_msi_user[]) { 71ac6e7348SCarl Huang { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 72ac6e7348SCarl Huang { .name = "CE", .num_vectors = 1, .base_vector = 0 }, 73ac6e7348SCarl Huang { .name = "WAKE", .num_vectors = 1, .base_vector = 0 }, 74ac6e7348SCarl Huang { .name = "DP", .num_vectors = 1, .base_vector = 0 }, 75ac6e7348SCarl Huang }, 76ac6e7348SCarl Huang }; 77ac6e7348SCarl Huang 787f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { 797f4beda2SGovind Singh "bhi", 807f4beda2SGovind Singh "mhi-er0", 817f4beda2SGovind Singh "mhi-er1", 827f4beda2SGovind Singh "ce0", 837f4beda2SGovind Singh "ce1", 847f4beda2SGovind Singh "ce2", 857f4beda2SGovind Singh "ce3", 867f4beda2SGovind Singh "ce4", 877f4beda2SGovind Singh "ce5", 887f4beda2SGovind Singh "ce6", 897f4beda2SGovind Singh "ce7", 907f4beda2SGovind Singh "ce8", 917f4beda2SGovind Singh "ce9", 927f4beda2SGovind Singh "ce10", 937f4beda2SGovind Singh "ce11", 947f4beda2SGovind Singh "host2wbm-desc-feed", 957f4beda2SGovind Singh "host2reo-re-injection", 967f4beda2SGovind Singh "host2reo-command", 977f4beda2SGovind Singh "host2rxdma-monitor-ring3", 987f4beda2SGovind Singh "host2rxdma-monitor-ring2", 997f4beda2SGovind Singh "host2rxdma-monitor-ring1", 1007f4beda2SGovind Singh "reo2ost-exception", 1017f4beda2SGovind Singh "wbm2host-rx-release", 1027f4beda2SGovind Singh "reo2host-status", 1037f4beda2SGovind Singh "reo2host-destination-ring4", 1047f4beda2SGovind Singh "reo2host-destination-ring3", 1057f4beda2SGovind Singh "reo2host-destination-ring2", 1067f4beda2SGovind Singh "reo2host-destination-ring1", 1077f4beda2SGovind Singh "rxdma2host-monitor-destination-mac3", 1087f4beda2SGovind Singh "rxdma2host-monitor-destination-mac2", 1097f4beda2SGovind Singh "rxdma2host-monitor-destination-mac1", 1107f4beda2SGovind Singh "ppdu-end-interrupts-mac3", 1117f4beda2SGovind Singh "ppdu-end-interrupts-mac2", 1127f4beda2SGovind Singh "ppdu-end-interrupts-mac1", 1137f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac3", 1147f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac2", 1157f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac1", 1167f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac3", 1177f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac2", 1187f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac1", 1197f4beda2SGovind Singh "rxdma2host-destination-ring-mac3", 1207f4beda2SGovind Singh "rxdma2host-destination-ring-mac2", 1217f4beda2SGovind Singh "rxdma2host-destination-ring-mac1", 1227f4beda2SGovind Singh "host2tcl-input-ring4", 1237f4beda2SGovind Singh "host2tcl-input-ring3", 1247f4beda2SGovind Singh "host2tcl-input-ring2", 1257f4beda2SGovind Singh "host2tcl-input-ring1", 1267f4beda2SGovind Singh "wbm2host-tx-completions-ring3", 1277f4beda2SGovind Singh "wbm2host-tx-completions-ring2", 1287f4beda2SGovind Singh "wbm2host-tx-completions-ring1", 1297f4beda2SGovind Singh "tcl2host-status-ring", 1307f4beda2SGovind Singh }; 1317f4beda2SGovind Singh 132654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset) 133654e959aSGovind Singh { 134654e959aSGovind Singh struct ath11k_base *ab = ab_pci->ab; 135654e959aSGovind Singh 136*948171b5SManikanta Pubbisetty u32 window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, offset); 137654e959aSGovind Singh 138654e959aSGovind Singh lockdep_assert_held(&ab_pci->window_lock); 139654e959aSGovind Singh 140654e959aSGovind Singh if (window != ab_pci->register_window) { 141*948171b5SManikanta Pubbisetty iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window, 142*948171b5SManikanta Pubbisetty ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); 143*948171b5SManikanta Pubbisetty ioread32(ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); 144654e959aSGovind Singh ab_pci->register_window = window; 145654e959aSGovind Singh } 146654e959aSGovind Singh } 147654e959aSGovind Singh 148480a7361SKarthikeyan Periyasamy static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci) 149480a7361SKarthikeyan Periyasamy { 150*948171b5SManikanta Pubbisetty u32 umac_window; 151*948171b5SManikanta Pubbisetty u32 ce_window; 152480a7361SKarthikeyan Periyasamy u32 window; 153480a7361SKarthikeyan Periyasamy 154*948171b5SManikanta Pubbisetty umac_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET); 155*948171b5SManikanta Pubbisetty ce_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE); 156480a7361SKarthikeyan Periyasamy window = (umac_window << 12) | (ce_window << 6); 157480a7361SKarthikeyan Periyasamy 158*948171b5SManikanta Pubbisetty iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window, 159*948171b5SManikanta Pubbisetty ab_pci->ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); 160480a7361SKarthikeyan Periyasamy } 161480a7361SKarthikeyan Periyasamy 162480a7361SKarthikeyan Periyasamy static inline u32 ath11k_pci_get_window_start(struct ath11k_base *ab, 163480a7361SKarthikeyan Periyasamy u32 offset) 164480a7361SKarthikeyan Periyasamy { 165480a7361SKarthikeyan Periyasamy u32 window_start; 166480a7361SKarthikeyan Periyasamy 167480a7361SKarthikeyan Periyasamy /* If offset lies within DP register range, use 3rd window */ 168*948171b5SManikanta Pubbisetty if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < ATH11K_PCI_WINDOW_RANGE_MASK) 169*948171b5SManikanta Pubbisetty window_start = 3 * ATH11K_PCI_WINDOW_START; 170480a7361SKarthikeyan Periyasamy /* If offset lies within CE register range, use 2nd window */ 171*948171b5SManikanta Pubbisetty else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < ATH11K_PCI_WINDOW_RANGE_MASK) 172*948171b5SManikanta Pubbisetty window_start = 2 * ATH11K_PCI_WINDOW_START; 173480a7361SKarthikeyan Periyasamy else 174*948171b5SManikanta Pubbisetty window_start = ATH11K_PCI_WINDOW_START; 175480a7361SKarthikeyan Periyasamy 176480a7361SKarthikeyan Periyasamy return window_start; 177480a7361SKarthikeyan Periyasamy } 178480a7361SKarthikeyan Periyasamy 179f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) 180654e959aSGovind Singh { 181654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 182480a7361SKarthikeyan Periyasamy u32 window_start; 1830d7a8a62SWen Gong int ret = 0; 184654e959aSGovind Singh 185a05bd851SCarl Huang /* for offset beyond BAR + 4K - 32, may 186a05bd851SCarl Huang * need to wakeup MHI to access. 187a05bd851SCarl Huang */ 188081e2d64SSeevalamuthu Mariappan if (ab->hw_params.wakeup_mhi && 189081e2d64SSeevalamuthu Mariappan test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 190*948171b5SManikanta Pubbisetty offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF) 1910d7a8a62SWen Gong ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); 192a05bd851SCarl Huang 193*948171b5SManikanta Pubbisetty if (offset < ATH11K_PCI_WINDOW_START) { 194654e959aSGovind Singh iowrite32(value, ab->mem + offset); 195654e959aSGovind Singh } else { 196480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 197480a7361SKarthikeyan Periyasamy window_start = ath11k_pci_get_window_start(ab, offset); 198480a7361SKarthikeyan Periyasamy else 199*948171b5SManikanta Pubbisetty window_start = ATH11K_PCI_WINDOW_START; 200480a7361SKarthikeyan Periyasamy 201*948171b5SManikanta Pubbisetty if (window_start == ATH11K_PCI_WINDOW_START) { 202654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 203654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 204480a7361SKarthikeyan Periyasamy iowrite32(value, ab->mem + window_start + 205*948171b5SManikanta Pubbisetty (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); 206654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 207480a7361SKarthikeyan Periyasamy } else { 208480a7361SKarthikeyan Periyasamy iowrite32(value, ab->mem + window_start + 209*948171b5SManikanta Pubbisetty (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); 210480a7361SKarthikeyan Periyasamy } 211654e959aSGovind Singh } 212a05bd851SCarl Huang 213081e2d64SSeevalamuthu Mariappan if (ab->hw_params.wakeup_mhi && 214081e2d64SSeevalamuthu Mariappan test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 215*948171b5SManikanta Pubbisetty offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && 2160d7a8a62SWen Gong !ret) 217a05bd851SCarl Huang mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); 218654e959aSGovind Singh } 219654e959aSGovind Singh 220f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) 221654e959aSGovind Singh { 222654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 223480a7361SKarthikeyan Periyasamy u32 val, window_start; 2240d7a8a62SWen Gong int ret = 0; 225654e959aSGovind Singh 226a05bd851SCarl Huang /* for offset beyond BAR + 4K - 32, may 227a05bd851SCarl Huang * need to wakeup MHI to access. 228a05bd851SCarl Huang */ 229081e2d64SSeevalamuthu Mariappan if (ab->hw_params.wakeup_mhi && 230081e2d64SSeevalamuthu Mariappan test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 231*948171b5SManikanta Pubbisetty offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF) 2320d7a8a62SWen Gong ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); 233a05bd851SCarl Huang 234*948171b5SManikanta Pubbisetty if (offset < ATH11K_PCI_WINDOW_START) { 235654e959aSGovind Singh val = ioread32(ab->mem + offset); 236654e959aSGovind Singh } else { 237480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 238480a7361SKarthikeyan Periyasamy window_start = ath11k_pci_get_window_start(ab, offset); 239480a7361SKarthikeyan Periyasamy else 240*948171b5SManikanta Pubbisetty window_start = ATH11K_PCI_WINDOW_START; 241480a7361SKarthikeyan Periyasamy 242*948171b5SManikanta Pubbisetty if (window_start == ATH11K_PCI_WINDOW_START) { 243654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 244654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 245480a7361SKarthikeyan Periyasamy val = ioread32(ab->mem + window_start + 246*948171b5SManikanta Pubbisetty (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); 247654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 248480a7361SKarthikeyan Periyasamy } else { 249480a7361SKarthikeyan Periyasamy val = ioread32(ab->mem + window_start + 250*948171b5SManikanta Pubbisetty (offset & ATH11K_PCI_WINDOW_RANGE_MASK)); 251480a7361SKarthikeyan Periyasamy } 252654e959aSGovind Singh } 253654e959aSGovind Singh 254081e2d64SSeevalamuthu Mariappan if (ab->hw_params.wakeup_mhi && 255081e2d64SSeevalamuthu Mariappan test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 256*948171b5SManikanta Pubbisetty offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && 2570d7a8a62SWen Gong !ret) 258a05bd851SCarl Huang mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); 259a05bd851SCarl Huang 260654e959aSGovind Singh return val; 261654e959aSGovind Singh } 262654e959aSGovind Singh 263f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) 264f3c603d4SCarl Huang { 265f3c603d4SCarl Huang u32 val, delay; 266f3c603d4SCarl Huang 267f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 268f3c603d4SCarl Huang 269f3c603d4SCarl Huang val |= PCIE_SOC_GLOBAL_RESET_V; 270f3c603d4SCarl Huang 271f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 272f3c603d4SCarl Huang 273f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 274f3c603d4SCarl Huang delay = 10; 275f3c603d4SCarl Huang mdelay(delay); 276f3c603d4SCarl Huang 277f3c603d4SCarl Huang /* Need to toggle V bit back otherwise stuck in reset status */ 278f3c603d4SCarl Huang val &= ~PCIE_SOC_GLOBAL_RESET_V; 279f3c603d4SCarl Huang 280f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 281f3c603d4SCarl Huang 282f3c603d4SCarl Huang mdelay(delay); 283f3c603d4SCarl Huang 284f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 285f3c603d4SCarl Huang if (val == 0xffffffff) 286f3c603d4SCarl Huang ath11k_warn(ab, "link down error during global reset\n"); 287f3c603d4SCarl Huang } 288f3c603d4SCarl Huang 289f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) 290f3c603d4SCarl Huang { 291f3c603d4SCarl Huang u32 val; 292f3c603d4SCarl Huang 293f3c603d4SCarl Huang /* read cookie */ 294f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR); 295f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val); 296f3c603d4SCarl Huang 297f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 298f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 299f3c603d4SCarl Huang 300f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 301f3c603d4SCarl Huang mdelay(10); 302f3c603d4SCarl Huang 303f3c603d4SCarl Huang /* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from 304f3c603d4SCarl Huang * continuing warm path and entering dead loop. 305f3c603d4SCarl Huang */ 306f3c603d4SCarl Huang ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0); 307f3c603d4SCarl Huang mdelay(10); 308f3c603d4SCarl Huang 309f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 310f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 311f3c603d4SCarl Huang 312f3c603d4SCarl Huang /* A read clear register. clear the register to prevent 313f3c603d4SCarl Huang * Q6 from entering wrong code path. 314f3c603d4SCarl Huang */ 315f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG); 316f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val); 317f3c603d4SCarl Huang } 318f3c603d4SCarl Huang 31906999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab, 32006999407SCarl Huang u32 offset, u32 value, u32 mask) 32106999407SCarl Huang { 32206999407SCarl Huang u32 v; 32306999407SCarl Huang int i; 32406999407SCarl Huang 32506999407SCarl Huang v = ath11k_pci_read32(ab, offset); 32606999407SCarl Huang if ((v & mask) == value) 32706999407SCarl Huang return 0; 32806999407SCarl Huang 32906999407SCarl Huang for (i = 0; i < 10; i++) { 33006999407SCarl Huang ath11k_pci_write32(ab, offset, (v & ~mask) | value); 33106999407SCarl Huang 33206999407SCarl Huang v = ath11k_pci_read32(ab, offset); 33306999407SCarl Huang if ((v & mask) == value) 33406999407SCarl Huang return 0; 33506999407SCarl Huang 33606999407SCarl Huang mdelay(2); 33706999407SCarl Huang } 33806999407SCarl Huang 33906999407SCarl Huang ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n", 34006999407SCarl Huang offset, v & mask, value); 34106999407SCarl Huang 34206999407SCarl Huang return -ETIMEDOUT; 34306999407SCarl Huang } 34406999407SCarl Huang 34506999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab) 34606999407SCarl Huang { 34706999407SCarl Huang int ret; 34806999407SCarl Huang 34906999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3506fe6f68fSKarthikeyan Periyasamy PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab), 35106999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL, 35206999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK); 35330d08503SDan Carpenter if (ret) { 35406999407SCarl Huang ath11k_warn(ab, "failed to set sysclk: %d\n", ret); 35506999407SCarl Huang return ret; 35606999407SCarl Huang } 35706999407SCarl Huang 35806999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3596fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab), 3606fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG1_VAL, 3616fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 36230d08503SDan Carpenter if (ret) { 36306999407SCarl Huang ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret); 36406999407SCarl Huang return ret; 36506999407SCarl Huang } 36606999407SCarl Huang 36706999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3686fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab), 3696fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG2_VAL, 3706fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 37130d08503SDan Carpenter if (ret) { 37206999407SCarl Huang ath11k_warn(ab, "failed to set dtct config2: %d\n", ret); 37306999407SCarl Huang return ret; 37406999407SCarl Huang } 37506999407SCarl Huang 37606999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 3776fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab), 3786fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG4_VAL, 3796fe6f68fSKarthikeyan Periyasamy PCIE_PCS_OSC_DTCT_CONFIG_MSK); 38030d08503SDan Carpenter if (ret) { 38106999407SCarl Huang ath11k_warn(ab, "failed to set dtct config4: %d\n", ret); 38206999407SCarl Huang return ret; 38306999407SCarl Huang } 38406999407SCarl Huang 38506999407SCarl Huang return 0; 38606999407SCarl Huang } 38706999407SCarl Huang 388babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab) 389babb0cedSCarl Huang { 390babb0cedSCarl Huang u32 val; 391babb0cedSCarl Huang int i; 392babb0cedSCarl Huang 393babb0cedSCarl Huang val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); 394babb0cedSCarl Huang 395babb0cedSCarl Huang /* PCIE link seems very unstable after the Hot Reset*/ 396babb0cedSCarl Huang for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) { 397babb0cedSCarl Huang if (val == 0xffffffff) 398babb0cedSCarl Huang mdelay(5); 399babb0cedSCarl Huang 400babb0cedSCarl Huang ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE); 401babb0cedSCarl Huang val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); 402babb0cedSCarl Huang } 403babb0cedSCarl Huang 404babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val); 405babb0cedSCarl Huang 406babb0cedSCarl Huang val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); 407562934adSKalle Valo val |= GCC_GCC_PCIE_HOT_RST_VAL; 408babb0cedSCarl Huang ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val); 409babb0cedSCarl Huang val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); 410babb0cedSCarl Huang 411babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val); 412babb0cedSCarl Huang 413babb0cedSCarl Huang mdelay(5); 414babb0cedSCarl Huang } 415babb0cedSCarl Huang 416babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab) 417babb0cedSCarl Huang { 418babb0cedSCarl Huang /* This is a WAR for PCIE Hotreset. 419babb0cedSCarl Huang * When target receive Hotreset, but will set the interrupt. 420babb0cedSCarl Huang * So when download SBL again, SBL will open Interrupt and 421babb0cedSCarl Huang * receive it, and crash immediately. 422babb0cedSCarl Huang */ 423babb0cedSCarl Huang ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL); 424babb0cedSCarl Huang } 425babb0cedSCarl Huang 4260ccdf439SCarl Huang static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab) 4270ccdf439SCarl Huang { 4280ccdf439SCarl Huang u32 val; 4290ccdf439SCarl Huang 4300ccdf439SCarl Huang val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG); 4310ccdf439SCarl Huang val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK; 4320ccdf439SCarl Huang ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val); 4330ccdf439SCarl Huang } 4340ccdf439SCarl Huang 435f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab) 436f3c603d4SCarl Huang { 437f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1); 438f3c603d4SCarl Huang mdelay(5); 439f3c603d4SCarl Huang } 440f3c603d4SCarl Huang 441babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on) 442f3c603d4SCarl Huang { 4438a0b899fSBaochen Qiang mdelay(100); 4448a0b899fSBaochen Qiang 445babb0cedSCarl Huang if (power_on) { 446babb0cedSCarl Huang ath11k_pci_enable_ltssm(ab); 447babb0cedSCarl Huang ath11k_pci_clear_all_intrs(ab); 4480ccdf439SCarl Huang ath11k_pci_set_wlaon_pwr_ctrl(ab); 4495088df05SBaochen Qiang if (ab->hw_params.fix_l1ss) 45006999407SCarl Huang ath11k_pci_fix_l1ss(ab); 451babb0cedSCarl Huang } 452babb0cedSCarl Huang 453f3c603d4SCarl Huang ath11k_mhi_clear_vector(ab); 4548a0b899fSBaochen Qiang ath11k_pci_clear_dbg_registers(ab); 455f3c603d4SCarl Huang ath11k_pci_soc_global_reset(ab); 456f3c603d4SCarl Huang ath11k_mhi_set_mhictrl_reset(ab); 457f3c603d4SCarl Huang } 458f3c603d4SCarl Huang 4591399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) 4601399fb87SGovind Singh { 4611399fb87SGovind Singh struct pci_dev *pci_dev = to_pci_dev(dev); 4621399fb87SGovind Singh 4631399fb87SGovind Singh return pci_irq_vector(pci_dev, vector); 4641399fb87SGovind Singh } 4651399fb87SGovind Singh 466*948171b5SManikanta Pubbisetty void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, 467c4eacabeSGovind Singh u32 *msi_addr_hi) 468c4eacabeSGovind Singh { 469e8e55d89SAnilkumar Kolli struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 470c4eacabeSGovind Singh struct pci_dev *pci_dev = to_pci_dev(ab->dev); 471c4eacabeSGovind Singh 472c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, 473c4eacabeSGovind Singh msi_addr_lo); 474c4eacabeSGovind Singh 475e8e55d89SAnilkumar Kolli if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) { 476c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, 477c4eacabeSGovind Singh msi_addr_hi); 478e8e55d89SAnilkumar Kolli } else { 479e8e55d89SAnilkumar Kolli *msi_addr_hi = 0; 480e8e55d89SAnilkumar Kolli } 481c4eacabeSGovind Singh } 482c4eacabeSGovind Singh 4831399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, 4841399fb87SGovind Singh int *num_vectors, u32 *user_base_data, 4851399fb87SGovind Singh u32 *base_vector) 4861399fb87SGovind Singh { 4871399fb87SGovind Singh struct ath11k_base *ab = ab_pci->ab; 4887a3aed0cSAnilkumar Kolli const struct ath11k_msi_config *msi_config = ab_pci->msi_config; 4891399fb87SGovind Singh int idx; 4901399fb87SGovind Singh 4917a3aed0cSAnilkumar Kolli for (idx = 0; idx < msi_config->total_users; idx++) { 4927a3aed0cSAnilkumar Kolli if (strcmp(user_name, msi_config->users[idx].name) == 0) { 4937a3aed0cSAnilkumar Kolli *num_vectors = msi_config->users[idx].num_vectors; 4947a3aed0cSAnilkumar Kolli *base_vector = msi_config->users[idx].base_vector; 495c41a6700SCarl Huang *user_base_data = *base_vector + ab_pci->msi_ep_base_data; 4961399fb87SGovind Singh 497c41a6700SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, 498c41a6700SCarl Huang "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", 4991399fb87SGovind Singh user_name, *num_vectors, *user_base_data, 5001399fb87SGovind Singh *base_vector); 5011399fb87SGovind Singh 5021399fb87SGovind Singh return 0; 5031399fb87SGovind Singh } 5041399fb87SGovind Singh } 5051399fb87SGovind Singh 5061399fb87SGovind Singh ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name); 5071399fb87SGovind Singh 5081399fb87SGovind Singh return -EINVAL; 5091399fb87SGovind Singh } 5101399fb87SGovind Singh 511*948171b5SManikanta Pubbisetty void ath11k_pci_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx) 5126289ac2bSKarthikeyan Periyasamy { 5136289ac2bSKarthikeyan Periyasamy u32 i, msi_data_idx; 5146289ac2bSKarthikeyan Periyasamy 5156289ac2bSKarthikeyan Periyasamy for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { 5166289ac2bSKarthikeyan Periyasamy if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5176289ac2bSKarthikeyan Periyasamy continue; 5186289ac2bSKarthikeyan Periyasamy 5196289ac2bSKarthikeyan Periyasamy if (ce_id == i) 5206289ac2bSKarthikeyan Periyasamy break; 5216289ac2bSKarthikeyan Periyasamy 5226289ac2bSKarthikeyan Periyasamy msi_data_idx++; 5236289ac2bSKarthikeyan Periyasamy } 5246289ac2bSKarthikeyan Periyasamy *msi_idx = msi_data_idx; 5256289ac2bSKarthikeyan Periyasamy } 5266289ac2bSKarthikeyan Periyasamy 527*948171b5SManikanta Pubbisetty int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, 528c4eacabeSGovind Singh int *num_vectors, u32 *user_base_data, 529c4eacabeSGovind Singh u32 *base_vector) 530c4eacabeSGovind Singh { 531c4eacabeSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 532c4eacabeSGovind Singh 533c4eacabeSGovind Singh return ath11k_pci_get_user_msi_assignment(ab_pci, user_name, 534c4eacabeSGovind Singh num_vectors, user_base_data, 535c4eacabeSGovind Singh base_vector); 536c4eacabeSGovind Singh } 537c4eacabeSGovind Singh 538d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab) 539d4ecb90bSCarl Huang { 540d4ecb90bSCarl Huang int i, j; 541d4ecb90bSCarl Huang 542d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 543d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 544d4ecb90bSCarl Huang 545d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) 546d4ecb90bSCarl Huang free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); 547d4ecb90bSCarl Huang 548d4ecb90bSCarl Huang netif_napi_del(&irq_grp->napi); 549d4ecb90bSCarl Huang } 550d4ecb90bSCarl Huang } 551d4ecb90bSCarl Huang 552*948171b5SManikanta Pubbisetty void ath11k_pci_free_irq(struct ath11k_base *ab) 5537f4beda2SGovind Singh { 5547f4beda2SGovind Singh int i, irq_idx; 5557f4beda2SGovind Singh 556d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 557e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 5587f4beda2SGovind Singh continue; 5597f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 5607f4beda2SGovind Singh free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); 5617f4beda2SGovind Singh } 562d4ecb90bSCarl Huang 563d4ecb90bSCarl Huang ath11k_pci_free_ext_irq(ab); 5647f4beda2SGovind Singh } 5657f4beda2SGovind Singh 5662c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) 5672c3960c2SGovind Singh { 568c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 5692c3960c2SGovind Singh u32 irq_idx; 5702c3960c2SGovind Singh 571c41a6700SCarl Huang /* In case of one MSI vector, we handle irq enable/disable in a 572c41a6700SCarl Huang * uniform way since we only have one irq 573c41a6700SCarl Huang */ 574c41a6700SCarl Huang if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 575c41a6700SCarl Huang return; 576c41a6700SCarl Huang 5772c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 5782c3960c2SGovind Singh enable_irq(ab->irq_num[irq_idx]); 5792c3960c2SGovind Singh } 5802c3960c2SGovind Singh 5817f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) 5827f4beda2SGovind Singh { 583c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 5847f4beda2SGovind Singh u32 irq_idx; 5857f4beda2SGovind Singh 586c41a6700SCarl Huang /* In case of one MSI vector, we handle irq enable/disable in a 587c41a6700SCarl Huang * uniform way since we only have one irq 588c41a6700SCarl Huang */ 589c41a6700SCarl Huang if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 590c41a6700SCarl Huang return; 591c41a6700SCarl Huang 5927f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 5937f4beda2SGovind Singh disable_irq_nosync(ab->irq_num[irq_idx]); 5947f4beda2SGovind Singh } 5957f4beda2SGovind Singh 5962c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab) 5972c3960c2SGovind Singh { 5982c3960c2SGovind Singh int i; 5992c3960c2SGovind Singh 60001279bcdSCarl Huang clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); 60101279bcdSCarl Huang 602d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 603e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 6042c3960c2SGovind Singh continue; 6052c3960c2SGovind Singh ath11k_pci_ce_irq_disable(ab, i); 6062c3960c2SGovind Singh } 6072c3960c2SGovind Singh } 6082c3960c2SGovind Singh 6092c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) 6102c3960c2SGovind Singh { 6112c3960c2SGovind Singh int i; 6122c3960c2SGovind Singh int irq_idx; 6132c3960c2SGovind Singh 614d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 615e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 6162c3960c2SGovind Singh continue; 6172c3960c2SGovind Singh 6182c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 6192c3960c2SGovind Singh synchronize_irq(ab->irq_num[irq_idx]); 6202c3960c2SGovind Singh } 6212c3960c2SGovind Singh } 6222c3960c2SGovind Singh 6230f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t) 6242c3960c2SGovind Singh { 6250f01dcb8SAllen Pais struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); 626ac6e7348SCarl Huang int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; 6272c3960c2SGovind Singh 6282c3960c2SGovind Singh ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); 6292c3960c2SGovind Singh 630ac6e7348SCarl Huang enable_irq(ce_pipe->ab->irq_num[irq_idx]); 6312c3960c2SGovind Singh } 6322c3960c2SGovind Singh 6337f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) 6347f4beda2SGovind Singh { 6357f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe = arg; 63601279bcdSCarl Huang struct ath11k_base *ab = ce_pipe->ab; 637ac6e7348SCarl Huang int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; 63801279bcdSCarl Huang 63901279bcdSCarl Huang if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags)) 64001279bcdSCarl Huang return IRQ_HANDLED; 6417f4beda2SGovind Singh 6427dc67af0SKarthikeyan Periyasamy /* last interrupt received for this CE */ 6437dc67af0SKarthikeyan Periyasamy ce_pipe->timestamp = jiffies; 6447dc67af0SKarthikeyan Periyasamy 645ac6e7348SCarl Huang disable_irq_nosync(ab->irq_num[irq_idx]); 646ac6e7348SCarl Huang 6472c3960c2SGovind Singh tasklet_schedule(&ce_pipe->intr_tq); 6487f4beda2SGovind Singh 6497f4beda2SGovind Singh return IRQ_HANDLED; 6507f4beda2SGovind Singh } 6517f4beda2SGovind Singh 652d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) 653d4ecb90bSCarl Huang { 654c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); 655d4ecb90bSCarl Huang int i; 656d4ecb90bSCarl Huang 657c41a6700SCarl Huang /* In case of one MSI vector, we handle irq enable/disable 658c41a6700SCarl Huang * in a uniform way since we only have one irq 659c41a6700SCarl Huang */ 660c41a6700SCarl Huang if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 661c41a6700SCarl Huang return; 662c41a6700SCarl Huang 663d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 664d4ecb90bSCarl Huang disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 665d4ecb90bSCarl Huang } 666d4ecb90bSCarl Huang 667d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc) 668d4ecb90bSCarl Huang { 669d4ecb90bSCarl Huang int i; 670d4ecb90bSCarl Huang 67101279bcdSCarl Huang clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags); 67201279bcdSCarl Huang 673d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 674d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; 675d4ecb90bSCarl Huang 676d4ecb90bSCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 677d4ecb90bSCarl Huang 678d943fdadSBen Greear if (irq_grp->napi_enabled) { 679d4ecb90bSCarl Huang napi_synchronize(&irq_grp->napi); 680d4ecb90bSCarl Huang napi_disable(&irq_grp->napi); 681d943fdadSBen Greear irq_grp->napi_enabled = false; 682d943fdadSBen Greear } 683d4ecb90bSCarl Huang } 684d4ecb90bSCarl Huang } 685d4ecb90bSCarl Huang 686d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) 687d4ecb90bSCarl Huang { 688c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(irq_grp->ab); 689d4ecb90bSCarl Huang int i; 690d4ecb90bSCarl Huang 691c41a6700SCarl Huang /* In case of one MSI vector, we handle irq enable/disable in a 692c41a6700SCarl Huang * uniform way since we only have one irq 693c41a6700SCarl Huang */ 694c41a6700SCarl Huang if (!test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 695c41a6700SCarl Huang return; 696c41a6700SCarl Huang 697d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 698d4ecb90bSCarl Huang enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 699d4ecb90bSCarl Huang } 700d4ecb90bSCarl Huang 701*948171b5SManikanta Pubbisetty void ath11k_pci_ext_irq_enable(struct ath11k_base *ab) 702d4ecb90bSCarl Huang { 703d4ecb90bSCarl Huang int i; 704d4ecb90bSCarl Huang 70501279bcdSCarl Huang set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); 70601279bcdSCarl Huang 707d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 708d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 709d4ecb90bSCarl Huang 710d943fdadSBen Greear if (!irq_grp->napi_enabled) { 711d4ecb90bSCarl Huang napi_enable(&irq_grp->napi); 712d943fdadSBen Greear irq_grp->napi_enabled = true; 713d943fdadSBen Greear } 714d4ecb90bSCarl Huang ath11k_pci_ext_grp_enable(irq_grp); 715d4ecb90bSCarl Huang } 716d4ecb90bSCarl Huang } 717d4ecb90bSCarl Huang 718d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab) 719d4ecb90bSCarl Huang { 720d4ecb90bSCarl Huang int i, j, irq_idx; 721d4ecb90bSCarl Huang 722d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 723d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 724d4ecb90bSCarl Huang 725d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 726d4ecb90bSCarl Huang irq_idx = irq_grp->irqs[j]; 727d4ecb90bSCarl Huang synchronize_irq(ab->irq_num[irq_idx]); 728d4ecb90bSCarl Huang } 729d4ecb90bSCarl Huang } 730d4ecb90bSCarl Huang } 731d4ecb90bSCarl Huang 732*948171b5SManikanta Pubbisetty void ath11k_pci_ext_irq_disable(struct ath11k_base *ab) 733d4ecb90bSCarl Huang { 734d4ecb90bSCarl Huang __ath11k_pci_ext_irq_disable(ab); 735d4ecb90bSCarl Huang ath11k_pci_sync_ext_irqs(ab); 736d4ecb90bSCarl Huang } 737d4ecb90bSCarl Huang 738d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) 739d4ecb90bSCarl Huang { 740d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = container_of(napi, 741d4ecb90bSCarl Huang struct ath11k_ext_irq_grp, 742d4ecb90bSCarl Huang napi); 743d4ecb90bSCarl Huang struct ath11k_base *ab = irq_grp->ab; 744d4ecb90bSCarl Huang int work_done; 745ac6e7348SCarl Huang int i; 746d4ecb90bSCarl Huang 747d4ecb90bSCarl Huang work_done = ath11k_dp_service_srng(ab, irq_grp, budget); 748d4ecb90bSCarl Huang if (work_done < budget) { 749d4ecb90bSCarl Huang napi_complete_done(napi, work_done); 750ac6e7348SCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 751ac6e7348SCarl Huang enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 752d4ecb90bSCarl Huang } 753d4ecb90bSCarl Huang 754d4ecb90bSCarl Huang if (work_done > budget) 755d4ecb90bSCarl Huang work_done = budget; 756d4ecb90bSCarl Huang 757d4ecb90bSCarl Huang return work_done; 758d4ecb90bSCarl Huang } 759d4ecb90bSCarl Huang 760d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) 761d4ecb90bSCarl Huang { 762d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = arg; 76301279bcdSCarl Huang struct ath11k_base *ab = irq_grp->ab; 764ac6e7348SCarl Huang int i; 76501279bcdSCarl Huang 76601279bcdSCarl Huang if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) 76701279bcdSCarl Huang return IRQ_HANDLED; 768d4ecb90bSCarl Huang 769d4ecb90bSCarl Huang ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); 770d4ecb90bSCarl Huang 7717dc67af0SKarthikeyan Periyasamy /* last interrupt received for this group */ 7727dc67af0SKarthikeyan Periyasamy irq_grp->timestamp = jiffies; 7737dc67af0SKarthikeyan Periyasamy 774ac6e7348SCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 775ac6e7348SCarl Huang disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 776d4ecb90bSCarl Huang 777d4ecb90bSCarl Huang napi_schedule(&irq_grp->napi); 778d4ecb90bSCarl Huang 779d4ecb90bSCarl Huang return IRQ_HANDLED; 780d4ecb90bSCarl Huang } 781d4ecb90bSCarl Huang 782d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) 783d4ecb90bSCarl Huang { 784c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 785d4ecb90bSCarl Huang int i, j, ret, num_vectors = 0; 7864ab4693fSCarl Huang u32 user_base_data = 0, base_vector = 0; 787d4ecb90bSCarl Huang 788b2c09458SColin Ian King ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", 789b2c09458SColin Ian King &num_vectors, 790b2c09458SColin Ian King &user_base_data, 791d4ecb90bSCarl Huang &base_vector); 792b2c09458SColin Ian King if (ret < 0) 793b2c09458SColin Ian King return ret; 794d4ecb90bSCarl Huang 795d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 796d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 797d4ecb90bSCarl Huang u32 num_irq = 0; 798d4ecb90bSCarl Huang 799d4ecb90bSCarl Huang irq_grp->ab = ab; 800d4ecb90bSCarl Huang irq_grp->grp_id = i; 801d4ecb90bSCarl Huang init_dummy_netdev(&irq_grp->napi_ndev); 802d4ecb90bSCarl Huang netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, 803d4ecb90bSCarl Huang ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT); 804d4ecb90bSCarl Huang 805d4ecb90bSCarl Huang if (ab->hw_params.ring_mask->tx[i] || 806d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx[i] || 807d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_err[i] || 808d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_wbm_rel[i] || 809d4ecb90bSCarl Huang ab->hw_params.ring_mask->reo_status[i] || 810d4ecb90bSCarl Huang ab->hw_params.ring_mask->rxdma2host[i] || 811d4ecb90bSCarl Huang ab->hw_params.ring_mask->host2rxdma[i] || 812d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_mon_status[i]) { 813d4ecb90bSCarl Huang num_irq = 1; 814d4ecb90bSCarl Huang } 815d4ecb90bSCarl Huang 816d4ecb90bSCarl Huang irq_grp->num_irq = num_irq; 8174ab4693fSCarl Huang irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i; 818d4ecb90bSCarl Huang 819d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 820d4ecb90bSCarl Huang int irq_idx = irq_grp->irqs[j]; 821d4ecb90bSCarl Huang int vector = (i % num_vectors) + base_vector; 822d4ecb90bSCarl Huang int irq = ath11k_pci_get_msi_irq(ab->dev, vector); 823d4ecb90bSCarl Huang 824d4ecb90bSCarl Huang ab->irq_num[irq_idx] = irq; 825d4ecb90bSCarl Huang 826d4ecb90bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, 827d4ecb90bSCarl Huang "irq:%d group:%d\n", irq, i); 8287dc67af0SKarthikeyan Periyasamy 8297dc67af0SKarthikeyan Periyasamy irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); 830d4ecb90bSCarl Huang ret = request_irq(irq, ath11k_pci_ext_interrupt_handler, 831c41a6700SCarl Huang ab_pci->irq_flags, 832d4ecb90bSCarl Huang "DP_EXT_IRQ", irq_grp); 833d4ecb90bSCarl Huang if (ret) { 834d4ecb90bSCarl Huang ath11k_err(ab, "failed request irq %d: %d\n", 835d4ecb90bSCarl Huang vector, ret); 836d4ecb90bSCarl Huang return ret; 837d4ecb90bSCarl Huang } 838d4ecb90bSCarl Huang } 839c41a6700SCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 840d4ecb90bSCarl Huang } 841d4ecb90bSCarl Huang 842d4ecb90bSCarl Huang return 0; 843d4ecb90bSCarl Huang } 844d4ecb90bSCarl Huang 845*948171b5SManikanta Pubbisetty int ath11k_pci_set_irq_affinity_hint(struct ath11k_pci *ab_pci, 846e94b0749SBaochen Qiang const struct cpumask *m) 847e94b0749SBaochen Qiang { 848e94b0749SBaochen Qiang if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 849e94b0749SBaochen Qiang return 0; 850e94b0749SBaochen Qiang 851e94b0749SBaochen Qiang return irq_set_affinity_hint(ab_pci->pdev->irq, m); 852e94b0749SBaochen Qiang } 853e94b0749SBaochen Qiang 854*948171b5SManikanta Pubbisetty int ath11k_pci_config_irq(struct ath11k_base *ab) 8557f4beda2SGovind Singh { 856c41a6700SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 8577f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe; 8587f4beda2SGovind Singh u32 msi_data_start; 8596289ac2bSKarthikeyan Periyasamy u32 msi_data_count, msi_data_idx; 8607f4beda2SGovind Singh u32 msi_irq_start; 8617f4beda2SGovind Singh unsigned int msi_data; 8627f4beda2SGovind Singh int irq, i, ret, irq_idx; 8637f4beda2SGovind Singh 8647f4beda2SGovind Singh ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), 8657f4beda2SGovind Singh "CE", &msi_data_count, 8667f4beda2SGovind Singh &msi_data_start, &msi_irq_start); 8677f4beda2SGovind Singh if (ret) 8687f4beda2SGovind Singh return ret; 8697f4beda2SGovind Singh 870e94b0749SBaochen Qiang ret = ath11k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0)); 871e94b0749SBaochen Qiang if (ret) { 872e94b0749SBaochen Qiang ath11k_err(ab, "failed to set irq affinity %d\n", ret); 873e94b0749SBaochen Qiang return ret; 874e94b0749SBaochen Qiang } 875e94b0749SBaochen Qiang 8767f4beda2SGovind Singh /* Configure CE irqs */ 8776289ac2bSKarthikeyan Periyasamy for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { 878e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 8797f4beda2SGovind Singh continue; 8807f4beda2SGovind Singh 8816289ac2bSKarthikeyan Periyasamy msi_data = (msi_data_idx % msi_data_count) + msi_irq_start; 8826289ac2bSKarthikeyan Periyasamy irq = ath11k_pci_get_msi_irq(ab->dev, msi_data); 8836289ac2bSKarthikeyan Periyasamy ce_pipe = &ab->ce.ce_pipe[i]; 8846289ac2bSKarthikeyan Periyasamy 8857f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 8867f4beda2SGovind Singh 8870f01dcb8SAllen Pais tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet); 8882c3960c2SGovind Singh 8897f4beda2SGovind Singh ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, 890c41a6700SCarl Huang ab_pci->irq_flags, irq_name[irq_idx], 8917f4beda2SGovind Singh ce_pipe); 8927f4beda2SGovind Singh if (ret) { 8937f4beda2SGovind Singh ath11k_err(ab, "failed to request irq %d: %d\n", 8947f4beda2SGovind Singh irq_idx, ret); 895e94b0749SBaochen Qiang goto err_irq_affinity_cleanup; 8967f4beda2SGovind Singh } 8977f4beda2SGovind Singh 8987f4beda2SGovind Singh ab->irq_num[irq_idx] = irq; 8996289ac2bSKarthikeyan Periyasamy msi_data_idx++; 900e678fbd4SKarthikeyan Periyasamy 901e5c860e1SCarl Huang ath11k_pci_ce_irq_disable(ab, i); 9027f4beda2SGovind Singh } 9037f4beda2SGovind Singh 904d4ecb90bSCarl Huang ret = ath11k_pci_ext_irq_config(ab); 905d4ecb90bSCarl Huang if (ret) 906e94b0749SBaochen Qiang goto err_irq_affinity_cleanup; 907d4ecb90bSCarl Huang 9087f4beda2SGovind Singh return 0; 909e94b0749SBaochen Qiang 910e94b0749SBaochen Qiang err_irq_affinity_cleanup: 911e94b0749SBaochen Qiang ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); 912e94b0749SBaochen Qiang return ret; 9137f4beda2SGovind Singh } 9147f4beda2SGovind Singh 9157f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) 9167f4beda2SGovind Singh { 9177f4beda2SGovind Singh struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; 9187f4beda2SGovind Singh 919967c1d11SAnilkumar Kolli cfg->tgt_ce = ab->hw_params.target_ce_config; 920967c1d11SAnilkumar Kolli cfg->tgt_ce_len = ab->hw_params.target_ce_count; 9217f4beda2SGovind Singh 922967c1d11SAnilkumar Kolli cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map; 923967c1d11SAnilkumar Kolli cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len; 92416001e4bSAnilkumar Kolli ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id; 925e838c14aSCarl Huang 926e838c14aSCarl Huang ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2, 927e838c14aSCarl Huang &cfg->shadow_reg_v2_len); 9287f4beda2SGovind Singh } 9297f4beda2SGovind Singh 930*948171b5SManikanta Pubbisetty void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) 9317f4beda2SGovind Singh { 9327f4beda2SGovind Singh int i; 9337f4beda2SGovind Singh 93401279bcdSCarl Huang set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); 93501279bcdSCarl Huang 936d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 937e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 9387f4beda2SGovind Singh continue; 9397f4beda2SGovind Singh ath11k_pci_ce_irq_enable(ab, i); 9407f4beda2SGovind Singh } 9417f4beda2SGovind Singh } 9427f4beda2SGovind Singh 94396527d52SBaochen Qiang static void ath11k_pci_msi_config(struct ath11k_pci *ab_pci, bool enable) 94496527d52SBaochen Qiang { 94596527d52SBaochen Qiang struct pci_dev *dev = ab_pci->pdev; 94696527d52SBaochen Qiang u16 control; 94796527d52SBaochen Qiang 94896527d52SBaochen Qiang pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control); 94996527d52SBaochen Qiang 95096527d52SBaochen Qiang if (enable) 95196527d52SBaochen Qiang control |= PCI_MSI_FLAGS_ENABLE; 95296527d52SBaochen Qiang else 95396527d52SBaochen Qiang control &= ~PCI_MSI_FLAGS_ENABLE; 95496527d52SBaochen Qiang 95596527d52SBaochen Qiang pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control); 95696527d52SBaochen Qiang } 95796527d52SBaochen Qiang 95896527d52SBaochen Qiang static void ath11k_pci_msi_enable(struct ath11k_pci *ab_pci) 95996527d52SBaochen Qiang { 96096527d52SBaochen Qiang ath11k_pci_msi_config(ab_pci, true); 96196527d52SBaochen Qiang } 96296527d52SBaochen Qiang 96396527d52SBaochen Qiang static void ath11k_pci_msi_disable(struct ath11k_pci *ab_pci) 96496527d52SBaochen Qiang { 96596527d52SBaochen Qiang ath11k_pci_msi_config(ab_pci, false); 96696527d52SBaochen Qiang } 96796527d52SBaochen Qiang 96896527d52SBaochen Qiang static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci) 9695697a564SGovind Singh { 9705697a564SGovind Singh struct ath11k_base *ab = ab_pci->ab; 9717a3aed0cSAnilkumar Kolli const struct ath11k_msi_config *msi_config = ab_pci->msi_config; 9725697a564SGovind Singh struct msi_desc *msi_desc; 9735697a564SGovind Singh int num_vectors; 9745697a564SGovind Singh int ret; 9755697a564SGovind Singh 9765697a564SGovind Singh num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 9777a3aed0cSAnilkumar Kolli msi_config->total_vectors, 9787a3aed0cSAnilkumar Kolli msi_config->total_vectors, 9795697a564SGovind Singh PCI_IRQ_MSI); 980ac6e7348SCarl Huang if (num_vectors == msi_config->total_vectors) { 981c41a6700SCarl Huang set_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); 982c41a6700SCarl Huang ab_pci->irq_flags = IRQF_SHARED; 983ac6e7348SCarl Huang } else { 984ac6e7348SCarl Huang num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 985ac6e7348SCarl Huang 1, 986ac6e7348SCarl Huang 1, 987ac6e7348SCarl Huang PCI_IRQ_MSI); 988ac6e7348SCarl Huang if (num_vectors < 0) { 989ac6e7348SCarl Huang ret = -EINVAL; 990ac6e7348SCarl Huang goto reset_msi_config; 9915697a564SGovind Singh } 992ac6e7348SCarl Huang clear_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags); 993ac6e7348SCarl Huang ab_pci->msi_config = &msi_config_one_msi; 994ac6e7348SCarl Huang ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING; 995ac6e7348SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n"); 996ac6e7348SCarl Huang } 997ac6e7348SCarl Huang ath11k_info(ab, "MSI vectors: %d\n", num_vectors); 998ac6e7348SCarl Huang 99996527d52SBaochen Qiang ath11k_pci_msi_disable(ab_pci); 10005697a564SGovind Singh 10015697a564SGovind Singh msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 10025697a564SGovind Singh if (!msi_desc) { 10035697a564SGovind Singh ath11k_err(ab, "msi_desc is NULL!\n"); 10045697a564SGovind Singh ret = -EINVAL; 10055697a564SGovind Singh goto free_msi_vector; 10065697a564SGovind Singh } 10075697a564SGovind Singh 10085697a564SGovind Singh ab_pci->msi_ep_base_data = msi_desc->msg.data; 1009e58f2259SThomas Gleixner if (msi_desc->pci.msi_attrib.is_64) 1010e8e55d89SAnilkumar Kolli set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags); 10115697a564SGovind Singh 10125697a564SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); 10135697a564SGovind Singh 10145697a564SGovind Singh return 0; 10155697a564SGovind Singh 10165697a564SGovind Singh free_msi_vector: 10175697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 10185697a564SGovind Singh 1019ac6e7348SCarl Huang reset_msi_config: 10205697a564SGovind Singh return ret; 10215697a564SGovind Singh } 10225697a564SGovind Singh 102396527d52SBaochen Qiang static void ath11k_pci_free_msi(struct ath11k_pci *ab_pci) 10245697a564SGovind Singh { 10255697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 10265697a564SGovind Singh } 10275697a564SGovind Singh 102887b4072dSCarl Huang static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci) 102987b4072dSCarl Huang { 103087b4072dSCarl Huang struct msi_desc *msi_desc; 103187b4072dSCarl Huang 103287b4072dSCarl Huang msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 103387b4072dSCarl Huang if (!msi_desc) { 103487b4072dSCarl Huang ath11k_err(ab_pci->ab, "msi_desc is NULL!\n"); 103587b4072dSCarl Huang pci_free_irq_vectors(ab_pci->pdev); 103687b4072dSCarl Huang return -EINVAL; 103787b4072dSCarl Huang } 103887b4072dSCarl Huang 103987b4072dSCarl Huang ab_pci->msi_ep_base_data = msi_desc->msg.data; 104087b4072dSCarl Huang 104187b4072dSCarl Huang ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n", 104287b4072dSCarl Huang ab_pci->msi_ep_base_data); 104387b4072dSCarl Huang 104487b4072dSCarl Huang return 0; 104587b4072dSCarl Huang } 104687b4072dSCarl Huang 10475762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) 10485762613eSGovind Singh { 10495762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 10505762613eSGovind Singh u16 device_id; 10515762613eSGovind Singh int ret = 0; 10525762613eSGovind Singh 10535762613eSGovind Singh pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 10545762613eSGovind Singh if (device_id != ab_pci->dev_id) { 10555762613eSGovind Singh ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", 10565762613eSGovind Singh device_id, ab_pci->dev_id); 10575762613eSGovind Singh ret = -EIO; 10585762613eSGovind Singh goto out; 10595762613eSGovind Singh } 10605762613eSGovind Singh 10615762613eSGovind Singh ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); 10625762613eSGovind Singh if (ret) { 10635762613eSGovind Singh ath11k_err(ab, "failed to assign pci resource: %d\n", ret); 10645762613eSGovind Singh goto out; 10655762613eSGovind Singh } 10665762613eSGovind Singh 10675762613eSGovind Singh ret = pci_enable_device(pdev); 10685762613eSGovind Singh if (ret) { 10695762613eSGovind Singh ath11k_err(ab, "failed to enable pci device: %d\n", ret); 10705762613eSGovind Singh goto out; 10715762613eSGovind Singh } 10725762613eSGovind Singh 10735762613eSGovind Singh ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); 10745762613eSGovind Singh if (ret) { 10755762613eSGovind Singh ath11k_err(ab, "failed to request pci region: %d\n", ret); 10765762613eSGovind Singh goto disable_device; 10775762613eSGovind Singh } 10785762613eSGovind Singh 1079923a1346SChristophe JAILLET ret = dma_set_mask_and_coherent(&pdev->dev, 1080923a1346SChristophe JAILLET DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 10815762613eSGovind Singh if (ret) { 10825762613eSGovind Singh ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", 10835762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 10845762613eSGovind Singh goto release_region; 10855762613eSGovind Singh } 10865762613eSGovind Singh 10875762613eSGovind Singh pci_set_master(pdev); 10885762613eSGovind Singh 10895762613eSGovind Singh ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); 10905762613eSGovind Singh ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); 10915762613eSGovind Singh if (!ab->mem) { 10925762613eSGovind Singh ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); 10935762613eSGovind Singh ret = -EIO; 10945762613eSGovind Singh goto clear_master; 10955762613eSGovind Singh } 10965762613eSGovind Singh 10975762613eSGovind Singh ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); 10985762613eSGovind Singh return 0; 10995762613eSGovind Singh 11005762613eSGovind Singh clear_master: 11015762613eSGovind Singh pci_clear_master(pdev); 11025762613eSGovind Singh release_region: 11035762613eSGovind Singh pci_release_region(pdev, ATH11K_PCI_BAR_NUM); 11045762613eSGovind Singh disable_device: 11055762613eSGovind Singh pci_disable_device(pdev); 11065762613eSGovind Singh out: 11075762613eSGovind Singh return ret; 11085762613eSGovind Singh } 11095762613eSGovind Singh 11105762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) 11115762613eSGovind Singh { 11125762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 11135762613eSGovind Singh struct pci_dev *pci_dev = ab_pci->pdev; 11145762613eSGovind Singh 11155762613eSGovind Singh pci_iounmap(pci_dev, ab->mem); 11165762613eSGovind Singh ab->mem = NULL; 11175762613eSGovind Singh pci_clear_master(pci_dev); 11185762613eSGovind Singh pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); 11195762613eSGovind Singh if (pci_is_enabled(pci_dev)) 11205762613eSGovind Singh pci_disable_device(pci_dev); 11215762613eSGovind Singh } 11225762613eSGovind Singh 1123e9603f4bSCarl Huang static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci) 1124e9603f4bSCarl Huang { 1125e9603f4bSCarl Huang struct ath11k_base *ab = ab_pci->ab; 1126e9603f4bSCarl Huang 1127e9603f4bSCarl Huang pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL, 1128e9603f4bSCarl Huang &ab_pci->link_ctl); 1129e9603f4bSCarl Huang 1130e9603f4bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n", 1131e9603f4bSCarl Huang ab_pci->link_ctl, 1132e9603f4bSCarl Huang u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S), 1133e9603f4bSCarl Huang u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1)); 1134e9603f4bSCarl Huang 1135e9603f4bSCarl Huang /* disable L0s and L1 */ 1136e9603f4bSCarl Huang pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, 1137e9603f4bSCarl Huang ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC); 1138e9603f4bSCarl Huang 1139e9603f4bSCarl Huang set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags); 1140e9603f4bSCarl Huang } 1141e9603f4bSCarl Huang 1142*948171b5SManikanta Pubbisetty void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci) 1143e9603f4bSCarl Huang { 1144e9603f4bSCarl Huang if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags)) 1145e9603f4bSCarl Huang pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL, 1146e9603f4bSCarl Huang ab_pci->link_ctl); 1147e9603f4bSCarl Huang } 1148e9603f4bSCarl Huang 11491399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab) 11501399fb87SGovind Singh { 11511399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 11521399fb87SGovind Singh int ret; 11531399fb87SGovind Singh 1154a05bd851SCarl Huang ab_pci->register_window = 0; 1155a05bd851SCarl Huang clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 1156babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, true); 1157f3c603d4SCarl Huang 1158e9603f4bSCarl Huang /* Disable ASPM during firmware download due to problems switching 1159e9603f4bSCarl Huang * to AMSS state. 1160e9603f4bSCarl Huang */ 1161e9603f4bSCarl Huang ath11k_pci_aspm_disable(ab_pci); 1162e9603f4bSCarl Huang 116396527d52SBaochen Qiang ath11k_pci_msi_enable(ab_pci); 116496527d52SBaochen Qiang 11651399fb87SGovind Singh ret = ath11k_mhi_start(ab_pci); 11661399fb87SGovind Singh if (ret) { 11671399fb87SGovind Singh ath11k_err(ab, "failed to start mhi: %d\n", ret); 11681399fb87SGovind Singh return ret; 11691399fb87SGovind Singh } 11701399fb87SGovind Singh 1171480a7361SKarthikeyan Periyasamy if (ab->bus_params.static_window_map) 1172480a7361SKarthikeyan Periyasamy ath11k_pci_select_static_window(ab_pci); 1173480a7361SKarthikeyan Periyasamy 11741399fb87SGovind Singh return 0; 11751399fb87SGovind Singh } 11761399fb87SGovind Singh 11771399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab) 11781399fb87SGovind Singh { 11791399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 11801399fb87SGovind Singh 1181e9603f4bSCarl Huang /* restore aspm in case firmware bootup fails */ 1182e9603f4bSCarl Huang ath11k_pci_aspm_restore(ab_pci); 1183e9603f4bSCarl Huang 1184babb0cedSCarl Huang ath11k_pci_force_wake(ab_pci->ab); 118596527d52SBaochen Qiang 118696527d52SBaochen Qiang ath11k_pci_msi_disable(ab_pci); 118796527d52SBaochen Qiang 11881399fb87SGovind Singh ath11k_mhi_stop(ab_pci); 1189a05bd851SCarl Huang clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 1190babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, false); 11911399fb87SGovind Singh } 11921399fb87SGovind Singh 1193fa5917e4SCarl Huang static int ath11k_pci_hif_suspend(struct ath11k_base *ab) 1194fa5917e4SCarl Huang { 1195fa5917e4SCarl Huang struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); 1196fa5917e4SCarl Huang 1197fa5917e4SCarl Huang ath11k_mhi_suspend(ar_pci); 1198fa5917e4SCarl Huang 1199fa5917e4SCarl Huang return 0; 1200fa5917e4SCarl Huang } 1201fa5917e4SCarl Huang 1202fa5917e4SCarl Huang static int ath11k_pci_hif_resume(struct ath11k_base *ab) 1203fa5917e4SCarl Huang { 1204fa5917e4SCarl Huang struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); 1205fa5917e4SCarl Huang 1206fa5917e4SCarl Huang ath11k_mhi_resume(ar_pci); 1207fa5917e4SCarl Huang 1208fa5917e4SCarl Huang return 0; 1209fa5917e4SCarl Huang } 1210fa5917e4SCarl Huang 12112c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) 12122c3960c2SGovind Singh { 12132c3960c2SGovind Singh int i; 12142c3960c2SGovind Singh 1215d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 12162c3960c2SGovind Singh struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; 12172c3960c2SGovind Singh 1218e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 12192c3960c2SGovind Singh continue; 12202c3960c2SGovind Singh 12212c3960c2SGovind Singh tasklet_kill(&ce_pipe->intr_tq); 12222c3960c2SGovind Singh } 12232c3960c2SGovind Singh } 12242c3960c2SGovind Singh 1225*948171b5SManikanta Pubbisetty void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab) 12267f4beda2SGovind Singh { 12272c3960c2SGovind Singh ath11k_pci_ce_irqs_disable(ab); 12282c3960c2SGovind Singh ath11k_pci_sync_ce_irqs(ab); 12292c3960c2SGovind Singh ath11k_pci_kill_tasklets(ab); 1230d578ec2aSCarl Huang } 1231d578ec2aSCarl Huang 1232*948171b5SManikanta Pubbisetty void ath11k_pci_stop(struct ath11k_base *ab) 1233d578ec2aSCarl Huang { 1234d578ec2aSCarl Huang ath11k_pci_ce_irq_disable_sync(ab); 12357f4beda2SGovind Singh ath11k_ce_cleanup_pipes(ab); 12367f4beda2SGovind Singh } 12377f4beda2SGovind Singh 1238*948171b5SManikanta Pubbisetty int ath11k_pci_start(struct ath11k_base *ab) 12397f4beda2SGovind Singh { 1240a05bd851SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 1241a05bd851SCarl Huang 1242a05bd851SCarl Huang set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 1243a05bd851SCarl Huang 1244915a081fSCarl Huang /* TODO: for now don't restore ASPM in case of single MSI 1245915a081fSCarl Huang * vector as MHI register reading in M2 causes system hang. 1246915a081fSCarl Huang */ 1247915a081fSCarl Huang if (test_bit(ATH11K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags)) 1248e9603f4bSCarl Huang ath11k_pci_aspm_restore(ab_pci); 1249915a081fSCarl Huang else 1250915a081fSCarl Huang ath11k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n"); 1251e9603f4bSCarl Huang 12527f4beda2SGovind Singh ath11k_pci_ce_irqs_enable(ab); 12532c3960c2SGovind Singh ath11k_ce_rx_post_buf(ab); 12542c3960c2SGovind Singh 12552c3960c2SGovind Singh return 0; 12562c3960c2SGovind Singh } 12572c3960c2SGovind Singh 1258d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab) 1259d578ec2aSCarl Huang { 1260d578ec2aSCarl Huang ath11k_pci_ce_irqs_enable(ab); 1261d578ec2aSCarl Huang } 1262d578ec2aSCarl Huang 1263d578ec2aSCarl Huang static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab) 1264d578ec2aSCarl Huang { 1265d578ec2aSCarl Huang ath11k_pci_ce_irq_disable_sync(ab); 1266d578ec2aSCarl Huang } 1267d578ec2aSCarl Huang 1268*948171b5SManikanta Pubbisetty int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, 12692c3960c2SGovind Singh u8 *ul_pipe, u8 *dl_pipe) 12702c3960c2SGovind Singh { 12712c3960c2SGovind Singh const struct service_to_pipe *entry; 12722c3960c2SGovind Singh bool ul_set = false, dl_set = false; 12732c3960c2SGovind Singh int i; 12742c3960c2SGovind Singh 1275967c1d11SAnilkumar Kolli for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) { 1276967c1d11SAnilkumar Kolli entry = &ab->hw_params.svc_to_ce_map[i]; 12772c3960c2SGovind Singh 12782c3960c2SGovind Singh if (__le32_to_cpu(entry->service_id) != service_id) 12792c3960c2SGovind Singh continue; 12802c3960c2SGovind Singh 12812c3960c2SGovind Singh switch (__le32_to_cpu(entry->pipedir)) { 12822c3960c2SGovind Singh case PIPEDIR_NONE: 12832c3960c2SGovind Singh break; 12842c3960c2SGovind Singh case PIPEDIR_IN: 12852c3960c2SGovind Singh WARN_ON(dl_set); 12862c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 12872c3960c2SGovind Singh dl_set = true; 12882c3960c2SGovind Singh break; 12892c3960c2SGovind Singh case PIPEDIR_OUT: 12902c3960c2SGovind Singh WARN_ON(ul_set); 12912c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 12922c3960c2SGovind Singh ul_set = true; 12932c3960c2SGovind Singh break; 12942c3960c2SGovind Singh case PIPEDIR_INOUT: 12952c3960c2SGovind Singh WARN_ON(dl_set); 12962c3960c2SGovind Singh WARN_ON(ul_set); 12972c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 12982c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 12992c3960c2SGovind Singh dl_set = true; 13002c3960c2SGovind Singh ul_set = true; 13012c3960c2SGovind Singh break; 13022c3960c2SGovind Singh } 13032c3960c2SGovind Singh } 13042c3960c2SGovind Singh 13052c3960c2SGovind Singh if (WARN_ON(!ul_set || !dl_set)) 13062c3960c2SGovind Singh return -ENOENT; 13077f4beda2SGovind Singh 13087f4beda2SGovind Singh return 0; 13097f4beda2SGovind Singh } 13107f4beda2SGovind Singh 13117f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = { 13127f4beda2SGovind Singh .start = ath11k_pci_start, 13137f4beda2SGovind Singh .stop = ath11k_pci_stop, 1314654e959aSGovind Singh .read32 = ath11k_pci_read32, 1315654e959aSGovind Singh .write32 = ath11k_pci_write32, 13161399fb87SGovind Singh .power_down = ath11k_pci_power_down, 13171399fb87SGovind Singh .power_up = ath11k_pci_power_up, 1318fa5917e4SCarl Huang .suspend = ath11k_pci_hif_suspend, 1319fa5917e4SCarl Huang .resume = ath11k_pci_hif_resume, 1320d4ecb90bSCarl Huang .irq_enable = ath11k_pci_ext_irq_enable, 1321d4ecb90bSCarl Huang .irq_disable = ath11k_pci_ext_irq_disable, 1322c4eacabeSGovind Singh .get_msi_address = ath11k_pci_get_msi_address, 1323c4eacabeSGovind Singh .get_user_msi_vector = ath11k_get_user_msi_assignment, 13242c3960c2SGovind Singh .map_service_to_pipe = ath11k_pci_map_service_to_pipe, 1325d578ec2aSCarl Huang .ce_irq_enable = ath11k_pci_hif_ce_irq_enable, 1326d578ec2aSCarl Huang .ce_irq_disable = ath11k_pci_hif_ce_irq_disable, 13276289ac2bSKarthikeyan Periyasamy .get_ce_msi_idx = ath11k_pci_get_ce_msi_idx, 13281399fb87SGovind Singh }; 13291399fb87SGovind Singh 13300fbf1957SBaochen Qiang static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor) 13310fbf1957SBaochen Qiang { 13320fbf1957SBaochen Qiang u32 soc_hw_version; 13330fbf1957SBaochen Qiang 13340fbf1957SBaochen Qiang soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION); 13350fbf1957SBaochen Qiang *major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK, 13360fbf1957SBaochen Qiang soc_hw_version); 13370fbf1957SBaochen Qiang *minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK, 13380fbf1957SBaochen Qiang soc_hw_version); 13390fbf1957SBaochen Qiang 13400fbf1957SBaochen Qiang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n", 13410fbf1957SBaochen Qiang *major, *minor); 13420fbf1957SBaochen Qiang } 13430fbf1957SBaochen Qiang 13446e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev, 13456e0355afSGovind Singh const struct pci_device_id *pci_dev) 13466e0355afSGovind Singh { 13476e0355afSGovind Singh struct ath11k_base *ab; 13485762613eSGovind Singh struct ath11k_pci *ab_pci; 13496ac04bdcSAnilkumar Kolli u32 soc_hw_version_major, soc_hw_version_minor, addr; 13505762613eSGovind Singh int ret; 13516e0355afSGovind Singh 13521ff8ed78SGovind Singh ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, 13531ff8ed78SGovind Singh &ath11k_pci_bus_params); 13546e0355afSGovind Singh if (!ab) { 13556e0355afSGovind Singh dev_err(&pdev->dev, "failed to allocate ath11k base\n"); 13566e0355afSGovind Singh return -ENOMEM; 13576e0355afSGovind Singh } 13586e0355afSGovind Singh 13596e0355afSGovind Singh ab->dev = &pdev->dev; 13606e0355afSGovind Singh pci_set_drvdata(pdev, ab); 13615762613eSGovind Singh ab_pci = ath11k_pci_priv(ab); 13625762613eSGovind Singh ab_pci->dev_id = pci_dev->device; 13635762613eSGovind Singh ab_pci->ab = ab; 13645697a564SGovind Singh ab_pci->pdev = pdev; 13657f4beda2SGovind Singh ab->hif.ops = &ath11k_pci_hif_ops; 13665762613eSGovind Singh pci_set_drvdata(pdev, ab); 1367654e959aSGovind Singh spin_lock_init(&ab_pci->window_lock); 13685762613eSGovind Singh 13696ac04bdcSAnilkumar Kolli /* Set fixed_mem_region to true for platforms support reserved memory 13706ac04bdcSAnilkumar Kolli * from DT. If memory is reserved from DT for FW, ath11k driver need not 13716ac04bdcSAnilkumar Kolli * allocate memory. 13726ac04bdcSAnilkumar Kolli */ 13736ac04bdcSAnilkumar Kolli ret = of_property_read_u32(ab->dev->of_node, "memory-region", &addr); 13746ac04bdcSAnilkumar Kolli if (!ret) 13756ac04bdcSAnilkumar Kolli set_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags); 13766ac04bdcSAnilkumar Kolli 13775762613eSGovind Singh ret = ath11k_pci_claim(ab_pci, pdev); 13785762613eSGovind Singh if (ret) { 13795762613eSGovind Singh ath11k_err(ab, "failed to claim device: %d\n", ret); 13805762613eSGovind Singh goto err_free_core; 13815762613eSGovind Singh } 13826e0355afSGovind Singh 1383fc95d10aSWen Gong ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n", 1384fc95d10aSWen Gong pdev->vendor, pdev->device, 1385fc95d10aSWen Gong pdev->subsystem_vendor, pdev->subsystem_device); 1386fc95d10aSWen Gong 1387fc95d10aSWen Gong ab->id.vendor = pdev->vendor; 1388fc95d10aSWen Gong ab->id.device = pdev->device; 1389fc95d10aSWen Gong ab->id.subsystem_vendor = pdev->subsystem_vendor; 1390fc95d10aSWen Gong ab->id.subsystem_device = pdev->subsystem_device; 1391fc95d10aSWen Gong 139218ac1665SKalle Valo switch (pci_dev->device) { 139318ac1665SKalle Valo case QCA6390_DEVICE_ID: 13940fbf1957SBaochen Qiang ath11k_pci_read_hw_version(ab, &soc_hw_version_major, 13950fbf1957SBaochen Qiang &soc_hw_version_minor); 139618ac1665SKalle Valo switch (soc_hw_version_major) { 139718ac1665SKalle Valo case 2: 139818ac1665SKalle Valo ab->hw_rev = ATH11K_HW_QCA6390_HW20; 139918ac1665SKalle Valo break; 140018ac1665SKalle Valo default: 140118ac1665SKalle Valo dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n", 140218ac1665SKalle Valo soc_hw_version_major, soc_hw_version_minor); 140318ac1665SKalle Valo ret = -EOPNOTSUPP; 140418ac1665SKalle Valo goto err_pci_free_region; 140518ac1665SKalle Valo } 14064e809461SAnilkumar Kolli ab_pci->msi_config = &ath11k_msi_config[0]; 14074e809461SAnilkumar Kolli break; 14084e809461SAnilkumar Kolli case QCN9074_DEVICE_ID: 14094e809461SAnilkumar Kolli ab_pci->msi_config = &ath11k_msi_config[1]; 14104e809461SAnilkumar Kolli ab->bus_params.static_window_map = true; 14114e809461SAnilkumar Kolli ab->hw_rev = ATH11K_HW_QCN9074_HW10; 141218ac1665SKalle Valo break; 14130fbf1957SBaochen Qiang case WCN6855_DEVICE_ID: 1414fc95d10aSWen Gong ab->id.bdf_search = ATH11K_BDF_SEARCH_BUS_AND_BOARD; 14150fbf1957SBaochen Qiang ath11k_pci_read_hw_version(ab, &soc_hw_version_major, 14160fbf1957SBaochen Qiang &soc_hw_version_minor); 14170fbf1957SBaochen Qiang switch (soc_hw_version_major) { 14180fbf1957SBaochen Qiang case 2: 1419d1147a31SBaochen Qiang switch (soc_hw_version_minor) { 1420d1147a31SBaochen Qiang case 0x00: 1421d1147a31SBaochen Qiang case 0x01: 14220fbf1957SBaochen Qiang ab->hw_rev = ATH11K_HW_WCN6855_HW20; 14230fbf1957SBaochen Qiang break; 1424d1147a31SBaochen Qiang case 0x10: 1425d1147a31SBaochen Qiang case 0x11: 1426d1147a31SBaochen Qiang ab->hw_rev = ATH11K_HW_WCN6855_HW21; 1427d1147a31SBaochen Qiang break; 14280fbf1957SBaochen Qiang default: 1429d1147a31SBaochen Qiang goto unsupported_wcn6855_soc; 1430d1147a31SBaochen Qiang } 1431d1147a31SBaochen Qiang break; 1432d1147a31SBaochen Qiang default: 1433d1147a31SBaochen Qiang unsupported_wcn6855_soc: 14340fbf1957SBaochen Qiang dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n", 14350fbf1957SBaochen Qiang soc_hw_version_major, soc_hw_version_minor); 14360fbf1957SBaochen Qiang ret = -EOPNOTSUPP; 14370fbf1957SBaochen Qiang goto err_pci_free_region; 14380fbf1957SBaochen Qiang } 14390fbf1957SBaochen Qiang ab_pci->msi_config = &ath11k_msi_config[0]; 14400fbf1957SBaochen Qiang break; 144118ac1665SKalle Valo default: 144218ac1665SKalle Valo dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", 144318ac1665SKalle Valo pci_dev->device); 144418ac1665SKalle Valo ret = -EOPNOTSUPP; 144518ac1665SKalle Valo goto err_pci_free_region; 144618ac1665SKalle Valo } 144718ac1665SKalle Valo 144896527d52SBaochen Qiang ret = ath11k_pci_alloc_msi(ab_pci); 14495697a564SGovind Singh if (ret) { 14505697a564SGovind Singh ath11k_err(ab, "failed to enable msi: %d\n", ret); 14515697a564SGovind Singh goto err_pci_free_region; 14525697a564SGovind Singh } 14535697a564SGovind Singh 1454b8246f88SKalle Valo ret = ath11k_core_pre_init(ab); 1455b8246f88SKalle Valo if (ret) 1456b8246f88SKalle Valo goto err_pci_disable_msi; 1457b8246f88SKalle Valo 14581399fb87SGovind Singh ret = ath11k_mhi_register(ab_pci); 14591399fb87SGovind Singh if (ret) { 14601399fb87SGovind Singh ath11k_err(ab, "failed to register mhi: %d\n", ret); 14611399fb87SGovind Singh goto err_pci_disable_msi; 14621399fb87SGovind Singh } 14631399fb87SGovind Singh 14647f4beda2SGovind Singh ret = ath11k_hal_srng_init(ab); 14657f4beda2SGovind Singh if (ret) 14667f4beda2SGovind Singh goto err_mhi_unregister; 14677f4beda2SGovind Singh 14687f4beda2SGovind Singh ret = ath11k_ce_alloc_pipes(ab); 14697f4beda2SGovind Singh if (ret) { 14707f4beda2SGovind Singh ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret); 14717f4beda2SGovind Singh goto err_hal_srng_deinit; 14727f4beda2SGovind Singh } 14737f4beda2SGovind Singh 14747f4beda2SGovind Singh ath11k_pci_init_qmi_ce_config(ab); 14757f4beda2SGovind Singh 14767f4beda2SGovind Singh ret = ath11k_pci_config_irq(ab); 14777f4beda2SGovind Singh if (ret) { 14787f4beda2SGovind Singh ath11k_err(ab, "failed to config irq: %d\n", ret); 14797f4beda2SGovind Singh goto err_ce_free; 14807f4beda2SGovind Singh } 14817f4beda2SGovind Singh 148287b4072dSCarl Huang /* kernel may allocate a dummy vector before request_irq and 148387b4072dSCarl Huang * then allocate a real vector when request_irq is called. 148487b4072dSCarl Huang * So get msi_data here again to avoid spurious interrupt 148587b4072dSCarl Huang * as msi_data will configured to srngs. 148687b4072dSCarl Huang */ 148787b4072dSCarl Huang ret = ath11k_pci_config_msi_data(ab_pci); 148887b4072dSCarl Huang if (ret) { 148987b4072dSCarl Huang ath11k_err(ab, "failed to config msi_data: %d\n", ret); 149087b4072dSCarl Huang goto err_free_irq; 149187b4072dSCarl Huang } 149287b4072dSCarl Huang 14937f4beda2SGovind Singh ret = ath11k_core_init(ab); 14947f4beda2SGovind Singh if (ret) { 14957f4beda2SGovind Singh ath11k_err(ab, "failed to init core: %d\n", ret); 14967f4beda2SGovind Singh goto err_free_irq; 14977f4beda2SGovind Singh } 14986e0355afSGovind Singh return 0; 14995762613eSGovind Singh 15007f4beda2SGovind Singh err_free_irq: 15017f4beda2SGovind Singh ath11k_pci_free_irq(ab); 15027f4beda2SGovind Singh 15037f4beda2SGovind Singh err_ce_free: 15047f4beda2SGovind Singh ath11k_ce_free_pipes(ab); 15057f4beda2SGovind Singh 15067f4beda2SGovind Singh err_hal_srng_deinit: 15077f4beda2SGovind Singh ath11k_hal_srng_deinit(ab); 15087f4beda2SGovind Singh 15097f4beda2SGovind Singh err_mhi_unregister: 15107f4beda2SGovind Singh ath11k_mhi_unregister(ab_pci); 15117f4beda2SGovind Singh 1512b8246f88SKalle Valo err_pci_disable_msi: 151396527d52SBaochen Qiang ath11k_pci_free_msi(ab_pci); 1514b8246f88SKalle Valo 15155697a564SGovind Singh err_pci_free_region: 15165697a564SGovind Singh ath11k_pci_free_region(ab_pci); 15175697a564SGovind Singh 15185762613eSGovind Singh err_free_core: 15195762613eSGovind Singh ath11k_core_free(ab); 15205697a564SGovind Singh 15215762613eSGovind Singh return ret; 15226e0355afSGovind Singh } 15236e0355afSGovind Singh 15246e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev) 15256e0355afSGovind Singh { 15266e0355afSGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 15275762613eSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 15286e0355afSGovind Singh 1529e94b0749SBaochen Qiang ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); 1530e94b0749SBaochen Qiang 153161a57e51SAnilkumar Kolli if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { 153261a57e51SAnilkumar Kolli ath11k_pci_power_down(ab); 153361a57e51SAnilkumar Kolli ath11k_debugfs_soc_destroy(ab); 153461a57e51SAnilkumar Kolli ath11k_qmi_deinit_service(ab); 153561a57e51SAnilkumar Kolli goto qmi_fail; 153661a57e51SAnilkumar Kolli } 153761a57e51SAnilkumar Kolli 15386e0355afSGovind Singh set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); 15396fbd8898SCarl Huang 15406fbd8898SCarl Huang ath11k_core_deinit(ab); 15416fbd8898SCarl Huang 154261a57e51SAnilkumar Kolli qmi_fail: 15431399fb87SGovind Singh ath11k_mhi_unregister(ab_pci); 15446fbd8898SCarl Huang 15456fbd8898SCarl Huang ath11k_pci_free_irq(ab); 154696527d52SBaochen Qiang ath11k_pci_free_msi(ab_pci); 15475762613eSGovind Singh ath11k_pci_free_region(ab_pci); 15486fbd8898SCarl Huang 15496fbd8898SCarl Huang ath11k_hal_srng_deinit(ab); 15506fbd8898SCarl Huang ath11k_ce_free_pipes(ab); 15516e0355afSGovind Singh ath11k_core_free(ab); 15526e0355afSGovind Singh } 15536e0355afSGovind Singh 15541399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev) 15551399fb87SGovind Singh { 15561399fb87SGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 15571399fb87SGovind Singh 15581399fb87SGovind Singh ath11k_pci_power_down(ab); 15591399fb87SGovind Singh } 15601399fb87SGovind Singh 1561d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev) 1562d1b0c338SCarl Huang { 1563d1b0c338SCarl Huang struct ath11k_base *ab = dev_get_drvdata(dev); 1564d1b0c338SCarl Huang int ret; 1565d1b0c338SCarl Huang 1566b4f4c564SKalle Valo if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { 1567b4f4c564SKalle Valo ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci suspend as qmi is not initialised\n"); 1568b4f4c564SKalle Valo return 0; 1569b4f4c564SKalle Valo } 1570b4f4c564SKalle Valo 1571d1b0c338SCarl Huang ret = ath11k_core_suspend(ab); 1572d1b0c338SCarl Huang if (ret) 1573d1b0c338SCarl Huang ath11k_warn(ab, "failed to suspend core: %d\n", ret); 1574d1b0c338SCarl Huang 1575d1b0c338SCarl Huang return ret; 1576d1b0c338SCarl Huang } 1577d1b0c338SCarl Huang 1578d1b0c338SCarl Huang static __maybe_unused int ath11k_pci_pm_resume(struct device *dev) 1579d1b0c338SCarl Huang { 1580d1b0c338SCarl Huang struct ath11k_base *ab = dev_get_drvdata(dev); 1581d1b0c338SCarl Huang int ret; 1582d1b0c338SCarl Huang 1583b4f4c564SKalle Valo if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { 1584b4f4c564SKalle Valo ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot skipping pci resume as qmi is not initialised\n"); 1585b4f4c564SKalle Valo return 0; 1586b4f4c564SKalle Valo } 1587b4f4c564SKalle Valo 1588d1b0c338SCarl Huang ret = ath11k_core_resume(ab); 1589d1b0c338SCarl Huang if (ret) 1590d1b0c338SCarl Huang ath11k_warn(ab, "failed to resume core: %d\n", ret); 1591d1b0c338SCarl Huang 1592d1b0c338SCarl Huang return ret; 1593d1b0c338SCarl Huang } 1594d1b0c338SCarl Huang 1595d1b0c338SCarl Huang static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops, 1596d1b0c338SCarl Huang ath11k_pci_pm_suspend, 1597d1b0c338SCarl Huang ath11k_pci_pm_resume); 1598d1b0c338SCarl Huang 15996e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = { 16006e0355afSGovind Singh .name = "ath11k_pci", 16016e0355afSGovind Singh .id_table = ath11k_pci_id_table, 16026e0355afSGovind Singh .probe = ath11k_pci_probe, 16036e0355afSGovind Singh .remove = ath11k_pci_remove, 16041399fb87SGovind Singh .shutdown = ath11k_pci_shutdown, 1605d1b0c338SCarl Huang #ifdef CONFIG_PM 1606d1b0c338SCarl Huang .driver.pm = &ath11k_pci_pm_ops, 1607d1b0c338SCarl Huang #endif 16086e0355afSGovind Singh }; 16096e0355afSGovind Singh 16106e0355afSGovind Singh static int ath11k_pci_init(void) 16116e0355afSGovind Singh { 16126e0355afSGovind Singh int ret; 16136e0355afSGovind Singh 16146e0355afSGovind Singh ret = pci_register_driver(&ath11k_pci_driver); 16156e0355afSGovind Singh if (ret) 16166e0355afSGovind Singh pr_err("failed to register ath11k pci driver: %d\n", 16176e0355afSGovind Singh ret); 16186e0355afSGovind Singh 16196e0355afSGovind Singh return ret; 16206e0355afSGovind Singh } 16216e0355afSGovind Singh module_init(ath11k_pci_init); 16226e0355afSGovind Singh 16236e0355afSGovind Singh static void ath11k_pci_exit(void) 16246e0355afSGovind Singh { 16256e0355afSGovind Singh pci_unregister_driver(&ath11k_pci_driver); 16266e0355afSGovind Singh } 16276e0355afSGovind Singh 16286e0355afSGovind Singh module_exit(ath11k_pci_exit); 16296e0355afSGovind Singh 16306e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); 16316e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL"); 16323dbd7fe7SDevin Bayer 16333dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */ 16343dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE); 16353dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE); 16363dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE); 1637