diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7915/pci.c')
| -rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7915/pci.c | 249 |
1 files changed, 150 insertions, 99 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c index 7937c6965f59..f6b03211a879 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +// SPDX-License-Identifier: BSD-3-Clause-Clear /* Copyright (C) 2020 MediaTek Inc. * * Author: Ryder Lee <ryder.lee@mediatek.com> @@ -12,87 +12,90 @@ #include "mac.h" #include "../trace.h" +static LIST_HEAD(hif_list); +static DEFINE_SPINLOCK(hif_lock); +static u32 hif_idx; + static const struct pci_device_id mt7915_pci_device_table[] = { - { PCI_DEVICE(0x14c3, 0x7915) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7915) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7906) }, { }, }; -static void -mt7915_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) -{ - struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); - - mt7915_irq_enable(dev, MT_INT_RX_DONE(q)); -} +static const struct pci_device_id mt7915_hif_device_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7916) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x790a) }, + { }, +}; -/* TODO: support 2/4/6/8 MSI-X vectors */ -static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) +static struct mt7915_hif *mt7915_pci_get_hif2(u32 idx) { - struct mt7915_dev *dev = dev_instance; - u32 intr; + struct mt7915_hif *hif; + u32 val; - intr = mt76_rr(dev, MT_INT_SOURCE_CSR); - mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + spin_lock_bh(&hif_lock); - if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) - return IRQ_NONE; + list_for_each_entry(hif, &hif_list, list) { + val = readl(hif->regs + MT_PCIE_RECOG_ID); + val &= MT_PCIE_RECOG_ID_MASK; + if (val != idx) + continue; - trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); + get_device(hif->dev); + hif->index = idx; + goto out; + } + hif = NULL; - intr &= dev->mt76.mmio.irqmask; +out: + spin_unlock_bh(&hif_lock); - if (intr & MT_INT_TX_DONE_ALL) { - mt7915_irq_disable(dev, MT_INT_TX_DONE_ALL); - napi_schedule(&dev->mt76.tx_napi); - } + return hif; +} - if (intr & MT_INT_RX_DONE_DATA) { - mt7915_irq_disable(dev, MT_INT_RX_DONE_DATA); - napi_schedule(&dev->mt76.napi[0]); - } +static void mt7915_put_hif2(struct mt7915_hif *hif) +{ + if (!hif) + return; - if (intr & MT_INT_RX_DONE_WM) { - mt7915_irq_disable(dev, MT_INT_RX_DONE_WM); - napi_schedule(&dev->mt76.napi[1]); - } + put_device(hif->dev); +} - if (intr & MT_INT_RX_DONE_WA) { - mt7915_irq_disable(dev, MT_INT_RX_DONE_WA); - napi_schedule(&dev->mt76.napi[2]); - } +static struct mt7915_hif *mt7915_pci_init_hif2(struct pci_dev *pdev) +{ + struct pci_dev *tmp_pdev; - if (intr & MT_INT_MCU_CMD) { - u32 val = mt76_rr(dev, MT_MCU_CMD); + hif_idx++; - mt76_wr(dev, MT_MCU_CMD, val); - if (val & MT_MCU_CMD_ERROR_MASK) { - dev->reset_state = val; - ieee80211_queue_work(mt76_hw(dev), &dev->reset_work); - wake_up(&dev->reset_wait); - } + tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7916, NULL); + if (!tmp_pdev) { + tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x790a, NULL); + if (!tmp_pdev) + return NULL; } + pci_dev_put(tmp_pdev); + + writel(hif_idx | MT_PCIE_RECOG_ID_SEM, + pcim_iomap_table(pdev)[0] + MT_PCIE_RECOG_ID); - return IRQ_HANDLED; + return mt7915_pci_get_hif2(hif_idx); } -static int -mt7915_alloc_device(struct pci_dev *pdev, struct mt7915_dev *dev) +static int mt7915_pci_hif2_probe(struct pci_dev *pdev) { -#define NUM_BANDS 2 - int i; - s8 **sku; + struct mt7915_hif *hif; - sku = devm_kzalloc(&pdev->dev, NUM_BANDS * sizeof(*sku), GFP_KERNEL); - if (!sku) + hif = devm_kzalloc(&pdev->dev, sizeof(*hif), GFP_KERNEL); + if (!hif) return -ENOMEM; - for (i = 0; i < NUM_BANDS; i++) { - sku[i] = devm_kzalloc(&pdev->dev, MT7915_SKU_TABLE_SIZE * - sizeof(**sku), GFP_KERNEL); - if (!sku[i]) - return -ENOMEM; - } - dev->rate_power = sku; + hif->dev = &pdev->dev; + hif->regs = pcim_iomap_table(pdev)[0]; + hif->irq = pdev->irq; + spin_lock_bh(&hif_lock); + list_add(&hif->list, &hif_list); + spin_unlock_bh(&hif_lock); + pci_set_drvdata(pdev, hif); return 0; } @@ -100,24 +103,10 @@ mt7915_alloc_device(struct pci_dev *pdev, struct mt7915_dev *dev) static int mt7915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - static const struct mt76_driver_ops drv_ops = { - /* txwi_size = txd size + txp size */ - .txwi_size = MT_TXD_SIZE + sizeof(struct mt7915_txp), - .drv_flags = MT_DRV_TXWI_NO_FREE, - .survey_flags = SURVEY_INFO_TIME_TX | - SURVEY_INFO_TIME_RX | - SURVEY_INFO_TIME_BSS_RX, - .tx_prepare_skb = mt7915_tx_prepare_skb, - .tx_complete_skb = mt7915_tx_complete_skb, - .rx_skb = mt7915_queue_rx_skb, - .rx_poll_complete = mt7915_rx_poll_complete, - .sta_ps = mt7915_sta_ps, - .sta_add = mt7915_mac_sta_add, - .sta_remove = mt7915_mac_sta_remove, - .update_survey = mt7915_update_channel, - }; + struct mt7915_hif *hif2 = NULL; struct mt7915_dev *dev; struct mt76_dev *mdev; + int irq; int ret; ret = pcim_enable_device(pdev); @@ -130,51 +119,112 @@ static int mt7915_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) return ret; - mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7915_ops, - &drv_ops); - if (!mdev) - return -ENOMEM; + mt76_pci_disable_aspm(pdev); - dev = container_of(mdev, struct mt7915_dev, mt76); - ret = mt7915_alloc_device(pdev, dev); - if (ret) - return ret; + if (id->device == 0x7916 || id->device == 0x790a) + return mt7915_pci_hif2_probe(pdev); - mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); - mdev->rev = (mt7915_l1_rr(dev, MT_HW_CHIPID) << 16) | - (mt7915_l1_rr(dev, MT_HW_REV) & 0xff); - dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); + dev = mt7915_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0], + id->device); + if (IS_ERR(dev)) + return PTR_ERR(dev); - /* master switch of PCIe tnterrupt enable */ - mt7915_l1_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); + mdev = &dev->mt76; + mt7915_wfsys_reset(dev); + hif2 = mt7915_pci_init_hif2(pdev); - ret = devm_request_irq(mdev->dev, pdev->irq, mt7915_irq_handler, + ret = mt7915_mmio_wed_init(dev, pdev, true, &irq); + if (ret < 0) + goto free_wed_or_irq_vector; + + if (!ret) { + hif2 = mt7915_pci_init_hif2(pdev); + + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + goto free_device; + + irq = pdev->irq; + } + + ret = devm_request_irq(mdev->dev, irq, mt7915_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) - goto error; + goto free_wed_or_irq_vector; + + /* master switch of PCIe tnterrupt enable */ + mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); + + if (hif2) { + dev->hif2 = hif2; + + mt76_wr(dev, MT_INT1_MASK_CSR, 0); + /* master switch of PCIe tnterrupt enable */ + if (is_mt7915(mdev)) + mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff); + else + mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE_MT7916, 0xff); + + ret = devm_request_irq(mdev->dev, dev->hif2->irq, + mt7915_irq_handler, IRQF_SHARED, + KBUILD_MODNAME "-hif", dev); + if (ret) + goto free_hif2; + } ret = mt7915_register_device(dev); if (ret) - goto error; + goto free_hif2_irq; return 0; -error: - ieee80211_free_hw(mt76_hw(dev)); + +free_hif2_irq: + if (dev->hif2) + devm_free_irq(mdev->dev, dev->hif2->irq, dev); +free_hif2: + if (dev->hif2) + put_device(dev->hif2->dev); + devm_free_irq(mdev->dev, irq, dev); +free_wed_or_irq_vector: + if (mtk_wed_device_active(&mdev->mmio.wed)) + mtk_wed_device_detach(&mdev->mmio.wed); + else + pci_free_irq_vectors(pdev); +free_device: + mt76_free_device(&dev->mt76); + return ret; } +static void mt7915_hif_remove(struct pci_dev *pdev) +{ + struct mt7915_hif *hif = pci_get_drvdata(pdev); + + list_del(&hif->list); +} + static void mt7915_pci_remove(struct pci_dev *pdev) { - struct mt76_dev *mdev = pci_get_drvdata(pdev); - struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + struct mt76_dev *mdev; + struct mt7915_dev *dev; + mdev = pci_get_drvdata(pdev); + dev = container_of(mdev, struct mt7915_dev, mt76); + mt7915_put_hif2(dev->hif2); mt7915_unregister_device(dev); } +struct pci_driver mt7915_hif_driver = { + .name = KBUILD_MODNAME "_hif", + .id_table = mt7915_hif_device_table, + .probe = mt7915_pci_probe, + .remove = mt7915_hif_remove, +}; + struct pci_driver mt7915_pci_driver = { .name = KBUILD_MODNAME, .id_table = mt7915_pci_device_table, @@ -182,10 +232,11 @@ struct pci_driver mt7915_pci_driver = { .remove = mt7915_pci_remove, }; -module_pci_driver(mt7915_pci_driver); - MODULE_DEVICE_TABLE(pci, mt7915_pci_device_table); +MODULE_DEVICE_TABLE(pci, mt7915_hif_device_table); MODULE_FIRMWARE(MT7915_FIRMWARE_WA); MODULE_FIRMWARE(MT7915_FIRMWARE_WM); MODULE_FIRMWARE(MT7915_ROM_PATCH); -MODULE_LICENSE("Dual BSD/GPL"); +MODULE_FIRMWARE(MT7916_FIRMWARE_WA); +MODULE_FIRMWARE(MT7916_FIRMWARE_WM); +MODULE_FIRMWARE(MT7916_ROM_PATCH); |
