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

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
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
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.
+3 −3
Original line number Diff line number Diff line
@@ -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
+195 −84
Original line number Diff line number Diff line
// 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");
+11 −8
Original line number Diff line number Diff line
@@ -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)
{
+60 −151
Original line number Diff line number Diff line
@@ -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[] = {
struct qtnf_bus *qtnf_pcie_pearl_alloc(struct pci_dev *pdev)
{
		PCIE_VENDOR_ID_QUANTENNA, PCIE_DEVICE_ID_QTN_PEARL,
		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
	},
	{ },
};
	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");
Loading