mirror of https://gitee.com/openkylin/linux.git
qtnfmac_pcie: use single PCIe driver for all platforms
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>
This commit is contained in:
parent
3419348a97
commit
b7da53cd6c
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
@ -15,14 +16,37 @@
|
|||
#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;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = dma_set_mask_and_coherent(&pdev->dev,
|
||||
pcie_priv->dma_mask_get_cb());
|
||||
if (ret) {
|
||||
pr_err("PCIE DMA coherent mask init failed 0x%llx\n",
|
||||
pcie_priv->dma_mask_get_cb());
|
||||
goto error;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
qtnf_tune_pcie_mps(pcie_priv);
|
||||
|
||||
ret = pcim_enable_device(pdev);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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");
|
||||
|
|
|
@ -23,9 +23,14 @@
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -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>
|
||||
|
@ -24,23 +23,7 @@
|
|||
#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;
|
||||
if (tx_bd_size == 0)
|
||||
tx_bd_size = PEARL_TX_BD_SIZE_DEFAULT;
|
||||
|
||||
val = tx_bd_size * sizeof(struct qtnf_pearl_tx_bd);
|
||||
|
||||
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->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 = 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 (!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);
|
||||
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);
|
||||
|
||||
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 0;
|
||||
|
||||
err_xfer:
|
||||
qtnf_pearl_free_xfer_buffers(ps);
|
||||
error:
|
||||
qtnf_pcie_remove(bus, &ps->base);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus);
|
||||
|
||||
bus = pci_get_drvdata(pdev);
|
||||
if (!bus)
|
||||
return;
|
||||
|
||||
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);
|
||||
return bus;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue