Path: blob/main/sys/contrib/dev/athk/ath12k/pci.c
107001 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/*2* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.3* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.4*/56#include <linux/module.h>7#include <linux/msi.h>8#include <linux/pci.h>9#if defined(__FreeBSD__)10#include <linux/delay.h>11#endif1213#include "pci.h"14#include "core.h"15#include "hif.h"16#include "mhi.h"17#include "debug.h"1819#define ATH12K_PCI_BAR_NUM 020#define ATH12K_PCI_DMA_MASK 322122#define ATH12K_PCI_IRQ_CE0_OFFSET 32324#define WINDOW_ENABLE_BIT 0x4000000025#define WINDOW_REG_ADDRESS 0x310c26#define WINDOW_VALUE_MASK GENMASK(24, 19)27#define WINDOW_START 0x8000028#define WINDOW_RANGE_MASK GENMASK(18, 0)29#define WINDOW_STATIC_MASK GENMASK(31, 6)3031#define TCSR_SOC_HW_VERSION 0x1B0000032#define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8)33#define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 4)3435/* BAR0 + 4k is always accessible, and no36* need to force wakeup.37* 4K - 32 = 0xFE038*/39#define ACCESS_ALWAYS_OFF 0xFE04041#define QCN9274_DEVICE_ID 0x110942#define WCN7850_DEVICE_ID 0x11074344static const struct pci_device_id ath12k_pci_id_table[] = {45{ PCI_VDEVICE(QCOM, QCN9274_DEVICE_ID) },46{ PCI_VDEVICE(QCOM, WCN7850_DEVICE_ID) },47{0}48};4950MODULE_DEVICE_TABLE(pci, ath12k_pci_id_table);5152/* TODO: revisit IRQ mapping for new SRNG's */53static const struct ath12k_msi_config ath12k_msi_config[] = {54{55.total_vectors = 16,56.total_users = 3,57.users = (struct ath12k_msi_user[]) {58{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },59{ .name = "CE", .num_vectors = 5, .base_vector = 3 },60{ .name = "DP", .num_vectors = 8, .base_vector = 8 },61},62},63};6465static const char *irq_name[ATH12K_IRQ_NUM_MAX] = {66"bhi",67"mhi-er0",68"mhi-er1",69"ce0",70"ce1",71"ce2",72"ce3",73"ce4",74"ce5",75"ce6",76"ce7",77"ce8",78"ce9",79"ce10",80"ce11",81"ce12",82"ce13",83"ce14",84"ce15",85"host2wbm-desc-feed",86"host2reo-re-injection",87"host2reo-command",88"host2rxdma-monitor-ring3",89"host2rxdma-monitor-ring2",90"host2rxdma-monitor-ring1",91"reo2ost-exception",92"wbm2host-rx-release",93"reo2host-status",94"reo2host-destination-ring4",95"reo2host-destination-ring3",96"reo2host-destination-ring2",97"reo2host-destination-ring1",98"rxdma2host-monitor-destination-mac3",99"rxdma2host-monitor-destination-mac2",100"rxdma2host-monitor-destination-mac1",101"ppdu-end-interrupts-mac3",102"ppdu-end-interrupts-mac2",103"ppdu-end-interrupts-mac1",104"rxdma2host-monitor-status-ring-mac3",105"rxdma2host-monitor-status-ring-mac2",106"rxdma2host-monitor-status-ring-mac1",107"host2rxdma-host-buf-ring-mac3",108"host2rxdma-host-buf-ring-mac2",109"host2rxdma-host-buf-ring-mac1",110"rxdma2host-destination-ring-mac3",111"rxdma2host-destination-ring-mac2",112"rxdma2host-destination-ring-mac1",113"host2tcl-input-ring4",114"host2tcl-input-ring3",115"host2tcl-input-ring2",116"host2tcl-input-ring1",117"wbm2host-tx-completions-ring4",118"wbm2host-tx-completions-ring3",119"wbm2host-tx-completions-ring2",120"wbm2host-tx-completions-ring1",121"tcl2host-status-ring",122};123124static int ath12k_pci_bus_wake_up(struct ath12k_base *ab)125{126struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);127128return mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);129}130131static void ath12k_pci_bus_release(struct ath12k_base *ab)132{133struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);134135mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);136}137138static const struct ath12k_pci_ops ath12k_pci_ops_qcn9274 = {139.wakeup = NULL,140.release = NULL,141};142143static const struct ath12k_pci_ops ath12k_pci_ops_wcn7850 = {144.wakeup = ath12k_pci_bus_wake_up,145.release = ath12k_pci_bus_release,146};147148static void ath12k_pci_select_window(struct ath12k_pci *ab_pci, u32 offset)149{150struct ath12k_base *ab = ab_pci->ab;151152u32 window = u32_get_bits(offset, WINDOW_VALUE_MASK);153u32 static_window;154155lockdep_assert_held(&ab_pci->window_lock);156157/* Preserve the static window configuration and reset only dynamic window */158static_window = ab_pci->register_window & WINDOW_STATIC_MASK;159window |= static_window;160161if (window != ab_pci->register_window) {162iowrite32(WINDOW_ENABLE_BIT | window,163#if defined(__linux__)164ab->mem + WINDOW_REG_ADDRESS);165ioread32(ab->mem + WINDOW_REG_ADDRESS);166#elif defined(__FreeBSD__)167(char *)ab->mem + WINDOW_REG_ADDRESS);168ioread32((char *)ab->mem + WINDOW_REG_ADDRESS);169#endif170ab_pci->register_window = window;171}172}173174static void ath12k_pci_select_static_window(struct ath12k_pci *ab_pci)175{176u32 umac_window = u32_get_bits(HAL_SEQ_WCSS_UMAC_OFFSET, WINDOW_VALUE_MASK);177u32 ce_window = u32_get_bits(HAL_CE_WFSS_CE_REG_BASE, WINDOW_VALUE_MASK);178u32 window;179180window = (umac_window << 12) | (ce_window << 6);181182spin_lock_bh(&ab_pci->window_lock);183ab_pci->register_window = window;184spin_unlock_bh(&ab_pci->window_lock);185186#if defined(__linux__)187iowrite32(WINDOW_ENABLE_BIT | window, ab_pci->ab->mem + WINDOW_REG_ADDRESS);188#elif defined(__FreeBSD__)189iowrite32(WINDOW_ENABLE_BIT | window, (char *)ab_pci->ab->mem + WINDOW_REG_ADDRESS);190#endif191}192193static u32 ath12k_pci_get_window_start(struct ath12k_base *ab,194u32 offset)195{196u32 window_start;197198/* If offset lies within DP register range, use 3rd window */199if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < WINDOW_RANGE_MASK)200window_start = 3 * WINDOW_START;201/* If offset lies within CE register range, use 2nd window */202else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK)203window_start = 2 * WINDOW_START;204/* If offset lies within PCI_BAR_WINDOW0_BASE and within PCI_SOC_PCI_REG_BASE205* use 0th window206*/207else if (((offset ^ PCI_BAR_WINDOW0_BASE) < WINDOW_RANGE_MASK) &&208!((offset ^ PCI_SOC_PCI_REG_BASE) < PCI_SOC_RANGE_MASK))209window_start = 0;210else211window_start = WINDOW_START;212213return window_start;214}215216static void ath12k_pci_soc_global_reset(struct ath12k_base *ab)217{218u32 val, delay;219220val = ath12k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);221222val |= PCIE_SOC_GLOBAL_RESET_V;223224ath12k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);225226/* TODO: exact time to sleep is uncertain */227delay = 10;228mdelay(delay);229230/* Need to toggle V bit back otherwise stuck in reset status */231val &= ~PCIE_SOC_GLOBAL_RESET_V;232233ath12k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);234235mdelay(delay);236237val = ath12k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);238if (val == 0xffffffff)239ath12k_warn(ab, "link down error during global reset\n");240}241242static void ath12k_pci_clear_dbg_registers(struct ath12k_base *ab)243{244u32 val;245246/* read cookie */247val = ath12k_pci_read32(ab, PCIE_Q6_COOKIE_ADDR);248ath12k_dbg(ab, ATH12K_DBG_PCI, "cookie:0x%x\n", val);249250val = ath12k_pci_read32(ab, WLAON_WARM_SW_ENTRY);251ath12k_dbg(ab, ATH12K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);252253/* TODO: exact time to sleep is uncertain */254mdelay(10);255256/* write 0 to WLAON_WARM_SW_ENTRY to prevent Q6 from257* continuing warm path and entering dead loop.258*/259ath12k_pci_write32(ab, WLAON_WARM_SW_ENTRY, 0);260mdelay(10);261262val = ath12k_pci_read32(ab, WLAON_WARM_SW_ENTRY);263ath12k_dbg(ab, ATH12K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val);264265/* A read clear register. clear the register to prevent266* Q6 from entering wrong code path.267*/268val = ath12k_pci_read32(ab, WLAON_SOC_RESET_CAUSE_REG);269ath12k_dbg(ab, ATH12K_DBG_PCI, "soc reset cause:%d\n", val);270}271272static void ath12k_pci_enable_ltssm(struct ath12k_base *ab)273{274u32 val;275int i;276277val = ath12k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);278279/* PCIE link seems very unstable after the Hot Reset*/280for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) {281if (val == 0xffffffff)282mdelay(5);283284ath12k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE);285val = ath12k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM);286}287288ath12k_dbg(ab, ATH12K_DBG_PCI, "pci ltssm 0x%x\n", val);289290val = ath12k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);291val |= GCC_GCC_PCIE_HOT_RST_VAL;292ath12k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val);293val = ath12k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);294295ath12k_dbg(ab, ATH12K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val);296297mdelay(5);298}299300static void ath12k_pci_clear_all_intrs(struct ath12k_base *ab)301{302/* This is a WAR for PCIE Hotreset.303* When target receive Hotreset, but will set the interrupt.304* So when download SBL again, SBL will open Interrupt and305* receive it, and crash immediately.306*/307ath12k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL);308}309310static void ath12k_pci_set_wlaon_pwr_ctrl(struct ath12k_base *ab)311{312u32 val;313314val = ath12k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG);315val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK;316ath12k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val);317}318319static void ath12k_pci_force_wake(struct ath12k_base *ab)320{321ath12k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1);322mdelay(5);323}324325static void ath12k_pci_sw_reset(struct ath12k_base *ab, bool power_on)326{327if (power_on) {328ath12k_pci_enable_ltssm(ab);329ath12k_pci_clear_all_intrs(ab);330ath12k_pci_set_wlaon_pwr_ctrl(ab);331}332333ath12k_mhi_clear_vector(ab);334ath12k_pci_clear_dbg_registers(ab);335ath12k_pci_soc_global_reset(ab);336ath12k_mhi_set_mhictrl_reset(ab);337}338339static void ath12k_pci_free_ext_irq(struct ath12k_base *ab)340{341int i, j;342343for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) {344struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];345346for (j = 0; j < irq_grp->num_irq; j++)347free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);348349netif_napi_del(&irq_grp->napi);350}351}352353static void ath12k_pci_free_irq(struct ath12k_base *ab)354{355int i, irq_idx;356357for (i = 0; i < ab->hw_params->ce_count; i++) {358if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)359continue;360irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + i;361free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);362}363364ath12k_pci_free_ext_irq(ab);365}366367static void ath12k_pci_ce_irq_enable(struct ath12k_base *ab, u16 ce_id)368{369u32 irq_idx;370371irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_id;372enable_irq(ab->irq_num[irq_idx]);373}374375static void ath12k_pci_ce_irq_disable(struct ath12k_base *ab, u16 ce_id)376{377u32 irq_idx;378379irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_id;380disable_irq_nosync(ab->irq_num[irq_idx]);381}382383static void ath12k_pci_ce_irqs_disable(struct ath12k_base *ab)384{385int i;386387for (i = 0; i < ab->hw_params->ce_count; i++) {388if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)389continue;390ath12k_pci_ce_irq_disable(ab, i);391}392}393394static void ath12k_pci_sync_ce_irqs(struct ath12k_base *ab)395{396int i;397int irq_idx;398399for (i = 0; i < ab->hw_params->ce_count; i++) {400if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)401continue;402403irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + i;404synchronize_irq(ab->irq_num[irq_idx]);405}406}407408static void ath12k_pci_ce_tasklet(struct tasklet_struct *t)409{410struct ath12k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);411412ath12k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);413414ath12k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);415}416417static irqreturn_t ath12k_pci_ce_interrupt_handler(int irq, void *arg)418{419struct ath12k_ce_pipe *ce_pipe = arg;420421/* last interrupt received for this CE */422ce_pipe->timestamp = jiffies;423424ath12k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);425tasklet_schedule(&ce_pipe->intr_tq);426427return IRQ_HANDLED;428}429430static void ath12k_pci_ext_grp_disable(struct ath12k_ext_irq_grp *irq_grp)431{432int i;433434for (i = 0; i < irq_grp->num_irq; i++)435disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);436}437438static void __ath12k_pci_ext_irq_disable(struct ath12k_base *sc)439{440int i;441442for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) {443struct ath12k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i];444445ath12k_pci_ext_grp_disable(irq_grp);446447napi_synchronize(&irq_grp->napi);448napi_disable(&irq_grp->napi);449}450}451452static void ath12k_pci_ext_grp_enable(struct ath12k_ext_irq_grp *irq_grp)453{454int i;455456for (i = 0; i < irq_grp->num_irq; i++)457enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);458}459460static void ath12k_pci_sync_ext_irqs(struct ath12k_base *ab)461{462int i, j, irq_idx;463464for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) {465struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];466467for (j = 0; j < irq_grp->num_irq; j++) {468irq_idx = irq_grp->irqs[j];469synchronize_irq(ab->irq_num[irq_idx]);470}471}472}473474static int ath12k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)475{476struct ath12k_ext_irq_grp *irq_grp = container_of(napi,477struct ath12k_ext_irq_grp,478napi);479struct ath12k_base *ab = irq_grp->ab;480int work_done;481482work_done = ath12k_dp_service_srng(ab, irq_grp, budget);483if (work_done < budget) {484napi_complete_done(napi, work_done);485ath12k_pci_ext_grp_enable(irq_grp);486}487488if (work_done > budget)489work_done = budget;490491return work_done;492}493494static irqreturn_t ath12k_pci_ext_interrupt_handler(int irq, void *arg)495{496struct ath12k_ext_irq_grp *irq_grp = arg;497498ath12k_dbg(irq_grp->ab, ATH12K_DBG_PCI, "ext irq:%d\n", irq);499500/* last interrupt received for this group */501irq_grp->timestamp = jiffies;502503ath12k_pci_ext_grp_disable(irq_grp);504505napi_schedule(&irq_grp->napi);506507return IRQ_HANDLED;508}509510static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)511{512int i, j, ret, num_vectors = 0;513u32 user_base_data = 0, base_vector = 0, base_idx;514515base_idx = ATH12K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX;516ret = ath12k_pci_get_user_msi_assignment(ab, "DP",517&num_vectors,518&user_base_data,519&base_vector);520if (ret < 0)521return ret;522523for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) {524struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];525u32 num_irq = 0;526527irq_grp->ab = ab;528irq_grp->grp_id = i;529init_dummy_netdev(&irq_grp->napi_ndev);530netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,531ath12k_pci_ext_grp_napi_poll);532533if (ab->hw_params->ring_mask->tx[i] ||534ab->hw_params->ring_mask->rx[i] ||535ab->hw_params->ring_mask->rx_err[i] ||536ab->hw_params->ring_mask->rx_wbm_rel[i] ||537ab->hw_params->ring_mask->reo_status[i] ||538ab->hw_params->ring_mask->host2rxdma[i] ||539ab->hw_params->ring_mask->rx_mon_dest[i]) {540num_irq = 1;541}542543irq_grp->num_irq = num_irq;544irq_grp->irqs[0] = base_idx + i;545546for (j = 0; j < irq_grp->num_irq; j++) {547int irq_idx = irq_grp->irqs[j];548int vector = (i % num_vectors) + base_vector;549int irq = ath12k_pci_get_msi_irq(ab->dev, vector);550551ab->irq_num[irq_idx] = irq;552553ath12k_dbg(ab, ATH12K_DBG_PCI,554"irq:%d group:%d\n", irq, i);555556irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);557ret = request_irq(irq, ath12k_pci_ext_interrupt_handler,558IRQF_SHARED,559"DP_EXT_IRQ", irq_grp);560if (ret) {561ath12k_err(ab, "failed request irq %d: %d\n",562vector, ret);563return ret;564}565566disable_irq_nosync(ab->irq_num[irq_idx]);567}568}569570return 0;571}572573static int ath12k_pci_config_irq(struct ath12k_base *ab)574{575struct ath12k_ce_pipe *ce_pipe;576u32 msi_data_start;577u32 msi_data_count, msi_data_idx;578u32 msi_irq_start;579unsigned int msi_data;580int irq, i, ret, irq_idx;581582ret = ath12k_pci_get_user_msi_assignment(ab,583"CE", &msi_data_count,584&msi_data_start, &msi_irq_start);585if (ret)586return ret;587588/* Configure CE irqs */589590for (i = 0, msi_data_idx = 0; i < ab->hw_params->ce_count; i++) {591if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)592continue;593594msi_data = (msi_data_idx % msi_data_count) + msi_irq_start;595irq = ath12k_pci_get_msi_irq(ab->dev, msi_data);596ce_pipe = &ab->ce.ce_pipe[i];597598irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + i;599600tasklet_setup(&ce_pipe->intr_tq, ath12k_pci_ce_tasklet);601602ret = request_irq(irq, ath12k_pci_ce_interrupt_handler,603IRQF_SHARED, irq_name[irq_idx],604ce_pipe);605if (ret) {606ath12k_err(ab, "failed to request irq %d: %d\n",607irq_idx, ret);608return ret;609}610611ab->irq_num[irq_idx] = irq;612msi_data_idx++;613614ath12k_pci_ce_irq_disable(ab, i);615}616617ret = ath12k_pci_ext_irq_config(ab);618if (ret)619return ret;620621return 0;622}623624static void ath12k_pci_init_qmi_ce_config(struct ath12k_base *ab)625{626struct ath12k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;627628cfg->tgt_ce = ab->hw_params->target_ce_config;629cfg->tgt_ce_len = ab->hw_params->target_ce_count;630631cfg->svc_to_ce_map = ab->hw_params->svc_to_ce_map;632cfg->svc_to_ce_map_len = ab->hw_params->svc_to_ce_map_len;633ab->qmi.service_ins_id = ab->hw_params->qmi_service_ins_id;634}635636static void ath12k_pci_ce_irqs_enable(struct ath12k_base *ab)637{638int i;639640for (i = 0; i < ab->hw_params->ce_count; i++) {641if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)642continue;643ath12k_pci_ce_irq_enable(ab, i);644}645}646647static void ath12k_pci_msi_config(struct ath12k_pci *ab_pci, bool enable)648{649struct pci_dev *dev = ab_pci->pdev;650u16 control;651652pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);653654if (enable)655control |= PCI_MSI_FLAGS_ENABLE;656else657control &= ~PCI_MSI_FLAGS_ENABLE;658659pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);660}661662static void ath12k_pci_msi_enable(struct ath12k_pci *ab_pci)663{664ath12k_pci_msi_config(ab_pci, true);665}666667static void ath12k_pci_msi_disable(struct ath12k_pci *ab_pci)668{669ath12k_pci_msi_config(ab_pci, false);670}671672static int ath12k_pci_msi_alloc(struct ath12k_pci *ab_pci)673{674struct ath12k_base *ab = ab_pci->ab;675const struct ath12k_msi_config *msi_config = ab_pci->msi_config;676struct msi_desc *msi_desc;677int num_vectors;678int ret;679680num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,681msi_config->total_vectors,682msi_config->total_vectors,683PCI_IRQ_MSI);684if (num_vectors != msi_config->total_vectors) {685ath12k_err(ab, "failed to get %d MSI vectors, only %d available",686msi_config->total_vectors, num_vectors);687688if (num_vectors >= 0)689return -EINVAL;690else691return num_vectors;692}693694ath12k_pci_msi_disable(ab_pci);695696msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);697if (!msi_desc) {698ath12k_err(ab, "msi_desc is NULL!\n");699ret = -EINVAL;700goto free_msi_vector;701}702703ab_pci->msi_ep_base_data = msi_desc->msg.data;704if (msi_desc->pci.msi_attrib.is_64)705set_bit(ATH12K_PCI_FLAG_IS_MSI_64, &ab_pci->flags);706707ath12k_dbg(ab, ATH12K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data);708709return 0;710711free_msi_vector:712pci_free_irq_vectors(ab_pci->pdev);713714return ret;715}716717static void ath12k_pci_msi_free(struct ath12k_pci *ab_pci)718{719pci_free_irq_vectors(ab_pci->pdev);720}721722static int ath12k_pci_claim(struct ath12k_pci *ab_pci, struct pci_dev *pdev)723{724struct ath12k_base *ab = ab_pci->ab;725u16 device_id;726int ret = 0;727728pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);729if (device_id != ab_pci->dev_id) {730ath12k_err(ab, "pci device id mismatch: 0x%x 0x%x\n",731device_id, ab_pci->dev_id);732ret = -EIO;733goto out;734}735736ret = pci_assign_resource(pdev, ATH12K_PCI_BAR_NUM);737if (ret) {738ath12k_err(ab, "failed to assign pci resource: %d\n", ret);739goto out;740}741742ret = pci_enable_device(pdev);743if (ret) {744ath12k_err(ab, "failed to enable pci device: %d\n", ret);745goto out;746}747748ret = pci_request_region(pdev, ATH12K_PCI_BAR_NUM, "ath12k_pci");749if (ret) {750ath12k_err(ab, "failed to request pci region: %d\n", ret);751goto disable_device;752}753754ret = dma_set_mask_and_coherent(&pdev->dev,755DMA_BIT_MASK(ATH12K_PCI_DMA_MASK));756if (ret) {757ath12k_err(ab, "failed to set pci dma mask to %d: %d\n",758ATH12K_PCI_DMA_MASK, ret);759goto release_region;760}761762pci_set_master(pdev);763764ab->mem_len = pci_resource_len(pdev, ATH12K_PCI_BAR_NUM);765ab->mem = pci_iomap(pdev, ATH12K_PCI_BAR_NUM, 0);766if (!ab->mem) {767ath12k_err(ab, "failed to map pci bar %d\n", ATH12K_PCI_BAR_NUM);768ret = -EIO;769goto release_region;770}771772ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem);773return 0;774775release_region:776pci_release_region(pdev, ATH12K_PCI_BAR_NUM);777disable_device:778pci_disable_device(pdev);779out:780return ret;781}782783static void ath12k_pci_free_region(struct ath12k_pci *ab_pci)784{785struct ath12k_base *ab = ab_pci->ab;786struct pci_dev *pci_dev = ab_pci->pdev;787788pci_iounmap(pci_dev, ab->mem);789ab->mem = NULL;790pci_release_region(pci_dev, ATH12K_PCI_BAR_NUM);791if (pci_is_enabled(pci_dev))792pci_disable_device(pci_dev);793}794795static void ath12k_pci_aspm_disable(struct ath12k_pci *ab_pci)796{797struct ath12k_base *ab = ab_pci->ab;798799pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL,800&ab_pci->link_ctl);801802ath12k_dbg(ab, ATH12K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n",803ab_pci->link_ctl,804u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S),805u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));806807/* disable L0s and L1 */808pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,809ab_pci->link_ctl & ~PCI_EXP_LNKCTL_ASPMC);810811set_bit(ATH12K_PCI_ASPM_RESTORE, &ab_pci->flags);812}813814static void ath12k_pci_aspm_restore(struct ath12k_pci *ab_pci)815{816if (test_and_clear_bit(ATH12K_PCI_ASPM_RESTORE, &ab_pci->flags))817pcie_capability_write_word(ab_pci->pdev, PCI_EXP_LNKCTL,818ab_pci->link_ctl);819}820821static void ath12k_pci_kill_tasklets(struct ath12k_base *ab)822{823int i;824825for (i = 0; i < ab->hw_params->ce_count; i++) {826struct ath12k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];827828if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)829continue;830831tasklet_kill(&ce_pipe->intr_tq);832}833}834835static void ath12k_pci_ce_irq_disable_sync(struct ath12k_base *ab)836{837ath12k_pci_ce_irqs_disable(ab);838ath12k_pci_sync_ce_irqs(ab);839ath12k_pci_kill_tasklets(ab);840}841842int ath12k_pci_map_service_to_pipe(struct ath12k_base *ab, u16 service_id,843u8 *ul_pipe, u8 *dl_pipe)844{845const struct service_to_pipe *entry;846bool ul_set = false, dl_set = false;847int i;848849for (i = 0; i < ab->hw_params->svc_to_ce_map_len; i++) {850entry = &ab->hw_params->svc_to_ce_map[i];851852if (__le32_to_cpu(entry->service_id) != service_id)853continue;854855switch (__le32_to_cpu(entry->pipedir)) {856case PIPEDIR_NONE:857break;858case PIPEDIR_IN:859WARN_ON(dl_set);860*dl_pipe = __le32_to_cpu(entry->pipenum);861dl_set = true;862break;863case PIPEDIR_OUT:864WARN_ON(ul_set);865*ul_pipe = __le32_to_cpu(entry->pipenum);866ul_set = true;867break;868case PIPEDIR_INOUT:869WARN_ON(dl_set);870WARN_ON(ul_set);871*dl_pipe = __le32_to_cpu(entry->pipenum);872*ul_pipe = __le32_to_cpu(entry->pipenum);873dl_set = true;874ul_set = true;875break;876}877}878879if (WARN_ON(!ul_set || !dl_set))880return -ENOENT;881882return 0;883}884885int ath12k_pci_get_msi_irq(struct device *dev, unsigned int vector)886{887struct pci_dev *pci_dev = to_pci_dev(dev);888889return pci_irq_vector(pci_dev, vector);890}891892int ath12k_pci_get_user_msi_assignment(struct ath12k_base *ab, char *user_name,893int *num_vectors, u32 *user_base_data,894u32 *base_vector)895{896struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);897const struct ath12k_msi_config *msi_config = ab_pci->msi_config;898int idx;899900for (idx = 0; idx < msi_config->total_users; idx++) {901if (strcmp(user_name, msi_config->users[idx].name) == 0) {902*num_vectors = msi_config->users[idx].num_vectors;903*user_base_data = msi_config->users[idx].base_vector904+ ab_pci->msi_ep_base_data;905*base_vector = msi_config->users[idx].base_vector;906907ath12k_dbg(ab, ATH12K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",908user_name, *num_vectors, *user_base_data,909*base_vector);910911return 0;912}913}914915ath12k_err(ab, "Failed to find MSI assignment for %s!\n", user_name);916917return -EINVAL;918}919920void ath12k_pci_get_msi_address(struct ath12k_base *ab, u32 *msi_addr_lo,921u32 *msi_addr_hi)922{923struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);924struct pci_dev *pci_dev = to_pci_dev(ab->dev);925926pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,927msi_addr_lo);928929if (test_bit(ATH12K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) {930pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,931msi_addr_hi);932} else {933*msi_addr_hi = 0;934}935}936937void ath12k_pci_get_ce_msi_idx(struct ath12k_base *ab, u32 ce_id,938u32 *msi_idx)939{940u32 i, msi_data_idx;941942for (i = 0, msi_data_idx = 0; i < ab->hw_params->ce_count; i++) {943if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)944continue;945946if (ce_id == i)947break;948949msi_data_idx++;950}951*msi_idx = msi_data_idx;952}953954void ath12k_pci_hif_ce_irq_enable(struct ath12k_base *ab)955{956ath12k_pci_ce_irqs_enable(ab);957}958959void ath12k_pci_hif_ce_irq_disable(struct ath12k_base *ab)960{961ath12k_pci_ce_irq_disable_sync(ab);962}963964void ath12k_pci_ext_irq_enable(struct ath12k_base *ab)965{966int i;967968for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) {969struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];970971napi_enable(&irq_grp->napi);972ath12k_pci_ext_grp_enable(irq_grp);973}974}975976void ath12k_pci_ext_irq_disable(struct ath12k_base *ab)977{978__ath12k_pci_ext_irq_disable(ab);979ath12k_pci_sync_ext_irqs(ab);980}981982int ath12k_pci_hif_suspend(struct ath12k_base *ab)983{984struct ath12k_pci *ar_pci = ath12k_pci_priv(ab);985986ath12k_mhi_suspend(ar_pci);987988return 0;989}990991int ath12k_pci_hif_resume(struct ath12k_base *ab)992{993struct ath12k_pci *ar_pci = ath12k_pci_priv(ab);994995ath12k_mhi_resume(ar_pci);996997return 0;998}9991000void ath12k_pci_stop(struct ath12k_base *ab)1001{1002ath12k_pci_ce_irq_disable_sync(ab);1003ath12k_ce_cleanup_pipes(ab);1004}10051006int ath12k_pci_start(struct ath12k_base *ab)1007{1008struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);10091010set_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags);10111012ath12k_pci_aspm_restore(ab_pci);10131014ath12k_pci_ce_irqs_enable(ab);1015ath12k_ce_rx_post_buf(ab);10161017return 0;1018}10191020u32 ath12k_pci_read32(struct ath12k_base *ab, u32 offset)1021{1022struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);1023u32 val, window_start;1024int ret = 0;10251026/* for offset beyond BAR + 4K - 32, may1027* need to wakeup MHI to access.1028*/1029if (test_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&1030offset >= ACCESS_ALWAYS_OFF && ab_pci->pci_ops->wakeup)1031ret = ab_pci->pci_ops->wakeup(ab);10321033if (offset < WINDOW_START) {1034#if defined(__linux__)1035val = ioread32(ab->mem + offset);1036#elif defined(__FreeBSD__)1037val = ioread32((char *)ab->mem + offset);1038#endif1039} else {1040if (ab->static_window_map)1041window_start = ath12k_pci_get_window_start(ab, offset);1042else1043window_start = WINDOW_START;10441045if (window_start == WINDOW_START) {1046spin_lock_bh(&ab_pci->window_lock);1047ath12k_pci_select_window(ab_pci, offset);1048#if defined(__linux__)1049val = ioread32(ab->mem + window_start +1050#elif defined(__FreeBSD__)1051val = ioread32((char *)ab->mem + window_start +1052#endif1053(offset & WINDOW_RANGE_MASK));1054spin_unlock_bh(&ab_pci->window_lock);1055} else {1056if ((!window_start) &&1057(offset >= PCI_MHIREGLEN_REG &&1058offset <= PCI_MHI_REGION_END))1059offset = offset - PCI_MHIREGLEN_REG;10601061#if defined(__linux__)1062val = ioread32(ab->mem + window_start +1063#elif defined(__FreeBSD__)1064val = ioread32((char *)ab->mem + window_start +1065#endif1066(offset & WINDOW_RANGE_MASK));1067}1068}10691070if (test_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&1071offset >= ACCESS_ALWAYS_OFF && ab_pci->pci_ops->release &&1072!ret)1073ab_pci->pci_ops->release(ab);1074return val;1075}10761077void ath12k_pci_write32(struct ath12k_base *ab, u32 offset, u32 value)1078{1079struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);1080u32 window_start;1081int ret = 0;10821083/* for offset beyond BAR + 4K - 32, may1084* need to wakeup MHI to access.1085*/1086if (test_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&1087offset >= ACCESS_ALWAYS_OFF && ab_pci->pci_ops->wakeup)1088ret = ab_pci->pci_ops->wakeup(ab);10891090if (offset < WINDOW_START) {1091#if defined(__linux__)1092iowrite32(value, ab->mem + offset);1093#elif defined(__FreeBSD__)1094iowrite32(value, (char *)ab->mem + offset);1095#endif1096} else {1097if (ab->static_window_map)1098window_start = ath12k_pci_get_window_start(ab, offset);1099else1100window_start = WINDOW_START;11011102if (window_start == WINDOW_START) {1103spin_lock_bh(&ab_pci->window_lock);1104ath12k_pci_select_window(ab_pci, offset);1105#if defined(__linux__)1106iowrite32(value, ab->mem + window_start +1107#elif defined(__FreeBSD__)1108iowrite32(value, (char *)ab->mem + window_start +1109#endif1110(offset & WINDOW_RANGE_MASK));1111spin_unlock_bh(&ab_pci->window_lock);1112} else {1113if ((!window_start) &&1114(offset >= PCI_MHIREGLEN_REG &&1115offset <= PCI_MHI_REGION_END))1116offset = offset - PCI_MHIREGLEN_REG;11171118#if defined(__linux__)1119iowrite32(value, ab->mem + window_start +1120#elif defined(__FreeBSD__)1121iowrite32(value, (char *)ab->mem + window_start +1122#endif1123(offset & WINDOW_RANGE_MASK));1124}1125}11261127if (test_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&1128offset >= ACCESS_ALWAYS_OFF && ab_pci->pci_ops->release &&1129!ret)1130ab_pci->pci_ops->release(ab);1131}11321133int ath12k_pci_power_up(struct ath12k_base *ab)1134{1135struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);1136int ret;11371138ab_pci->register_window = 0;1139clear_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags);1140ath12k_pci_sw_reset(ab_pci->ab, true);11411142/* Disable ASPM during firmware download due to problems switching1143* to AMSS state.1144*/1145ath12k_pci_aspm_disable(ab_pci);11461147ath12k_pci_msi_enable(ab_pci);11481149ret = ath12k_mhi_start(ab_pci);1150if (ret) {1151ath12k_err(ab, "failed to start mhi: %d\n", ret);1152return ret;1153}11541155if (ab->static_window_map)1156ath12k_pci_select_static_window(ab_pci);11571158return 0;1159}11601161void ath12k_pci_power_down(struct ath12k_base *ab)1162{1163struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);11641165/* restore aspm in case firmware bootup fails */1166ath12k_pci_aspm_restore(ab_pci);11671168ath12k_pci_force_wake(ab_pci->ab);1169ath12k_pci_msi_disable(ab_pci);1170ath12k_mhi_stop(ab_pci);1171clear_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags);1172ath12k_pci_sw_reset(ab_pci->ab, false);1173}11741175static const struct ath12k_hif_ops ath12k_pci_hif_ops = {1176.start = ath12k_pci_start,1177.stop = ath12k_pci_stop,1178.read32 = ath12k_pci_read32,1179.write32 = ath12k_pci_write32,1180.power_down = ath12k_pci_power_down,1181.power_up = ath12k_pci_power_up,1182.suspend = ath12k_pci_hif_suspend,1183.resume = ath12k_pci_hif_resume,1184.irq_enable = ath12k_pci_ext_irq_enable,1185.irq_disable = ath12k_pci_ext_irq_disable,1186.get_msi_address = ath12k_pci_get_msi_address,1187.get_user_msi_vector = ath12k_pci_get_user_msi_assignment,1188.map_service_to_pipe = ath12k_pci_map_service_to_pipe,1189.ce_irq_enable = ath12k_pci_hif_ce_irq_enable,1190.ce_irq_disable = ath12k_pci_hif_ce_irq_disable,1191.get_ce_msi_idx = ath12k_pci_get_ce_msi_idx,1192};11931194static1195void ath12k_pci_read_hw_version(struct ath12k_base *ab, u32 *major, u32 *minor)1196{1197u32 soc_hw_version;11981199soc_hw_version = ath12k_pci_read32(ab, TCSR_SOC_HW_VERSION);1200*major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,1201soc_hw_version);1202*minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,1203soc_hw_version);12041205ath12k_dbg(ab, ATH12K_DBG_PCI,1206"pci tcsr_soc_hw_version major %d minor %d\n",1207*major, *minor);1208}12091210static int ath12k_pci_probe(struct pci_dev *pdev,1211const struct pci_device_id *pci_dev)1212{1213struct ath12k_base *ab;1214struct ath12k_pci *ab_pci;1215u32 soc_hw_version_major, soc_hw_version_minor;1216int ret;12171218ab = ath12k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH12K_BUS_PCI);1219if (!ab) {1220dev_err(&pdev->dev, "failed to allocate ath12k base\n");1221return -ENOMEM;1222}12231224ab->dev = &pdev->dev;1225pci_set_drvdata(pdev, ab);1226ab_pci = ath12k_pci_priv(ab);1227ab_pci->dev_id = pci_dev->device;1228ab_pci->ab = ab;1229ab_pci->pdev = pdev;1230ab->hif.ops = &ath12k_pci_hif_ops;1231pci_set_drvdata(pdev, ab);1232spin_lock_init(&ab_pci->window_lock);12331234ret = ath12k_pci_claim(ab_pci, pdev);1235if (ret) {1236ath12k_err(ab, "failed to claim device: %d\n", ret);1237goto err_free_core;1238}12391240switch (pci_dev->device) {1241case QCN9274_DEVICE_ID:1242ab_pci->msi_config = &ath12k_msi_config[0];1243ab->static_window_map = true;1244ab_pci->pci_ops = &ath12k_pci_ops_qcn9274;1245ath12k_pci_read_hw_version(ab, &soc_hw_version_major,1246&soc_hw_version_minor);1247switch (soc_hw_version_major) {1248case ATH12K_PCI_SOC_HW_VERSION_2:1249ab->hw_rev = ATH12K_HW_QCN9274_HW20;1250break;1251case ATH12K_PCI_SOC_HW_VERSION_1:1252ab->hw_rev = ATH12K_HW_QCN9274_HW10;1253break;1254default:1255dev_err(&pdev->dev,1256"Unknown hardware version found for QCN9274: 0x%x\n",1257soc_hw_version_major);1258ret = -EOPNOTSUPP;1259goto err_pci_free_region;1260}1261break;1262case WCN7850_DEVICE_ID:1263ab_pci->msi_config = &ath12k_msi_config[0];1264ab->static_window_map = false;1265ab_pci->pci_ops = &ath12k_pci_ops_wcn7850;1266ath12k_pci_read_hw_version(ab, &soc_hw_version_major,1267&soc_hw_version_minor);1268switch (soc_hw_version_major) {1269case ATH12K_PCI_SOC_HW_VERSION_2:1270ab->hw_rev = ATH12K_HW_WCN7850_HW20;1271break;1272default:1273dev_err(&pdev->dev,1274"Unknown hardware version found for WCN7850: 0x%x\n",1275soc_hw_version_major);1276ret = -EOPNOTSUPP;1277goto err_pci_free_region;1278}1279break;12801281default:1282dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",1283pci_dev->device);1284ret = -EOPNOTSUPP;1285goto err_pci_free_region;1286}12871288ret = ath12k_pci_msi_alloc(ab_pci);1289if (ret) {1290ath12k_err(ab, "failed to alloc msi: %d\n", ret);1291goto err_pci_free_region;1292}12931294ret = ath12k_core_pre_init(ab);1295if (ret)1296goto err_pci_msi_free;12971298ret = ath12k_mhi_register(ab_pci);1299if (ret) {1300ath12k_err(ab, "failed to register mhi: %d\n", ret);1301goto err_pci_msi_free;1302}13031304ret = ath12k_hal_srng_init(ab);1305if (ret)1306goto err_mhi_unregister;13071308ret = ath12k_ce_alloc_pipes(ab);1309if (ret) {1310ath12k_err(ab, "failed to allocate ce pipes: %d\n", ret);1311goto err_hal_srng_deinit;1312}13131314ath12k_pci_init_qmi_ce_config(ab);13151316ret = ath12k_pci_config_irq(ab);1317if (ret) {1318ath12k_err(ab, "failed to config irq: %d\n", ret);1319goto err_ce_free;1320}13211322ret = ath12k_core_init(ab);1323if (ret) {1324ath12k_err(ab, "failed to init core: %d\n", ret);1325goto err_free_irq;1326}1327return 0;13281329err_free_irq:1330ath12k_pci_free_irq(ab);13311332err_ce_free:1333ath12k_ce_free_pipes(ab);13341335err_hal_srng_deinit:1336ath12k_hal_srng_deinit(ab);13371338err_mhi_unregister:1339ath12k_mhi_unregister(ab_pci);13401341err_pci_msi_free:1342ath12k_pci_msi_free(ab_pci);13431344err_pci_free_region:1345ath12k_pci_free_region(ab_pci);13461347err_free_core:1348ath12k_core_free(ab);13491350return ret;1351}13521353static void ath12k_pci_remove(struct pci_dev *pdev)1354{1355struct ath12k_base *ab = pci_get_drvdata(pdev);1356struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);13571358if (test_bit(ATH12K_FLAG_QMI_FAIL, &ab->dev_flags)) {1359ath12k_pci_power_down(ab);1360ath12k_qmi_deinit_service(ab);1361goto qmi_fail;1362}13631364set_bit(ATH12K_FLAG_UNREGISTERING, &ab->dev_flags);13651366cancel_work_sync(&ab->reset_work);1367ath12k_core_deinit(ab);13681369qmi_fail:1370ath12k_mhi_unregister(ab_pci);13711372ath12k_pci_free_irq(ab);1373ath12k_pci_msi_free(ab_pci);1374ath12k_pci_free_region(ab_pci);13751376ath12k_hal_srng_deinit(ab);1377ath12k_ce_free_pipes(ab);1378ath12k_core_free(ab);1379}13801381static void ath12k_pci_shutdown(struct pci_dev *pdev)1382{1383struct ath12k_base *ab = pci_get_drvdata(pdev);13841385ath12k_pci_power_down(ab);1386}13871388static __maybe_unused int ath12k_pci_pm_suspend(struct device *dev)1389{1390struct ath12k_base *ab = dev_get_drvdata(dev);1391int ret;13921393ret = ath12k_core_suspend(ab);1394if (ret)1395ath12k_warn(ab, "failed to suspend core: %d\n", ret);13961397return ret;1398}13991400static __maybe_unused int ath12k_pci_pm_resume(struct device *dev)1401{1402struct ath12k_base *ab = dev_get_drvdata(dev);1403int ret;14041405ret = ath12k_core_resume(ab);1406if (ret)1407ath12k_warn(ab, "failed to resume core: %d\n", ret);14081409return ret;1410}14111412static SIMPLE_DEV_PM_OPS(ath12k_pci_pm_ops,1413ath12k_pci_pm_suspend,1414ath12k_pci_pm_resume);14151416static struct pci_driver ath12k_pci_driver = {1417.name = "ath12k_pci",1418.id_table = ath12k_pci_id_table,1419.probe = ath12k_pci_probe,1420.remove = ath12k_pci_remove,1421.shutdown = ath12k_pci_shutdown,1422.driver.pm = &ath12k_pci_pm_ops,1423};14241425static int ath12k_pci_init(void)1426{1427int ret;14281429ret = pci_register_driver(&ath12k_pci_driver);1430if (ret) {1431pr_err("failed to register ath12k pci driver: %d\n",1432ret);1433return ret;1434}14351436return 0;1437}1438module_init(ath12k_pci_init);14391440static void ath12k_pci_exit(void)1441{1442pci_unregister_driver(&ath12k_pci_driver);1443}14441445module_exit(ath12k_pci_exit);14461447MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11be WLAN PCIe devices");1448MODULE_LICENSE("Dual BSD/GPL");144914501451