Commit b7da53cd authored by Igor Mitsyanko's avatar Igor Mitsyanko Committed by Kalle Valo

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: default avatarIgor Mitsyanko <igor.mitsyanko.os@quantenna.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 3419348a
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
// 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;
}
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");
......@@ -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;
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");
......@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment