diff options
author | Lorenzo Bianconi <lorenzo@kernel.org> | 2020-05-01 12:36:15 +0200 |
---|---|---|
committer | Felix Fietkau <nbd@nbd.name> | 2020-05-12 19:52:34 +0200 |
commit | 6dd4072c1e8bc46ee81bdd5f779590bc43ab9ae4 (patch) | |
tree | f083d5a57a796a36d7f57bea1281f0d604b4db97 /drivers/net/wireless/mediatek/mt76/mt7615/pci.c | |
parent | mt76: mt7663u: introduce suspend/resume to mt7663u (diff) | |
download | linux-6dd4072c1e8bc46ee81bdd5f779590bc43ab9ae4.tar.xz linux-6dd4072c1e8bc46ee81bdd5f779590bc43ab9ae4.zip |
mt76: mt7615: introduce PM support
Introduce suspend/resume to mt7615e driver
Co-developed-by: Wan-Feng Jiang <Wan-Feng.Jiang@mediatek.com>
Signed-off-by: Wan-Feng Jiang <Wan-Feng.Jiang@mediatek.com>
Co-developed-by: Soul Huang <Soul.Huang@mediatek.com>
Signed-off-by: Soul Huang <Soul.Huang@mediatek.com>
Co-developed-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7615/pci.c')
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7615/pci.c | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index 0605c908059e..88ff14564521 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -66,11 +66,119 @@ static void mt7615_pci_remove(struct pci_dev *pdev) pci_free_irq_vectors(pdev); } +#ifdef CONFIG_PM +static int mt7615_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + bool hif_suspend; + int i, err; + + hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && + mt7615_firmware_offload(dev); + if (hif_suspend) { + err = mt7615_mcu_set_hif_suspend(dev, true); + if (err) + return err; + } + + napi_disable(&mdev->tx_napi); + tasklet_kill(&mdev->tx_tasklet); + + for (i = 0; i < ARRAY_SIZE(mdev->q_rx); i++) + napi_disable(&mdev->napi[i]); + tasklet_kill(&dev->irq_tasklet); + + mt7615_dma_reset(dev); + + err = mt7615_wait_pdma_busy(dev); + if (err) + goto restore; + + if (is_mt7663(mdev)) { + mt76_set(dev, MT_PDMA_SLP_PROT, MT_PDMA_AXI_SLPPROT_ENABLE); + if (!mt76_poll_msec(dev, MT_PDMA_SLP_PROT, + MT_PDMA_AXI_SLPPROT_RDY, + MT_PDMA_AXI_SLPPROT_RDY, 1000)) { + dev_err(mdev->dev, "PDMA sleep protection failed\n"); + err = -EIO; + goto restore; + } + } + + pci_enable_wake(pdev, pci_choose_state(pdev, state), true); + pci_save_state(pdev); + err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); + if (err) + goto restore; + + err = mt7615_firmware_own(dev); + if (err) + goto restore; + + return 0; + +restore: + for (i = 0; i < ARRAY_SIZE(mdev->q_rx); i++) + napi_enable(&mdev->napi[i]); + napi_enable(&mdev->tx_napi); + if (hif_suspend) + mt7615_mcu_set_hif_suspend(dev, false); + + return err; +} + +static int mt7615_pci_resume(struct pci_dev *pdev) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + bool pdma_reset; + int i, err; + + err = mt7615_driver_own(dev); + if (err < 0) + return err; + + err = pci_set_power_state(pdev, PCI_D0); + if (err) + return err; + + pci_restore_state(pdev); + + if (is_mt7663(&dev->mt76)) { + mt76_clear(dev, MT_PDMA_SLP_PROT, MT_PDMA_AXI_SLPPROT_ENABLE); + mt76_wr(dev, MT_PCIE_IRQ_ENABLE, 1); + } + + pdma_reset = !mt76_rr(dev, MT_WPDMA_TX_RING0_CTRL0) && + !mt76_rr(dev, MT_WPDMA_TX_RING0_CTRL1); + if (pdma_reset) + dev_err(mdev->dev, "PDMA engine must be reinitialized\n"); + + for (i = 0; i < ARRAY_SIZE(mdev->q_rx); i++) { + napi_enable(&mdev->napi[i]); + napi_schedule(&mdev->napi[i]); + } + napi_enable(&mdev->tx_napi); + napi_schedule(&mdev->tx_napi); + + if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && + mt7615_firmware_offload(dev)) + err = mt7615_mcu_set_hif_suspend(dev, false); + + return err; +} +#endif /* CONFIG_PM */ + struct pci_driver mt7615_pci_driver = { .name = KBUILD_MODNAME, .id_table = mt7615_pci_device_table, .probe = mt7615_pci_probe, .remove = mt7615_pci_remove, +#ifdef CONFIG_PM + .suspend = mt7615_pci_suspend, + .resume = mt7615_pci_resume, +#endif /* CONFIG_PM */ }; MODULE_DEVICE_TABLE(pci, mt7615_pci_device_table); |