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
......@@ -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