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 19*7f4beda2SGovind Singh #define ATH11K_PCI_IRQ_CE0_OFFSET 3 20*7f4beda2SGovind Singh 216e0355afSGovind Singh #define QCA6390_DEVICE_ID 0x1101 226e0355afSGovind Singh 236e0355afSGovind Singh static const struct pci_device_id ath11k_pci_id_table[] = { 246e0355afSGovind Singh { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, 256e0355afSGovind Singh {0} 266e0355afSGovind Singh }; 276e0355afSGovind Singh 286e0355afSGovind Singh MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); 296e0355afSGovind Singh 305697a564SGovind Singh static const struct ath11k_msi_config msi_config = { 315697a564SGovind Singh .total_vectors = 32, 325697a564SGovind Singh .total_users = 4, 335697a564SGovind Singh .users = (struct ath11k_msi_user[]) { 345697a564SGovind Singh { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 355697a564SGovind Singh { .name = "CE", .num_vectors = 10, .base_vector = 3 }, 365697a564SGovind Singh { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, 375697a564SGovind Singh { .name = "DP", .num_vectors = 18, .base_vector = 14 }, 385697a564SGovind Singh }, 395697a564SGovind Singh }; 405697a564SGovind Singh 41*7f4beda2SGovind Singh /* Target firmware's Copy Engine configuration. */ 42*7f4beda2SGovind Singh static const struct ce_pipe_config target_ce_config_wlan[] = { 43*7f4beda2SGovind Singh /* CE0: host->target HTC control and raw streams */ 44*7f4beda2SGovind Singh { 45*7f4beda2SGovind Singh .pipenum = __cpu_to_le32(0), 46*7f4beda2SGovind Singh .pipedir = __cpu_to_le32(PIPEDIR_OUT), 47*7f4beda2SGovind Singh .nentries = __cpu_to_le32(32), 48*7f4beda2SGovind Singh .nbytes_max = __cpu_to_le32(2048), 49*7f4beda2SGovind Singh .flags = __cpu_to_le32(CE_ATTR_FLAGS), 50*7f4beda2SGovind Singh .reserved = __cpu_to_le32(0), 51*7f4beda2SGovind Singh }, 52*7f4beda2SGovind Singh 53*7f4beda2SGovind Singh /* CE1: target->host HTT + HTC control */ 54*7f4beda2SGovind Singh { 55*7f4beda2SGovind Singh .pipenum = __cpu_to_le32(1), 56*7f4beda2SGovind Singh .pipedir = __cpu_to_le32(PIPEDIR_IN), 57*7f4beda2SGovind Singh .nentries = __cpu_to_le32(32), 58*7f4beda2SGovind Singh .nbytes_max = __cpu_to_le32(2048), 59*7f4beda2SGovind Singh .flags = __cpu_to_le32(CE_ATTR_FLAGS), 60*7f4beda2SGovind Singh .reserved = __cpu_to_le32(0), 61*7f4beda2SGovind Singh }, 62*7f4beda2SGovind Singh 63*7f4beda2SGovind Singh /* CE2: target->host WMI */ 64*7f4beda2SGovind Singh { 65*7f4beda2SGovind Singh .pipenum = __cpu_to_le32(2), 66*7f4beda2SGovind Singh .pipedir = __cpu_to_le32(PIPEDIR_IN), 67*7f4beda2SGovind Singh .nentries = __cpu_to_le32(32), 68*7f4beda2SGovind Singh .nbytes_max = __cpu_to_le32(2048), 69*7f4beda2SGovind Singh .flags = __cpu_to_le32(CE_ATTR_FLAGS), 70*7f4beda2SGovind Singh .reserved = __cpu_to_le32(0), 71*7f4beda2SGovind Singh }, 72*7f4beda2SGovind Singh 73*7f4beda2SGovind Singh /* CE3: host->target WMI */ 74*7f4beda2SGovind Singh { 75*7f4beda2SGovind Singh .pipenum = __cpu_to_le32(3), 76*7f4beda2SGovind Singh .pipedir = __cpu_to_le32(PIPEDIR_OUT), 77*7f4beda2SGovind Singh .nentries = __cpu_to_le32(32), 78*7f4beda2SGovind Singh .nbytes_max = __cpu_to_le32(2048), 79*7f4beda2SGovind Singh .flags = __cpu_to_le32(CE_ATTR_FLAGS), 80*7f4beda2SGovind Singh .reserved = __cpu_to_le32(0), 81*7f4beda2SGovind Singh }, 82*7f4beda2SGovind Singh 83*7f4beda2SGovind Singh /* CE4: host->target HTT */ 84*7f4beda2SGovind Singh { 85*7f4beda2SGovind Singh .pipenum = __cpu_to_le32(4), 86*7f4beda2SGovind Singh .pipedir = __cpu_to_le32(PIPEDIR_OUT), 87*7f4beda2SGovind Singh .nentries = __cpu_to_le32(256), 88*7f4beda2SGovind Singh .nbytes_max = __cpu_to_le32(256), 89*7f4beda2SGovind Singh .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), 90*7f4beda2SGovind Singh .reserved = __cpu_to_le32(0), 91*7f4beda2SGovind Singh }, 92*7f4beda2SGovind Singh 93*7f4beda2SGovind Singh /* CE5: target->host Pktlog */ 94*7f4beda2SGovind Singh { 95*7f4beda2SGovind Singh .pipenum = __cpu_to_le32(5), 96*7f4beda2SGovind Singh .pipedir = __cpu_to_le32(PIPEDIR_IN), 97*7f4beda2SGovind Singh .nentries = __cpu_to_le32(32), 98*7f4beda2SGovind Singh .nbytes_max = __cpu_to_le32(2048), 99*7f4beda2SGovind Singh .flags = __cpu_to_le32(CE_ATTR_FLAGS), 100*7f4beda2SGovind Singh .reserved = __cpu_to_le32(0), 101*7f4beda2SGovind Singh }, 102*7f4beda2SGovind Singh 103*7f4beda2SGovind Singh /* CE6: Reserved for target autonomous hif_memcpy */ 104*7f4beda2SGovind Singh { 105*7f4beda2SGovind Singh .pipenum = __cpu_to_le32(6), 106*7f4beda2SGovind Singh .pipedir = __cpu_to_le32(PIPEDIR_INOUT), 107*7f4beda2SGovind Singh .nentries = __cpu_to_le32(32), 108*7f4beda2SGovind Singh .nbytes_max = __cpu_to_le32(16384), 109*7f4beda2SGovind Singh .flags = __cpu_to_le32(CE_ATTR_FLAGS), 110*7f4beda2SGovind Singh .reserved = __cpu_to_le32(0), 111*7f4beda2SGovind Singh }, 112*7f4beda2SGovind Singh 113*7f4beda2SGovind Singh /* CE7 used only by Host */ 114*7f4beda2SGovind Singh { 115*7f4beda2SGovind Singh .pipenum = __cpu_to_le32(7), 116*7f4beda2SGovind Singh .pipedir = __cpu_to_le32(PIPEDIR_INOUT_H2H), 117*7f4beda2SGovind Singh .nentries = __cpu_to_le32(0), 118*7f4beda2SGovind Singh .nbytes_max = __cpu_to_le32(0), 119*7f4beda2SGovind Singh .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), 120*7f4beda2SGovind Singh .reserved = __cpu_to_le32(0), 121*7f4beda2SGovind Singh }, 122*7f4beda2SGovind Singh 123*7f4beda2SGovind Singh /* CE8 target->host used only by IPA */ 124*7f4beda2SGovind Singh { 125*7f4beda2SGovind Singh .pipenum = __cpu_to_le32(8), 126*7f4beda2SGovind Singh .pipedir = __cpu_to_le32(PIPEDIR_INOUT), 127*7f4beda2SGovind Singh .nentries = __cpu_to_le32(32), 128*7f4beda2SGovind Singh .nbytes_max = __cpu_to_le32(16384), 129*7f4beda2SGovind Singh .flags = __cpu_to_le32(CE_ATTR_FLAGS), 130*7f4beda2SGovind Singh .reserved = __cpu_to_le32(0), 131*7f4beda2SGovind Singh }, 132*7f4beda2SGovind Singh /* CE 9, 10, 11 are used by MHI driver */ 133*7f4beda2SGovind Singh }; 134*7f4beda2SGovind Singh 135*7f4beda2SGovind Singh /* Map from service/endpoint to Copy Engine. 136*7f4beda2SGovind Singh * This table is derived from the CE_PCI TABLE, above. 137*7f4beda2SGovind Singh * It is passed to the Target at startup for use by firmware. 138*7f4beda2SGovind Singh */ 139*7f4beda2SGovind Singh static const struct service_to_pipe target_service_to_ce_map_wlan[] = { 140*7f4beda2SGovind Singh { 141*7f4beda2SGovind Singh __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VO), 142*7f4beda2SGovind Singh __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ 143*7f4beda2SGovind Singh __cpu_to_le32(3), 144*7f4beda2SGovind Singh }, 145*7f4beda2SGovind Singh { 146*7f4beda2SGovind Singh __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VO), 147*7f4beda2SGovind Singh __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ 148*7f4beda2SGovind Singh __cpu_to_le32(2), 149*7f4beda2SGovind Singh }, 150*7f4beda2SGovind Singh { 151*7f4beda2SGovind Singh __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BK), 152*7f4beda2SGovind Singh __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ 153*7f4beda2SGovind Singh __cpu_to_le32(3), 154*7f4beda2SGovind Singh }, 155*7f4beda2SGovind Singh { 156*7f4beda2SGovind Singh __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BK), 157*7f4beda2SGovind Singh __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ 158*7f4beda2SGovind Singh __cpu_to_le32(2), 159*7f4beda2SGovind Singh }, 160*7f4beda2SGovind Singh { 161*7f4beda2SGovind Singh __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BE), 162*7f4beda2SGovind Singh __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ 163*7f4beda2SGovind Singh __cpu_to_le32(3), 164*7f4beda2SGovind Singh }, 165*7f4beda2SGovind Singh { 166*7f4beda2SGovind Singh __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BE), 167*7f4beda2SGovind Singh __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ 168*7f4beda2SGovind Singh __cpu_to_le32(2), 169*7f4beda2SGovind Singh }, 170*7f4beda2SGovind Singh { 171*7f4beda2SGovind Singh __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VI), 172*7f4beda2SGovind Singh __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ 173*7f4beda2SGovind Singh __cpu_to_le32(3), 174*7f4beda2SGovind Singh }, 175*7f4beda2SGovind Singh { 176*7f4beda2SGovind Singh __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VI), 177*7f4beda2SGovind Singh __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ 178*7f4beda2SGovind Singh __cpu_to_le32(2), 179*7f4beda2SGovind Singh }, 180*7f4beda2SGovind Singh { 181*7f4beda2SGovind Singh __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL), 182*7f4beda2SGovind Singh __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ 183*7f4beda2SGovind Singh __cpu_to_le32(3), 184*7f4beda2SGovind Singh }, 185*7f4beda2SGovind Singh { 186*7f4beda2SGovind Singh __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL), 187*7f4beda2SGovind Singh __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ 188*7f4beda2SGovind Singh __cpu_to_le32(2), 189*7f4beda2SGovind Singh }, 190*7f4beda2SGovind Singh 191*7f4beda2SGovind Singh { 192*7f4beda2SGovind Singh __cpu_to_le32(ATH11K_HTC_SVC_ID_RSVD_CTRL), 193*7f4beda2SGovind Singh __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ 194*7f4beda2SGovind Singh __cpu_to_le32(0), 195*7f4beda2SGovind Singh }, 196*7f4beda2SGovind Singh { 197*7f4beda2SGovind Singh __cpu_to_le32(ATH11K_HTC_SVC_ID_RSVD_CTRL), 198*7f4beda2SGovind Singh __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ 199*7f4beda2SGovind Singh __cpu_to_le32(2), 200*7f4beda2SGovind Singh }, 201*7f4beda2SGovind Singh 202*7f4beda2SGovind Singh { 203*7f4beda2SGovind Singh __cpu_to_le32(ATH11K_HTC_SVC_ID_HTT_DATA_MSG), 204*7f4beda2SGovind Singh __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ 205*7f4beda2SGovind Singh __cpu_to_le32(4), 206*7f4beda2SGovind Singh }, 207*7f4beda2SGovind Singh { 208*7f4beda2SGovind Singh __cpu_to_le32(ATH11K_HTC_SVC_ID_HTT_DATA_MSG), 209*7f4beda2SGovind Singh __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ 210*7f4beda2SGovind Singh __cpu_to_le32(1), 211*7f4beda2SGovind Singh }, 212*7f4beda2SGovind Singh 213*7f4beda2SGovind Singh /* (Additions here) */ 214*7f4beda2SGovind Singh 215*7f4beda2SGovind Singh { /* must be last */ 216*7f4beda2SGovind Singh __cpu_to_le32(0), 217*7f4beda2SGovind Singh __cpu_to_le32(0), 218*7f4beda2SGovind Singh __cpu_to_le32(0), 219*7f4beda2SGovind Singh }, 220*7f4beda2SGovind Singh }; 221*7f4beda2SGovind Singh 222*7f4beda2SGovind Singh static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { 223*7f4beda2SGovind Singh "bhi", 224*7f4beda2SGovind Singh "mhi-er0", 225*7f4beda2SGovind Singh "mhi-er1", 226*7f4beda2SGovind Singh "ce0", 227*7f4beda2SGovind Singh "ce1", 228*7f4beda2SGovind Singh "ce2", 229*7f4beda2SGovind Singh "ce3", 230*7f4beda2SGovind Singh "ce4", 231*7f4beda2SGovind Singh "ce5", 232*7f4beda2SGovind Singh "ce6", 233*7f4beda2SGovind Singh "ce7", 234*7f4beda2SGovind Singh "ce8", 235*7f4beda2SGovind Singh "ce9", 236*7f4beda2SGovind Singh "ce10", 237*7f4beda2SGovind Singh "ce11", 238*7f4beda2SGovind Singh "host2wbm-desc-feed", 239*7f4beda2SGovind Singh "host2reo-re-injection", 240*7f4beda2SGovind Singh "host2reo-command", 241*7f4beda2SGovind Singh "host2rxdma-monitor-ring3", 242*7f4beda2SGovind Singh "host2rxdma-monitor-ring2", 243*7f4beda2SGovind Singh "host2rxdma-monitor-ring1", 244*7f4beda2SGovind Singh "reo2ost-exception", 245*7f4beda2SGovind Singh "wbm2host-rx-release", 246*7f4beda2SGovind Singh "reo2host-status", 247*7f4beda2SGovind Singh "reo2host-destination-ring4", 248*7f4beda2SGovind Singh "reo2host-destination-ring3", 249*7f4beda2SGovind Singh "reo2host-destination-ring2", 250*7f4beda2SGovind Singh "reo2host-destination-ring1", 251*7f4beda2SGovind Singh "rxdma2host-monitor-destination-mac3", 252*7f4beda2SGovind Singh "rxdma2host-monitor-destination-mac2", 253*7f4beda2SGovind Singh "rxdma2host-monitor-destination-mac1", 254*7f4beda2SGovind Singh "ppdu-end-interrupts-mac3", 255*7f4beda2SGovind Singh "ppdu-end-interrupts-mac2", 256*7f4beda2SGovind Singh "ppdu-end-interrupts-mac1", 257*7f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac3", 258*7f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac2", 259*7f4beda2SGovind Singh "rxdma2host-monitor-status-ring-mac1", 260*7f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac3", 261*7f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac2", 262*7f4beda2SGovind Singh "host2rxdma-host-buf-ring-mac1", 263*7f4beda2SGovind Singh "rxdma2host-destination-ring-mac3", 264*7f4beda2SGovind Singh "rxdma2host-destination-ring-mac2", 265*7f4beda2SGovind Singh "rxdma2host-destination-ring-mac1", 266*7f4beda2SGovind Singh "host2tcl-input-ring4", 267*7f4beda2SGovind Singh "host2tcl-input-ring3", 268*7f4beda2SGovind Singh "host2tcl-input-ring2", 269*7f4beda2SGovind Singh "host2tcl-input-ring1", 270*7f4beda2SGovind Singh "wbm2host-tx-completions-ring3", 271*7f4beda2SGovind Singh "wbm2host-tx-completions-ring2", 272*7f4beda2SGovind Singh "wbm2host-tx-completions-ring1", 273*7f4beda2SGovind Singh "tcl2host-status-ring", 274*7f4beda2SGovind Singh }; 275*7f4beda2SGovind Singh 2761399fb87SGovind Singh int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) 2771399fb87SGovind Singh { 2781399fb87SGovind Singh struct pci_dev *pci_dev = to_pci_dev(dev); 2791399fb87SGovind Singh 2801399fb87SGovind Singh return pci_irq_vector(pci_dev, vector); 2811399fb87SGovind Singh } 2821399fb87SGovind Singh 2831399fb87SGovind Singh int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, 2841399fb87SGovind Singh int *num_vectors, u32 *user_base_data, 2851399fb87SGovind Singh u32 *base_vector) 2861399fb87SGovind Singh { 2871399fb87SGovind Singh struct ath11k_base *ab = ab_pci->ab; 2881399fb87SGovind Singh int idx; 2891399fb87SGovind Singh 2901399fb87SGovind Singh for (idx = 0; idx < msi_config.total_users; idx++) { 2911399fb87SGovind Singh if (strcmp(user_name, msi_config.users[idx].name) == 0) { 2921399fb87SGovind Singh *num_vectors = msi_config.users[idx].num_vectors; 2931399fb87SGovind Singh *user_base_data = msi_config.users[idx].base_vector 2941399fb87SGovind Singh + ab_pci->msi_ep_base_data; 2951399fb87SGovind Singh *base_vector = msi_config.users[idx].base_vector; 2961399fb87SGovind Singh 2971399fb87SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", 2981399fb87SGovind Singh user_name, *num_vectors, *user_base_data, 2991399fb87SGovind Singh *base_vector); 3001399fb87SGovind Singh 3011399fb87SGovind Singh return 0; 3021399fb87SGovind Singh } 3031399fb87SGovind Singh } 3041399fb87SGovind Singh 3051399fb87SGovind Singh ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name); 3061399fb87SGovind Singh 3071399fb87SGovind Singh return -EINVAL; 3081399fb87SGovind Singh } 3091399fb87SGovind Singh 310*7f4beda2SGovind Singh static void ath11k_pci_free_irq(struct ath11k_base *ab) 311*7f4beda2SGovind Singh { 312*7f4beda2SGovind Singh int i, irq_idx; 313*7f4beda2SGovind Singh 314*7f4beda2SGovind Singh for (i = 0; i < CE_COUNT; i++) { 315*7f4beda2SGovind Singh if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) 316*7f4beda2SGovind Singh continue; 317*7f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 318*7f4beda2SGovind Singh free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); 319*7f4beda2SGovind Singh } 320*7f4beda2SGovind Singh } 321*7f4beda2SGovind Singh 322*7f4beda2SGovind Singh static void ath11k_pci_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) 323*7f4beda2SGovind Singh { 324*7f4beda2SGovind Singh u32 irq_idx; 325*7f4beda2SGovind Singh 326*7f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 327*7f4beda2SGovind Singh disable_irq_nosync(ab->irq_num[irq_idx]); 328*7f4beda2SGovind Singh } 329*7f4beda2SGovind Singh 330*7f4beda2SGovind Singh static irqreturn_t ath11k_pci_ce_interrupt_handler(int irq, void *arg) 331*7f4beda2SGovind Singh { 332*7f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe = arg; 333*7f4beda2SGovind Singh 334*7f4beda2SGovind Singh ath11k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num); 335*7f4beda2SGovind Singh 336*7f4beda2SGovind Singh return IRQ_HANDLED; 337*7f4beda2SGovind Singh } 338*7f4beda2SGovind Singh 339*7f4beda2SGovind Singh static int ath11k_pci_config_irq(struct ath11k_base *ab) 340*7f4beda2SGovind Singh { 341*7f4beda2SGovind Singh struct ath11k_ce_pipe *ce_pipe; 342*7f4beda2SGovind Singh u32 msi_data_start; 343*7f4beda2SGovind Singh u32 msi_data_count; 344*7f4beda2SGovind Singh u32 msi_irq_start; 345*7f4beda2SGovind Singh unsigned int msi_data; 346*7f4beda2SGovind Singh int irq, i, ret, irq_idx; 347*7f4beda2SGovind Singh 348*7f4beda2SGovind Singh ret = ath11k_pci_get_user_msi_assignment(ath11k_pci_priv(ab), 349*7f4beda2SGovind Singh "CE", &msi_data_count, 350*7f4beda2SGovind Singh &msi_data_start, &msi_irq_start); 351*7f4beda2SGovind Singh if (ret) 352*7f4beda2SGovind Singh return ret; 353*7f4beda2SGovind Singh 354*7f4beda2SGovind Singh /* Configure CE irqs */ 355*7f4beda2SGovind Singh for (i = 0; i < CE_COUNT; i++) { 356*7f4beda2SGovind Singh msi_data = (i % msi_data_count) + msi_irq_start; 357*7f4beda2SGovind Singh irq = ath11k_pci_get_msi_irq(ab->dev, msi_data); 358*7f4beda2SGovind Singh ce_pipe = &ab->ce.ce_pipe[i]; 359*7f4beda2SGovind Singh 360*7f4beda2SGovind Singh if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) 361*7f4beda2SGovind Singh continue; 362*7f4beda2SGovind Singh 363*7f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 364*7f4beda2SGovind Singh 365*7f4beda2SGovind Singh ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, 366*7f4beda2SGovind Singh IRQF_SHARED, irq_name[irq_idx], 367*7f4beda2SGovind Singh ce_pipe); 368*7f4beda2SGovind Singh if (ret) { 369*7f4beda2SGovind Singh ath11k_err(ab, "failed to request irq %d: %d\n", 370*7f4beda2SGovind Singh irq_idx, ret); 371*7f4beda2SGovind Singh return ret; 372*7f4beda2SGovind Singh } 373*7f4beda2SGovind Singh 374*7f4beda2SGovind Singh ab->irq_num[irq_idx] = irq; 375*7f4beda2SGovind Singh } 376*7f4beda2SGovind Singh 377*7f4beda2SGovind Singh return 0; 378*7f4beda2SGovind Singh } 379*7f4beda2SGovind Singh 380*7f4beda2SGovind Singh static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab) 381*7f4beda2SGovind Singh { 382*7f4beda2SGovind Singh struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; 383*7f4beda2SGovind Singh 384*7f4beda2SGovind Singh cfg->tgt_ce = target_ce_config_wlan; 385*7f4beda2SGovind Singh cfg->tgt_ce_len = ARRAY_SIZE(target_ce_config_wlan); 386*7f4beda2SGovind Singh 387*7f4beda2SGovind Singh cfg->svc_to_ce_map = target_service_to_ce_map_wlan; 388*7f4beda2SGovind Singh cfg->svc_to_ce_map_len = ARRAY_SIZE(target_service_to_ce_map_wlan); 389*7f4beda2SGovind Singh } 390*7f4beda2SGovind Singh 391*7f4beda2SGovind Singh static void ath11k_pci_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) 392*7f4beda2SGovind Singh { 393*7f4beda2SGovind Singh u32 irq_idx; 394*7f4beda2SGovind Singh 395*7f4beda2SGovind Singh irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 396*7f4beda2SGovind Singh enable_irq(ab->irq_num[irq_idx]); 397*7f4beda2SGovind Singh } 398*7f4beda2SGovind Singh 399*7f4beda2SGovind Singh static void ath11k_pci_ce_irqs_enable(struct ath11k_base *ab) 400*7f4beda2SGovind Singh { 401*7f4beda2SGovind Singh int i; 402*7f4beda2SGovind Singh 403*7f4beda2SGovind Singh for (i = 0; i < CE_COUNT; i++) { 404*7f4beda2SGovind Singh if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR) 405*7f4beda2SGovind Singh continue; 406*7f4beda2SGovind Singh ath11k_pci_ce_irq_enable(ab, i); 407*7f4beda2SGovind Singh } 408*7f4beda2SGovind Singh } 409*7f4beda2SGovind Singh 4105697a564SGovind Singh static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci) 4115697a564SGovind Singh { 4125697a564SGovind Singh struct ath11k_base *ab = ab_pci->ab; 4135697a564SGovind Singh struct msi_desc *msi_desc; 4145697a564SGovind Singh int num_vectors; 4155697a564SGovind Singh int ret; 4165697a564SGovind Singh 4175697a564SGovind Singh num_vectors = pci_alloc_irq_vectors(ab_pci->pdev, 4185697a564SGovind Singh msi_config.total_vectors, 4195697a564SGovind Singh msi_config.total_vectors, 4205697a564SGovind Singh PCI_IRQ_MSI); 4215697a564SGovind Singh if (num_vectors != msi_config.total_vectors) { 4225697a564SGovind Singh ath11k_err(ab, "failed to get %d MSI vectors, only %d available", 4235697a564SGovind Singh msi_config.total_vectors, num_vectors); 4245697a564SGovind Singh 4255697a564SGovind Singh if (num_vectors >= 0) 4265697a564SGovind Singh return -EINVAL; 4275697a564SGovind Singh else 4285697a564SGovind Singh return num_vectors; 4295697a564SGovind Singh } 4305697a564SGovind Singh 4315697a564SGovind Singh msi_desc = irq_get_msi_desc(ab_pci->pdev->irq); 4325697a564SGovind Singh if (!msi_desc) { 4335697a564SGovind Singh ath11k_err(ab, "msi_desc is NULL!\n"); 4345697a564SGovind Singh ret = -EINVAL; 4355697a564SGovind Singh goto free_msi_vector; 4365697a564SGovind Singh } 4375697a564SGovind Singh 4385697a564SGovind Singh ab_pci->msi_ep_base_data = msi_desc->msg.data; 4395697a564SGovind Singh 4405697a564SGovind Singh ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); 4415697a564SGovind Singh 4425697a564SGovind Singh return 0; 4435697a564SGovind Singh 4445697a564SGovind Singh free_msi_vector: 4455697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 4465697a564SGovind Singh 4475697a564SGovind Singh return ret; 4485697a564SGovind Singh } 4495697a564SGovind Singh 4505697a564SGovind Singh static void ath11k_pci_disable_msi(struct ath11k_pci *ab_pci) 4515697a564SGovind Singh { 4525697a564SGovind Singh pci_free_irq_vectors(ab_pci->pdev); 4535697a564SGovind Singh } 4545697a564SGovind Singh 4555762613eSGovind Singh static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) 4565762613eSGovind Singh { 4575762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 4585762613eSGovind Singh u16 device_id; 4595762613eSGovind Singh int ret = 0; 4605762613eSGovind Singh 4615762613eSGovind Singh pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); 4625762613eSGovind Singh if (device_id != ab_pci->dev_id) { 4635762613eSGovind Singh ath11k_err(ab, "pci device id mismatch: 0x%x 0x%x\n", 4645762613eSGovind Singh device_id, ab_pci->dev_id); 4655762613eSGovind Singh ret = -EIO; 4665762613eSGovind Singh goto out; 4675762613eSGovind Singh } 4685762613eSGovind Singh 4695762613eSGovind Singh ret = pci_assign_resource(pdev, ATH11K_PCI_BAR_NUM); 4705762613eSGovind Singh if (ret) { 4715762613eSGovind Singh ath11k_err(ab, "failed to assign pci resource: %d\n", ret); 4725762613eSGovind Singh goto out; 4735762613eSGovind Singh } 4745762613eSGovind Singh 4755762613eSGovind Singh ret = pci_enable_device(pdev); 4765762613eSGovind Singh if (ret) { 4775762613eSGovind Singh ath11k_err(ab, "failed to enable pci device: %d\n", ret); 4785762613eSGovind Singh goto out; 4795762613eSGovind Singh } 4805762613eSGovind Singh 4815762613eSGovind Singh ret = pci_request_region(pdev, ATH11K_PCI_BAR_NUM, "ath11k_pci"); 4825762613eSGovind Singh if (ret) { 4835762613eSGovind Singh ath11k_err(ab, "failed to request pci region: %d\n", ret); 4845762613eSGovind Singh goto disable_device; 4855762613eSGovind Singh } 4865762613eSGovind Singh 4875762613eSGovind Singh ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 4885762613eSGovind Singh if (ret) { 4895762613eSGovind Singh ath11k_err(ab, "failed to set pci dma mask to %d: %d\n", 4905762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 4915762613eSGovind Singh goto release_region; 4925762613eSGovind Singh } 4935762613eSGovind Singh 4945762613eSGovind Singh ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ATH11K_PCI_DMA_MASK)); 4955762613eSGovind Singh if (ret) { 4965762613eSGovind Singh ath11k_err(ab, "failed to set pci consistent dma mask to %d: %d\n", 4975762613eSGovind Singh ATH11K_PCI_DMA_MASK, ret); 4985762613eSGovind Singh goto release_region; 4995762613eSGovind Singh } 5005762613eSGovind Singh 5015762613eSGovind Singh pci_set_master(pdev); 5025762613eSGovind Singh 5035762613eSGovind Singh ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM); 5045762613eSGovind Singh ab->mem = pci_iomap(pdev, ATH11K_PCI_BAR_NUM, 0); 5055762613eSGovind Singh if (!ab->mem) { 5065762613eSGovind Singh ath11k_err(ab, "failed to map pci bar %d\n", ATH11K_PCI_BAR_NUM); 5075762613eSGovind Singh ret = -EIO; 5085762613eSGovind Singh goto clear_master; 5095762613eSGovind Singh } 5105762613eSGovind Singh 5115762613eSGovind Singh ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); 5125762613eSGovind Singh return 0; 5135762613eSGovind Singh 5145762613eSGovind Singh clear_master: 5155762613eSGovind Singh pci_clear_master(pdev); 5165762613eSGovind Singh release_region: 5175762613eSGovind Singh pci_release_region(pdev, ATH11K_PCI_BAR_NUM); 5185762613eSGovind Singh disable_device: 5195762613eSGovind Singh pci_disable_device(pdev); 5205762613eSGovind Singh out: 5215762613eSGovind Singh return ret; 5225762613eSGovind Singh } 5235762613eSGovind Singh 5245762613eSGovind Singh static void ath11k_pci_free_region(struct ath11k_pci *ab_pci) 5255762613eSGovind Singh { 5265762613eSGovind Singh struct ath11k_base *ab = ab_pci->ab; 5275762613eSGovind Singh struct pci_dev *pci_dev = ab_pci->pdev; 5285762613eSGovind Singh 5295762613eSGovind Singh pci_iounmap(pci_dev, ab->mem); 5305762613eSGovind Singh ab->mem = NULL; 5315762613eSGovind Singh pci_clear_master(pci_dev); 5325762613eSGovind Singh pci_release_region(pci_dev, ATH11K_PCI_BAR_NUM); 5335762613eSGovind Singh if (pci_is_enabled(pci_dev)) 5345762613eSGovind Singh pci_disable_device(pci_dev); 5355762613eSGovind Singh } 5365762613eSGovind Singh 5371399fb87SGovind Singh static int ath11k_pci_power_up(struct ath11k_base *ab) 5381399fb87SGovind Singh { 5391399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 5401399fb87SGovind Singh int ret; 5411399fb87SGovind Singh 5421399fb87SGovind Singh ret = ath11k_mhi_start(ab_pci); 5431399fb87SGovind Singh if (ret) { 5441399fb87SGovind Singh ath11k_err(ab, "failed to start mhi: %d\n", ret); 5451399fb87SGovind Singh return ret; 5461399fb87SGovind Singh } 5471399fb87SGovind Singh 5481399fb87SGovind Singh return 0; 5491399fb87SGovind Singh } 5501399fb87SGovind Singh 5511399fb87SGovind Singh static void ath11k_pci_power_down(struct ath11k_base *ab) 5521399fb87SGovind Singh { 5531399fb87SGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 5541399fb87SGovind Singh 5551399fb87SGovind Singh ath11k_mhi_stop(ab_pci); 5561399fb87SGovind Singh } 5571399fb87SGovind Singh 558*7f4beda2SGovind Singh static void ath11k_pci_stop(struct ath11k_base *ab) 559*7f4beda2SGovind Singh { 560*7f4beda2SGovind Singh ath11k_ce_cleanup_pipes(ab); 561*7f4beda2SGovind Singh } 562*7f4beda2SGovind Singh 563*7f4beda2SGovind Singh static int ath11k_pci_start(struct ath11k_base *ab) 564*7f4beda2SGovind Singh { 565*7f4beda2SGovind Singh ath11k_pci_ce_irqs_enable(ab); 566*7f4beda2SGovind Singh 567*7f4beda2SGovind Singh return 0; 568*7f4beda2SGovind Singh } 569*7f4beda2SGovind Singh 570*7f4beda2SGovind Singh static const struct ath11k_hif_ops ath11k_pci_hif_ops = { 571*7f4beda2SGovind Singh .start = ath11k_pci_start, 572*7f4beda2SGovind Singh .stop = ath11k_pci_stop, 5731399fb87SGovind Singh .power_down = ath11k_pci_power_down, 5741399fb87SGovind Singh .power_up = ath11k_pci_power_up, 5751399fb87SGovind Singh }; 5761399fb87SGovind Singh 5776e0355afSGovind Singh static int ath11k_pci_probe(struct pci_dev *pdev, 5786e0355afSGovind Singh const struct pci_device_id *pci_dev) 5796e0355afSGovind Singh { 5806e0355afSGovind Singh struct ath11k_base *ab; 5815762613eSGovind Singh struct ath11k_pci *ab_pci; 5826e0355afSGovind Singh enum ath11k_hw_rev hw_rev; 5835762613eSGovind Singh int ret; 5846e0355afSGovind Singh 5856e0355afSGovind Singh dev_warn(&pdev->dev, "WARNING: ath11k PCI support is experimental!\n"); 5866e0355afSGovind Singh 5876e0355afSGovind Singh switch (pci_dev->device) { 5886e0355afSGovind Singh case QCA6390_DEVICE_ID: 5896e0355afSGovind Singh hw_rev = ATH11K_HW_QCA6390_HW20; 5906e0355afSGovind Singh break; 5916e0355afSGovind Singh default: 5926e0355afSGovind Singh dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", 5936e0355afSGovind Singh pci_dev->device); 5946e0355afSGovind Singh return -ENOTSUPP; 5956e0355afSGovind Singh } 5966e0355afSGovind Singh 5975762613eSGovind Singh ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI); 5986e0355afSGovind Singh if (!ab) { 5996e0355afSGovind Singh dev_err(&pdev->dev, "failed to allocate ath11k base\n"); 6006e0355afSGovind Singh return -ENOMEM; 6016e0355afSGovind Singh } 6026e0355afSGovind Singh 6036e0355afSGovind Singh ab->dev = &pdev->dev; 6046e0355afSGovind Singh ab->hw_rev = hw_rev; 6056e0355afSGovind Singh pci_set_drvdata(pdev, ab); 6065762613eSGovind Singh ab_pci = ath11k_pci_priv(ab); 6075762613eSGovind Singh ab_pci->dev_id = pci_dev->device; 6085762613eSGovind Singh ab_pci->ab = ab; 6095697a564SGovind Singh ab_pci->pdev = pdev; 610*7f4beda2SGovind Singh ab->hif.ops = &ath11k_pci_hif_ops; 6115762613eSGovind Singh pci_set_drvdata(pdev, ab); 6125762613eSGovind Singh 6135762613eSGovind Singh ret = ath11k_pci_claim(ab_pci, pdev); 6145762613eSGovind Singh if (ret) { 6155762613eSGovind Singh ath11k_err(ab, "failed to claim device: %d\n", ret); 6165762613eSGovind Singh goto err_free_core; 6175762613eSGovind Singh } 6186e0355afSGovind Singh 6195697a564SGovind Singh ret = ath11k_pci_enable_msi(ab_pci); 6205697a564SGovind Singh if (ret) { 6215697a564SGovind Singh ath11k_err(ab, "failed to enable msi: %d\n", ret); 6225697a564SGovind Singh goto err_pci_free_region; 6235697a564SGovind Singh } 6245697a564SGovind Singh 625b8246f88SKalle Valo ret = ath11k_core_pre_init(ab); 626b8246f88SKalle Valo if (ret) 627b8246f88SKalle Valo goto err_pci_disable_msi; 628b8246f88SKalle Valo 6291399fb87SGovind Singh ret = ath11k_mhi_register(ab_pci); 6301399fb87SGovind Singh if (ret) { 6311399fb87SGovind Singh ath11k_err(ab, "failed to register mhi: %d\n", ret); 6321399fb87SGovind Singh goto err_pci_disable_msi; 6331399fb87SGovind Singh } 6341399fb87SGovind Singh 635*7f4beda2SGovind Singh ret = ath11k_hal_srng_init(ab); 636*7f4beda2SGovind Singh if (ret) 637*7f4beda2SGovind Singh goto err_mhi_unregister; 638*7f4beda2SGovind Singh 639*7f4beda2SGovind Singh ret = ath11k_ce_alloc_pipes(ab); 640*7f4beda2SGovind Singh if (ret) { 641*7f4beda2SGovind Singh ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret); 642*7f4beda2SGovind Singh goto err_hal_srng_deinit; 643*7f4beda2SGovind Singh } 644*7f4beda2SGovind Singh 645*7f4beda2SGovind Singh ath11k_pci_init_qmi_ce_config(ab); 646*7f4beda2SGovind Singh 647*7f4beda2SGovind Singh ret = ath11k_pci_config_irq(ab); 648*7f4beda2SGovind Singh if (ret) { 649*7f4beda2SGovind Singh ath11k_err(ab, "failed to config irq: %d\n", ret); 650*7f4beda2SGovind Singh goto err_ce_free; 651*7f4beda2SGovind Singh } 652*7f4beda2SGovind Singh 653*7f4beda2SGovind Singh ret = ath11k_core_init(ab); 654*7f4beda2SGovind Singh if (ret) { 655*7f4beda2SGovind Singh ath11k_err(ab, "failed to init core: %d\n", ret); 656*7f4beda2SGovind Singh goto err_free_irq; 657*7f4beda2SGovind Singh } 6586e0355afSGovind Singh return 0; 6595762613eSGovind Singh 660*7f4beda2SGovind Singh err_free_irq: 661*7f4beda2SGovind Singh ath11k_pci_free_irq(ab); 662*7f4beda2SGovind Singh 663*7f4beda2SGovind Singh err_ce_free: 664*7f4beda2SGovind Singh ath11k_ce_free_pipes(ab); 665*7f4beda2SGovind Singh 666*7f4beda2SGovind Singh err_hal_srng_deinit: 667*7f4beda2SGovind Singh ath11k_hal_srng_deinit(ab); 668*7f4beda2SGovind Singh 669*7f4beda2SGovind Singh err_mhi_unregister: 670*7f4beda2SGovind Singh ath11k_mhi_unregister(ab_pci); 671*7f4beda2SGovind Singh 672b8246f88SKalle Valo err_pci_disable_msi: 673b8246f88SKalle Valo ath11k_pci_disable_msi(ab_pci); 674b8246f88SKalle Valo 6755697a564SGovind Singh err_pci_free_region: 6765697a564SGovind Singh ath11k_pci_free_region(ab_pci); 6775697a564SGovind Singh 6785762613eSGovind Singh err_free_core: 6795762613eSGovind Singh ath11k_core_free(ab); 6805697a564SGovind Singh 6815762613eSGovind Singh return ret; 6826e0355afSGovind Singh } 6836e0355afSGovind Singh 6846e0355afSGovind Singh static void ath11k_pci_remove(struct pci_dev *pdev) 6856e0355afSGovind Singh { 6866e0355afSGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 6875762613eSGovind Singh struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); 6886e0355afSGovind Singh 6896e0355afSGovind Singh set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); 6901399fb87SGovind Singh ath11k_mhi_unregister(ab_pci); 6915697a564SGovind Singh ath11k_pci_disable_msi(ab_pci); 6925762613eSGovind Singh ath11k_pci_free_region(ab_pci); 693*7f4beda2SGovind Singh ath11k_pci_free_irq(ab); 6946e0355afSGovind Singh ath11k_core_free(ab); 6956e0355afSGovind Singh } 6966e0355afSGovind Singh 6971399fb87SGovind Singh static void ath11k_pci_shutdown(struct pci_dev *pdev) 6981399fb87SGovind Singh { 6991399fb87SGovind Singh struct ath11k_base *ab = pci_get_drvdata(pdev); 7001399fb87SGovind Singh 7011399fb87SGovind Singh ath11k_pci_power_down(ab); 7021399fb87SGovind Singh } 7031399fb87SGovind Singh 7046e0355afSGovind Singh static struct pci_driver ath11k_pci_driver = { 7056e0355afSGovind Singh .name = "ath11k_pci", 7066e0355afSGovind Singh .id_table = ath11k_pci_id_table, 7076e0355afSGovind Singh .probe = ath11k_pci_probe, 7086e0355afSGovind Singh .remove = ath11k_pci_remove, 7091399fb87SGovind Singh .shutdown = ath11k_pci_shutdown, 7106e0355afSGovind Singh }; 7116e0355afSGovind Singh 7126e0355afSGovind Singh static int ath11k_pci_init(void) 7136e0355afSGovind Singh { 7146e0355afSGovind Singh int ret; 7156e0355afSGovind Singh 7166e0355afSGovind Singh ret = pci_register_driver(&ath11k_pci_driver); 7176e0355afSGovind Singh if (ret) 7186e0355afSGovind Singh pr_err("failed to register ath11k pci driver: %d\n", 7196e0355afSGovind Singh ret); 7206e0355afSGovind Singh 7216e0355afSGovind Singh return ret; 7226e0355afSGovind Singh } 7236e0355afSGovind Singh module_init(ath11k_pci_init); 7246e0355afSGovind Singh 7256e0355afSGovind Singh static void ath11k_pci_exit(void) 7266e0355afSGovind Singh { 7276e0355afSGovind Singh pci_unregister_driver(&ath11k_pci_driver); 7286e0355afSGovind Singh } 7296e0355afSGovind Singh 7306e0355afSGovind Singh module_exit(ath11k_pci_exit); 7316e0355afSGovind Singh 7326e0355afSGovind Singh MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); 7336e0355afSGovind Singh MODULE_LICENSE("Dual BSD/GPL"); 734