qtnfmac_pcie: use single PCIe driver for all platforms
authorIgor Mitsyanko <igor.mitsyanko.os@quantenna.com>
Tue, 16 Oct 2018 10:23:56 +0000 (10:23 +0000)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 6 Nov 2018 16:53:49 +0000 (18:53 +0200)
Single PCIe driver can identify hardware type by reading CHIP ID at
probe time and invoking a correct initialization sequence.

Signed-off-by: Igor Mitsyanko <igor.mitsyanko.os@quantenna.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/quantenna/qtnfmac/Kconfig
drivers/net/wireless/quantenna/qtnfmac/Makefile
drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c
drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h
drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c
drivers/net/wireless/quantenna/qtnfmac/util.c
drivers/net/wireless/quantenna/qtnfmac/util.h

index b8c12a5..696c500 100644 (file)
@@ -1,10 +1,10 @@
 config QTNFMAC
        tristate
-       depends on QTNFMAC_PEARL_PCIE
-       default m if QTNFMAC_PEARL_PCIE=m
-       default y if QTNFMAC_PEARL_PCIE=y
+       depends on QTNFMAC_PCIE
+       default m if QTNFMAC_PCIE=m
+       default y if QTNFMAC_PCIE=y
 
-config QTNFMAC_PEARL_PCIE
+config QTNFMAC_PCIE
        tristate "Quantenna QSR10g PCIe support"
        default n
        depends on PCI && CFG80211
@@ -16,4 +16,4 @@ config QTNFMAC_PEARL_PCIE
          802.11ac QSR10g (aka Pearl) FullMAC chipset running over PCIe.
 
          If you choose to build it as a module, two modules will be built:
-         qtnfmac.ko and qtnfmac_pearl_pcie.ko.
+         qtnfmac.ko and qtnfmac_pcie.ko.
index 17cd7ad..d7e8185 100644 (file)
@@ -19,11 +19,11 @@ qtnfmac-objs += \
 
 #
 
-obj-$(CONFIG_QTNFMAC_PEARL_PCIE) += qtnfmac_pearl_pcie.o
+obj-$(CONFIG_QTNFMAC_PCIE) += qtnfmac_pcie.o
 
-qtnfmac_pearl_pcie-objs += \
+qtnfmac_pcie-objs += \
        shm_ipc.o \
        pcie/pcie.o \
        pcie/pearl_pcie.o
 
-qtnfmac_pearl_pcie-$(CONFIG_DEBUG_FS) += debug.o
+qtnfmac_pcie-$(CONFIG_DEBUG_FS) += debug.o
index 16795db..70dd8da 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 /* Copyright (c) 2018 Quantenna Communications, Inc. All rights reserved. */
 
+#include <linux/module.h>
 #include <linux/printk.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
 #include "shm_ipc.h"
 #include "core.h"
 #include "debug.h"
-
-#undef pr_fmt
-#define pr_fmt(fmt)    "qtnf_pcie: %s: " fmt, __func__
+#include "util.h"
+#include "qtn_hw_ids.h"
 
 #define QTN_SYSCTL_BAR 0
 #define QTN_SHMEM_BAR  2
 #define QTN_DMA_BAR    3
 
+#define QTN_PCIE_MAX_FW_BUFSZ          (1 * 1024 * 1024)
+
+static bool use_msi = true;
+module_param(use_msi, bool, 0644);
+MODULE_PARM_DESC(use_msi, "set 0 to use legacy interrupt");
+
+static unsigned int tx_bd_size_param;
+module_param(tx_bd_size_param, uint, 0644);
+MODULE_PARM_DESC(tx_bd_size_param, "Tx descriptors queue size");
+
+static unsigned int rx_bd_size_param = 256;
+module_param(rx_bd_size_param, uint, 0644);
+MODULE_PARM_DESC(rx_bd_size_param, "Rx descriptors queue size");
+
+static u8 flashboot = 1;
+module_param(flashboot, byte, 0644);
+MODULE_PARM_DESC(flashboot, "set to 0 to use FW binary file on FS");
+
+static unsigned int fw_blksize_param = QTN_PCIE_MAX_FW_BUFSZ;
+module_param(fw_blksize_param, uint, 0644);
+MODULE_PARM_DESC(fw_blksize_param, "firmware loading block size in bytes");
+
+#define DRV_NAME       "qtnfmac_pcie"
+
 int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb)
 {
        struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
@@ -58,7 +82,7 @@ int qtnf_pcie_alloc_skb_array(struct qtnf_pcie_bus_priv *priv)
        return 0;
 }
 
