brintos

brintos / linux-shallow public Read only

0
0
Text · 11.4 KiB · f66eb43 Raw
494 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/* Copyright (c) 2018 Quantenna Communications, Inc. All rights reserved. */3 4#include <linux/module.h>5#include <linux/printk.h>6#include <linux/pci.h>7#include <linux/spinlock.h>8#include <linux/mutex.h>9#include <linux/netdevice.h>10#include <linux/seq_file.h>11#include <linux/workqueue.h>12#include <linux/completion.h>13 14#include "pcie_priv.h"15#include "bus.h"16#include "shm_ipc.h"17#include "core.h"18#include "debug.h"19#include "util.h"20#include "qtn_hw_ids.h"21 22#define QTN_SYSCTL_BAR	023#define QTN_SHMEM_BAR	224#define QTN_DMA_BAR	325 26#define QTN_PCIE_MAX_FW_BUFSZ		(1 * 1024 * 1024)27 28static bool use_msi = true;29module_param(use_msi, bool, 0644);30MODULE_PARM_DESC(use_msi, "set 0 to use legacy interrupt");31 32static unsigned int tx_bd_size_param;33module_param(tx_bd_size_param, uint, 0644);34MODULE_PARM_DESC(tx_bd_size_param, "Tx descriptors queue size");35 36static unsigned int rx_bd_size_param;37module_param(rx_bd_size_param, uint, 0644);38MODULE_PARM_DESC(rx_bd_size_param, "Rx descriptors queue size");39 40static u8 flashboot = 1;41module_param(flashboot, byte, 0644);42MODULE_PARM_DESC(flashboot, "set to 0 to use FW binary file on FS");43 44static unsigned int fw_blksize_param = QTN_PCIE_MAX_FW_BUFSZ;45module_param(fw_blksize_param, uint, 0644);46MODULE_PARM_DESC(fw_blksize_param, "firmware loading block size in bytes");47 48#define DRV_NAME	"qtnfmac_pcie"49 50int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb)51{52	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);53	int ret;54 55	ret = qtnf_shm_ipc_send(&priv->shm_ipc_ep_in, skb->data, skb->len);56 57	if (ret == -ETIMEDOUT) {58		pr_err("EP firmware is dead\n");59		bus->fw_state = QTNF_FW_STATE_DEAD;60	}61 62	return ret;63}64 65int qtnf_pcie_alloc_skb_array(struct qtnf_pcie_bus_priv *priv)66{67	struct sk_buff **vaddr;68	int len;69 70	len = priv->tx_bd_num * sizeof(*priv->tx_skb) +71		priv->rx_bd_num * sizeof(*priv->rx_skb);72	vaddr = devm_kzalloc(&priv->pdev->dev, len, GFP_KERNEL);73 74	if (!vaddr)75		return -ENOMEM;76 77	priv->tx_skb = vaddr;78 79	vaddr += priv->tx_bd_num;80	priv->rx_skb = vaddr;81 82	return 0;83}84 85static void qtnf_pcie_bringup_fw_async(struct qtnf_bus *bus)86{87	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);88	struct pci_dev *pdev = priv->pdev;89 90	get_device(&pdev->dev);91	schedule_work(&bus->fw_work);92}93 94static int qtnf_dbg_mps_show(struct seq_file *s, void *data)95{96	struct qtnf_bus *bus = dev_get_drvdata(s->private);97	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);98 99	seq_printf(s, "%d\n", pcie_get_mps(priv->pdev));100 101	return 0;102}103 104static int qtnf_dbg_msi_show(struct seq_file *s, void *data)105{106	struct qtnf_bus *bus = dev_get_drvdata(s->private);107	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);108 109	seq_printf(s, "%u\n", priv->msi_enabled);110 111	return 0;112}113 114static int qtnf_dbg_shm_stats(struct seq_file *s, void *data)115{116	struct qtnf_bus *bus = dev_get_drvdata(s->private);117	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);118 119	seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n",120		   priv->shm_ipc_ep_in.tx_packet_count);121	seq_printf(s, "shm_ipc_ep_in.rx_packet_count(%zu)\n",122		   priv->shm_ipc_ep_in.rx_packet_count);123	seq_printf(s, "shm_ipc_ep_out.tx_packet_count(%zu)\n",124		   priv->shm_ipc_ep_out.tx_timeout_count);125	seq_printf(s, "shm_ipc_ep_out.rx_packet_count(%zu)\n",126		   priv->shm_ipc_ep_out.rx_packet_count);127 128	return 0;129}130 131int qtnf_pcie_fw_boot_done(struct qtnf_bus *bus)132{133	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus);134	char card_id[64];135	int ret;136 137	bus->fw_state = QTNF_FW_STATE_BOOT_DONE;138	ret = qtnf_core_attach(bus);139	if (ret) {140		pr_err("failed to attach core\n");141	} else {142		snprintf(card_id, sizeof(card_id), "%s:%s",143			 DRV_NAME, pci_name(priv->pdev));144		qtnf_debugfs_init(bus, card_id);145		qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show);146		qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show);147		qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats);148	}149 150	return ret;151}152 153static void qtnf_tune_pcie_mps(struct pci_dev *pdev)154{155	struct pci_dev *parent;156	int mps_p, mps_o, mps_m, mps;157	int ret;158 159	/* current mps */160	mps_o = pcie_get_mps(pdev);161 162	/* maximum supported mps */163	mps_m = 128 << pdev->pcie_mpss;164 165	/* suggested new mps value */166	mps = mps_m;167 168	if (pdev->bus && pdev->bus->self) {169		/* parent (bus) mps */170		parent = pdev->bus->self;171 172		if (pci_is_pcie(parent)) {173			mps_p = pcie_get_mps(parent);174			mps = min(mps_m, mps_p);175		}176	}177 178	ret = pcie_set_mps(pdev, mps);179	if (ret) {180		pr_err("failed to set mps to %d, keep using current %d\n",181		       mps, mps_o);182		return;183	}184 185	pr_debug("set mps to %d (was %d, max %d)\n", mps, mps_o, mps_m);186}187 188static void qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv, bool use_msi)189{190	struct pci_dev *pdev = priv->pdev;191 192	/* fall back to legacy INTx interrupts by default */193	priv->msi_enabled = 0;194 195	/* check if MSI capability is available */196	if (use_msi) {197		if (!pci_enable_msi(pdev)) {198			pr_debug("enabled MSI interrupt\n");199			priv->msi_enabled = 1;200		} else {201			pr_warn("failed to enable MSI interrupts");202		}203	}204 205	if (!priv->msi_enabled) {206		pr_warn("legacy PCIE interrupts enabled\n");207		pci_intx(pdev, 1);208	}209}210 211static void __iomem *qtnf_map_bar(struct pci_dev *pdev, u8 index)212{213	void __iomem *vaddr;214	dma_addr_t busaddr;215	size_t len;216	int ret;217 218	ret = pcim_iomap_regions(pdev, 1 << index, "qtnfmac_pcie");219	if (ret)220		return IOMEM_ERR_PTR(ret);221 222	busaddr = pci_resource_start(pdev, index);223	len = pci_resource_len(pdev, index);224	vaddr = pcim_iomap_table(pdev)[index];225	if (!vaddr)226		return IOMEM_ERR_PTR(-ENOMEM);227 228	pr_debug("BAR%u vaddr=0x%p busaddr=%pad len=%u\n",229		 index, vaddr, &busaddr, (int)len);230 231	return vaddr;232}233 234static void qtnf_pcie_control_rx_callback(void *arg, const u8 __iomem *buf,235					  size_t len)236{237	struct qtnf_pcie_bus_priv *priv = arg;238	struct qtnf_bus *bus = pci_get_drvdata(priv->pdev);239	struct sk_buff *skb;240 241	if (unlikely(len == 0)) {242		pr_warn("zero length packet received\n");243		return;244	}245 246	skb = __dev_alloc_skb(len, GFP_KERNEL);247 248	if (unlikely(!skb)) {249		pr_err("failed to allocate skb\n");250		return;251	}252 253	memcpy_fromio(skb_put(skb, len), buf, len);254 255	qtnf_trans_handle_rx_ctl_packet(bus, skb);256}257 258void qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv,259			    struct qtnf_shm_ipc_region __iomem *ipc_tx_reg,260			    struct qtnf_shm_ipc_region __iomem *ipc_rx_reg,261			    const struct qtnf_shm_ipc_int *ipc_int)262{263	const struct qtnf_shm_ipc_rx_callback rx_callback = {264					qtnf_pcie_control_rx_callback, priv };265 266	qtnf_shm_ipc_init(&priv->shm_ipc_ep_in, QTNF_SHM_IPC_OUTBOUND,267			  ipc_tx_reg, priv->workqueue,268			  ipc_int, &rx_callback);269	qtnf_shm_ipc_init(&priv->shm_ipc_ep_out, QTNF_SHM_IPC_INBOUND,270			  ipc_rx_reg, priv->workqueue,271			  ipc_int, &rx_callback);272}273 274static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)275{276	struct qtnf_pcie_bus_priv *pcie_priv;277	struct qtnf_bus *bus;278	void __iomem *sysctl_bar;279	void __iomem *epmem_bar;280	void __iomem *dmareg_bar;281	unsigned int chipid;282	int ret;283 284	if (!pci_is_pcie(pdev)) {285		pr_err("device %s is not PCI Express\n", pci_name(pdev));286		return -EIO;287	}288 289	qtnf_tune_pcie_mps(pdev);290 291	ret = pcim_enable_device(pdev);292	if (ret) {293		pr_err("failed to init PCI device %x\n", pdev->device);294		return ret;295	}296 297	pci_set_master(pdev);298 299	sysctl_bar = qtnf_map_bar(pdev, QTN_SYSCTL_BAR);300	if (IS_ERR(sysctl_bar)) {301		pr_err("failed to map BAR%u\n", QTN_SYSCTL_BAR);302		return PTR_ERR(sysctl_bar);303	}304 305	dmareg_bar = qtnf_map_bar(pdev, QTN_DMA_BAR);306	if (IS_ERR(dmareg_bar)) {307		pr_err("failed to map BAR%u\n", QTN_DMA_BAR);308		return PTR_ERR(dmareg_bar);309	}310 311	epmem_bar = qtnf_map_bar(pdev, QTN_SHMEM_BAR);312	if (IS_ERR(epmem_bar)) {313		pr_err("failed to map BAR%u\n", QTN_SHMEM_BAR);314		return PTR_ERR(epmem_bar);315	}316 317	chipid = qtnf_chip_id_get(sysctl_bar);318 319	pr_info("identified device: %s\n", qtnf_chipid_to_string(chipid));320 321	switch (chipid) {322	case QTN_CHIP_ID_PEARL:323	case QTN_CHIP_ID_PEARL_B:324	case QTN_CHIP_ID_PEARL_C:325		bus = qtnf_pcie_pearl_alloc(pdev);326		break;327	case QTN_CHIP_ID_TOPAZ:328		bus = qtnf_pcie_topaz_alloc(pdev);329		break;330	default:331		pr_err("unsupported chip ID 0x%x\n", chipid);332		return -ENOTSUPP;333	}334 335	if (!bus)336		return -ENOMEM;337 338	pcie_priv = get_bus_priv(bus);339	pci_set_drvdata(pdev, bus);340	bus->dev = &pdev->dev;341	bus->fw_state = QTNF_FW_STATE_DETACHED;342	pcie_priv->pdev = pdev;343	pcie_priv->tx_stopped = 0;344	pcie_priv->flashboot = flashboot;345 346	if (fw_blksize_param > QTN_PCIE_MAX_FW_BUFSZ)347		pcie_priv->fw_blksize =  QTN_PCIE_MAX_FW_BUFSZ;348	else349		pcie_priv->fw_blksize = fw_blksize_param;350 351	mutex_init(&bus->bus_lock);352	spin_lock_init(&pcie_priv->tx_lock);353	spin_lock_init(&pcie_priv->tx_reclaim_lock);354 355	pcie_priv->tx_full_count = 0;356	pcie_priv->tx_done_count = 0;357	pcie_priv->pcie_irq_count = 0;358	pcie_priv->tx_reclaim_done = 0;359	pcie_priv->tx_reclaim_req = 0;360 361	pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PCIE");362	if (!pcie_priv->workqueue) {363		pr_err("failed to alloc bus workqueue\n");364		return -ENODEV;365	}366 367	ret = dma_set_mask_and_coherent(&pdev->dev,368					pcie_priv->dma_mask_get_cb());369	if (ret) {370		pr_err("PCIE DMA coherent mask init failed 0x%llx\n",371		       pcie_priv->dma_mask_get_cb());372		goto error;373	}374 375	bus->mux_dev = alloc_netdev_dummy(0);376	if (!bus->mux_dev) {377		ret = -ENOMEM;378		goto error;379	}380 381	qtnf_pcie_init_irq(pcie_priv, use_msi);382	pcie_priv->sysctl_bar = sysctl_bar;383	pcie_priv->dmareg_bar = dmareg_bar;384	pcie_priv->epmem_bar = epmem_bar;385	pci_save_state(pdev);386 387	ret = pcie_priv->probe_cb(bus, tx_bd_size_param, rx_bd_size_param);388	if (ret)389		goto error_free;390 391	qtnf_pcie_bringup_fw_async(bus);392	return 0;393 394error_free:395	free_netdev(bus->mux_dev);396error:397	destroy_workqueue(pcie_priv->workqueue);398	pci_set_drvdata(pdev, NULL);399	return ret;400}401 402static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_bus_priv *priv)403{404	qtnf_shm_ipc_free(&priv->shm_ipc_ep_in);405	qtnf_shm_ipc_free(&priv->shm_ipc_ep_out);406}407 408static void qtnf_pcie_remove(struct pci_dev *dev)409{410	struct qtnf_pcie_bus_priv *priv;411	struct qtnf_bus *bus;412 413	bus = pci_get_drvdata(dev);414	if (!bus)415		return;416 417	priv = get_bus_priv(bus);418 419	cancel_work_sync(&bus->fw_work);420 421	if (qtnf_fw_is_attached(bus))422		qtnf_core_detach(bus);423 424	netif_napi_del(&bus->mux_napi);425	destroy_workqueue(priv->workqueue);426	tasklet_kill(&priv->reclaim_tq);427	free_netdev(bus->mux_dev);428 429	qtnf_pcie_free_shm_ipc(priv);430	qtnf_debugfs_remove(bus);431	priv->remove_cb(bus);432	pci_set_drvdata(priv->pdev, NULL);433}434 435#ifdef CONFIG_PM_SLEEP436static int qtnf_pcie_suspend(struct device *dev)437{438	struct qtnf_pcie_bus_priv *priv;439	struct qtnf_bus *bus;440 441	bus = dev_get_drvdata(dev);442	if (!bus)443		return -EFAULT;444 445	priv = get_bus_priv(bus);446	return priv->suspend_cb(bus);447}448 449static int qtnf_pcie_resume(struct device *dev)450{451	struct qtnf_pcie_bus_priv *priv;452	struct qtnf_bus *bus;453 454	bus = dev_get_drvdata(dev);455	if (!bus)456		return -EFAULT;457 458	priv = get_bus_priv(bus);459	return priv->resume_cb(bus);460}461 462/* Power Management Hooks */463static SIMPLE_DEV_PM_OPS(qtnf_pcie_pm_ops, qtnf_pcie_suspend,464			 qtnf_pcie_resume);465#endif466 467static const struct pci_device_id qtnf_pcie_devid_table[] = {468	{469		PCIE_VENDOR_ID_QUANTENNA, PCIE_DEVICE_ID_QSR,470		PCI_ANY_ID, PCI_ANY_ID, 0, 0,471	},472	{ },473};474 475MODULE_DEVICE_TABLE(pci, qtnf_pcie_devid_table);476 477static struct pci_driver qtnf_pcie_drv_data = {478	.name = DRV_NAME,479	.id_table = qtnf_pcie_devid_table,480	.probe = qtnf_pcie_probe,481	.remove = qtnf_pcie_remove,482#ifdef CONFIG_PM_SLEEP483	.driver = {484		.pm = &qtnf_pcie_pm_ops,485	},486#endif487};488 489module_pci_driver(qtnf_pcie_drv_data)490 491MODULE_AUTHOR("Quantenna Communications");492MODULE_DESCRIPTION("Quantenna PCIe bus driver for 802.11 wireless LAN.");493MODULE_LICENSE("GPL");494