linux/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
<<
>>
Prefs
   1// SPDX-License-Identifier: ISC
   2/* Copyright (C) 2020 MediaTek Inc.
   3 *
   4 */
   5
   6#include <linux/kernel.h>
   7#include <linux/module.h>
   8#include <linux/pci.h>
   9
  10#include "mt7921.h"
  11#include "mac.h"
  12#include "mcu.h"
  13#include "../trace.h"
  14
  15static const struct pci_device_id mt7921_pci_device_table[] = {
  16        { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7961) },
  17        { },
  18};
  19
  20static void
  21mt7921_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
  22{
  23        struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
  24
  25        if (q == MT_RXQ_MAIN)
  26                mt7921_irq_enable(dev, MT_INT_RX_DONE_DATA);
  27        else if (q == MT_RXQ_MCU_WA)
  28                mt7921_irq_enable(dev, MT_INT_RX_DONE_WM2);
  29        else
  30                mt7921_irq_enable(dev, MT_INT_RX_DONE_WM);
  31}
  32
  33static irqreturn_t mt7921_irq_handler(int irq, void *dev_instance)
  34{
  35        struct mt7921_dev *dev = dev_instance;
  36
  37        mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
  38
  39        if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
  40                return IRQ_NONE;
  41
  42        tasklet_schedule(&dev->irq_tasklet);
  43
  44        return IRQ_HANDLED;
  45}
  46
  47static void mt7921_irq_tasklet(unsigned long data)
  48{
  49        struct mt7921_dev *dev = (struct mt7921_dev *)data;
  50        u32 intr, mask = 0;
  51
  52        mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
  53
  54        intr = mt76_rr(dev, MT_WFDMA0_HOST_INT_STA);
  55        intr &= dev->mt76.mmio.irqmask;
  56        mt76_wr(dev, MT_WFDMA0_HOST_INT_STA, intr);
  57
  58        trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask);
  59
  60        mask |= intr & MT_INT_RX_DONE_ALL;
  61        if (intr & MT_INT_TX_DONE_MCU)
  62                mask |= MT_INT_TX_DONE_MCU;
  63
  64        if (intr & MT_INT_MCU_CMD) {
  65                u32 intr_sw;
  66
  67                intr_sw = mt76_rr(dev, MT_MCU_CMD);
  68                /* ack MCU2HOST_SW_INT_STA */
  69                mt76_wr(dev, MT_MCU_CMD, intr_sw);
  70                if (intr_sw & MT_MCU_CMD_WAKE_RX_PCIE) {
  71                        mask |= MT_INT_RX_DONE_DATA;
  72                        intr |= MT_INT_RX_DONE_DATA;
  73                }
  74        }
  75
  76        mt76_set_irq_mask(&dev->mt76, MT_WFDMA0_HOST_INT_ENA, mask, 0);
  77
  78        if (intr & MT_INT_TX_DONE_ALL)
  79                napi_schedule(&dev->mt76.tx_napi);
  80
  81        if (intr & MT_INT_RX_DONE_WM)
  82                napi_schedule(&dev->mt76.napi[MT_RXQ_MCU]);
  83
  84        if (intr & MT_INT_RX_DONE_WM2)
  85                napi_schedule(&dev->mt76.napi[MT_RXQ_MCU_WA]);
  86
  87        if (intr & MT_INT_RX_DONE_DATA)
  88                napi_schedule(&dev->mt76.napi[MT_RXQ_MAIN]);
  89}
  90
  91static int mt7921_pci_probe(struct pci_dev *pdev,
  92                            const struct pci_device_id *id)
  93{
  94        static const struct mt76_driver_ops drv_ops = {
  95                /* txwi_size = txd size + txp size */
  96                .txwi_size = MT_TXD_SIZE + sizeof(struct mt7921_txp_common),
  97                .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ |
  98                             MT_DRV_AMSDU_OFFLOAD,
  99                .survey_flags = SURVEY_INFO_TIME_TX |
 100                                SURVEY_INFO_TIME_RX |
 101                                SURVEY_INFO_TIME_BSS_RX,
 102                .token_size = MT7921_TOKEN_SIZE,
 103                .tx_prepare_skb = mt7921_tx_prepare_skb,
 104                .tx_complete_skb = mt7921_tx_complete_skb,
 105                .rx_skb = mt7921_queue_rx_skb,
 106                .rx_poll_complete = mt7921_rx_poll_complete,
 107                .sta_ps = mt7921_sta_ps,
 108                .sta_add = mt7921_mac_sta_add,
 109                .sta_assoc = mt7921_mac_sta_assoc,
 110                .sta_remove = mt7921_mac_sta_remove,
 111                .update_survey = mt7921_update_channel,
 112        };
 113        struct mt7921_dev *dev;
 114        struct mt76_dev *mdev;
 115        int ret;
 116
 117        ret = pcim_enable_device(pdev);
 118        if (ret)
 119                return ret;
 120
 121        ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
 122        if (ret)
 123                return ret;
 124
 125        pci_set_master(pdev);
 126
 127        ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
 128        if (ret < 0)
 129                return ret;
 130
 131        ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
 132        if (ret)
 133                goto err_free_pci_vec;
 134
 135        mt76_pci_disable_aspm(pdev);
 136
 137        mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7921_ops,
 138                                 &drv_ops);
 139        if (!mdev) {
 140                ret = -ENOMEM;
 141                goto err_free_pci_vec;
 142        }
 143
 144        dev = container_of(mdev, struct mt7921_dev, mt76);
 145
 146        mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
 147        tasklet_init(&dev->irq_tasklet, mt7921_irq_tasklet, (unsigned long)dev);
 148        mdev->rev = (mt7921_l1_rr(dev, MT_HW_CHIPID) << 16) |
 149                    (mt7921_l1_rr(dev, MT_HW_REV) & 0xff);
 150        dev_err(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
 151
 152        mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
 153
 154        mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
 155
 156        ret = devm_request_irq(mdev->dev, pdev->irq, mt7921_irq_handler,
 157                               IRQF_SHARED, KBUILD_MODNAME, dev);
 158        if (ret)
 159                goto err_free_dev;
 160
 161        ret = mt7921_register_device(dev);
 162        if (ret)
 163                goto err_free_irq;
 164
 165        return 0;
 166
 167err_free_irq:
 168        devm_free_irq(&pdev->dev, pdev->irq, dev);
 169err_free_dev:
 170        mt76_free_device(&dev->mt76);
 171err_free_pci_vec:
 172        pci_free_irq_vectors(pdev);
 173
 174        return ret;
 175}
 176
 177static void mt7921_pci_remove(struct pci_dev *pdev)
 178{
 179        struct mt76_dev *mdev = pci_get_drvdata(pdev);
 180        struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
 181
 182        mt7921_unregister_device(dev);
 183        devm_free_irq(&pdev->dev, pdev->irq, dev);
 184        pci_free_irq_vectors(pdev);
 185}
 186
 187#ifdef CONFIG_PM
 188static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 189{
 190        struct mt76_dev *mdev = pci_get_drvdata(pdev);
 191        struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
 192        struct mt76_connac_pm *pm = &dev->pm;
 193        bool hif_suspend;
 194        int i, err;
 195
 196        pm->suspended = true;
 197        cancel_delayed_work_sync(&pm->ps_work);
 198        cancel_work_sync(&pm->wake_work);
 199
 200        err = mt7921_mcu_drv_pmctrl(dev);
 201        if (err < 0)
 202                goto restore_suspend;
 203
 204        hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state);
 205        if (hif_suspend) {
 206                err = mt76_connac_mcu_set_hif_suspend(mdev, true);
 207                if (err)
 208                        goto restore_suspend;
 209        }
 210
 211        /* always enable deep sleep during suspend to reduce
 212         * power consumption
 213         */
 214        mt76_connac_mcu_set_deep_sleep(&dev->mt76, true);
 215
 216        napi_disable(&mdev->tx_napi);
 217        mt76_worker_disable(&mdev->tx_worker);
 218
 219        mt76_for_each_q_rx(mdev, i) {
 220                napi_disable(&mdev->napi[i]);
 221        }
 222
 223        pci_enable_wake(pdev, pci_choose_state(pdev, state), true);
 224
 225        /* wait until dma is idle  */
 226        mt76_poll(dev, MT_WFDMA0_GLO_CFG,
 227                  MT_WFDMA0_GLO_CFG_TX_DMA_BUSY |
 228                  MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000);
 229
 230        /* put dma disabled */
 231        mt76_clear(dev, MT_WFDMA0_GLO_CFG,
 232                   MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
 233
 234        /* disable interrupt */
 235        mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
 236        mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
 237        synchronize_irq(pdev->irq);
 238        tasklet_kill(&dev->irq_tasklet);
 239
 240        err = mt7921_mcu_fw_pmctrl(dev);
 241        if (err)
 242                goto restore_napi;
 243
 244        pci_save_state(pdev);
 245        err = pci_set_power_state(pdev, pci_choose_state(pdev, state));
 246        if (err)
 247                goto restore_napi;
 248
 249        return 0;
 250
 251restore_napi:
 252        mt76_for_each_q_rx(mdev, i) {
 253                napi_enable(&mdev->napi[i]);
 254        }
 255        napi_enable(&mdev->tx_napi);
 256
 257        if (!pm->ds_enable)
 258                mt76_connac_mcu_set_deep_sleep(&dev->mt76, false);
 259
 260        if (hif_suspend)
 261                mt76_connac_mcu_set_hif_suspend(mdev, false);
 262
 263restore_suspend:
 264        pm->suspended = false;
 265
 266        return err;
 267}
 268
 269static int mt7921_pci_resume(struct pci_dev *pdev)
 270{
 271        struct mt76_dev *mdev = pci_get_drvdata(pdev);
 272        struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
 273        struct mt76_connac_pm *pm = &dev->pm;
 274        int i, err;
 275
 276        pm->suspended = false;
 277        err = pci_set_power_state(pdev, PCI_D0);
 278        if (err)
 279                return err;
 280
 281        pci_restore_state(pdev);
 282
 283        err = mt7921_mcu_drv_pmctrl(dev);
 284        if (err < 0)
 285                return err;
 286
 287        mt7921_wpdma_reinit_cond(dev);
 288
 289        /* enable interrupt */
 290        mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
 291        mt7921_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
 292                          MT_INT_MCU_CMD);
 293        mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE);
 294
 295        /* put dma enabled */
 296        mt76_set(dev, MT_WFDMA0_GLO_CFG,
 297                 MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
 298
 299        mt76_worker_enable(&mdev->tx_worker);
 300        mt76_for_each_q_rx(mdev, i) {
 301                napi_enable(&mdev->napi[i]);
 302                napi_schedule(&mdev->napi[i]);
 303        }
 304        napi_enable(&mdev->tx_napi);
 305        napi_schedule(&mdev->tx_napi);
 306
 307        /* restore previous ds setting */
 308        if (!pm->ds_enable)
 309                mt76_connac_mcu_set_deep_sleep(&dev->mt76, false);
 310
 311        if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state))
 312                err = mt76_connac_mcu_set_hif_suspend(mdev, false);
 313
 314        return err;
 315}
 316#endif /* CONFIG_PM */
 317
 318struct pci_driver mt7921_pci_driver = {
 319        .name           = KBUILD_MODNAME,
 320        .id_table       = mt7921_pci_device_table,
 321        .probe          = mt7921_pci_probe,
 322        .remove         = mt7921_pci_remove,
 323#ifdef CONFIG_PM
 324        .suspend        = mt7921_pci_suspend,
 325        .resume         = mt7921_pci_resume,
 326#endif /* CONFIG_PM */
 327};
 328
 329module_pci_driver(mt7921_pci_driver);
 330
 331MODULE_DEVICE_TABLE(pci, mt7921_pci_device_table);
 332MODULE_FIRMWARE(MT7921_FIRMWARE_WM);
 333MODULE_FIRMWARE(MT7921_ROM_PATCH);
 334MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
 335MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
 336MODULE_LICENSE("Dual BSD/GPL");
 337