-void qtnf_pcie_bringup_fw_async(struct qtnf_bus *bus)
+static void qtnf_pcie_bringup_fw_async(struct qtnf_bus *bus)
 {
        struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
        struct pci_dev *pdev = priv->pdev;
@@ -72,7 +96,7 @@ static int qtnf_dbg_mps_show(struct seq_file *s, void *data)
        struct qtnf_bus *bus = dev_get_drvdata(s->private);
        struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
 
-       seq_printf(s, "%d\n", priv->mps);
+       seq_printf(s, "%d\n", pcie_get_mps(priv->pdev));
 
        return 0;
 }
@@ -104,8 +128,7 @@ static int qtnf_dbg_shm_stats(struct seq_file *s, void *data)
        return 0;
 }
 
-void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success,
-                           const char *drv_name)
+void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success)
 {
        struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);
        struct pci_dev *pdev = priv->pdev;
@@ -122,7 +145,7 @@ void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success,
        }
 
        if (boot_success) {
-               qtnf_debugfs_init(bus, drv_name);
+               qtnf_debugfs_init(bus, DRV_NAME);
                qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show);
                qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show);
                qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats);
@@ -133,9 +156,8 @@ void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success,
        put_device(&pdev->dev);
 }
 
-static void qtnf_tune_pcie_mps(struct qtnf_pcie_bus_priv *priv)
+static void qtnf_tune_pcie_mps(struct pci_dev *pdev)
 {
-       struct pci_dev *pdev = priv->pdev;
        struct pci_dev *parent;
        int mps_p, mps_o, mps_m, mps;
        int ret;
@@ -163,12 +185,10 @@ static void qtnf_tune_pcie_mps(struct qtnf_pcie_bus_priv *priv)
        if (ret) {
                pr_err("failed to set mps to %d, keep using current %d\n",
                       mps, mps_o);
-               priv->mps = mps_o;
                return;
        }
 
        pr_debug("set mps to %d (was %d, max %d)\n", mps, mps_o, mps_m);
-       priv->mps = mps;
 }
 
 static void qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv, bool use_msi)
@@ -194,20 +214,20 @@ static void qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv, bool use_msi)
        }
 }
 
-static void __iomem *qtnf_map_bar(struct qtnf_pcie_bus_priv *priv, u8 index)
+static void __iomem *qtnf_map_bar(struct pci_dev *pdev, u8 index)
 {
        void __iomem *vaddr;
        dma_addr_t busaddr;
        size_t len;
        int ret;
 
-       ret = pcim_iomap_regions(priv->pdev, 1 << index, "qtnfmac_pcie");
+       ret = pcim_iomap_regions(pdev, 1 << index, "qtnfmac_pcie");
        if (ret)
                return IOMEM_ERR_PTR(ret);
 
-       busaddr = pci_resource_start(priv->pdev, index);
-       len = pci_resource_len(priv->pdev, index);
-       vaddr = pcim_iomap_table(priv->pdev)[index];
+       busaddr = pci_resource_start(pdev, index);
+       len = pci_resource_len(pdev, index);
+       vaddr = pcim_iomap_table(pdev)[index];
        if (!vaddr)
                return IOMEM_ERR_PTR(-ENOMEM);
 
@@ -217,31 +237,6 @@ static void __iomem *qtnf_map_bar(struct qtnf_pcie_bus_priv *priv, u8 index)
        return vaddr;
 }
 
-static int qtnf_pcie_init_memory(struct qtnf_pcie_bus_priv *priv)
-{
-       int ret = -ENOMEM;
-
-       priv->sysctl_bar = qtnf_map_bar(priv, QTN_SYSCTL_BAR);
-       if (IS_ERR(priv->sysctl_bar)) {
-               pr_err("failed to map BAR%u\n", QTN_SYSCTL_BAR);
-               return ret;
-       }
-
-       priv->dmareg_bar = qtnf_map_bar(priv, QTN_DMA_BAR);
-       if (IS_ERR(priv->dmareg_bar)) {
-               pr_err("failed to map BAR%u\n", QTN_DMA_BAR);
-               return ret;
-       }
-
-       priv->epmem_bar = qtnf_map_bar(priv, QTN_SHMEM_BAR);
-       if (IS_ERR(priv->epmem_bar)) {
-               pr_err("failed to map BAR%u\n", QTN_SHMEM_BAR);
-               return ret;
-       }
-
-       return 0;
-}
-
 static void qtnf_pcie_control_rx_callback(void *arg, const u8 __iomem *buf,
                                          size_t len)
 {
@@ -282,27 +277,80 @@ void qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv,
                          ipc_int, &rx_callback);
 }
 
