16e0355afSGovind Singh // SPDX-License-Identifier: BSD-3-Clause-Clear 26e0355afSGovind Singh /* 36e0355afSGovind Singh * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. 46e0355afSGovind Singh */ 56e0355afSGovind Singh 66e0355afSGovind Singh #include <linux/module.h> 75697a564SGovind Singh #include <linux/msi.h> 86e0355afSGovind Singh #include <linux/pci.h> 96e0355afSGovind Singh 105762613eSGovind Singh #include "pci.h" 116e0355afSGovind Singh #include "core.h" 121399fb87SGovind Singh #include "hif.h" 131399fb87SGovind Singh #include "mhi.h" 146e0355afSGovind Singh #include "debug.h" 156e0355afSGovind Singh 165762613eSGovind Singh #define ATH11K_PCI_BAR_NUM 0 175762613eSGovind Singh #define ATH11K_PCI_DMA_MASK 32 185762613eSGovind Singh 197f4beda2SGovind Singh #define ATH11K_PCI_IRQ_CE0_OFFSET 3 207f4beda2SGovind Singh 21654e959aSGovind Singh #define WINDOW_ENABLE_BIT 0x40000000 22654e959aSGovind Singh #define WINDOW_REG_ADDRESS 0x310c 23654e959aSGovind Singh #define WINDOW_VALUE_MASK GENMASK(24, 19) 24654e959aSGovind Singh #define WINDOW_START 0x80000 25654e959aSGovind Singh #define WINDOW_RANGE_MASK GENMASK(18, 0) 26654e959aSGovind Singh 2718ac1665SKalle Valo #define TCSR_SOC_HW_VERSION 0x0224 2818ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(16, 8) 2918ac1665SKalle Valo #define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 0) 3018ac1665SKalle Valo 31a05bd851SCarl Huang /* BAR0 + 4k is always accessible, and no 32a05bd851SCarl Huang * need to force wakeup. 33a05bd851SCarl Huang * 4K - 32 = 0xFE0 34a05bd851SCarl Huang */ 35a05bd851SCarl Huang #define ACCESS_ALWAYS_OFF 0xFE0 36a05bd851SCarl Huang 376e0355afSGovind Singh #define QCA6390_DEVICE_ID 0x1101 386e0355afSGovind Singh 396e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = { 406e0355afSGovind Singh { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, 416e0355afSGovind Singh {0} 426e0355afSGovind Singh }; 436e0355afSGovind Singh 446e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); 456e0355afSGovind Singh 461ff8ed78SGovind Singh static const struct ath11k_bus_params ath11k_pci_bus_params = { 471ff8ed78SGovind Singh .mhi_support = true, 4856970454SGovind Singh .m3_fw_support = true, 496eb6ea51SGovind Singh .fixed_bdf_addr = false, 506eb6ea51SGovind Singh .fixed_mem_region = false, 511ff8ed78SGovind Singh }; 521ff8ed78SGovind Singh 535697a564SGovind Singh static const struct ath11k_msi_config msi_config = { 545697a564SGovind Singh .total_vectors = 32, 555697a564SGovind Singh .total_users = 4, 565697a564SGovind Singh .users = (struct ath11k_msi_user[]) { 575697a564SGovind Singh { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 585697a564SGovind Singh { .name = "CE", .num_vectors = 10, .base_vector = 3 }, 595697a564SGovind Singh { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, 605697a564SGovind Singh { .name = "DP", .num_vectors = 18, .base_vector = 14 }, 615697a564SGovind Singh }, 625697a564SGovind Singh }; 635697a564SGovind Singh 647f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { 657f4beda2SGovind Singh "bhi", 667f4beda2SGovind Singh "mhi-er0", 677f4beda2SGovind Singh "mhi-er1", 687f4beda2SGovind Singh "ce0", 697f4beda2SGovind Singh "ce1", 707f4beda2SGovind Singh "ce2", 717f4beda2SGovind Singh "ce3", 727f4beda2SGovind Singh "ce4", 737f4beda2SGovind Singh "ce5", 747f4beda2SGovind Singh "ce6", 757f4beda2SGovind Singh "ce7", 767f4beda2SGovind Singh "ce8", 777f4beda2SGovind Singh "ce9", 787f4beda2SGovind Singh "ce10", 797f4beda2SGovind Singh "ce11", 807f4beda2SGovind Singh "host2wbm-desc-feed", 817f4beda2SGovind Singh "host2reo-re-injection", 827f4beda2SGovind Singh "host2reo-command", 837f4beda2SGovind Singh "host2rxdma-monitor-ring3", 847f4beda2SGovind Singh "host2rxdma-monitor-ring2", 857f4beda2SGovind Singh "host2rxdma-monitor-ring1", 867f4beda2SGovind Singh "reo2ost-exception", 877f4beda2SGovind Singh "wbm2host-rx-release", 887f4beda2SGovind Singh "reo2host-status", 897f4beda2SGovind Singh "reo2host-destination-ring4", 907f4beda2SGovind Singh "reo2host-destination-ring3", 917f4beda2SGovind Singh "reo2host-destination-ring2", 927f4beda2SGovind Singh "reo2host-destination-ring1", 937f4beda2SGovind Singh "rxdma2host-monitor-destination-mac3", 947f4beda2SGovind Singh "rxdma2host-monitor-destination-mac2", 957f4beda2SGovind Singh "rxdma2host-monitor-destination-mac1", 967f4beda2SGovind Singh "ppdu-end-interrupts-mac3", 977f4beda2SGovind Singh "ppdu-end-interrupts-mac2", 987f4beda2SGovind Singh "ppdu-end-interrupts-mac1", 997f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac3", 1007f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac2", 1017f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac1", 1027f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac3", 1037f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac2", 1047f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac1", 1057f4beda2SGovind Singh "rxdma2host-destination-ring-mac3", 1067f4beda2SGovind Singh "rxdma2host-destination-ring-mac2", 1077f4beda2SGovind Singh "rxdma2host-destination-ring-mac1", 1087f4beda2SGovind Singh "host2tcl-input-ring4", 1097f4beda2SGovind Singh "host2tcl-input-ring3", 1107f4beda2SGovind Singh "host2tcl-input-ring2", 1117f4beda2SGovind Singh "host2tcl-input-ring1", 1127f4beda2SGovind Singh "wbm2host-tx-completions-ring3", 1137f4beda2SGovind Singh "wbm2host-tx-completions-ring2", 1147f4beda2SGovind Singh "wbm2host-tx-completions-ring1", 1157f4beda2SGovind Singh "tcl2host-status-ring", 1167f4beda2SGovind Singh }; 1177f4beda2SGovind Singh 118654e959aSGovind Singh static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offset) 119654e959aSGovind Singh { 120654e959aSGovind Singh struct ath11k_base *ab = ab_pci->ab; 121654e959aSGovind Singh 122654e959aSGovind Singh u32 window = FIELD_GET(WINDOW_VALUE_MASK, offset); 123654e959aSGovind Singh 124654e959aSGovind Singh lockdep_assert_held(&ab_pci->window_lock); 125654e959aSGovind Singh 126654e959aSGovind Singh if (window != ab_pci->register_window) { 127654e959aSGovind Singh iowrite32(WINDOW_ENABLE_BIT | window, 128654e959aSGovind Singh ab->mem + WINDOW_REG_ADDRESS); 129654e959aSGovind Singh ab_pci->register_window = window; 130654e959aSGovind Singh } 131654e959aSGovind Singh } 132654e959aSGovind Singh 133f3c603d4SCarl Huang void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) 134654e959aSGovind Singh { 135654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 136654e959aSGovind Singh 137a05bd851SCarl Huang /* for offset beyond BAR + 4K - 32, may 138a05bd851SCarl Huang * need to wakeup MHI to access. 139a05bd851SCarl Huang */ 140a05bd851SCarl Huang if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 141a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 142a05bd851SCarl Huang mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); 143a05bd851SCarl Huang 144654e959aSGovind Singh if (offset < WINDOW_START) { 145654e959aSGovind Singh iowrite32(value, ab->mem + offset); 146654e959aSGovind Singh } else { 147654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 148654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 149654e959aSGovind Singh iowrite32(value, ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK)); 150654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 151654e959aSGovind Singh } 152a05bd851SCarl Huang 153a05bd851SCarl Huang if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 154a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 155a05bd851SCarl Huang mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); 156654e959aSGovind Singh } 157654e959aSGovind Singh 158f3c603d4SCarl Huang u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) 159654e959aSGovind Singh { 160654e959aSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 161654e959aSGovind Singh u32 val; 162654e959aSGovind Singh 163a05bd851SCarl Huang /* for offset beyond BAR + 4K - 32, may 164a05bd851SCarl Huang * need to wakeup MHI to access. 165a05bd851SCarl Huang */ 166a05bd851SCarl Huang if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 167a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 168a05bd851SCarl Huang mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); 169a05bd851SCarl Huang 170654e959aSGovind Singh if (offset < WINDOW_START) { 171654e959aSGovind Singh val = ioread32(ab->mem + offset); 172654e959aSGovind Singh } else { 173654e959aSGovind Singh spin_lock_bh(&ab_pci->window_lock); 174654e959aSGovind Singh ath11k_pci_select_window(ab_pci, offset); 175654e959aSGovind Singh val = ioread32(ab->mem + WINDOW_START + (offset & WINDOW_RANGE_MASK)); 176654e959aSGovind Singh spin_unlock_bh(&ab_pci->window_lock); 177654e959aSGovind Singh } 178654e959aSGovind Singh 179a05bd851SCarl Huang if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && 180a05bd851SCarl Huang offset >= ACCESS_ALWAYS_OFF) 181a05bd851SCarl Huang mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); 182a05bd851SCarl Huang 183654e959aSGovind Singh return val; 184654e959aSGovind Singh } 185654e959aSGovind Singh 186f3c603d4SCarl Huang static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) 187f3c603d4SCarl Huang { 188f3c603d4SCarl Huang u32 val, delay; 189f3c603d4SCarl Huang 190f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 191f3c603d4SCarl Huang 192f3c603d4SCarl Huang val |= PCIE_SOC_GLOBAL_RESET_V; 193f3c603d4SCarl Huang 194f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 195f3c603d4SCarl Huang 196f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 197f3c603d4SCarl Huang delay = 10; 198f3c603d4SCarl Huang mdelay(delay); 199f3c603d4SCarl Huang 200f3c603d4SCarl Huang /* Need to toggle V bit back otherwise stuck in reset status */ 201f3c603d4SCarl Huang val &= ~PCIE_SOC_GLOBAL_RESET_V; 202f3c603d4SCarl Huang 203f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val); 204f3c603d4SCarl Huang 205f3c603d4SCarl Huang mdelay(delay); 206f3c603d4SCarl Huang 207f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET); 208f3c603d4SCarl Huang if (val == 0xffffffff) 209f3c603d4SCarl Huang ath11k_warn(ab, "link down error during global reset\n"); 210f3c603d4SCarl Huang } 211f3c603d4SCarl Huang 212f3c603d4SCarl Huang static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) 213f3c603d4SCarl Huang { 214f3c603d4SCarl Huang u32 val; 215f3c603d4SCarl Huang 216f3c603d4SCarl Huang /* read cookie */ 217f3c603d4SCarl Huang val = ath11k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR); 218f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val); 219f3c603d4SCarl Huang 220f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 221f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 222f3c603d4SCarl Huang 223f3c603d4SCarl Huang /* TODO: exact time to sleep is uncertain */ 224f3c603d4SCarl Huang mdelay(10); 225f3c603d4SCarl Huang 226f3c603d4SCarl Huang /* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from 227f3c603d4SCarl Huang * continuing warm path and entering dead loop. 228f3c603d4SCarl Huang */ 229f3c603d4SCarl Huang ath11k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0); 230f3c603d4SCarl Huang mdelay(10); 231f3c603d4SCarl Huang 232f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_WARM_SW_ENTRY); 233f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); 234f3c603d4SCarl Huang 235f3c603d4SCarl Huang /* A read clear register. clear the register to prevent 236f3c603d4SCarl Huang * Q6 from entering wrong code path. 237f3c603d4SCarl Huang */ 238f3c603d4SCarl Huang val = ath11k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG); 239f3c603d4SCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val); 240f3c603d4SCarl Huang } 241f3c603d4SCarl Huang 242*06999407SCarl Huang static int ath11k_pci_set_link_reg(struct ath11k_base *ab, 243*06999407SCarl Huang u32 offset, u32 value, u32 mask) 244*06999407SCarl Huang { 245*06999407SCarl Huang u32 v; 246*06999407SCarl Huang int i; 247*06999407SCarl Huang 248*06999407SCarl Huang v = ath11k_pci_read32(ab, offset); 249*06999407SCarl Huang if ((v & mask) == value) 250*06999407SCarl Huang return 0; 251*06999407SCarl Huang 252*06999407SCarl Huang for (i = 0; i < 10; i++) { 253*06999407SCarl Huang ath11k_pci_write32(ab, offset, (v & ~mask) | value); 254*06999407SCarl Huang 255*06999407SCarl Huang v = ath11k_pci_read32(ab, offset); 256*06999407SCarl Huang if ((v & mask) == value) 257*06999407SCarl Huang return 0; 258*06999407SCarl Huang 259*06999407SCarl Huang mdelay(2); 260*06999407SCarl Huang } 261*06999407SCarl Huang 262*06999407SCarl Huang ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n", 263*06999407SCarl Huang offset, v & mask, value); 264*06999407SCarl Huang 265*06999407SCarl Huang return -ETIMEDOUT; 266*06999407SCarl Huang } 267*06999407SCarl Huang 268*06999407SCarl Huang static int ath11k_pci_fix_l1ss(struct ath11k_base *ab) 269*06999407SCarl Huang { 270*06999407SCarl Huang int ret; 271*06999407SCarl Huang 272*06999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 273*06999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG, 274*06999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL, 275*06999407SCarl Huang PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK); 276*06999407SCarl Huang if (!ret) { 277*06999407SCarl Huang ath11k_warn(ab, "failed to set sysclk: %d\n", ret); 278*06999407SCarl Huang return ret; 279*06999407SCarl Huang } 280*06999407SCarl Huang 281*06999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 282*06999407SCarl Huang PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_REG, 283*06999407SCarl Huang PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_VAL, 284*06999407SCarl Huang PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK); 285*06999407SCarl Huang if (!ret) { 286*06999407SCarl Huang ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret); 287*06999407SCarl Huang return ret; 288*06999407SCarl Huang } 289*06999407SCarl Huang 290*06999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 291*06999407SCarl Huang PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_REG, 292*06999407SCarl Huang PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_VAL, 293*06999407SCarl Huang PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK); 294*06999407SCarl Huang if (!ret) { 295*06999407SCarl Huang ath11k_warn(ab, "failed to set dtct config2: %d\n", ret); 296*06999407SCarl Huang return ret; 297*06999407SCarl Huang } 298*06999407SCarl Huang 299*06999407SCarl Huang ret = ath11k_pci_set_link_reg(ab, 300*06999407SCarl Huang PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_REG, 301*06999407SCarl Huang PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_VAL, 302*06999407SCarl Huang PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK); 303*06999407SCarl Huang if (!ret) { 304*06999407SCarl Huang ath11k_warn(ab, "failed to set dtct config4: %d\n", ret); 305*06999407SCarl Huang return ret; 306*06999407SCarl Huang } 307*06999407SCarl Huang 308*06999407SCarl Huang return 0; 309*06999407SCarl Huang } 310*06999407SCarl Huang 311babb0cedSCarl Huang static void ath11k_pci_enable_ltssm(struct ath11k_base *ab) 312babb0cedSCarl Huang { 313babb0cedSCarl Huang u32 val; 314babb0cedSCarl Huang int i; 315babb0cedSCarl Huang 316babb0cedSCarl Huang val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); 317babb0cedSCarl Huang 318babb0cedSCarl Huang /* PCIE link seems very unstable after the Hot Reset*/ 319babb0cedSCarl Huang for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) { 320babb0cedSCarl Huang if (val == 0xffffffff) 321babb0cedSCarl Huang mdelay(5); 322babb0cedSCarl Huang 323babb0cedSCarl Huang ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE); 324babb0cedSCarl Huang val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); 325babb0cedSCarl Huang } 326babb0cedSCarl Huang 327babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val); 328babb0cedSCarl Huang 329babb0cedSCarl Huang val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); 330babb0cedSCarl Huang val |= GCC_GCC_PCIE_HOT_RST_VAL | 0x10; 331babb0cedSCarl Huang ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val); 332babb0cedSCarl Huang val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); 333babb0cedSCarl Huang 334babb0cedSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val); 335babb0cedSCarl Huang 336babb0cedSCarl Huang mdelay(5); 337babb0cedSCarl Huang } 338babb0cedSCarl Huang 339babb0cedSCarl Huang static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab) 340babb0cedSCarl Huang { 341babb0cedSCarl Huang /* This is a WAR for PCIE Hotreset. 342babb0cedSCarl Huang * When target receive Hotreset, but will set the interrupt. 343babb0cedSCarl Huang * So when download SBL again, SBL will open Interrupt and 344babb0cedSCarl Huang * receive it, and crash immediately. 345babb0cedSCarl Huang */ 346babb0cedSCarl Huang ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL); 347babb0cedSCarl Huang } 348babb0cedSCarl Huang 349f3c603d4SCarl Huang static void ath11k_pci_force_wake(struct ath11k_base *ab) 350f3c603d4SCarl Huang { 351f3c603d4SCarl Huang ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1); 352f3c603d4SCarl Huang mdelay(5); 353f3c603d4SCarl Huang } 354f3c603d4SCarl Huang 355babb0cedSCarl Huang static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on) 356f3c603d4SCarl Huang { 357babb0cedSCarl Huang if (power_on) { 358babb0cedSCarl Huang ath11k_pci_enable_ltssm(ab); 359babb0cedSCarl Huang ath11k_pci_clear_all_intrs(ab); 360*06999407SCarl Huang ath11k_pci_fix_l1ss(ab); 361babb0cedSCarl Huang } 362babb0cedSCarl Huang 363f3c603d4SCarl Huang ath11k_mhi_clear_vector(ab); 364f3c603d4SCarl Huang ath11k_pci_soc_global_reset(ab); 365f3c603d4SCarl Huang ath11k_mhi_set_mhictrl_reset(ab); 366f3c603d4SCarl Huang ath11k_pci_clear_dbg_registers(ab); 367f3c603d4SCarl Huang } 368f3c603d4SCarl Huang 3691399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) 3701399fb87SGovind Singh { 3711399fb87SGovind Singh struct pci_dev *pci_dev = to_pci_dev(dev); 3721399fb87SGovind Singh 3731399fb87SGovind Singh return pci_irq_vector(pci_dev, vector); 3741399fb87SGovind Singh } 3751399fb87SGovind Singh 376c4eacabeSGovind Singh static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, 377c4eacabeSGovind Singh u32 *msi_addr_hi) 378c4eacabeSGovind Singh { 379e8e55d89SAnilkumar Kolli struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 380c4eacabeSGovind Singh struct pci_dev *pci_dev = to_pci_dev(ab->dev); 381c4eacabeSGovind Singh 382c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, 383c4eacabeSGovind Singh msi_addr_lo); 384c4eacabeSGovind Singh 385e8e55d89SAnilkumar Kolli if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) { 386c4eacabeSGovind Singh pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, 387c4eacabeSGovind Singh msi_addr_hi); 388e8e55d89SAnilkumar Kolli } else { 389e8e55d89SAnilkumar Kolli *msi_addr_hi = 0; 390e8e55d89SAnilkumar Kolli } 391c4eacabeSGovind Singh } 392c4eacabeSGovind Singh 3931399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, 3941399fb87SGovind Singh int *num_vectors, u32 *user_base_data, 3951399fb87SGovind Singh u32 *base_vector) 3961399fb87SGovind Singh { 3971399fb87SGovind Singh struct ath11k_base *ab = ab_pci->ab; 3981399fb87SGovind Singh int idx; 3991399fb87SGovind Singh 4001399fb87SGovind Singh for (idx = 0; idx < msi_config.total_users; idx++) { 4011399fb87SGovind Singh if (strcmp(user_name, msi_config.users[idx].name) == 0) { 4021399fb87SGovind Singh *num_vectors = msi_config.users[idx].num_vectors; 4031399fb87SGovind Singh *user_base_data = msi_config.users[idx].base_vector 4041399fb87SGovind Singh + ab_pci->msi_ep_base_data; 4051399fb87SGovind Singh *base_vector = msi_config.users[idx].base_vector; 4061399fb87SGovind Singh 4071399fb87SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", 4081399fb87SGovind Singh user_name, *num_vectors, *user_base_data, 4091399fb87SGovind Singh *base_vector); 4101399fb87SGovind Singh 4111399fb87SGovind Singh return 0; 4121399fb87SGovind Singh } 4131399fb87SGovind Singh } 4141399fb87SGovind Singh 4151399fb87SGovind Singh ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name); 4161399fb87SGovind Singh 4171399fb87SGovind Singh return -EINVAL; 4181399fb87SGovind Singh } 4191399fb87SGovind Singh 420c4eacabeSGovind Singh static int ath11k_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, 421c4eacabeSGovind Singh int *num_vectors, u32 *user_base_data, 422c4eacabeSGovind Singh u32 *base_vector) 423c4eacabeSGovind Singh { 424c4eacabeSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 425c4eacabeSGovind Singh 426c4eacabeSGovind Singh return ath11k_pci_get_user_msi_assignment(ab_pci, user_name, 427c4eacabeSGovind Singh num_vectors, user_base_data, 428c4eacabeSGovind Singh base_vector); 429c4eacabeSGovind Singh } 430c4eacabeSGovind Singh 431d4ecb90bSCarl Huang static void ath11k_pci_free_ext_irq(struct ath11k_base *ab) 432d4ecb90bSCarl Huang { 433d4ecb90bSCarl Huang int i, j; 434d4ecb90bSCarl Huang 435d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 436d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 437d4ecb90bSCarl Huang 438d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) 439d4ecb90bSCarl Huang free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); 440d4ecb90bSCarl Huang 441d4ecb90bSCarl Huang netif_napi_del(&irq_grp->napi); 442d4ecb90bSCarl Huang } 443d4ecb90bSCarl Huang } 444d4ecb90bSCarl Huang 4457f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab) 4467f4beda2SGovind Singh { 4477f4beda2SGovind Singh int i, irq_idx; 4487f4beda2SGovind Singh 449d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 450e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 4517f4beda2SGovind Singh continue; 4527f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 4537f4beda2SGovind Singh free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); 4547f4beda2SGovind Singh } 455d4ecb90bSCarl Huang 456d4ecb90bSCarl Huang ath11k_pci_free_ext_irq(ab); 4577f4beda2SGovind Singh } 4587f4beda2SGovind Singh 4592c3960c2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) 4602c3960c2SGovind Singh { 4612c3960c2SGovind Singh u32 irq_idx; 4622c3960c2SGovind Singh 4632c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 4642c3960c2SGovind Singh enable_irq(ab->irq_num[irq_idx]); 4652c3960c2SGovind Singh } 4662c3960c2SGovind Singh 4677f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) 4687f4beda2SGovind Singh { 4697f4beda2SGovind Singh u32 irq_idx; 4707f4beda2SGovind Singh 4717f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 4727f4beda2SGovind Singh disable_irq_nosync(ab->irq_num[irq_idx]); 4737f4beda2SGovind Singh } 4747f4beda2SGovind Singh 4752c3960c2SGovind Singh static void ath11k_pci_ce_irqs_disable(struct ath11k_base *ab) 4762c3960c2SGovind Singh { 4772c3960c2SGovind Singh int i; 4782c3960c2SGovind Singh 479d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 480e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 4812c3960c2SGovind Singh continue; 4822c3960c2SGovind Singh ath11k_pci_ce_irq_disable(ab, i); 4832c3960c2SGovind Singh } 4842c3960c2SGovind Singh } 4852c3960c2SGovind Singh 4862c3960c2SGovind Singh static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) 4872c3960c2SGovind Singh { 4882c3960c2SGovind Singh int i; 4892c3960c2SGovind Singh int irq_idx; 4902c3960c2SGovind Singh 491d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 492e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 4932c3960c2SGovind Singh continue; 4942c3960c2SGovind Singh 4952c3960c2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 4962c3960c2SGovind Singh synchronize_irq(ab->irq_num[irq_idx]); 4972c3960c2SGovind Singh } 4982c3960c2SGovind Singh } 4992c3960c2SGovind Singh 5000f01dcb8SAllen Pais static void ath11k_pci_ce_tasklet(struct tasklet_struct *t) 5012c3960c2SGovind Singh { 5020f01dcb8SAllen Pais struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); 5032c3960c2SGovind Singh 5042c3960c2SGovind Singh ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); 5052c3960c2SGovind Singh 5062c3960c2SGovind Singh ath11k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num); 5072c3960c2SGovind Singh } 5082c3960c2SGovind Singh 5097f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) 5107f4beda2SGovind Singh { 5117f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe = arg; 5127f4beda2SGovind Singh 5137f4beda2SGovind Singh ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num); 5142c3960c2SGovind Singh tasklet_schedule(&ce_pipe->intr_tq); 5157f4beda2SGovind Singh 5167f4beda2SGovind Singh return IRQ_HANDLED; 5177f4beda2SGovind Singh } 5187f4beda2SGovind Singh 519d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) 520d4ecb90bSCarl Huang { 521d4ecb90bSCarl Huang int i; 522d4ecb90bSCarl Huang 523d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 524d4ecb90bSCarl Huang disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 525d4ecb90bSCarl Huang } 526d4ecb90bSCarl Huang 527d4ecb90bSCarl Huang static void __ath11k_pci_ext_irq_disable(struct ath11k_base *sc) 528d4ecb90bSCarl Huang { 529d4ecb90bSCarl Huang int i; 530d4ecb90bSCarl Huang 531d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 532d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; 533d4ecb90bSCarl Huang 534d4ecb90bSCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 535d4ecb90bSCarl Huang 536d4ecb90bSCarl Huang napi_synchronize(&irq_grp->napi); 537d4ecb90bSCarl Huang napi_disable(&irq_grp->napi); 538d4ecb90bSCarl Huang } 539d4ecb90bSCarl Huang } 540d4ecb90bSCarl Huang 541d4ecb90bSCarl Huang static void ath11k_pci_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) 542d4ecb90bSCarl Huang { 543d4ecb90bSCarl Huang int i; 544d4ecb90bSCarl Huang 545d4ecb90bSCarl Huang for (i = 0; i < irq_grp->num_irq; i++) 546d4ecb90bSCarl Huang enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 547d4ecb90bSCarl Huang } 548d4ecb90bSCarl Huang 549d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_enable(struct ath11k_base *ab) 550d4ecb90bSCarl Huang { 551d4ecb90bSCarl Huang int i; 552d4ecb90bSCarl Huang 553d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 554d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 555d4ecb90bSCarl Huang 556d4ecb90bSCarl Huang napi_enable(&irq_grp->napi); 557d4ecb90bSCarl Huang ath11k_pci_ext_grp_enable(irq_grp); 558d4ecb90bSCarl Huang } 559d4ecb90bSCarl Huang } 560d4ecb90bSCarl Huang 561d4ecb90bSCarl Huang static void ath11k_pci_sync_ext_irqs(struct ath11k_base *ab) 562d4ecb90bSCarl Huang { 563d4ecb90bSCarl Huang int i, j, irq_idx; 564d4ecb90bSCarl Huang 565d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 566d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 567d4ecb90bSCarl Huang 568d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 569d4ecb90bSCarl Huang irq_idx = irq_grp->irqs[j]; 570d4ecb90bSCarl Huang synchronize_irq(ab->irq_num[irq_idx]); 571d4ecb90bSCarl Huang } 572d4ecb90bSCarl Huang } 573d4ecb90bSCarl Huang } 574d4ecb90bSCarl Huang 575d4ecb90bSCarl Huang static void ath11k_pci_ext_irq_disable(struct ath11k_base *ab) 576d4ecb90bSCarl Huang { 577d4ecb90bSCarl Huang __ath11k_pci_ext_irq_disable(ab); 578d4ecb90bSCarl Huang ath11k_pci_sync_ext_irqs(ab); 579d4ecb90bSCarl Huang } 580d4ecb90bSCarl Huang 581d4ecb90bSCarl Huang static int ath11k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) 582d4ecb90bSCarl Huang { 583d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = container_of(napi, 584d4ecb90bSCarl Huang struct ath11k_ext_irq_grp, 585d4ecb90bSCarl Huang napi); 586d4ecb90bSCarl Huang struct ath11k_base *ab = irq_grp->ab; 587d4ecb90bSCarl Huang int work_done; 588d4ecb90bSCarl Huang 589d4ecb90bSCarl Huang work_done = ath11k_dp_service_srng(ab, irq_grp, budget); 590d4ecb90bSCarl Huang if (work_done < budget) { 591d4ecb90bSCarl Huang napi_complete_done(napi, work_done); 592d4ecb90bSCarl Huang ath11k_pci_ext_grp_enable(irq_grp); 593d4ecb90bSCarl Huang } 594d4ecb90bSCarl Huang 595d4ecb90bSCarl Huang if (work_done > budget) 596d4ecb90bSCarl Huang work_done = budget; 597d4ecb90bSCarl Huang 598d4ecb90bSCarl Huang return work_done; 599d4ecb90bSCarl Huang } 600d4ecb90bSCarl Huang 601d4ecb90bSCarl Huang static irqreturn_t ath11k_pci_ext_interrupt_handler(int irq, void *arg) 602d4ecb90bSCarl Huang { 603d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = arg; 604d4ecb90bSCarl Huang 605d4ecb90bSCarl Huang ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); 606d4ecb90bSCarl Huang 607d4ecb90bSCarl Huang ath11k_pci_ext_grp_disable(irq_grp); 608d4ecb90bSCarl Huang 609d4ecb90bSCarl Huang napi_schedule(&irq_grp->napi); 610d4ecb90bSCarl Huang 611d4ecb90bSCarl Huang return IRQ_HANDLED; 612d4ecb90bSCarl Huang } 613d4ecb90bSCarl Huang 614d4ecb90bSCarl Huang static int ath11k_pci_ext_irq_config(struct ath11k_base *ab) 615d4ecb90bSCarl Huang { 616d4ecb90bSCarl Huang int i, j, ret, num_vectors = 0; 617d4ecb90bSCarl Huang u32 user_base_data = 0, base_vector = 0; 618d4ecb90bSCarl Huang 619b2c09458SColin Ian King ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), "DP", 620b2c09458SColin Ian King &num_vectors, 621b2c09458SColin Ian King &user_base_data, 622d4ecb90bSCarl Huang &base_vector); 623b2c09458SColin Ian King if (ret < 0) 624b2c09458SColin Ian King return ret; 625d4ecb90bSCarl Huang 626d4ecb90bSCarl Huang for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 627d4ecb90bSCarl Huang struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 628d4ecb90bSCarl Huang u32 num_irq = 0; 629d4ecb90bSCarl Huang 630d4ecb90bSCarl Huang irq_grp->ab = ab; 631d4ecb90bSCarl Huang irq_grp->grp_id = i; 632d4ecb90bSCarl Huang init_dummy_netdev(&irq_grp->napi_ndev); 633d4ecb90bSCarl Huang netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, 634d4ecb90bSCarl Huang ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT); 635d4ecb90bSCarl Huang 636d4ecb90bSCarl Huang if (ab->hw_params.ring_mask->tx[i] || 637d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx[i] || 638d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_err[i] || 639d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_wbm_rel[i] || 640d4ecb90bSCarl Huang ab->hw_params.ring_mask->reo_status[i] || 641d4ecb90bSCarl Huang ab->hw_params.ring_mask->rxdma2host[i] || 642d4ecb90bSCarl Huang ab->hw_params.ring_mask->host2rxdma[i] || 643d4ecb90bSCarl Huang ab->hw_params.ring_mask->rx_mon_status[i]) { 644d4ecb90bSCarl Huang num_irq = 1; 645d4ecb90bSCarl Huang } 646d4ecb90bSCarl Huang 647d4ecb90bSCarl Huang irq_grp->num_irq = num_irq; 648d4ecb90bSCarl Huang irq_grp->irqs[0] = base_vector + i; 649d4ecb90bSCarl Huang 650d4ecb90bSCarl Huang for (j = 0; j < irq_grp->num_irq; j++) { 651d4ecb90bSCarl Huang int irq_idx = irq_grp->irqs[j]; 652d4ecb90bSCarl Huang int vector = (i % num_vectors) + base_vector; 653d4ecb90bSCarl Huang int irq = ath11k_pci_get_msi_irq(ab->dev, vector); 654d4ecb90bSCarl Huang 655d4ecb90bSCarl Huang ab->irq_num[irq_idx] = irq; 656d4ecb90bSCarl Huang 657d4ecb90bSCarl Huang ath11k_dbg(ab, ATH11K_DBG_PCI, 658d4ecb90bSCarl Huang "irq:%d group:%d\n", irq, i); 659d4ecb90bSCarl Huang ret = request_irq(irq, ath11k_pci_ext_interrupt_handler, 660d4ecb90bSCarl Huang IRQF_SHARED, 661d4ecb90bSCarl Huang "DP_EXT_IRQ", irq_grp); 662d4ecb90bSCarl Huang if (ret) { 663d4ecb90bSCarl Huang ath11k_err(ab, "failed request irq %d: %d\n", 664d4ecb90bSCarl Huang vector, ret); 665d4ecb90bSCarl Huang return ret; 666d4ecb90bSCarl Huang } 667d4ecb90bSCarl Huang 668d4ecb90bSCarl Huang disable_irq_nosync(ab->irq_num[irq_idx]); 669d4ecb90bSCarl Huang } 670d4ecb90bSCarl Huang } 671d4ecb90bSCarl Huang 672d4ecb90bSCarl Huang return 0; 673d4ecb90bSCarl Huang } 674d4ecb90bSCarl Huang 6757f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab) 6767f4beda2SGovind Singh { 6777f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe; 6787f4beda2SGovind Singh u32 msi_data_start; 6797f4beda2SGovind Singh u32 msi_data_count; 6807f4beda2SGovind Singh u32 msi_irq_start; 6817f4beda2SGovind Singh unsigned int msi_data; 6827f4beda2SGovind Singh int irq, i, ret, irq_idx; 6837f4beda2SGovind Singh 6847f4beda2SGovind Singh ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), 6857f4beda2SGovind Singh "CE", &msi_data_count, 6867f4beda2SGovind Singh &msi_data_start, &msi_irq_start); 6877f4beda2SGovind Singh if (ret) 6887f4beda2SGovind Singh return ret; 6897f4beda2SGovind Singh 6907f4beda2SGovind Singh /* Configure CE irqs */ 691d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 6927f4beda2SGovind Singh msi_data = (i % msi_data_count) + msi_irq_start; 6937f4beda2SGovind Singh irq = ath11k_pci_get_msi_irq(ab->dev, msi_data); 6947f4beda2SGovind Singh ce_pipe = &ab->ce.ce_pipe[i]; 6957f4beda2SGovind Singh 696e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 6977f4beda2SGovind Singh continue; 6987f4beda2SGovind Singh 6997f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 7007f4beda2SGovind Singh 7010f01dcb8SAllen Pais tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet); 7022c3960c2SGovind Singh 7037f4beda2SGovind Singh ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, 7047f4beda2SGovind Singh IRQF_SHARED, irq_name[irq_idx], 7057f4beda2SGovind Singh ce_pipe); 7067f4beda2SGovind Singh if (ret) { 7077f4beda2SGovind Singh ath11k_err(ab, "failed to request irq %d: %d\n", 7087f4beda2SGovind Singh irq_idx, ret); 7097f4beda2SGovind Singh return ret; 7107f4beda2SGovind Singh } 7117f4beda2SGovind Singh 7127f4beda2SGovind Singh ab->irq_num[irq_idx] = irq; 713e5c860e1SCarl Huang ath11k_pci_ce_irq_disable(ab, i); 7147f4beda2SGovind Singh } 7157f4beda2SGovind Singh 716d4ecb90bSCarl Huang ret = ath11k_pci_ext_irq_config(ab); 717d4ecb90bSCarl Huang if (ret) 718d4ecb90bSCarl Huang return ret; 719d4ecb90bSCarl Huang 7207f4beda2SGovind Singh return 0; 7217f4beda2SGovind Singh } 7227f4beda2SGovind Singh 7237f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) 7247f4beda2SGovind Singh { 7257f4beda2SGovind Singh struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; 7267f4beda2SGovind Singh 727967c1d11SAnilkumar Kolli cfg->tgt_ce = ab->hw_params.target_ce_config; 728967c1d11SAnilkumar Kolli cfg->tgt_ce_len = ab->hw_params.target_ce_count; 7297f4beda2SGovind Singh 730967c1d11SAnilkumar Kolli cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map; 731967c1d11SAnilkumar Kolli cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len; 732eb8de049SGovind Singh ab->qmi.service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390; 733e838c14aSCarl Huang 734e838c14aSCarl Huang ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2, 735e838c14aSCarl Huang &cfg->shadow_reg_v2_len); 7367f4beda2SGovind Singh } 7377f4beda2SGovind Singh 7387f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) 7397f4beda2SGovind Singh { 7407f4beda2SGovind Singh int i; 7417f4beda2SGovind Singh 742d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 743e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 7447f4beda2SGovind Singh continue; 7457f4beda2SGovind Singh ath11k_pci_ce_irq_enable(ab, i); 7467f4beda2SGovind Singh } 7477f4beda2SGovind Singh } 7487f4beda2SGovind Singh 7495697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci) 7505697a564SGovind Singh { 7515697a564SGovind Singh struct ath11k_base *ab = ab_pci->ab; 7525697a564SGovind Singh struct msi_desc *msi_desc; 7535697a564SGovind Singh int num_vectors; 7545697a564SGovind Singh int ret; 7555697a564SGovind Singh 7565697a564SGovind Singh num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 7575697a564SGovind Singh msi_config.total_vectors, 7585697a564SGovind Singh msi_config.total_vectors, 7595697a564SGovind Singh PCI_IRQ_MSI); 7605697a564SGovind Singh if (num_vectors != msi_config.total_vectors) { 7615697a564SGovind Singh ath11k_err(ab, "failed to get %d MSI vectors, only %d available", 7625697a564SGovind Singh msi_config.total_vectors, num_vectors); 7635697a564SGovind Singh 7645697a564SGovind Singh if (num_vectors >= 0) 7655697a564SGovind Singh return -EINVAL; 7665697a564SGovind Singh else 7675697a564SGovind Singh return num_vectors; 7685697a564SGovind Singh } 7695697a564SGovind Singh 7705697a564SGovind Singh msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 7715697a564SGovind Singh if (!msi_desc) { 7725697a564SGovind Singh ath11k_err(ab, "msi_desc is NULL!\n"); 7735697a564SGovind Singh ret = -EINVAL; 7745697a564SGovind Singh goto free_msi_vector; 7755697a564SGovind Singh } 7765697a564SGovind Singh 7775697a564SGovind Singh ab_pci->msi_ep_base_data = msi_desc->msg.data; 778e8e55d89SAnilkumar Kolli if (msi_desc->msi_attrib.is_64) 779e8e55d89SAnilkumar Kolli set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags); 7805697a564SGovind Singh 7815697a564SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); 7825697a564SGovind Singh 7835697a564SGovind Singh return 0; 7845697a564SGovind Singh 7855697a564SGovind Singh free_msi_vector: 7865697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 7875697a564SGovind Singh 7885697a564SGovind Singh return ret; 7895697a564SGovind Singh } 7905697a564SGovind Singh 7915697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci) 7925697a564SGovind Singh { 7935697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 7945697a564SGovind Singh } 7955697a564SGovind Singh 7965762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) 7975762613eSGovind Singh { 7985762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 7995762613eSGovind Singh u16 device_id; 8005762613eSGovind Singh int ret = 0; 8015762613eSGovind Singh 8025762613eSGovind Singh pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 8035762613eSGovind Singh if (device_id != ab_pci->dev_id) { 8045762613eSGovind Singh ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", 8055762613eSGovind Singh device_id, ab_pci->dev_id); 8065762613eSGovind Singh ret = -EIO; 8075762613eSGovind Singh goto out; 8085762613eSGovind Singh } 8095762613eSGovind Singh 8105762613eSGovind Singh ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); 8115762613eSGovind Singh if (ret) { 8125762613eSGovind Singh ath11k_err(ab, "failed to assign pci resource: %d\n", ret); 8135762613eSGovind Singh goto out; 8145762613eSGovind Singh } 8155762613eSGovind Singh 8165762613eSGovind Singh ret = pci_enable_device(pdev); 8175762613eSGovind Singh if (ret) { 8185762613eSGovind Singh ath11k_err(ab, "failed to enable pci device: %d\n", ret); 8195762613eSGovind Singh goto out; 8205762613eSGovind Singh } 8215762613eSGovind Singh 8225762613eSGovind Singh ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); 8235762613eSGovind Singh if (ret) { 8245762613eSGovind Singh ath11k_err(ab, "failed to request pci region: %d\n", ret); 8255762613eSGovind Singh goto disable_device; 8265762613eSGovind Singh } 8275762613eSGovind Singh 8285762613eSGovind Singh ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 8295762613eSGovind Singh if (ret) { 8305762613eSGovind Singh ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", 8315762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 8325762613eSGovind Singh goto release_region; 8335762613eSGovind Singh } 8345762613eSGovind Singh 8355762613eSGovind Singh ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 8365762613eSGovind Singh if (ret) { 8375762613eSGovind Singh ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n", 8385762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 8395762613eSGovind Singh goto release_region; 8405762613eSGovind Singh } 8415762613eSGovind Singh 8425762613eSGovind Singh pci_set_master(pdev); 8435762613eSGovind Singh 8445762613eSGovind Singh ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); 8455762613eSGovind Singh ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); 8465762613eSGovind Singh if (!ab->mem) { 8475762613eSGovind Singh ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); 8485762613eSGovind Singh ret = -EIO; 8495762613eSGovind Singh goto clear_master; 8505762613eSGovind Singh } 8515762613eSGovind Singh 8525762613eSGovind Singh ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); 8535762613eSGovind Singh return 0; 8545762613eSGovind Singh 8555762613eSGovind Singh clear_master: 8565762613eSGovind Singh pci_clear_master(pdev); 8575762613eSGovind Singh release_region: 8585762613eSGovind Singh pci_release_region(pdev, ATH11K_PCI_BAR_NUM); 8595762613eSGovind Singh disable_device: 8605762613eSGovind Singh pci_disable_device(pdev); 8615762613eSGovind Singh out: 8625762613eSGovind Singh return ret; 8635762613eSGovind Singh } 8645762613eSGovind Singh 8655762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) 8665762613eSGovind Singh { 8675762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 8685762613eSGovind Singh struct pci_dev *pci_dev = ab_pci->pdev; 8695762613eSGovind Singh 8705762613eSGovind Singh pci_iounmap(pci_dev, ab->mem); 8715762613eSGovind Singh ab->mem = NULL; 8725762613eSGovind Singh pci_clear_master(pci_dev); 8735762613eSGovind Singh pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); 8745762613eSGovind Singh if (pci_is_enabled(pci_dev)) 8755762613eSGovind Singh pci_disable_device(pci_dev); 8765762613eSGovind Singh } 8775762613eSGovind Singh 8781399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab) 8791399fb87SGovind Singh { 8801399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 8811399fb87SGovind Singh int ret; 8821399fb87SGovind Singh 883a05bd851SCarl Huang ab_pci->register_window = 0; 884a05bd851SCarl Huang clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 885babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, true); 886f3c603d4SCarl Huang 8871399fb87SGovind Singh ret = ath11k_mhi_start(ab_pci); 8881399fb87SGovind Singh if (ret) { 8891399fb87SGovind Singh ath11k_err(ab, "failed to start mhi: %d\n", ret); 8901399fb87SGovind Singh return ret; 8911399fb87SGovind Singh } 8921399fb87SGovind Singh 8931399fb87SGovind Singh return 0; 8941399fb87SGovind Singh } 8951399fb87SGovind Singh 8961399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab) 8971399fb87SGovind Singh { 8981399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 8991399fb87SGovind Singh 900babb0cedSCarl Huang ath11k_pci_force_wake(ab_pci->ab); 9011399fb87SGovind Singh ath11k_mhi_stop(ab_pci); 902a05bd851SCarl Huang clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 903babb0cedSCarl Huang ath11k_pci_sw_reset(ab_pci->ab, false); 9041399fb87SGovind Singh } 9051399fb87SGovind Singh 9062c3960c2SGovind Singh static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) 9072c3960c2SGovind Singh { 9082c3960c2SGovind Singh int i; 9092c3960c2SGovind Singh 910d9d4b5f3SKalle Valo for (i = 0; i < ab->hw_params.ce_count; i++) { 9112c3960c2SGovind Singh struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; 9122c3960c2SGovind Singh 913e3396b8bSCarl Huang if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 9142c3960c2SGovind Singh continue; 9152c3960c2SGovind Singh 9162c3960c2SGovind Singh tasklet_kill(&ce_pipe->intr_tq); 9172c3960c2SGovind Singh } 9182c3960c2SGovind Singh } 9192c3960c2SGovind Singh 9207f4beda2SGovind Singh static void ath11k_pci_stop(struct ath11k_base *ab) 9217f4beda2SGovind Singh { 9222c3960c2SGovind Singh ath11k_pci_ce_irqs_disable(ab); 9232c3960c2SGovind Singh ath11k_pci_sync_ce_irqs(ab); 9242c3960c2SGovind Singh ath11k_pci_kill_tasklets(ab); 9257f4beda2SGovind Singh ath11k_ce_cleanup_pipes(ab); 9267f4beda2SGovind Singh } 9277f4beda2SGovind Singh 9287f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab) 9297f4beda2SGovind Singh { 930a05bd851SCarl Huang struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 931a05bd851SCarl Huang 932a05bd851SCarl Huang set_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); 933a05bd851SCarl Huang 9347f4beda2SGovind Singh ath11k_pci_ce_irqs_enable(ab); 9352c3960c2SGovind Singh ath11k_ce_rx_post_buf(ab); 9362c3960c2SGovind Singh 9372c3960c2SGovind Singh return 0; 9382c3960c2SGovind Singh } 9392c3960c2SGovind Singh 9402c3960c2SGovind Singh static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, 9412c3960c2SGovind Singh u8 *ul_pipe, u8 *dl_pipe) 9422c3960c2SGovind Singh { 9432c3960c2SGovind Singh const struct service_to_pipe *entry; 9442c3960c2SGovind Singh bool ul_set = false, dl_set = false; 9452c3960c2SGovind Singh int i; 9462c3960c2SGovind Singh 947967c1d11SAnilkumar Kolli for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) { 948967c1d11SAnilkumar Kolli entry = &ab->hw_params.svc_to_ce_map[i]; 9492c3960c2SGovind Singh 9502c3960c2SGovind Singh if (__le32_to_cpu(entry->service_id) != service_id) 9512c3960c2SGovind Singh continue; 9522c3960c2SGovind Singh 9532c3960c2SGovind Singh switch (__le32_to_cpu(entry->pipedir)) { 9542c3960c2SGovind Singh case PIPEDIR_NONE: 9552c3960c2SGovind Singh break; 9562c3960c2SGovind Singh case PIPEDIR_IN: 9572c3960c2SGovind Singh WARN_ON(dl_set); 9582c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 9592c3960c2SGovind Singh dl_set = true; 9602c3960c2SGovind Singh break; 9612c3960c2SGovind Singh case PIPEDIR_OUT: 9622c3960c2SGovind Singh WARN_ON(ul_set); 9632c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 9642c3960c2SGovind Singh ul_set = true; 9652c3960c2SGovind Singh break; 9662c3960c2SGovind Singh case PIPEDIR_INOUT: 9672c3960c2SGovind Singh WARN_ON(dl_set); 9682c3960c2SGovind Singh WARN_ON(ul_set); 9692c3960c2SGovind Singh *dl_pipe = __le32_to_cpu(entry->pipenum); 9702c3960c2SGovind Singh *ul_pipe = __le32_to_cpu(entry->pipenum); 9712c3960c2SGovind Singh dl_set = true; 9722c3960c2SGovind Singh ul_set = true; 9732c3960c2SGovind Singh break; 9742c3960c2SGovind Singh } 9752c3960c2SGovind Singh } 9762c3960c2SGovind Singh 9772c3960c2SGovind Singh if (WARN_ON(!ul_set || !dl_set)) 9782c3960c2SGovind Singh return -ENOENT; 9797f4beda2SGovind Singh 9807f4beda2SGovind Singh return 0; 9817f4beda2SGovind Singh } 9827f4beda2SGovind Singh 9837f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = { 9847f4beda2SGovind Singh .start = ath11k_pci_start, 9857f4beda2SGovind Singh .stop = ath11k_pci_stop, 986654e959aSGovind Singh .read32 = ath11k_pci_read32, 987654e959aSGovind Singh .write32 = ath11k_pci_write32, 9881399fb87SGovind Singh .power_down = ath11k_pci_power_down, 9891399fb87SGovind Singh .power_up = ath11k_pci_power_up, 990d4ecb90bSCarl Huang .irq_enable = ath11k_pci_ext_irq_enable, 991d4ecb90bSCarl Huang .irq_disable = ath11k_pci_ext_irq_disable, 992c4eacabeSGovind Singh .get_msi_address = ath11k_pci_get_msi_address, 993c4eacabeSGovind Singh .get_user_msi_vector = ath11k_get_user_msi_assignment, 9942c3960c2SGovind Singh .map_service_to_pipe = ath11k_pci_map_service_to_pipe, 9951399fb87SGovind Singh }; 9961399fb87SGovind Singh 9976e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev, 9986e0355afSGovind Singh const struct pci_device_id *pci_dev) 9996e0355afSGovind Singh { 10006e0355afSGovind Singh struct ath11k_base *ab; 10015762613eSGovind Singh struct ath11k_pci *ab_pci; 100218ac1665SKalle Valo u32 soc_hw_version, soc_hw_version_major, soc_hw_version_minor; 10035762613eSGovind Singh int ret; 10046e0355afSGovind Singh 10056e0355afSGovind Singh dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n"); 10066e0355afSGovind Singh 10071ff8ed78SGovind Singh ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, 10081ff8ed78SGovind Singh &ath11k_pci_bus_params); 10096e0355afSGovind Singh if (!ab) { 10106e0355afSGovind Singh dev_err(&pdev->dev, "failed to allocate ath11k base\n"); 10116e0355afSGovind Singh return -ENOMEM; 10126e0355afSGovind Singh } 10136e0355afSGovind Singh 10146e0355afSGovind Singh ab->dev = &pdev->dev; 10156e0355afSGovind Singh pci_set_drvdata(pdev, ab); 10165762613eSGovind Singh ab_pci = ath11k_pci_priv(ab); 10175762613eSGovind Singh ab_pci->dev_id = pci_dev->device; 10185762613eSGovind Singh ab_pci->ab = ab; 10195697a564SGovind Singh ab_pci->pdev = pdev; 10207f4beda2SGovind Singh ab->hif.ops = &ath11k_pci_hif_ops; 10215762613eSGovind Singh pci_set_drvdata(pdev, ab); 1022654e959aSGovind Singh spin_lock_init(&ab_pci->window_lock); 10235762613eSGovind Singh 10245762613eSGovind Singh ret = ath11k_pci_claim(ab_pci, pdev); 10255762613eSGovind Singh if (ret) { 10265762613eSGovind Singh ath11k_err(ab, "failed to claim device: %d\n", ret); 10275762613eSGovind Singh goto err_free_core; 10285762613eSGovind Singh } 10296e0355afSGovind Singh 103018ac1665SKalle Valo switch (pci_dev->device) { 103118ac1665SKalle Valo case QCA6390_DEVICE_ID: 103218ac1665SKalle Valo soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION); 103318ac1665SKalle Valo soc_hw_version_major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK, 103418ac1665SKalle Valo soc_hw_version); 103518ac1665SKalle Valo soc_hw_version_minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK, 103618ac1665SKalle Valo soc_hw_version); 103718ac1665SKalle Valo 103818ac1665SKalle Valo ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n", 103918ac1665SKalle Valo soc_hw_version_major, soc_hw_version_minor); 104018ac1665SKalle Valo 104118ac1665SKalle Valo switch (soc_hw_version_major) { 104218ac1665SKalle Valo case 2: 104318ac1665SKalle Valo ab->hw_rev = ATH11K_HW_QCA6390_HW20; 104418ac1665SKalle Valo break; 104518ac1665SKalle Valo default: 104618ac1665SKalle Valo dev_err(&pdev->dev, "Unsupported QCA6390 SOC hardware version: %d %d\n", 104718ac1665SKalle Valo soc_hw_version_major, soc_hw_version_minor); 104818ac1665SKalle Valo ret = -EOPNOTSUPP; 104918ac1665SKalle Valo goto err_pci_free_region; 105018ac1665SKalle Valo } 105118ac1665SKalle Valo break; 105218ac1665SKalle Valo default: 105318ac1665SKalle Valo dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", 105418ac1665SKalle Valo pci_dev->device); 105518ac1665SKalle Valo ret = -EOPNOTSUPP; 105618ac1665SKalle Valo goto err_pci_free_region; 105718ac1665SKalle Valo } 105818ac1665SKalle Valo 10595697a564SGovind Singh ret = ath11k_pci_enable_msi(ab_pci); 10605697a564SGovind Singh if (ret) { 10615697a564SGovind Singh ath11k_err(ab, "failed to enable msi: %d\n", ret); 10625697a564SGovind Singh goto err_pci_free_region; 10635697a564SGovind Singh } 10645697a564SGovind Singh 1065b8246f88SKalle Valo ret = ath11k_core_pre_init(ab); 1066b8246f88SKalle Valo if (ret) 1067b8246f88SKalle Valo goto err_pci_disable_msi; 1068b8246f88SKalle Valo 10691399fb87SGovind Singh ret = ath11k_mhi_register(ab_pci); 10701399fb87SGovind Singh if (ret) { 10711399fb87SGovind Singh ath11k_err(ab, "failed to register mhi: %d\n", ret); 10721399fb87SGovind Singh goto err_pci_disable_msi; 10731399fb87SGovind Singh } 10741399fb87SGovind Singh 10757f4beda2SGovind Singh ret = ath11k_hal_srng_init(ab); 10767f4beda2SGovind Singh if (ret) 10777f4beda2SGovind Singh goto err_mhi_unregister; 10787f4beda2SGovind Singh 10797f4beda2SGovind Singh ret = ath11k_ce_alloc_pipes(ab); 10807f4beda2SGovind Singh if (ret) { 10817f4beda2SGovind Singh ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret); 10827f4beda2SGovind Singh goto err_hal_srng_deinit; 10837f4beda2SGovind Singh } 10847f4beda2SGovind Singh 10857f4beda2SGovind Singh ath11k_pci_init_qmi_ce_config(ab); 10867f4beda2SGovind Singh 10877f4beda2SGovind Singh ret = ath11k_pci_config_irq(ab); 10887f4beda2SGovind Singh if (ret) { 10897f4beda2SGovind Singh ath11k_err(ab, "failed to config irq: %d\n", ret); 10907f4beda2SGovind Singh goto err_ce_free; 10917f4beda2SGovind Singh } 10927f4beda2SGovind Singh 10937f4beda2SGovind Singh ret = ath11k_core_init(ab); 10947f4beda2SGovind Singh if (ret) { 10957f4beda2SGovind Singh ath11k_err(ab, "failed to init core: %d\n", ret); 10967f4beda2SGovind Singh goto err_free_irq; 10977f4beda2SGovind Singh } 10986e0355afSGovind Singh return 0; 10995762613eSGovind Singh 11007f4beda2SGovind Singh err_free_irq: 11017f4beda2SGovind Singh ath11k_pci_free_irq(ab); 11027f4beda2SGovind Singh 11037f4beda2SGovind Singh err_ce_free: 11047f4beda2SGovind Singh ath11k_ce_free_pipes(ab); 11057f4beda2SGovind Singh 11067f4beda2SGovind Singh err_hal_srng_deinit: 11077f4beda2SGovind Singh ath11k_hal_srng_deinit(ab); 11087f4beda2SGovind Singh 11097f4beda2SGovind Singh err_mhi_unregister: 11107f4beda2SGovind Singh ath11k_mhi_unregister(ab_pci); 11117f4beda2SGovind Singh 1112b8246f88SKalle Valo err_pci_disable_msi: 1113b8246f88SKalle Valo ath11k_pci_disable_msi(ab_pci); 1114b8246f88SKalle Valo 11155697a564SGovind Singh err_pci_free_region: 11165697a564SGovind Singh ath11k_pci_free_region(ab_pci); 11175697a564SGovind Singh 11185762613eSGovind Singh err_free_core: 11195762613eSGovind Singh ath11k_core_free(ab); 11205697a564SGovind Singh 11215762613eSGovind Singh return ret; 11226e0355afSGovind Singh } 11236e0355afSGovind Singh 11246e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev) 11256e0355afSGovind Singh { 11266e0355afSGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 11275762613eSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 11286e0355afSGovind Singh 112961a57e51SAnilkumar Kolli if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { 113061a57e51SAnilkumar Kolli ath11k_pci_power_down(ab); 113161a57e51SAnilkumar Kolli ath11k_debugfs_soc_destroy(ab); 113261a57e51SAnilkumar Kolli ath11k_qmi_deinit_service(ab); 113361a57e51SAnilkumar Kolli goto qmi_fail; 113461a57e51SAnilkumar Kolli } 113561a57e51SAnilkumar Kolli 11366e0355afSGovind Singh set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); 11376fbd8898SCarl Huang 11386fbd8898SCarl Huang ath11k_core_deinit(ab); 11396fbd8898SCarl Huang 114061a57e51SAnilkumar Kolli qmi_fail: 11411399fb87SGovind Singh ath11k_mhi_unregister(ab_pci); 11426fbd8898SCarl Huang 11436fbd8898SCarl Huang ath11k_pci_free_irq(ab); 11445697a564SGovind Singh ath11k_pci_disable_msi(ab_pci); 11455762613eSGovind Singh ath11k_pci_free_region(ab_pci); 11466fbd8898SCarl Huang 11476fbd8898SCarl Huang ath11k_hal_srng_deinit(ab); 11486fbd8898SCarl Huang ath11k_ce_free_pipes(ab); 11496e0355afSGovind Singh ath11k_core_free(ab); 11506e0355afSGovind Singh } 11516e0355afSGovind Singh 11521399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev) 11531399fb87SGovind Singh { 11541399fb87SGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 11551399fb87SGovind Singh 11561399fb87SGovind Singh ath11k_pci_power_down(ab); 11571399fb87SGovind Singh } 11581399fb87SGovind Singh 11596e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = { 11606e0355afSGovind Singh .name = "ath11k_pci", 11616e0355afSGovind Singh .id_table = ath11k_pci_id_table, 11626e0355afSGovind Singh .probe = ath11k_pci_probe, 11636e0355afSGovind Singh .remove = ath11k_pci_remove, 11641399fb87SGovind Singh .shutdown = ath11k_pci_shutdown, 11656e0355afSGovind Singh }; 11666e0355afSGovind Singh 11676e0355afSGovind Singh static int ath11k_pci_init(void) 11686e0355afSGovind Singh { 11696e0355afSGovind Singh int ret; 11706e0355afSGovind Singh 11716e0355afSGovind Singh ret = pci_register_driver(&ath11k_pci_driver); 11726e0355afSGovind Singh if (ret) 11736e0355afSGovind Singh pr_err("failed to register ath11k pci driver: %d\n", 11746e0355afSGovind Singh ret); 11756e0355afSGovind Singh 11766e0355afSGovind Singh return ret; 11776e0355afSGovind Singh } 11786e0355afSGovind Singh module_init(ath11k_pci_init); 11796e0355afSGovind Singh 11806e0355afSGovind Singh static void ath11k_pci_exit(void) 11816e0355afSGovind Singh { 11826e0355afSGovind Singh pci_unregister_driver(&ath11k_pci_driver); 11836e0355afSGovind Singh } 11846e0355afSGovind Singh 11856e0355afSGovind Singh module_exit(ath11k_pci_exit); 11866e0355afSGovind Singh 11876e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); 11886e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL"); 11893dbd7fe7SDevin Bayer 11903dbd7fe7SDevin Bayer /* QCA639x 2.0 firmware files */ 11913dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE); 11923dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE); 11933dbd7fe7SDevin Bayer MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE); 1194