18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci/* Copyright (C) 2020 MediaTek Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Author: Ryder Lee <ryder.lee@mediatek.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/pci.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "mt7915.h" 128c2ecf20Sopenharmony_ci#include "mac.h" 138c2ecf20Sopenharmony_ci#include "../trace.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic const struct pci_device_id mt7915_pci_device_table[] = { 168c2ecf20Sopenharmony_ci { PCI_DEVICE(0x14c3, 0x7915) }, 178c2ecf20Sopenharmony_ci { }, 188c2ecf20Sopenharmony_ci}; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic void 218c2ecf20Sopenharmony_cimt7915_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci mt7915_irq_enable(dev, MT_INT_RX_DONE(q)); 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* TODO: support 2/4/6/8 MSI-X vectors */ 298c2ecf20Sopenharmony_cistatic irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci struct mt7915_dev *dev = dev_instance; 328c2ecf20Sopenharmony_ci u32 intr, mask; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci intr = mt76_rr(dev, MT_INT_SOURCE_CSR); 358c2ecf20Sopenharmony_ci intr &= dev->mt76.mmio.irqmask; 368c2ecf20Sopenharmony_ci mt76_wr(dev, MT_INT_SOURCE_CSR, intr); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) 398c2ecf20Sopenharmony_ci return IRQ_NONE; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci mask = intr & MT_INT_RX_DONE_ALL; 448c2ecf20Sopenharmony_ci if (intr & MT_INT_TX_DONE_MCU) 458c2ecf20Sopenharmony_ci mask |= MT_INT_TX_DONE_MCU; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci mt7915_irq_disable(dev, mask); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (intr & MT_INT_TX_DONE_MCU) 508c2ecf20Sopenharmony_ci napi_schedule(&dev->mt76.tx_napi); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (intr & MT_INT_RX_DONE_DATA) 538c2ecf20Sopenharmony_ci napi_schedule(&dev->mt76.napi[0]); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (intr & MT_INT_RX_DONE_WM) 568c2ecf20Sopenharmony_ci napi_schedule(&dev->mt76.napi[1]); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (intr & MT_INT_RX_DONE_WA) 598c2ecf20Sopenharmony_ci napi_schedule(&dev->mt76.napi[2]); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (intr & MT_INT_MCU_CMD) { 628c2ecf20Sopenharmony_ci u32 val = mt76_rr(dev, MT_MCU_CMD); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci mt76_wr(dev, MT_MCU_CMD, val); 658c2ecf20Sopenharmony_ci if (val & MT_MCU_CMD_ERROR_MASK) { 668c2ecf20Sopenharmony_ci dev->reset_state = val; 678c2ecf20Sopenharmony_ci ieee80211_queue_work(mt76_hw(dev), &dev->reset_work); 688c2ecf20Sopenharmony_ci wake_up(&dev->reset_wait); 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci return IRQ_HANDLED; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic int 768c2ecf20Sopenharmony_cimt7915_alloc_device(struct pci_dev *pdev, struct mt7915_dev *dev) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci#define NUM_BANDS 2 798c2ecf20Sopenharmony_ci int i; 808c2ecf20Sopenharmony_ci s8 **sku; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci sku = devm_kzalloc(&pdev->dev, NUM_BANDS * sizeof(*sku), GFP_KERNEL); 838c2ecf20Sopenharmony_ci if (!sku) 848c2ecf20Sopenharmony_ci return -ENOMEM; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci for (i = 0; i < NUM_BANDS; i++) { 878c2ecf20Sopenharmony_ci sku[i] = devm_kzalloc(&pdev->dev, MT7915_SKU_TABLE_SIZE * 888c2ecf20Sopenharmony_ci sizeof(**sku), GFP_KERNEL); 898c2ecf20Sopenharmony_ci if (!sku[i]) 908c2ecf20Sopenharmony_ci return -ENOMEM; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci dev->rate_power = sku; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return 0; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int mt7915_pci_probe(struct pci_dev *pdev, 988c2ecf20Sopenharmony_ci const struct pci_device_id *id) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci static const struct mt76_driver_ops drv_ops = { 1018c2ecf20Sopenharmony_ci /* txwi_size = txd size + txp size */ 1028c2ecf20Sopenharmony_ci .txwi_size = MT_TXD_SIZE + sizeof(struct mt7915_txp), 1038c2ecf20Sopenharmony_ci .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ | 1048c2ecf20Sopenharmony_ci MT_DRV_AMSDU_OFFLOAD, 1058c2ecf20Sopenharmony_ci .survey_flags = SURVEY_INFO_TIME_TX | 1068c2ecf20Sopenharmony_ci SURVEY_INFO_TIME_RX | 1078c2ecf20Sopenharmony_ci SURVEY_INFO_TIME_BSS_RX, 1088c2ecf20Sopenharmony_ci .tx_prepare_skb = mt7915_tx_prepare_skb, 1098c2ecf20Sopenharmony_ci .tx_complete_skb = mt7915_tx_complete_skb, 1108c2ecf20Sopenharmony_ci .rx_skb = mt7915_queue_rx_skb, 1118c2ecf20Sopenharmony_ci .rx_poll_complete = mt7915_rx_poll_complete, 1128c2ecf20Sopenharmony_ci .sta_ps = mt7915_sta_ps, 1138c2ecf20Sopenharmony_ci .sta_add = mt7915_mac_sta_add, 1148c2ecf20Sopenharmony_ci .sta_remove = mt7915_mac_sta_remove, 1158c2ecf20Sopenharmony_ci .update_survey = mt7915_update_channel, 1168c2ecf20Sopenharmony_ci }; 1178c2ecf20Sopenharmony_ci struct mt7915_dev *dev; 1188c2ecf20Sopenharmony_ci struct mt76_dev *mdev; 1198c2ecf20Sopenharmony_ci int ret; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci ret = pcim_enable_device(pdev); 1228c2ecf20Sopenharmony_ci if (ret) 1238c2ecf20Sopenharmony_ci return ret; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); 1268c2ecf20Sopenharmony_ci if (ret) 1278c2ecf20Sopenharmony_ci return ret; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci pci_set_master(pdev); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 1328c2ecf20Sopenharmony_ci if (ret) 1338c2ecf20Sopenharmony_ci return ret; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7915_ops, 1368c2ecf20Sopenharmony_ci &drv_ops); 1378c2ecf20Sopenharmony_ci if (!mdev) 1388c2ecf20Sopenharmony_ci return -ENOMEM; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci dev = container_of(mdev, struct mt7915_dev, mt76); 1418c2ecf20Sopenharmony_ci ret = mt7915_alloc_device(pdev, dev); 1428c2ecf20Sopenharmony_ci if (ret) 1438c2ecf20Sopenharmony_ci goto error; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); 1468c2ecf20Sopenharmony_ci mdev->rev = (mt7915_l1_rr(dev, MT_HW_CHIPID) << 16) | 1478c2ecf20Sopenharmony_ci (mt7915_l1_rr(dev, MT_HW_REV) & 0xff); 1488c2ecf20Sopenharmony_ci dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci mt76_wr(dev, MT_INT_MASK_CSR, 0); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* master switch of PCIe tnterrupt enable */ 1538c2ecf20Sopenharmony_ci mt7915_l1_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci ret = devm_request_irq(mdev->dev, pdev->irq, mt7915_irq_handler, 1568c2ecf20Sopenharmony_ci IRQF_SHARED, KBUILD_MODNAME, dev); 1578c2ecf20Sopenharmony_ci if (ret) 1588c2ecf20Sopenharmony_ci goto error; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci ret = mt7915_register_device(dev); 1618c2ecf20Sopenharmony_ci if (ret) 1628c2ecf20Sopenharmony_ci goto error; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_cierror: 1668c2ecf20Sopenharmony_ci mt76_free_device(&dev->mt76); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return ret; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic void mt7915_pci_remove(struct pci_dev *pdev) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct mt76_dev *mdev = pci_get_drvdata(pdev); 1748c2ecf20Sopenharmony_ci struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci mt7915_unregister_device(dev); 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistruct pci_driver mt7915_pci_driver = { 1808c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 1818c2ecf20Sopenharmony_ci .id_table = mt7915_pci_device_table, 1828c2ecf20Sopenharmony_ci .probe = mt7915_pci_probe, 1838c2ecf20Sopenharmony_ci .remove = mt7915_pci_remove, 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cimodule_pci_driver(mt7915_pci_driver); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mt7915_pci_device_table); 1898c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7915_FIRMWARE_WA); 1908c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7915_FIRMWARE_WM); 1918c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7915_ROM_PATCH); 1928c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 193