-int qtnf_pcie_probe(struct pci_dev *pdev, size_t priv_size,
-                   const struct qtnf_bus_ops *bus_ops, u64 dma_mask,
-                   bool use_msi)
+static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct qtnf_pcie_bus_priv *pcie_priv;
        struct qtnf_bus *bus;
+       void __iomem *sysctl_bar;
+       void __iomem *epmem_bar;
+       void __iomem *dmareg_bar;
+       unsigned int chipid;
        int ret;
 
-       bus = devm_kzalloc(&pdev->dev,
-                          sizeof(*bus) + priv_size, GFP_KERNEL);
+       if (!pci_is_pcie(pdev)) {
+               pr_err("device %s is not PCI Express\n", pci_name(pdev));
+               return -EIO;
+       }
+
+       qtnf_tune_pcie_mps(pdev);
+
+       ret = pcim_enable_device(pdev);
+       if (ret) {
+               pr_err("failed to init PCI device %x\n", pdev->device);
+               return ret;
+       }
+
+       pci_set_master(pdev);
+
+       sysctl_bar = qtnf_map_bar(pdev, QTN_SYSCTL_BAR);
+       if (IS_ERR(sysctl_bar)) {
+               pr_err("failed to map BAR%u\n", QTN_SYSCTL_BAR);
+               return ret;
+       }
+
+       dmareg_bar = qtnf_map_bar(pdev, QTN_DMA_BAR);
+       if (IS_ERR(dmareg_bar)) {
+               pr_err("failed to map BAR%u\n", QTN_DMA_BAR);
+               return ret;
+       }
+
+       epmem_bar = qtnf_map_bar(pdev, QTN_SHMEM_BAR);
+       if (IS_ERR(epmem_bar)) {
+               pr_err("failed to map BAR%u\n", QTN_SHMEM_BAR);
+               return ret;
+       }
+
+       chipid = qtnf_chip_id_get(sysctl_bar);
+
+       pr_info("identified device: %s\n", qtnf_chipid_to_string(chipid));
+
+       switch (chipid) {
+       case QTN_CHIP_ID_PEARL:
+       case QTN_CHIP_ID_PEARL_B:
+       case QTN_CHIP_ID_PEARL_C:
+               bus = qtnf_pcie_pearl_alloc(pdev);
+               break;
+       default:
+               pr_err("unsupported chip ID 0x%x\n", chipid);
+               return -ENOTSUPP;
+       }
+
        if (!bus)
                return -ENOMEM;
 
        pcie_priv = get_bus_priv(bus);
-
        pci_set_drvdata(pdev, bus);
-       bus->bus_ops = bus_ops;
        bus->dev = &pdev->dev;
        bus->fw_state = QTNF_FW_STATE_RESET;
        pcie_priv->pdev = pdev;
        pcie_priv->tx_stopped = 0;
+       pcie_priv->rx_bd_num = rx_bd_size_param;
+       pcie_priv->flashboot = flashboot;
+
+       if (fw_blksize_param > QTN_PCIE_MAX_FW_BUFSZ)
+               pcie_priv->fw_blksize =  QTN_PCIE_MAX_FW_BUFSZ;
+       else
+               pcie_priv->fw_blksize = fw_blksize_param;
 
        mutex_init(&bus->bus_lock);
        spin_lock_init(&pcie_priv->tx_lock);
