1addc7540SIgor Mitsyanko // SPDX-License-Identifier: GPL-2.0+ 2addc7540SIgor Mitsyanko /* Copyright (c) 2018 Quantenna Communications, Inc. All rights reserved. */ 3addc7540SIgor Mitsyanko 4b7da53cdSIgor Mitsyanko #include <linux/module.h> 5addc7540SIgor Mitsyanko #include <linux/printk.h> 6addc7540SIgor Mitsyanko #include <linux/pci.h> 7addc7540SIgor Mitsyanko #include <linux/spinlock.h> 8addc7540SIgor Mitsyanko #include <linux/mutex.h> 9addc7540SIgor Mitsyanko #include <linux/netdevice.h> 10addc7540SIgor Mitsyanko #include <linux/seq_file.h> 11addc7540SIgor Mitsyanko #include <linux/workqueue.h> 12addc7540SIgor Mitsyanko #include <linux/completion.h> 13addc7540SIgor Mitsyanko 14addc7540SIgor Mitsyanko #include "pcie_priv.h" 15addc7540SIgor Mitsyanko #include "bus.h" 16addc7540SIgor Mitsyanko #include "shm_ipc.h" 17addc7540SIgor Mitsyanko #include "core.h" 18addc7540SIgor Mitsyanko #include "debug.h" 19b7da53cdSIgor Mitsyanko #include "util.h" 20b7da53cdSIgor Mitsyanko #include "qtn_hw_ids.h" 21addc7540SIgor Mitsyanko 22addc7540SIgor Mitsyanko #define QTN_SYSCTL_BAR 0 23addc7540SIgor Mitsyanko #define QTN_SHMEM_BAR 2 24addc7540SIgor Mitsyanko #define QTN_DMA_BAR 3 25addc7540SIgor Mitsyanko 26b7da53cdSIgor Mitsyanko #define QTN_PCIE_MAX_FW_BUFSZ (1 * 1024 * 1024) 27b7da53cdSIgor Mitsyanko 28b7da53cdSIgor Mitsyanko static bool use_msi = true; 29b7da53cdSIgor Mitsyanko module_param(use_msi, bool, 0644); 30b7da53cdSIgor Mitsyanko MODULE_PARM_DESC(use_msi, "set 0 to use legacy interrupt"); 31b7da53cdSIgor Mitsyanko 32b7da53cdSIgor Mitsyanko static unsigned int tx_bd_size_param; 33b7da53cdSIgor Mitsyanko module_param(tx_bd_size_param, uint, 0644); 34b7da53cdSIgor Mitsyanko MODULE_PARM_DESC(tx_bd_size_param, "Tx descriptors queue size"); 35b7da53cdSIgor Mitsyanko 3697aef03cSSergey Matyukevich static unsigned int rx_bd_size_param; 37b7da53cdSIgor Mitsyanko module_param(rx_bd_size_param, uint, 0644); 38b7da53cdSIgor Mitsyanko MODULE_PARM_DESC(rx_bd_size_param, "Rx descriptors queue size"); 39b7da53cdSIgor Mitsyanko 40b7da53cdSIgor Mitsyanko static u8 flashboot = 1; 41b7da53cdSIgor Mitsyanko module_param(flashboot, byte, 0644); 42b7da53cdSIgor Mitsyanko MODULE_PARM_DESC(flashboot, "set to 0 to use FW binary file on FS"); 43b7da53cdSIgor Mitsyanko 44b7da53cdSIgor Mitsyanko static unsigned int fw_blksize_param = QTN_PCIE_MAX_FW_BUFSZ; 45b7da53cdSIgor Mitsyanko module_param(fw_blksize_param, uint, 0644); 46b7da53cdSIgor Mitsyanko MODULE_PARM_DESC(fw_blksize_param, "firmware loading block size in bytes"); 47b7da53cdSIgor Mitsyanko 48b7da53cdSIgor Mitsyanko #define DRV_NAME "qtnfmac_pcie" 49b7da53cdSIgor Mitsyanko 50addc7540SIgor Mitsyanko int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) 51addc7540SIgor Mitsyanko { 52addc7540SIgor Mitsyanko struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); 53addc7540SIgor Mitsyanko int ret; 54addc7540SIgor Mitsyanko 55addc7540SIgor Mitsyanko ret = qtnf_shm_ipc_send(&priv->shm_ipc_ep_in, skb->data, skb->len); 56addc7540SIgor Mitsyanko 57addc7540SIgor Mitsyanko if (ret == -ETIMEDOUT) { 58addc7540SIgor Mitsyanko pr_err("EP firmware is dead\n"); 5983b00f6eSSergey Matyukevich bus->fw_state = QTNF_FW_STATE_DEAD; 60addc7540SIgor Mitsyanko } 61addc7540SIgor Mitsyanko 62addc7540SIgor Mitsyanko return ret; 63addc7540SIgor Mitsyanko } 64addc7540SIgor Mitsyanko 65addc7540SIgor Mitsyanko int qtnf_pcie_alloc_skb_array(struct qtnf_pcie_bus_priv *priv) 66addc7540SIgor Mitsyanko { 67addc7540SIgor Mitsyanko struct sk_buff **vaddr; 68addc7540SIgor Mitsyanko int len; 69addc7540SIgor Mitsyanko 70addc7540SIgor Mitsyanko len = priv->tx_bd_num * sizeof(*priv->tx_skb) + 71addc7540SIgor Mitsyanko priv->rx_bd_num * sizeof(*priv->rx_skb); 72addc7540SIgor Mitsyanko vaddr = devm_kzalloc(&priv->pdev->dev, len, GFP_KERNEL); 73addc7540SIgor Mitsyanko 74addc7540SIgor Mitsyanko if (!vaddr) 75addc7540SIgor Mitsyanko return -ENOMEM; 76addc7540SIgor Mitsyanko 77addc7540SIgor Mitsyanko priv->tx_skb = vaddr; 78addc7540SIgor Mitsyanko 79addc7540SIgor Mitsyanko vaddr += priv->tx_bd_num; 80addc7540SIgor Mitsyanko priv->rx_skb = vaddr; 81addc7540SIgor Mitsyanko 82addc7540SIgor Mitsyanko return 0; 83addc7540SIgor Mitsyanko } 84addc7540SIgor Mitsyanko 85b7da53cdSIgor Mitsyanko static void qtnf_pcie_bringup_fw_async(struct qtnf_bus *bus) 86addc7540SIgor Mitsyanko { 87addc7540SIgor Mitsyanko struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); 88addc7540SIgor Mitsyanko struct pci_dev *pdev = priv->pdev; 89addc7540SIgor Mitsyanko 90addc7540SIgor Mitsyanko get_device(&pdev->dev); 91addc7540SIgor Mitsyanko schedule_work(&bus->fw_work); 92addc7540SIgor Mitsyanko } 93addc7540SIgor Mitsyanko 94addc7540SIgor Mitsyanko static int qtnf_dbg_mps_show(struct seq_file *s, void *data) 95addc7540SIgor Mitsyanko { 96addc7540SIgor Mitsyanko struct qtnf_bus *bus = dev_get_drvdata(s->private); 97addc7540SIgor Mitsyanko struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); 98addc7540SIgor Mitsyanko 99b7da53cdSIgor Mitsyanko seq_printf(s, "%d\n", pcie_get_mps(priv->pdev)); 100addc7540SIgor Mitsyanko 101addc7540SIgor Mitsyanko return 0; 102addc7540SIgor Mitsyanko } 103addc7540SIgor Mitsyanko 104addc7540SIgor Mitsyanko static int qtnf_dbg_msi_show(struct seq_file *s, void *data) 105addc7540SIgor Mitsyanko { 106addc7540SIgor Mitsyanko struct qtnf_bus *bus = dev_get_drvdata(s->private); 107addc7540SIgor Mitsyanko struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); 108addc7540SIgor Mitsyanko 109addc7540SIgor Mitsyanko seq_printf(s, "%u\n", priv->msi_enabled); 110addc7540SIgor Mitsyanko 111addc7540SIgor Mitsyanko return 0; 112addc7540SIgor Mitsyanko } 113addc7540SIgor Mitsyanko 114addc7540SIgor Mitsyanko static int qtnf_dbg_shm_stats(struct seq_file *s, void *data) 115addc7540SIgor Mitsyanko { 116addc7540SIgor Mitsyanko struct qtnf_bus *bus = dev_get_drvdata(s->private); 117addc7540SIgor Mitsyanko struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); 118addc7540SIgor Mitsyanko 119addc7540SIgor Mitsyanko seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n", 120addc7540SIgor Mitsyanko priv->shm_ipc_ep_in.tx_packet_count); 121addc7540SIgor Mitsyanko seq_printf(s, "shm_ipc_ep_in.rx_packet_count(%zu)\n", 122addc7540SIgor Mitsyanko priv->shm_ipc_ep_in.rx_packet_count); 123addc7540SIgor Mitsyanko seq_printf(s, "shm_ipc_ep_out.tx_packet_count(%zu)\n", 124addc7540SIgor Mitsyanko priv->shm_ipc_ep_out.tx_timeout_count); 125addc7540SIgor Mitsyanko seq_printf(s, "shm_ipc_ep_out.rx_packet_count(%zu)\n", 126addc7540SIgor Mitsyanko priv->shm_ipc_ep_out.rx_packet_count); 127addc7540SIgor Mitsyanko 128addc7540SIgor Mitsyanko return 0; 129addc7540SIgor Mitsyanko } 130addc7540SIgor Mitsyanko 131ae1946beSSergey Matyukevich int qtnf_pcie_fw_boot_done(struct qtnf_bus *bus) 132addc7540SIgor Mitsyanko { 133dd4c2260SSergey Matyukevich struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); 134dd4c2260SSergey Matyukevich char card_id[64]; 135addc7540SIgor Mitsyanko int ret; 136addc7540SIgor Mitsyanko 13783b00f6eSSergey Matyukevich bus->fw_state = QTNF_FW_STATE_BOOT_DONE; 138addc7540SIgor Mitsyanko ret = qtnf_core_attach(bus); 139addc7540SIgor Mitsyanko if (ret) { 140addc7540SIgor Mitsyanko pr_err("failed to attach core\n"); 141ae1946beSSergey Matyukevich } else { 142dd4c2260SSergey Matyukevich snprintf(card_id, sizeof(card_id), "%s:%s", 143dd4c2260SSergey Matyukevich DRV_NAME, pci_name(priv->pdev)); 144dd4c2260SSergey Matyukevich qtnf_debugfs_init(bus, card_id); 145addc7540SIgor Mitsyanko qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show); 146addc7540SIgor Mitsyanko qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show); 147addc7540SIgor Mitsyanko qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats); 148addc7540SIgor Mitsyanko } 149addc7540SIgor Mitsyanko 150ae1946beSSergey Matyukevich return ret; 151addc7540SIgor Mitsyanko } 152addc7540SIgor Mitsyanko 153b7da53cdSIgor Mitsyanko static void qtnf_tune_pcie_mps(struct pci_dev *pdev) 154addc7540SIgor Mitsyanko { 155addc7540SIgor Mitsyanko struct pci_dev *parent; 156addc7540SIgor Mitsyanko int mps_p, mps_o, mps_m, mps; 157addc7540SIgor Mitsyanko int ret; 158addc7540SIgor Mitsyanko 159addc7540SIgor Mitsyanko /* current mps */ 160addc7540SIgor Mitsyanko mps_o = pcie_get_mps(pdev); 161addc7540SIgor Mitsyanko 162addc7540SIgor Mitsyanko /* maximum supported mps */ 163addc7540SIgor Mitsyanko mps_m = 128 << pdev->pcie_mpss; 164addc7540SIgor Mitsyanko 165addc7540SIgor Mitsyanko /* suggested new mps value */ 166addc7540SIgor Mitsyanko mps = mps_m; 167addc7540SIgor Mitsyanko 168addc7540SIgor Mitsyanko if (pdev->bus && pdev->bus->self) { 169addc7540SIgor Mitsyanko /* parent (bus) mps */ 170addc7540SIgor Mitsyanko parent = pdev->bus->self; 171addc7540SIgor Mitsyanko 172addc7540SIgor Mitsyanko if (pci_is_pcie(parent)) { 173addc7540SIgor Mitsyanko mps_p = pcie_get_mps(parent); 174addc7540SIgor Mitsyanko mps = min(mps_m, mps_p); 175addc7540SIgor Mitsyanko } 176addc7540SIgor Mitsyanko } 177addc7540SIgor Mitsyanko 178addc7540SIgor Mitsyanko ret = pcie_set_mps(pdev, mps); 179addc7540SIgor Mitsyanko if (ret) { 180addc7540SIgor Mitsyanko pr_err("failed to set mps to %d, keep using current %d\n", 181addc7540SIgor Mitsyanko mps, mps_o); 182addc7540SIgor Mitsyanko return; 183addc7540SIgor Mitsyanko } 184addc7540SIgor Mitsyanko 185addc7540SIgor Mitsyanko pr_debug("set mps to %d (was %d, max %d)\n", mps, mps_o, mps_m); 186addc7540SIgor Mitsyanko } 187addc7540SIgor Mitsyanko 188addc7540SIgor Mitsyanko static void qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv, bool use_msi) 189addc7540SIgor Mitsyanko { 190addc7540SIgor Mitsyanko struct pci_dev *pdev = priv->pdev; 191addc7540SIgor Mitsyanko 192addc7540SIgor Mitsyanko /* fall back to legacy INTx interrupts by default */ 193addc7540SIgor Mitsyanko priv->msi_enabled = 0; 194addc7540SIgor Mitsyanko 195addc7540SIgor Mitsyanko /* check if MSI capability is available */ 196addc7540SIgor Mitsyanko if (use_msi) { 197addc7540SIgor Mitsyanko if (!pci_enable_msi(pdev)) { 198addc7540SIgor Mitsyanko pr_debug("enabled MSI interrupt\n"); 199addc7540SIgor Mitsyanko priv->msi_enabled = 1; 200addc7540SIgor Mitsyanko } else { 201addc7540SIgor Mitsyanko pr_warn("failed to enable MSI interrupts"); 202addc7540SIgor Mitsyanko } 203addc7540SIgor Mitsyanko } 204addc7540SIgor Mitsyanko 205addc7540SIgor Mitsyanko if (!priv->msi_enabled) { 206addc7540SIgor Mitsyanko pr_warn("legacy PCIE interrupts enabled\n"); 207addc7540SIgor Mitsyanko pci_intx(pdev, 1); 208addc7540SIgor Mitsyanko } 209addc7540SIgor Mitsyanko } 210addc7540SIgor Mitsyanko 211b7da53cdSIgor Mitsyanko static void __iomem *qtnf_map_bar(struct pci_dev *pdev, u8 index) 212addc7540SIgor Mitsyanko { 213addc7540SIgor Mitsyanko void __iomem *vaddr; 214addc7540SIgor Mitsyanko dma_addr_t busaddr; 215addc7540SIgor Mitsyanko size_t len; 216addc7540SIgor Mitsyanko int ret; 217addc7540SIgor Mitsyanko 218b7da53cdSIgor Mitsyanko ret = pcim_iomap_regions(pdev, 1 << index, "qtnfmac_pcie"); 219addc7540SIgor Mitsyanko if (ret) 220addc7540SIgor Mitsyanko return IOMEM_ERR_PTR(ret); 221addc7540SIgor Mitsyanko 222b7da53cdSIgor Mitsyanko busaddr = pci_resource_start(pdev, index); 223b7da53cdSIgor Mitsyanko len = pci_resource_len(pdev, index); 224b7da53cdSIgor Mitsyanko vaddr = pcim_iomap_table(pdev)[index]; 225addc7540SIgor Mitsyanko if (!vaddr) 226addc7540SIgor Mitsyanko return IOMEM_ERR_PTR(-ENOMEM); 227addc7540SIgor Mitsyanko 228addc7540SIgor Mitsyanko pr_debug("BAR%u vaddr=0x%p busaddr=%pad len=%u\n", 229addc7540SIgor Mitsyanko index, vaddr, &busaddr, (int)len); 230addc7540SIgor Mitsyanko 231addc7540SIgor Mitsyanko return vaddr; 232addc7540SIgor Mitsyanko } 233addc7540SIgor Mitsyanko 2348804ea9eSSergey Matyukevich static void qtnf_pcie_control_rx_callback(void *arg, const u8 __iomem *buf, 2358804ea9eSSergey Matyukevich size_t len) 236addc7540SIgor Mitsyanko { 237addc7540SIgor Mitsyanko struct qtnf_pcie_bus_priv *priv = arg; 238addc7540SIgor Mitsyanko struct qtnf_bus *bus = pci_get_drvdata(priv->pdev); 239addc7540SIgor Mitsyanko struct sk_buff *skb; 240addc7540SIgor Mitsyanko 241addc7540SIgor Mitsyanko if (unlikely(len == 0)) { 242addc7540SIgor Mitsyanko pr_warn("zero length packet received\n"); 243addc7540SIgor Mitsyanko return; 244addc7540SIgor Mitsyanko } 245addc7540SIgor Mitsyanko 246addc7540SIgor Mitsyanko skb = __dev_alloc_skb(len, GFP_KERNEL); 247addc7540SIgor Mitsyanko 248addc7540SIgor Mitsyanko if (unlikely(!skb)) { 249addc7540SIgor Mitsyanko pr_err("failed to allocate skb\n"); 250addc7540SIgor Mitsyanko return; 251addc7540SIgor Mitsyanko } 252addc7540SIgor Mitsyanko 2538804ea9eSSergey Matyukevich memcpy_fromio(skb_put(skb, len), buf, len); 254addc7540SIgor Mitsyanko 255addc7540SIgor Mitsyanko qtnf_trans_handle_rx_ctl_packet(bus, skb); 256addc7540SIgor Mitsyanko } 257addc7540SIgor Mitsyanko 258addc7540SIgor Mitsyanko void qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv, 259addc7540SIgor Mitsyanko struct qtnf_shm_ipc_region __iomem *ipc_tx_reg, 260addc7540SIgor Mitsyanko struct qtnf_shm_ipc_region __iomem *ipc_rx_reg, 261addc7540SIgor Mitsyanko const struct qtnf_shm_ipc_int *ipc_int) 262addc7540SIgor Mitsyanko { 263addc7540SIgor Mitsyanko const struct qtnf_shm_ipc_rx_callback rx_callback = { 264addc7540SIgor Mitsyanko qtnf_pcie_control_rx_callback, priv }; 265addc7540SIgor Mitsyanko 266addc7540SIgor Mitsyanko qtnf_shm_ipc_init(&priv->shm_ipc_ep_in, QTNF_SHM_IPC_OUTBOUND, 267addc7540SIgor Mitsyanko ipc_tx_reg, priv->workqueue, 268addc7540SIgor Mitsyanko ipc_int, &rx_callback); 269addc7540SIgor Mitsyanko qtnf_shm_ipc_init(&priv->shm_ipc_ep_out, QTNF_SHM_IPC_INBOUND, 270addc7540SIgor Mitsyanko ipc_rx_reg, priv->workqueue, 271addc7540SIgor Mitsyanko ipc_int, &rx_callback); 272addc7540SIgor Mitsyanko } 273addc7540SIgor Mitsyanko 274b7da53cdSIgor Mitsyanko static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) 275addc7540SIgor Mitsyanko { 276addc7540SIgor Mitsyanko struct qtnf_pcie_bus_priv *pcie_priv; 277addc7540SIgor Mitsyanko struct qtnf_bus *bus; 278b7da53cdSIgor Mitsyanko void __iomem *sysctl_bar; 279b7da53cdSIgor Mitsyanko void __iomem *epmem_bar; 280b7da53cdSIgor Mitsyanko void __iomem *dmareg_bar; 281b7da53cdSIgor Mitsyanko unsigned int chipid; 282addc7540SIgor Mitsyanko int ret; 283addc7540SIgor Mitsyanko 284b7da53cdSIgor Mitsyanko if (!pci_is_pcie(pdev)) { 285b7da53cdSIgor Mitsyanko pr_err("device %s is not PCI Express\n", pci_name(pdev)); 286b7da53cdSIgor Mitsyanko return -EIO; 287b7da53cdSIgor Mitsyanko } 288b7da53cdSIgor Mitsyanko 289b7da53cdSIgor Mitsyanko qtnf_tune_pcie_mps(pdev); 290b7da53cdSIgor Mitsyanko 291b7da53cdSIgor Mitsyanko ret = pcim_enable_device(pdev); 292b7da53cdSIgor Mitsyanko if (ret) { 293b7da53cdSIgor Mitsyanko pr_err("failed to init PCI device %x\n", pdev->device); 294b7da53cdSIgor Mitsyanko return ret; 295b7da53cdSIgor Mitsyanko } 296b7da53cdSIgor Mitsyanko 297b7da53cdSIgor Mitsyanko pci_set_master(pdev); 298b7da53cdSIgor Mitsyanko 299b7da53cdSIgor Mitsyanko sysctl_bar = qtnf_map_bar(pdev, QTN_SYSCTL_BAR); 300b7da53cdSIgor Mitsyanko if (IS_ERR(sysctl_bar)) { 301b7da53cdSIgor Mitsyanko pr_err("failed to map BAR%u\n", QTN_SYSCTL_BAR); 302b7da53cdSIgor Mitsyanko return ret; 303b7da53cdSIgor Mitsyanko } 304b7da53cdSIgor Mitsyanko 305b7da53cdSIgor Mitsyanko dmareg_bar = qtnf_map_bar(pdev, QTN_DMA_BAR); 306b7da53cdSIgor Mitsyanko if (IS_ERR(dmareg_bar)) { 307b7da53cdSIgor Mitsyanko pr_err("failed to map BAR%u\n", QTN_DMA_BAR); 308b7da53cdSIgor Mitsyanko return ret; 309b7da53cdSIgor Mitsyanko } 310b7da53cdSIgor Mitsyanko 311b7da53cdSIgor Mitsyanko epmem_bar = qtnf_map_bar(pdev, QTN_SHMEM_BAR); 312b7da53cdSIgor Mitsyanko if (IS_ERR(epmem_bar)) { 313b7da53cdSIgor Mitsyanko pr_err("failed to map BAR%u\n", QTN_SHMEM_BAR); 314b7da53cdSIgor Mitsyanko return ret; 315b7da53cdSIgor Mitsyanko } 316b7da53cdSIgor Mitsyanko 317b7da53cdSIgor Mitsyanko chipid = qtnf_chip_id_get(sysctl_bar); 318b7da53cdSIgor Mitsyanko 319b7da53cdSIgor Mitsyanko pr_info("identified device: %s\n", qtnf_chipid_to_string(chipid)); 320b7da53cdSIgor Mitsyanko 321b7da53cdSIgor Mitsyanko switch (chipid) { 322b7da53cdSIgor Mitsyanko case QTN_CHIP_ID_PEARL: 323b7da53cdSIgor Mitsyanko case QTN_CHIP_ID_PEARL_B: 324b7da53cdSIgor Mitsyanko case QTN_CHIP_ID_PEARL_C: 325b7da53cdSIgor Mitsyanko bus = qtnf_pcie_pearl_alloc(pdev); 326b7da53cdSIgor Mitsyanko break; 327e401fa25SSergey Matyukevich case QTN_CHIP_ID_TOPAZ: 328e401fa25SSergey Matyukevich bus = qtnf_pcie_topaz_alloc(pdev); 329e401fa25SSergey Matyukevich break; 330b7da53cdSIgor Mitsyanko default: 331b7da53cdSIgor Mitsyanko pr_err("unsupported chip ID 0x%x\n", chipid); 332b7da53cdSIgor Mitsyanko return -ENOTSUPP; 333b7da53cdSIgor Mitsyanko } 334b7da53cdSIgor Mitsyanko 335addc7540SIgor Mitsyanko if (!bus) 336addc7540SIgor Mitsyanko return -ENOMEM; 337addc7540SIgor Mitsyanko 338addc7540SIgor Mitsyanko pcie_priv = get_bus_priv(bus); 339addc7540SIgor Mitsyanko pci_set_drvdata(pdev, bus); 340addc7540SIgor Mitsyanko bus->dev = &pdev->dev; 34183b00f6eSSergey Matyukevich bus->fw_state = QTNF_FW_STATE_DETACHED; 342addc7540SIgor Mitsyanko pcie_priv->pdev = pdev; 343addc7540SIgor Mitsyanko pcie_priv->tx_stopped = 0; 344b7da53cdSIgor Mitsyanko pcie_priv->flashboot = flashboot; 345b7da53cdSIgor Mitsyanko 346b7da53cdSIgor Mitsyanko if (fw_blksize_param > QTN_PCIE_MAX_FW_BUFSZ) 347b7da53cdSIgor Mitsyanko pcie_priv->fw_blksize = QTN_PCIE_MAX_FW_BUFSZ; 348b7da53cdSIgor Mitsyanko else 349b7da53cdSIgor Mitsyanko pcie_priv->fw_blksize = fw_blksize_param; 350addc7540SIgor Mitsyanko 351addc7540SIgor Mitsyanko mutex_init(&bus->bus_lock); 352addc7540SIgor Mitsyanko spin_lock_init(&pcie_priv->tx_lock); 353addc7540SIgor Mitsyanko spin_lock_init(&pcie_priv->tx_reclaim_lock); 354addc7540SIgor Mitsyanko 355addc7540SIgor Mitsyanko pcie_priv->tx_full_count = 0; 356addc7540SIgor Mitsyanko pcie_priv->tx_done_count = 0; 357addc7540SIgor Mitsyanko pcie_priv->pcie_irq_count = 0; 358addc7540SIgor Mitsyanko pcie_priv->tx_reclaim_done = 0; 359addc7540SIgor Mitsyanko pcie_priv->tx_reclaim_req = 0; 360bc70732fSIgor Mitsyanko pcie_priv->tx_eapol = 0; 361addc7540SIgor Mitsyanko 362addc7540SIgor Mitsyanko pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PCIE"); 363addc7540SIgor Mitsyanko if (!pcie_priv->workqueue) { 364addc7540SIgor Mitsyanko pr_err("failed to alloc bus workqueue\n"); 365b7da53cdSIgor Mitsyanko return -ENODEV; 366b7da53cdSIgor Mitsyanko } 367b7da53cdSIgor Mitsyanko 368b7da53cdSIgor Mitsyanko ret = dma_set_mask_and_coherent(&pdev->dev, 369b7da53cdSIgor Mitsyanko pcie_priv->dma_mask_get_cb()); 370b7da53cdSIgor Mitsyanko if (ret) { 371b7da53cdSIgor Mitsyanko pr_err("PCIE DMA coherent mask init failed 0x%llx\n", 372b7da53cdSIgor Mitsyanko pcie_priv->dma_mask_get_cb()); 373b7da53cdSIgor Mitsyanko goto error; 374addc7540SIgor Mitsyanko } 375addc7540SIgor Mitsyanko 376addc7540SIgor Mitsyanko init_dummy_netdev(&bus->mux_dev); 377addc7540SIgor Mitsyanko qtnf_pcie_init_irq(pcie_priv, use_msi); 378b7da53cdSIgor Mitsyanko pcie_priv->sysctl_bar = sysctl_bar; 379b7da53cdSIgor Mitsyanko pcie_priv->dmareg_bar = dmareg_bar; 380b7da53cdSIgor Mitsyanko pcie_priv->epmem_bar = epmem_bar; 381addc7540SIgor Mitsyanko pci_save_state(pdev); 382addc7540SIgor Mitsyanko 38397aef03cSSergey Matyukevich ret = pcie_priv->probe_cb(bus, tx_bd_size_param, rx_bd_size_param); 384b7da53cdSIgor Mitsyanko if (ret) 385b7da53cdSIgor Mitsyanko goto error; 386b7da53cdSIgor Mitsyanko 387b7da53cdSIgor Mitsyanko qtnf_pcie_bringup_fw_async(bus); 388addc7540SIgor Mitsyanko return 0; 389addc7540SIgor Mitsyanko 390b7da53cdSIgor Mitsyanko error: 391addc7540SIgor Mitsyanko flush_workqueue(pcie_priv->workqueue); 392addc7540SIgor Mitsyanko destroy_workqueue(pcie_priv->workqueue); 393addc7540SIgor Mitsyanko pci_set_drvdata(pdev, NULL); 394addc7540SIgor Mitsyanko return ret; 395addc7540SIgor Mitsyanko } 396addc7540SIgor Mitsyanko 397addc7540SIgor Mitsyanko static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_bus_priv *priv) 398addc7540SIgor Mitsyanko { 399addc7540SIgor Mitsyanko qtnf_shm_ipc_free(&priv->shm_ipc_ep_in); 400addc7540SIgor Mitsyanko qtnf_shm_ipc_free(&priv->shm_ipc_ep_out); 401addc7540SIgor Mitsyanko } 402addc7540SIgor Mitsyanko 403b7da53cdSIgor Mitsyanko static void qtnf_pcie_remove(struct pci_dev *dev) 404addc7540SIgor Mitsyanko { 405b7da53cdSIgor Mitsyanko struct qtnf_pcie_bus_priv *priv; 406b7da53cdSIgor Mitsyanko struct qtnf_bus *bus; 407b7da53cdSIgor Mitsyanko 408b7da53cdSIgor Mitsyanko bus = pci_get_drvdata(dev); 409b7da53cdSIgor Mitsyanko if (!bus) 410b7da53cdSIgor Mitsyanko return; 411b7da53cdSIgor Mitsyanko 412b7da53cdSIgor Mitsyanko priv = get_bus_priv(bus); 413b7da53cdSIgor Mitsyanko 41486ca238cSIgor Mitsyanko cancel_work_sync(&bus->fw_work); 415addc7540SIgor Mitsyanko 41683b00f6eSSergey Matyukevich if (qtnf_fw_is_attached(bus)) 417addc7540SIgor Mitsyanko qtnf_core_detach(bus); 418addc7540SIgor Mitsyanko 419addc7540SIgor Mitsyanko netif_napi_del(&bus->mux_napi); 420addc7540SIgor Mitsyanko flush_workqueue(priv->workqueue); 421addc7540SIgor Mitsyanko destroy_workqueue(priv->workqueue); 422addc7540SIgor Mitsyanko tasklet_kill(&priv->reclaim_tq); 423addc7540SIgor Mitsyanko 424addc7540SIgor Mitsyanko qtnf_pcie_free_shm_ipc(priv); 425addc7540SIgor Mitsyanko qtnf_debugfs_remove(bus); 426b7da53cdSIgor Mitsyanko priv->remove_cb(bus); 427addc7540SIgor Mitsyanko pci_set_drvdata(priv->pdev, NULL); 428addc7540SIgor Mitsyanko } 429b7da53cdSIgor Mitsyanko 430b7da53cdSIgor Mitsyanko #ifdef CONFIG_PM_SLEEP 431b7da53cdSIgor Mitsyanko static int qtnf_pcie_suspend(struct device *dev) 432b7da53cdSIgor Mitsyanko { 433b7da53cdSIgor Mitsyanko struct qtnf_pcie_bus_priv *priv; 434b7da53cdSIgor Mitsyanko struct qtnf_bus *bus; 435b7da53cdSIgor Mitsyanko 4361f5f5ea7SChuhong Yuan bus = dev_get_drvdata(dev); 437b7da53cdSIgor Mitsyanko if (!bus) 438b7da53cdSIgor Mitsyanko return -EFAULT; 439b7da53cdSIgor Mitsyanko 440b7da53cdSIgor Mitsyanko priv = get_bus_priv(bus); 441b7da53cdSIgor Mitsyanko return priv->suspend_cb(bus); 442b7da53cdSIgor Mitsyanko } 443b7da53cdSIgor Mitsyanko 444b7da53cdSIgor Mitsyanko static int qtnf_pcie_resume(struct device *dev) 445b7da53cdSIgor Mitsyanko { 446b7da53cdSIgor Mitsyanko struct qtnf_pcie_bus_priv *priv; 447b7da53cdSIgor Mitsyanko struct qtnf_bus *bus; 448b7da53cdSIgor Mitsyanko 4491f5f5ea7SChuhong Yuan bus = dev_get_drvdata(dev); 450b7da53cdSIgor Mitsyanko if (!bus) 451b7da53cdSIgor Mitsyanko return -EFAULT; 452b7da53cdSIgor Mitsyanko 453b7da53cdSIgor Mitsyanko priv = get_bus_priv(bus); 454b7da53cdSIgor Mitsyanko return priv->resume_cb(bus); 455b7da53cdSIgor Mitsyanko } 456b7da53cdSIgor Mitsyanko 457b7da53cdSIgor Mitsyanko /* Power Management Hooks */ 458b7da53cdSIgor Mitsyanko static SIMPLE_DEV_PM_OPS(qtnf_pcie_pm_ops, qtnf_pcie_suspend, 459b7da53cdSIgor Mitsyanko qtnf_pcie_resume); 460b7da53cdSIgor Mitsyanko #endif 461b7da53cdSIgor Mitsyanko 462b7da53cdSIgor Mitsyanko static const struct pci_device_id qtnf_pcie_devid_table[] = { 463b7da53cdSIgor Mitsyanko { 464e401fa25SSergey Matyukevich PCIE_VENDOR_ID_QUANTENNA, PCIE_DEVICE_ID_QSR, 465b7da53cdSIgor Mitsyanko PCI_ANY_ID, PCI_ANY_ID, 0, 0, 466b7da53cdSIgor Mitsyanko }, 467b7da53cdSIgor Mitsyanko { }, 468b7da53cdSIgor Mitsyanko }; 469b7da53cdSIgor Mitsyanko 470b7da53cdSIgor Mitsyanko MODULE_DEVICE_TABLE(pci, qtnf_pcie_devid_table); 471b7da53cdSIgor Mitsyanko 472b7da53cdSIgor Mitsyanko static struct pci_driver qtnf_pcie_drv_data = { 473b7da53cdSIgor Mitsyanko .name = DRV_NAME, 474b7da53cdSIgor Mitsyanko .id_table = qtnf_pcie_devid_table, 475b7da53cdSIgor Mitsyanko .probe = qtnf_pcie_probe, 476b7da53cdSIgor Mitsyanko .remove = qtnf_pcie_remove, 477b7da53cdSIgor Mitsyanko #ifdef CONFIG_PM_SLEEP 478b7da53cdSIgor Mitsyanko .driver = { 479b7da53cdSIgor Mitsyanko .pm = &qtnf_pcie_pm_ops, 480b7da53cdSIgor Mitsyanko }, 481b7da53cdSIgor Mitsyanko #endif 482b7da53cdSIgor Mitsyanko }; 483b7da53cdSIgor Mitsyanko 484b7da53cdSIgor Mitsyanko static int __init qtnf_pcie_register(void) 485b7da53cdSIgor Mitsyanko { 486b7da53cdSIgor Mitsyanko return pci_register_driver(&qtnf_pcie_drv_data); 487b7da53cdSIgor Mitsyanko } 488b7da53cdSIgor Mitsyanko 489b7da53cdSIgor Mitsyanko static void __exit qtnf_pcie_exit(void) 490b7da53cdSIgor Mitsyanko { 491b7da53cdSIgor Mitsyanko pci_unregister_driver(&qtnf_pcie_drv_data); 492b7da53cdSIgor Mitsyanko } 493b7da53cdSIgor Mitsyanko 494b7da53cdSIgor Mitsyanko module_init(qtnf_pcie_register); 495b7da53cdSIgor Mitsyanko module_exit(qtnf_pcie_exit); 496b7da53cdSIgor Mitsyanko 497b7da53cdSIgor Mitsyanko MODULE_AUTHOR("Quantenna Communications"); 498b7da53cdSIgor Mitsyanko MODULE_DESCRIPTION("Quantenna PCIe bus driver for 802.11 wireless LAN."); 499b7da53cdSIgor Mitsyanko MODULE_LICENSE("GPL"); 500