@@ -317,53 +365,35 @@ int qtnf_pcie_probe(struct pci_dev *pdev, size_t priv_size,
        pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PCIE");
        if (!pcie_priv->workqueue) {
                pr_err("failed to alloc bus workqueue\n");
-               ret = -ENODEV;
-               goto err_init;
-       }
-
-       init_dummy_netdev(&bus->mux_dev);
-
-       if (!pci_is_pcie(pdev)) {
-               pr_err("device %s is not PCI Express\n", pci_name(pdev));
-               ret = -EIO;
-               goto err_base;
+               return -ENODEV;
        }
 
-       qtnf_tune_pcie_mps(pcie_priv);
-
-       ret = pcim_enable_device(pdev);
+       ret = dma_set_mask_and_coherent(&pdev->dev,
+                                       pcie_priv->dma_mask_get_cb());
        if (ret) {
-               pr_err("failed to init PCI device %x\n", pdev->device);
-               goto err_base;
-       } else {
-               pr_debug("successful init of PCI device %x\n", pdev->device);
+               pr_err("PCIE DMA coherent mask init failed 0x%llx\n",
+                      pcie_priv->dma_mask_get_cb());
+               goto error;
        }
 
-       ret = dma_set_mask_and_coherent(&pdev->dev, dma_mask);
-       if (ret) {
-               pr_err("PCIE DMA coherent mask init failed\n");
-               goto err_base;
-       }
-
-       pci_set_master(pdev);
+       init_dummy_netdev(&bus->mux_dev);
        qtnf_pcie_init_irq(pcie_priv, use_msi);
-
-       ret = qtnf_pcie_init_memory(pcie_priv);
-       if (ret < 0) {
-               pr_err("PCIE memory init failed\n");
-               goto err_base;
-       }
-
+       pcie_priv->sysctl_bar = sysctl_bar;
+       pcie_priv->dmareg_bar = dmareg_bar;
+       pcie_priv->epmem_bar = epmem_bar;
        pci_save_state(pdev);
 
+       ret = pcie_priv->probe_cb(bus, tx_bd_size_param);
+       if (ret)
+               goto error;
+
+       qtnf_pcie_bringup_fw_async(bus);
        return 0;
 
-err_base:
+error:
        flush_workqueue(pcie_priv->workqueue);
        destroy_workqueue(pcie_priv->workqueue);
-err_init:
        pci_set_drvdata(pdev, NULL);
-
        return ret;
 }
 
@@ -373,8 +403,17 @@ static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_bus_priv *priv)
        qtnf_shm_ipc_free(&priv->shm_ipc_ep_out);
 }
 
-void qtnf_pcie_remove(struct qtnf_bus *bus, struct qtnf_pcie_bus_priv *priv)
+static void qtnf_pcie_remove(struct pci_dev *dev)
 {
+       struct qtnf_pcie_bus_priv *priv;
+       struct qtnf_bus *bus;
+
+       bus = pci_get_drvdata(dev);
+       if (!bus)
+               return;
+
+       priv = get_bus_priv(bus);
+
        cancel_work_sync(&bus->fw_work);
 
        if (bus->fw_state == QTNF_FW_STATE_ACTIVE ||
@@ -388,5 +427,77 @@ void qtnf_pcie_remove(struct qtnf_bus *bus, struct qtnf_pcie_bus_priv *priv)
 
        qtnf_pcie_free_shm_ipc(priv);
        qtnf_debugfs_remove(bus);
+       priv->remove_cb(bus);
        pci_set_drvdata(priv->pdev, NULL);
 }
+
+#ifdef CONFIG_PM_SLEEP
+static int qtnf_pcie_suspend(struct device *dev)
+{
+       struct qtnf_pcie_bus_priv *priv;
+       struct qtnf_bus *bus;
+
+       bus = pci_get_drvdata(to_pci_dev(dev));
+       if (!bus)
+               return -EFAULT;
+
+       priv = get_bus_priv(bus);
+       return priv->suspend_cb(bus);
+}
+
+static int qtnf_pcie_resume(struct device *dev)
+{
+       struct qtnf_pcie_bus_priv *priv;
+       struct qtnf_bus *bus;
+
+       bus = pci_get_drvdata(to_pci_dev(dev));
+       if (!bus)
+               return -EFAULT;
+
+       priv = get_bus_priv(bus);
+       return priv->resume_cb(bus);
+}
+
+/* Power Management Hooks */
+static SIMPLE_DEV_PM_OPS(qtnf_pcie_pm_ops, qtnf_pcie_suspend,
+                        qtnf_pcie_resume);
+#endif
+
+static const struct pci_device_id qtnf_pcie_devid_table[] = {
+       {
+               PCIE_VENDOR_ID_QUANTENNA, PCIE_DEVICE_ID_QTN_PEARL,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+       },
+       { },
+};
+
+MODULE_DEVICE_TABLE(pci, qtnf_pcie_devid_table);
+
+static struct pci_driver qtnf_pcie_drv_data = {
+       .name = DRV_NAME,
+       .id_table = qtnf_pcie_devid_table,
+       .probe = qtnf_pcie_probe,
+       .remove = qtnf_pcie_remove,
+#ifdef CONFIG_PM_SLEEP
+       .driver = {
+               .pm = &qtnf_pcie_pm_ops,
+       },
+#endif
+};
+
+static int __init qtnf_pcie_register(void)
+{
+       return pci_register_driver(&qtnf_pcie_drv_data);
+}
+
+static void __exit qtnf_pcie_exit(void)
+{
+       pci_unregister_driver(&qtnf_pcie_drv_data);
+}
+
+module_init(qtnf_pcie_register);
+module_exit(qtnf_pcie_exit);
+
+MODULE_AUTHOR("Quantenna Communications");
+MODULE_DESCRIPTION("Quantenna PCIe bus driver for 802.11 wireless LAN.");
+MODULE_LICENSE("GPL");
index 5c70fb4..7c742c5 100644 (file)
 struct qtnf_pcie_bus_priv {
        struct pci_dev *pdev;
 
+       int (*probe_cb)(struct qtnf_bus *bus, unsigned int tx_bd_size);
+       void (*remove_cb)(struct qtnf_bus *bus);
+       int (*suspend_cb)(struct qtnf_bus *bus);
+       int (*resume_cb)(struct qtnf_bus *bus);
+       u64 (*dma_mask_get_cb)(void);
+
        spinlock_t tx_reclaim_lock;
        spinlock_t tx_lock;
-       int mps;
 
        struct workqueue_struct *workqueue;
        struct tasklet_struct reclaim_tq;
@@ -43,6 +48,8 @@ struct qtnf_pcie_bus_priv {
        struct sk_buff **tx_skb;
        struct sk_buff **rx_skb;
 
+       unsigned int fw_blksize;
+
        u32 rx_bd_w_index;
        u32 rx_bd_r_index;
 
@@ -58,21 +65,17 @@ struct qtnf_pcie_bus_priv {
 
        u8 msi_enabled;
        u8 tx_stopped;
+       bool flashboot;
 };
 
 int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb);
 int qtnf_pcie_alloc_skb_array(struct qtnf_pcie_bus_priv *priv);
-void qtnf_pcie_bringup_fw_async(struct qtnf_bus *bus);
-void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success,
-                           const char *drv_name);
+void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success);
 void qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv,
                            struct qtnf_shm_ipc_region __iomem *ipc_tx_reg,
                            struct qtnf_shm_ipc_region __iomem *ipc_rx_reg,
                            const struct qtnf_shm_ipc_int *ipc_int);
-int qtnf_pcie_probe(struct pci_dev *pdev, size_t priv_size,
-                   const struct qtnf_bus_ops *bus_ops, u64 dma_mask,
-                   bool use_msi);
-void qtnf_pcie_remove(struct qtnf_bus *bus, struct qtnf_pcie_bus_priv *priv);
+struct qtnf_bus *qtnf_pcie_pearl_alloc(struct pci_dev *pdev);
 
 static inline void qtnf_non_posted_write(u32 val, void __iomem *basereg)
 {
index 95c7b95..1f5facb 100644 (file)
@@ -2,7 +2,6 @@
 /* Copyright (c) 2018 Quantenna Communications */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include "shm_ipc.h"
 #include "debug.h"
 
-static bool use_msi = true;
-module_param(use_msi, bool, 0644);
-MODULE_PARM_DESC(use_msi, "set 0 to use legacy interrupt");
-
-static unsigned int tx_bd_size_param = 32;
-module_param(tx_bd_size_param, uint, 0644);
-MODULE_PARM_DESC(tx_bd_size_param, "Tx descriptors queue size, power of two");
-
-static unsigned int rx_bd_size_param = 256;
-module_param(rx_bd_size_param, uint, 0644);
-MODULE_PARM_DESC(rx_bd_size_param, "Rx descriptors queue size, power of two");
-
-static u8 flashboot = 1;
-module_param(flashboot, byte, 0644);
-MODULE_PARM_DESC(flashboot, "set to 0 to use FW binary file on FS");
-
-#define DRV_NAME       "qtnfmac_pearl_pcie"
+#define PEARL_TX_BD_SIZE_DEFAULT       32
 
 struct qtnf_pearl_bda {
        __le16 bda_len;
@@ -415,30 +398,28 @@ static int pearl_hhbm_init(struct qtnf_pcie_pearl_state *ps)
        return 0;
 }
 
-static int qtnf_pcie_pearl_init_xfer(struct qtnf_pcie_pearl_state *ps)
+static int qtnf_pcie_pearl_init_xfer(struct qtnf_pcie_pearl_state *ps,
+                                    unsigned int tx_bd_size)
 {
        struct qtnf_pcie_bus_priv *priv = &ps->base;
        int ret;
        u32 val;
 
-       priv->tx_bd_num = tx_bd_size_param;
-       priv->rx_bd_num = rx_bd_size_param;
-       priv->rx_bd_w_index = 0;
-       priv->rx_bd_r_index = 0;
+       if (tx_bd_size == 0)
+               tx_bd_size = PEARL_TX_BD_SIZE_DEFAULT;
 
-       if (!priv->tx_bd_num || !is_power_of_2(priv->tx_bd_num)) {
-               pr_err("tx_bd_size_param %u is not power of two\n",
-                      priv->tx_bd_num);
-               return -EINVAL;
-       }
+       val = tx_bd_size * sizeof(struct qtnf_pearl_tx_bd);
 
-       val = priv->tx_bd_num * sizeof(struct qtnf_pearl_tx_bd);
-       if (val > PCIE_HHBM_MAX_SIZE) {
-               pr_err("tx_bd_size_param %u is too large\n",
-                      priv->tx_bd_num);
-               return -EINVAL;
+       if (!is_power_of_2(tx_bd_size) || val > PCIE_HHBM_MAX_SIZE) {
+               pr_warn("bad tx_bd_size value %u\n", tx_bd_size);
+               priv->tx_bd_num = PEARL_TX_BD_SIZE_DEFAULT;
+       } else {
+               priv->tx_bd_num = tx_bd_size;
        }
 
+       priv->rx_bd_w_index = 0;
+       priv->rx_bd_r_index = 0;
+
        if (!priv->rx_bd_num || !is_power_of_2(priv->rx_bd_num)) {
                pr_err("rx_bd_size_param %u is not power of two\n",
                       priv->rx_bd_num);
@@ -1006,7 +987,7 @@ static void qtnf_pearl_fw_work_handler(struct work_struct *work)
        const char *fwname = QTN_PCI_PEARL_FW_NAME;
        bool fw_boot_success = false;
 
-       if (flashboot) {
+       if (ps->base.flashboot) {
                state |= QTN_RC_FW_FLASHBOOT;
        } else {
                ret = request_firmware(&fw, fwname, &pdev->dev);
@@ -1022,7 +1003,7 @@ static void qtnf_pearl_fw_work_handler(struct work_struct *work)
                            QTN_FW_DL_TIMEOUT_MS)) {
                pr_err("card is not ready\n");
 
-               if (!flashboot)
+               if (!ps->base.flashboot)
                        release_firmware(fw);
 
                goto fw_load_exit;
@@ -1030,7 +1011,7 @@ static void qtnf_pearl_fw_work_handler(struct work_struct *work)
 
        qtnf_clear_state(&ps->bda->bda_ep_state, QTN_EP_FW_LOADRDY);
 
-       if (flashboot) {
+       if (ps->base.flashboot) {
                pr_info("booting firmware from flash\n");
 
        } else {
@@ -1061,7 +1042,7 @@ static void qtnf_pearl_fw_work_handler(struct work_struct *work)
        fw_boot_success = true;
 
 fw_load_exit:
-       qtnf_pcie_fw_boot_done(bus, fw_boot_success, DRV_NAME);
+       qtnf_pcie_fw_boot_done(bus, fw_boot_success);
 
        if (fw_boot_success) {
                qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats);
@@ -1077,74 +1058,34 @@ static void qtnf_pearl_reclaim_tasklet_fn(unsigned long data)
        qtnf_en_txdone_irq(ps);
 }
 
-static int qtnf_pearl_check_chip_id(struct qtnf_pcie_pearl_state *ps)
+static u64 qtnf_pearl_dma_mask_get(void)
 {
-       unsigned int chipid;
-
-       chipid = qtnf_chip_id_get(ps->base.sysctl_bar);
-
-       switch (chipid) {
-       case QTN_CHIP_ID_PEARL:
-       case QTN_CHIP_ID_PEARL_B:
-       case QTN_CHIP_ID_PEARL_C:
-               pr_info("chip ID is 0x%x\n", chipid);
-               break;
-       default:
-               pr_err("incorrect chip ID 0x%x\n", chipid);
-               return -ENODEV;
-       }
-
-       return 0;
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+       return DMA_BIT_MASK(64);
+#else
+       return DMA_BIT_MASK(32);
+#endif
 }
 
-static int qtnf_pcie_pearl_probe(struct pci_dev *pdev,
-                                const struct pci_device_id *id)
+static int qtnf_pcie_pearl_probe(struct qtnf_bus *bus, unsigned int tx_bd_size)
 {
        struct qtnf_shm_ipc_int ipc_int;
-       struct qtnf_pcie_pearl_state *ps;
-       struct qtnf_bus *bus;
+       struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus);
+       struct pci_dev *pdev = ps->base.pdev;
        int ret;
-       u64 dma_mask;
-
-#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
-       dma_mask = DMA_BIT_MASK(64);
-#else
-       dma_mask = DMA_BIT_MASK(32);
-#endif
-
-       ret = qtnf_pcie_probe(pdev, sizeof(*ps), &qtnf_pcie_pearl_bus_ops,
-                             dma_mask, use_msi);
-       if (ret)
-               return ret;
-
-       bus = pci_get_drvdata(pdev);
-       ps = get_bus_priv(bus);
 
+       bus->bus_ops = &qtnf_pcie_pearl_bus_ops;
        spin_lock_init(&ps->irq_lock);
-
-       tasklet_init(&ps->base.reclaim_tq, qtnf_pearl_reclaim_tasklet_fn,
-                    (unsigned long)ps);
-       netif_napi_add(&bus->mux_dev, &bus->mux_napi,
-                      qtnf_pcie_pearl_rx_poll, 10);
        INIT_WORK(&bus->fw_work, qtnf_pearl_fw_work_handler);
 
        ps->pcie_reg_base = ps->base.dmareg_bar;
        ps->bda = ps->base.epmem_bar;
        writel(ps->base.msi_enabled, &ps->bda->bda_rc_msi_enabled);
 
-       ipc_int.fn = qtnf_pcie_pearl_ipc_gen_ep_int;
-       ipc_int.arg = ps;
-       qtnf_pcie_init_shm_ipc(&ps->base, &ps->bda->bda_shm_reg1,
-                              &ps->bda->bda_shm_reg2, &ipc_int);
-
-       ret = qtnf_pearl_check_chip_id(ps);
-       if (ret)
-               goto error;
-
-       ret = qtnf_pcie_pearl_init_xfer(ps);
+       ret = qtnf_pcie_pearl_init_xfer(ps, tx_bd_size);
        if (ret) {
                pr_err("PCIE xfer init failed\n");
-               goto error;
+               return ret;
        }
 
        /* init default irq settings */
@@ -1155,95 +1096,63 @@ static int qtnf_pcie_pearl_probe(struct pci_dev *pdev,
 
        ret = devm_request_irq(&pdev->dev, pdev->irq,
                               &qtnf_pcie_pearl_interrupt, 0,
-                              "qtnf_pcie_irq", (void *)bus);
+                              "qtnf_pearl_irq", (void *)bus);
        if (ret) {
                pr_err("failed to request pcie irq %d\n", pdev->irq);
-               goto err_xfer;
+               qtnf_pearl_free_xfer_buffers(ps);
+               return ret;
        }
 
-       qtnf_pcie_bringup_fw_async(bus);
-
-       return 0;
+       tasklet_init(&ps->base.reclaim_tq, qtnf_pearl_reclaim_tasklet_fn,
+                    (unsigned long)ps);
+       netif_napi_add(&bus->mux_dev, &bus->mux_napi,
+                      qtnf_pcie_pearl_rx_poll, 10);
 
-err_xfer:
-       qtnf_pearl_free_xfer_buffers(ps);
-error:
-       qtnf_pcie_remove(bus, &ps->base);
+       ipc_int.fn = qtnf_pcie_pearl_ipc_gen_ep_int;
+       ipc_int.arg = ps;
+       qtnf_pcie_init_shm_ipc(&ps->base, &ps->bda->bda_shm_reg1,
+                              &ps->bda->bda_shm_reg2, &ipc_int);
 
-       return ret;
+       return 0;
 }
 
-static void qtnf_pcie_pearl_remove(struct pci_dev *pdev)
+static void qtnf_pcie_pearl_remove(struct qtnf_bus *bus)
 {
-       struct qtnf_pcie_pearl_state *ps;
-       struct qtnf_bus *bus;
-
-       bus = pci_get_drvdata(pdev);
-       if (!bus)
-               return;
-
-       ps = get_bus_priv(bus);
+       struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus);
 
-       qtnf_pcie_remove(bus, &ps->base);
        qtnf_pearl_reset_ep(ps);
        qtnf_pearl_free_xfer_buffers(ps);
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int qtnf_pcie_pearl_suspend(struct device *dev)
+static int qtnf_pcie_pearl_suspend(struct qtnf_bus *bus)
 {
        return -EOPNOTSUPP;
 }
 
-static int qtnf_pcie_pearl_resume(struct device *dev)
+static int qtnf_pcie_pearl_resume(struct qtnf_bus *bus)
 {
        return 0;
 }
-#endif /* CONFIG_PM_SLEEP */
-
-#ifdef CONFIG_PM_SLEEP
-/* Power Management Hooks */
-static SIMPLE_DEV_PM_OPS(qtnf_pcie_pearl_pm_ops, qtnf_pcie_pearl_suspend,
-                        qtnf_pcie_pearl_resume);
 #endif
 
-static const struct pci_device_id qtnf_pcie_devid_table[] = {
-       {
-               PCIE_VENDOR_ID_QUANTENNA, PCIE_DEVICE_ID_QTN_PEARL,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-       },
-       { },
-};
+struct qtnf_bus *qtnf_pcie_pearl_alloc(struct pci_dev *pdev)
+{
+       struct qtnf_bus *bus;
+       struct qtnf_pcie_pearl_state *ps;
 
-MODULE_DEVICE_TABLE(pci, qtnf_pcie_devid_table);
+       bus = devm_kzalloc(&pdev->dev, sizeof(*bus) + sizeof(*ps), GFP_KERNEL);
+       if (!bus)
+               return NULL;
 
-static struct pci_driver qtnf_pcie_pearl_drv_data = {
-       .name = DRV_NAME,
-       .id_table = qtnf_pcie_devid_table,
-       .probe = qtnf_pcie_pearl_probe,
-       .remove = qtnf_pcie_pearl_remove,
+       ps = get_bus_priv(bus);
+       ps->base.probe_cb = qtnf_pcie_pearl_probe;
+       ps->base.remove_cb = qtnf_pcie_pearl_remove;
+       ps->base.dma_mask_get_cb = qtnf_pearl_dma_mask_get;
 #ifdef CONFIG_PM_SLEEP
-       .driver = {
-               .pm = &qtnf_pcie_pearl_pm_ops,
-       },
+       ps->base.resume_cb = qtnf_pcie_pearl_resume;
+       ps->base.suspend_cb = qtnf_pcie_pearl_suspend;
 #endif
-};
-
-static int __init qtnf_pcie_pearl_register(void)
-{
-       pr_info("register Quantenna QSR10g FullMAC PCIE driver\n");
-       return pci_register_driver(&qtnf_pcie_pearl_drv_data);
-}
 
-static void __exit qtnf_pcie_pearl_exit(void)
-{
-       pr_info("unregister Quantenna QSR10g FullMAC PCIE driver\n");
-       pci_unregister_driver(&qtnf_pcie_pearl_drv_data);
+       return bus;
 }
-
-module_init(qtnf_pcie_pearl_register);
-module_exit(qtnf_pcie_pearl_exit);
-
-MODULE_AUTHOR("Quantenna Communications");
-MODULE_DESCRIPTION("Quantenna QSR10g PCIe bus driver for 802.11 wireless LAN.");
-MODULE_LICENSE("GPL");
index e745733..dfe3fe8 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include "util.h"
+#include "qtn_hw_ids.h"
 
 void qtnf_sta_list_init(struct qtnf_sta_list *list)
 {
@@ -116,3 +117,18 @@ void qtnf_sta_list_free(struct qtnf_sta_list *list)
 
        INIT_LIST_HEAD(&list->head);
 }
+
+const char *qtnf_chipid_to_string(unsigned long chip_id)
+{
+       switch (chip_id) {
+       case QTN_CHIP_ID_PEARL:
+               return "Pearl revA";
+       case QTN_CHIP_ID_PEARL_B:
+               return "Pearl revB";
+       case QTN_CHIP_ID_PEARL_C:
+               return "Pearl revC";
+       default:
+               return "unknown";
+       }
+}
+EXPORT_SYMBOL_GPL(qtnf_chipid_to_string);
index 0d4d92b..b8744ba 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/kernel.h>
 #include "core.h"
 
+const char *qtnf_chipid_to_string(unsigned long chip_id);
+
 void qtnf_sta_list_init(struct qtnf_sta_list *list);
 
 struct qtnf_sta_node *qtnf_sta_list_lookup(struct qtnf_sta_list *list,