Commit e7ac4ea0 authored by David S. Miller's avatar David S. Miller

Merge branch 'ionic-Add-ionic-driver'

Shannon Nelson says:

====================
ionic: Add ionic driver

This is a patch series that adds the ionic driver, supporting the Pensando
ethernet device.

In this initial patchset we implement basic transmit and receive.  Later
patchsets will add more advanced features.

Our thanks to Saeed Mahameed, David Miller, Andrew Lunn, Michal Kubecek,
Jacub Kicinski, Jiri Pirko, Yunsheng Lin, and the ever present kbuild
test robots for their comments and suggestions.

New in v7:
 - stop Tx queue if no descriptor space left after a Tx
 - return ETIMEDOUT if the module data can't be copied out safely
 - remove unnecessary synchronize_irq() before free_irq()
 - use eth_prepare_mac_addr_change() and eth_commit_mac_addr_change() helpers
 - propagate error out of ionic_dl_info_get()

New in v6:
 - added a new patch with devlink info tags for ASIC and general FW
 - use the new devlink info tags in the driver
 - fixed up TxRx cleanup on setup failure
 - allow for possible 0 address from dma mapping of Tx buffers
 - remove a few more unnecessary debugfs error checks
 - use innocuous hardcoded strings in the identify message
 - removed a couple of unused functions and definitions
 - fix a leak in the error handling of port_info setup
 - changed from BUILD_BUG_ON() to static_assert()

New in v5:
 - code reorganized for more sane layout, with a side benefit of getting
   rid of a "defined but not used" complaint after patch 5
 - added "ionic_" prefix to struct definitions and fixed up remaining
   reverse christmas tree formatting (I think I got them all...)
 - ndo_open and ndo_stop reworked for better error recovery
 - interrupt coalescing enabled at driver start
 - unnecessary log messaging removed from events
 - double copy added in the module prom read to assure a clean copy
 - added BQL counting
 - fixed a TSO unmap issue found in testing
 - generalize a bit-flag wait with timeout
 - added devlink into earlier code and dropped patch 19

New in v4:
 - use devlink struct alloc for ionic device specific struct
 - add support for devlink_port
 - fixup devlink fixed vs running version usage
 - use bitmap_copy() instead of memcpy() for link_ksettings
 - don't bother to zero out the advertising bits before copying
   in the support bits
 - drop unknown xcvr types (will be expanded on later)
 - flap the connection to force auto-negotiation
 - use is_power_of_2() rather than open code
 - simplify set/get_pauseparam use of pause->autoneg
 - add a couple comments about NIC status data updated in DMA spaces

New in v3:
 - use le32_to_cpu() on queue_count[] values in debugfs
 - dma_free_coherent() can handle NULL pointers
 - remove unused SS_TEST from ethtool handlers
 - one more case of stop the tx ring if there is no room
 - remove a couple of stray // comments

New in v2:
 - removed debugfs error checking and cut down on debugfs use
 - remove redundant bounds checking on incoming values for mtu and ethtool
 - don't alloc rx_filter memory until the match type has been checked
 - free the ionic struct on remove
 - simplified link_up and netif_carrier_ok comparison
 - put stats into ethtool -S, out of debugfs
 - moved dev_cmd and dev_info dumping to ethtool -d, out of debugfs
 - added devlink support
 - used kernel's rss init routines rather than open code
 - set the Kbuild dependant on 64BIT
 - cut down on some unnecessary log messaging
 - cleaned up ionic_get_link_ksettings
 - cleaned up other little code bits here and there
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 0d622143 8c15440b
......@@ -23,6 +23,7 @@ Contents:
intel/ice
google/gve
mellanox/mlx5
pensando/ionic
.. only:: subproject
......
.. SPDX-License-Identifier: GPL-2.0+
==========================================================
Linux* Driver for the Pensando(R) Ethernet adapter family
==========================================================
Pensando Linux Ethernet driver.
Copyright(c) 2019 Pensando Systems, Inc
Contents
========
- Identifying the Adapter
- Support
Identifying the Adapter
=======================
To find if one or more Pensando PCI Ethernet devices are installed on the
host, check for the PCI devices::
$ lspci -d 1dd8:
b5:00.0 Ethernet controller: Device 1dd8:1002
b6:00.0 Ethernet controller: Device 1dd8:1002
If such devices are listed as above, then the ionic.ko driver should find
and configure them for use. There should be log entries in the kernel
messages such as these::
$ dmesg | grep ionic
ionic Pensando Ethernet NIC Driver, ver 0.15.0-k
ionic 0000:b5:00.0 enp181s0: renamed from eth0
ionic 0000:b6:00.0 enp182s0: renamed from eth0
Support
=======
For general Linux networking support, please use the netdev mailing
list, which is monitored by Pensando personnel::
netdev@vger.kernel.org
For more specific support needs, please use the Pensando driver support
email::
drivers@pensando.io
......@@ -14,11 +14,27 @@ board.rev
Board design revision.
asic.id
=======
ASIC design identifier.
asic.rev
========
ASIC design revision.
board.manufacture
=================
An identifier of the company or the facility which produced the part.
fw
==
Overall firmware version, often representing the collection of
fw.mgmt, fw.app, etc.
fw.mgmt
=======
......
......@@ -12608,6 +12608,14 @@ L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/peaq-wmi.c
PENSANDO ETHERNET DRIVERS
M: Shannon Nelson <snelson@pensando.io>
M: Pensando Drivers <drivers@pensando.io>
L: netdev@vger.kernel.org
S: Supported
F: Documentation/networking/device_drivers/pensando/ionic.rst
F: drivers/net/ethernet/pensando/
PER-CPU MEMORY ALLOCATOR
M: Dennis Zhou <dennis@kernel.org>
M: Tejun Heo <tj@kernel.org>
......
......@@ -168,6 +168,7 @@ config ETHOC
source "drivers/net/ethernet/packetengines/Kconfig"
source "drivers/net/ethernet/pasemi/Kconfig"
source "drivers/net/ethernet/pensando/Kconfig"
source "drivers/net/ethernet/qlogic/Kconfig"
source "drivers/net/ethernet/qualcomm/Kconfig"
source "drivers/net/ethernet/rdc/Kconfig"
......
......@@ -97,3 +97,4 @@ obj-$(CONFIG_NET_VENDOR_WIZNET) += wiznet/
obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/
obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/
obj-$(CONFIG_NET_VENDOR_PENSANDO) += pensando/
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2019 Pensando Systems, Inc
#
# Pensando device configuration
#
config NET_VENDOR_PENSANDO
bool "Pensando devices"
default y
help
If you have a network (Ethernet) card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about Pensando cards. If you say Y, you will be asked
for your specific card in the following questions.
if NET_VENDOR_PENSANDO
config IONIC
tristate "Pensando Ethernet IONIC Support"
depends on 64BIT && PCI
help
This enables the support for the Pensando family of Ethernet
adapters. More specific information on this driver can be
found in
<file:Documentation/networking/device_drivers/pensando/ionic.rst>.
To compile this driver as a module, choose M here. The module
will be called ionic.
endif # NET_VENDOR_PENSANDO
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the Pensando network device drivers.
#
obj-$(CONFIG_IONIC) += ionic/
# SPDX-License-Identifier: GPL-2.0
# Copyright(c) 2017 - 2019 Pensando Systems, Inc
obj-$(CONFIG_IONIC) := ionic.o
ionic-y := ionic_main.o ionic_bus_pci.o ionic_devlink.o ionic_dev.o \
ionic_debugfs.o ionic_lif.o ionic_rx_filter.o ionic_ethtool.o \
ionic_txrx.o ionic_stats.o
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
#ifndef _IONIC_H_
#define _IONIC_H_
struct ionic_lif;
#include "ionic_if.h"
#include "ionic_dev.h"
#include "ionic_devlink.h"
#define IONIC_DRV_NAME "ionic"
#define IONIC_DRV_DESCRIPTION "Pensando Ethernet NIC Driver"
#define IONIC_DRV_VERSION "0.15.0-k"
#define PCI_VENDOR_ID_PENSANDO 0x1dd8
#define PCI_DEVICE_ID_PENSANDO_IONIC_ETH_PF 0x1002
#define PCI_DEVICE_ID_PENSANDO_IONIC_ETH_VF 0x1003
#define IONIC_SUBDEV_ID_NAPLES_25 0x4000
#define IONIC_SUBDEV_ID_NAPLES_100_4 0x4001
#define IONIC_SUBDEV_ID_NAPLES_100_8 0x4002
#define DEVCMD_TIMEOUT 10
struct ionic {
struct pci_dev *pdev;
struct device *dev;
struct devlink_port dl_port;
struct ionic_dev idev;
struct mutex dev_cmd_lock; /* lock for dev_cmd operations */
struct dentry *dentry;
struct ionic_dev_bar bars[IONIC_BARS_MAX];
unsigned int num_bars;
struct ionic_identity ident;
struct list_head lifs;
struct ionic_lif *master_lif;
unsigned int nnqs_per_lif;
unsigned int neqs_per_lif;
unsigned int ntxqs_per_lif;
unsigned int nrxqs_per_lif;
DECLARE_BITMAP(lifbits, IONIC_LIFS_MAX);
unsigned int nintrs;
DECLARE_BITMAP(intrs, IONIC_INTR_CTRL_REGS_MAX);
struct work_struct nb_work;
struct notifier_block nb;
};
struct ionic_admin_ctx {
struct completion work;
union ionic_adminq_cmd cmd;
union ionic_adminq_comp comp;
};
int ionic_napi(struct napi_struct *napi, int budget, ionic_cq_cb cb,
ionic_cq_done_cb done_cb, void *done_arg);
int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx);
int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_wait);
int ionic_set_dma_mask(struct ionic *ionic);
int ionic_setup(struct ionic *ionic);
int ionic_identify(struct ionic *ionic);
int ionic_init(struct ionic *ionic);
int ionic_reset(struct ionic *ionic);
int ionic_port_identify(struct ionic *ionic);
int ionic_port_init(struct ionic *ionic);
int ionic_port_reset(struct ionic *ionic);
#endif /* _IONIC_H_ */
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
#ifndef _IONIC_BUS_H_
#define _IONIC_BUS_H_
int ionic_bus_get_irq(struct ionic *ionic, unsigned int num);
const char *ionic_bus_info(struct ionic *ionic);
int ionic_bus_alloc_irq_vectors(struct ionic *ionic, unsigned int nintrs);
void ionic_bus_free_irq_vectors(struct ionic *ionic);
int ionic_bus_register_driver(void);
void ionic_bus_unregister_driver(void);
void __iomem *ionic_bus_map_dbpage(struct ionic *ionic, int page_num);
void ionic_bus_unmap_dbpage(struct ionic *ionic, void __iomem *page);
#endif /* _IONIC_BUS_H_ */
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/pci.h>
#include "ionic.h"
#include "ionic_bus.h"
#include "ionic_lif.h"
#include "ionic_debugfs.h"
/* Supported devices */
static const struct pci_device_id ionic_id_table[] = {
{ PCI_VDEVICE(PENSANDO, PCI_DEVICE_ID_PENSANDO_IONIC_ETH_PF) },
{ PCI_VDEVICE(PENSANDO, PCI_DEVICE_ID_PENSANDO_IONIC_ETH_VF) },
{ 0, } /* end of table */
};
MODULE_DEVICE_TABLE(pci, ionic_id_table);
int ionic_bus_get_irq(struct ionic *ionic, unsigned int num)
{
return pci_irq_vector(ionic->pdev, num);
}
const char *ionic_bus_info(struct ionic *ionic)
{
return pci_name(ionic->pdev);
}
int ionic_bus_alloc_irq_vectors(struct ionic *ionic, unsigned int nintrs)
{
return pci_alloc_irq_vectors(ionic->pdev, nintrs, nintrs,
PCI_IRQ_MSIX);
}
void ionic_bus_free_irq_vectors(struct ionic *ionic)
{
pci_free_irq_vectors(ionic->pdev);
}
static int ionic_map_bars(struct ionic *ionic)
{
struct pci_dev *pdev = ionic->pdev;
struct device *dev = ionic->dev;
struct ionic_dev_bar *bars;
unsigned int i, j;
bars = ionic->bars;
ionic->num_bars = 0;
for (i = 0, j = 0; i < IONIC_BARS_MAX; i++) {
if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
continue;
bars[j].len = pci_resource_len(pdev, i);
/* only map the whole bar 0 */
if (j > 0) {
bars[j].vaddr = NULL;
} else {
bars[j].vaddr = pci_iomap(pdev, i, bars[j].len);
if (!bars[j].vaddr) {
dev_err(dev,
"Cannot memory-map BAR %d, aborting\n",
i);
return -ENODEV;
}
}
bars[j].bus_addr = pci_resource_start(pdev, i);
bars[j].res_index = i;
ionic->num_bars++;
j++;
}
return 0;
}
static void ionic_unmap_bars(struct ionic *ionic)
{
struct ionic_dev_bar *bars = ionic->bars;
unsigned int i;
for (i = 0; i < IONIC_BARS_MAX; i++) {
if (bars[i].vaddr) {
iounmap(bars[i].vaddr);
bars[i].bus_addr = 0;
bars[i].vaddr = NULL;
bars[i].len = 0;
}
}
}
void __iomem *ionic_bus_map_dbpage(struct ionic *ionic, int page_num)
{
return pci_iomap_range(ionic->pdev,
ionic->bars[IONIC_PCI_BAR_DBELL].res_index,
(u64)page_num << PAGE_SHIFT, PAGE_SIZE);
}
void ionic_bus_unmap_dbpage(struct ionic *ionic, void __iomem *page)
{
iounmap(page);
}
static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct device *dev = &pdev->dev;
struct ionic *ionic;
int err;
ionic = ionic_devlink_alloc(dev);
if (!ionic)
return -ENOMEM;
ionic->pdev = pdev;
ionic->dev = dev;
pci_set_drvdata(pdev, ionic);
mutex_init(&ionic->dev_cmd_lock);
/* Query system for DMA addressing limitation for the device. */
err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(IONIC_ADDR_LEN));
if (err) {
dev_err(dev, "Unable to obtain 64-bit DMA for consistent allocations, aborting. err=%d\n",
err);
goto err_out_clear_drvdata;
}
ionic_debugfs_add_dev(ionic);
/* Setup PCI device */
err = pci_enable_device_mem(pdev);
if (err) {
dev_err(dev, "Cannot enable PCI device: %d, aborting\n", err);
goto err_out_debugfs_del_dev;
}
err = pci_request_regions(pdev, IONIC_DRV_NAME);
if (err) {
dev_err(dev, "Cannot request PCI regions: %d, aborting\n", err);
goto err_out_pci_disable_device;
}
pci_set_master(pdev);
err = ionic_map_bars(ionic);
if (err)
goto err_out_pci_clear_master;
/* Configure the device */
err = ionic_setup(ionic);
if (err) {
dev_err(dev, "Cannot setup device: %d, aborting\n", err);
goto err_out_unmap_bars;
}
err = ionic_identify(ionic);
if (err) {
dev_err(dev, "Cannot identify device: %d, aborting\n", err);
goto err_out_teardown;
}
err = ionic_init(ionic);
if (err) {
dev_err(dev, "Cannot init device: %d, aborting\n", err);
goto err_out_teardown;
}
/* Configure the ports */
err = ionic_port_identify(ionic);
if (err) {
dev_err(dev, "Cannot identify port: %d, aborting\n", err);
goto err_out_reset;
}
err = ionic_port_init(ionic);
if (err) {
dev_err(dev, "Cannot init port: %d, aborting\n", err);
goto err_out_reset;
}
/* Configure LIFs */
err = ionic_lif_identify(ionic, IONIC_LIF_TYPE_CLASSIC,
&ionic->ident.lif);
if (err) {
dev_err(dev, "Cannot identify LIFs: %d, aborting\n", err);
goto err_out_port_reset;
}
err = ionic_lifs_size(ionic);
if (err) {
dev_err(dev, "Cannot size LIFs: %d, aborting\n", err);
goto err_out_port_reset;
}
err = ionic_lifs_alloc(ionic);
if (err) {
dev_err(dev, "Cannot allocate LIFs: %d, aborting\n", err);
goto err_out_free_irqs;
}
err = ionic_lifs_init(ionic);
if (err) {
dev_err(dev, "Cannot init LIFs: %d, aborting\n", err);
goto err_out_free_lifs;
}
err = ionic_lifs_register(ionic);
if (err) {
dev_err(dev, "Cannot register LIFs: %d, aborting\n", err);
goto err_out_deinit_lifs;
}
err = ionic_devlink_register(ionic);
if (err) {
dev_err(dev, "Cannot register devlink: %d\n", err);
goto err_out_deregister_lifs;
}
return 0;
err_out_deregister_lifs:
ionic_lifs_unregister(ionic);
err_out_deinit_lifs:
ionic_lifs_deinit(ionic);
err_out_free_lifs:
ionic_lifs_free(ionic);
err_out_free_irqs:
ionic_bus_free_irq_vectors(ionic);
err_out_port_reset:
ionic_port_reset(ionic);
err_out_reset:
ionic_reset(ionic);
err_out_teardown:
ionic_dev_teardown(ionic);
err_out_unmap_bars:
ionic_unmap_bars(ionic);
pci_release_regions(pdev);
err_out_pci_clear_master:
pci_clear_master(pdev);
err_out_pci_disable_device:
pci_disable_device(pdev);
err_out_debugfs_del_dev:
ionic_debugfs_del_dev(ionic);
err_out_clear_drvdata:
mutex_destroy(&ionic->dev_cmd_lock);
ionic_devlink_free(ionic);
return err;
}
static void ionic_remove(struct pci_dev *pdev)
{
struct ionic *ionic = pci_get_drvdata(pdev);
if (!ionic)
return;
ionic_devlink_unregister(ionic);
ionic_lifs_unregister(ionic);
ionic_lifs_deinit(ionic);
ionic_lifs_free(ionic);
ionic_bus_free_irq_vectors(ionic);
ionic_port_reset(ionic);
ionic_reset(ionic);
ionic_dev_teardown(ionic);
ionic_unmap_bars(ionic);
pci_release_regions(pdev);
pci_clear_master(pdev);
pci_disable_device(pdev);
ionic_debugfs_del_dev(ionic);
mutex_destroy(&ionic->dev_cmd_lock);
ionic_devlink_free(ionic);
}
static struct pci_driver ionic_driver = {
.name = IONIC_DRV_NAME,
.id_table = ionic_id_table,
.probe = ionic_probe,
.remove = ionic_remove,
};
int ionic_bus_register_driver(void)
{
return pci_register_driver(&ionic_driver);
}
void ionic_bus_unregister_driver(void)
{
pci_unregister_driver(&ionic_driver);
}
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
#include <linux/pci.h>
#include <linux/netdevice.h>
#include "ionic.h"
#include "ionic_bus.h"
#include "ionic_lif.h"
#include "ionic_debugfs.h"
#ifdef CONFIG_DEBUG_FS
static struct dentry *ionic_dir;
void ionic_debugfs_create(void)
{
ionic_dir = debugfs_create_dir(IONIC_DRV_NAME, NULL);
}
void ionic_debugfs_destroy(void)
{
debugfs_remove_recursive(ionic_dir);
}
void ionic_debugfs_add_dev(struct ionic *ionic)
{
ionic->dentry = debugfs_create_dir(ionic_bus_info(ionic), ionic_dir);
}
void ionic_debugfs_del_dev(struct ionic *ionic)
{
debugfs_remove_recursive(ionic->dentry);
ionic->dentry = NULL;
}
static int identity_show(struct seq_file *seq, void *v)
{
struct ionic *ionic = seq->private;
struct ionic_identity *ident;
ident = &ionic->ident;
seq_printf(seq, "nlifs: %d\n", ident->dev.nlifs);
seq_printf(seq, "nintrs: %d\n", ident->dev.nintrs);
seq_printf(seq, "ndbpgs_per_lif: %d\n", ident->dev.ndbpgs_per_lif);
seq_printf(seq, "intr_coal_mult: %d\n", ident->dev.intr_coal_mult);
seq_printf(seq, "intr_coal_div: %d\n", ident->dev.intr_coal_div);
seq_printf(seq, "max_ucast_filters: %d\n", ident->lif.eth.max_ucast_filters);
seq_printf(seq, "max_mcast_filters: %d\n", ident->lif.eth.max_mcast_filters);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(identity);
void ionic_debugfs_add_ident(struct ionic *ionic)
{
debugfs_create_file("identity", 0400, ionic->dentry,
ionic, &identity_fops) ? 0 : -EOPNOTSUPP;
}
void ionic_debugfs_add_sizes(struct ionic *ionic)
{
debugfs_create_u32("nlifs", 0400, ionic->dentry,
(u32 *)&ionic->ident.dev.nlifs);
debugfs_create_u32("nintrs", 0400, ionic->dentry, &ionic->nintrs);
debugfs_create_u32("ntxqs_per_lif", 0400, ionic->dentry,
(u32 *)&ionic->ident.lif.eth.config.queue_count[IONIC_QTYPE_TXQ]);
debugfs_create_u32("nrxqs_per_lif", 0400, ionic->dentry,
(u32 *)&ionic->ident.lif.eth.config.queue_count[IONIC_QTYPE_RXQ]);
}
static int q_tail_show(struct seq_file *seq, void *v)
{
struct ionic_queue *q = seq->private;
seq_printf(seq, "%d\n", q->tail->index);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(q_tail);
static int q_head_show(struct seq_file *seq, void *v)
{
struct ionic_queue *q = seq->private;
seq_printf(seq, "%d\n", q->head->index);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(q_head);
static int cq_tail_show(struct seq_file *seq, void *v)
{
struct ionic_cq *cq = seq->private;
seq_printf(seq, "%d\n", cq->tail->index);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(cq_tail);
static const struct debugfs_reg32 intr_ctrl_regs[] = {
{ .name = "coal_init", .offset = 0, },
{ .name = "mask", .offset = 4, },
{ .name = "credits", .offset = 8, },
{ .name = "mask_on_assert", .offset = 12, },
{ .name = "coal_timer", .offset = 16, },
};
void ionic_debugfs_add_qcq(struct ionic_lif *lif, struct ionic_qcq *qcq)
{
struct dentry *q_dentry, *cq_dentry, *intr_dentry, *stats_dentry;
struct ionic_dev *idev = &lif->ionic->idev;
struct debugfs_regset32 *intr_ctrl_regset;
struct ionic_intr_info *intr = &qcq->intr;
struct debugfs_blob_wrapper *desc_blob;
struct device *dev = lif->ionic->dev;
struct ionic_queue *q = &qcq->q;
struct ionic_cq *cq = &qcq->cq;
qcq->dentry = debugfs_create_dir(q->name, lif->dentry);
debugfs_create_x32("total_size", 0400, qcq->dentry, &qcq->total_size);
debugfs_create_x64("base_pa", 0400, qcq->dentry, &qcq->base_pa);
q_dentry = debugfs_create_dir("q", qcq->dentry);
debugfs_create_u32("index", 0400, q_dentry, &q->index);
debugfs_create_x64("base_pa", 0400, q_dentry, &q->base_pa);
if (qcq->flags & IONIC_QCQ_F_SG) {
debugfs_create_x64("sg_base_pa", 0400, q_dentry,
&q->sg_base_pa);
debugfs_create_u32("sg_desc_size", 0400, q_dentry,
&q->sg_desc_size);
}
debugfs_create_u32("num_descs", 0400, q_dentry, &q->num_descs);
debugfs_create_u32("desc_size", 0400, q_dentry, &q->desc_size);
debugfs_create_u32("pid", 0400, q_dentry, &q->pid);
debugfs_create_u32("qid", 0400, q_dentry, &q->hw_index);
debugfs_create_u32("qtype", 0400, q_dentry, &q->hw_type);
debugfs_create_u64("drop", 0400, q_dentry, &q->drop);
debugfs_create_u64("stop", 0400, q_dentry, &q->stop);
debugfs_create_u64("wake", 0400, q_dentry, &q->wake);
debugfs_create_file("tail", 0400, q_dentry, q, &q_tail_fops);
debugfs_create_file("head", 0400, q_dentry, q, &q_head_fops);
desc_blob = devm_kzalloc(dev, sizeof(*desc_blob), GFP_KERNEL);
if (!desc_blob)
return;
desc_blob->data = q->base;
desc_blob->size = (unsigned long)q->num_descs * q->desc_size;
debugfs_create_blob("desc_blob", 0400, q_dentry, desc_blob);
if (qcq->flags & IONIC_QCQ_F_SG) {
desc_blob = devm_kzalloc(dev, sizeof(*desc_blob), GFP_KERNEL);
if (!desc_blob)
return;
desc_blob->data = q->sg_base;
desc_blob->size = (unsigned long)q->num_descs * q->sg_desc_size;
debugfs_create_blob("sg_desc_blob", 0400, q_dentry,
desc_blob);
}
cq_dentry = debugfs_create_dir("cq", qcq->dentry);
debugfs_create_x64("base_pa", 0400, cq_dentry, &cq->base_pa);
debugfs_create_u32("num_descs", 0400, cq_dentry, &cq->num_descs);
debugfs_create_u32("desc_size", 0400, cq_dentry, &cq->desc_size);
debugfs_create_u8("done_color", 0400, cq_dentry,
(u8 *)&cq->done_color);
debugfs_create_file("tail", 0400, cq_dentry, cq, &cq_tail_fops);
desc_blob = devm_kzalloc(dev, sizeof(*desc_blob), GFP_KERNEL);
if (!desc_blob)
return;
desc_blob->data = cq->base;
desc_blob->size = (unsigned long)cq->num_descs * cq->desc_size;
debugfs_create_blob("desc_blob", 0400, cq_dentry, desc_blob);
if (qcq->flags & IONIC_QCQ_F_INTR) {
intr_dentry = debugfs_create_dir("intr", qcq->dentry);
debugfs_create_u32("index", 0400, intr_dentry,
&intr->index);
debugfs_create_u32("vector", 0400, intr_dentry,
&intr->vector);
intr_ctrl_regset = devm_kzalloc(dev, sizeof(*intr_ctrl_regset),
GFP_KERNEL);
if (!intr_ctrl_regset)
return;
intr_ctrl_regset->regs = intr_ctrl_regs;
intr_ctrl_regset->nregs = ARRAY_SIZE(intr_ctrl_regs);
intr_ctrl_regset->base = &idev->intr_ctrl[intr->index];
debugfs_create_regset32("intr_ctrl", 0400, intr_dentry,
intr_ctrl_regset);
}
if (qcq->flags & IONIC_QCQ_F_NOTIFYQ) {
stats_dentry = debugfs_create_dir("notifyblock", qcq->dentry);
debugfs_create_u64("eid", 0400, stats_dentry,
(u64 *)&lif->info->status.eid);
debugfs_create_u16("link_status", 0400, stats_dentry,
(u16 *)&lif->info->status.link_status);
debugfs_create_u32("link_speed", 0400, stats_dentry,
(u32 *)&lif->info->status.link_speed);
debugfs_create_u16("link_down_count", 0400, stats_dentry,
(u16 *)&lif->info->status.link_down_count);
}
}
static int netdev_show(struct seq_file *seq, void *v)
{
struct net_device *netdev = seq->private;
seq_printf(seq, "%s\n", netdev->name);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(netdev);
void ionic_debugfs_add_lif(struct ionic_lif *lif)
{
lif->dentry = debugfs_create_dir(lif->name, lif->ionic->dentry);
debugfs_create_file("netdev", 0400, lif->dentry,
lif->netdev, &netdev_fops);
}
void ionic_debugfs_del_lif(struct ionic_lif *lif)
{
debugfs_remove_recursive(lif->dentry);
lif->dentry = NULL;
}
void ionic_debugfs_del_qcq(struct ionic_qcq *qcq)
{
debugfs_remove_recursive(qcq->dentry);
qcq->dentry = NULL;
}
#endif
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
#ifndef _IONIC_DEBUGFS_H_
#define _IONIC_DEBUGFS_H_
#include <linux/debugfs.h>
#ifdef CONFIG_DEBUG_FS
void ionic_debugfs_create(void);
void ionic_debugfs_destroy(void);
void ionic_debugfs_add_dev(struct ionic *ionic);
void ionic_debugfs_del_dev(struct ionic *ionic);
void ionic_debugfs_add_ident(struct ionic *ionic);
void ionic_debugfs_add_sizes(struct ionic *ionic);
void ionic_debugfs_add_lif(struct ionic_lif *lif);
void ionic_debugfs_add_qcq(struct ionic_lif *lif, struct ionic_qcq *qcq);
void ionic_debugfs_del_lif(struct ionic_lif *lif);
void ionic_debugfs_del_qcq(struct ionic_qcq *qcq);
#else
static inline void ionic_debugfs_create(void) { }
static inline void ionic_debugfs_destroy(void) { }
static inline void ionic_debugfs_add_dev(struct ionic *ionic) { }
static inline void ionic_debugfs_del_dev(struct ionic *ionic) { }
static inline void ionic_debugfs_add_ident(struct ionic *ionic) { }
static inline void ionic_debugfs_add_sizes(struct ionic *ionic) { }
static inline void ionic_debugfs_add_lif(struct ionic_lif *lif) { }
static inline void ionic_debugfs_add_qcq(struct ionic_lif *lif, struct ionic_qcq *qcq) { }
static inline void ionic_debugfs_del_lif(struct ionic_lif *lif) { }
static inline void ionic_debugfs_del_qcq(struct ionic_qcq *qcq) { }
#endif
#endif /* _IONIC_DEBUGFS_H_ */
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
#ifndef _IONIC_DEV_H_
#define _IONIC_DEV_H_
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include "ionic_if.h"
#include "ionic_regs.h"
#define IONIC_MIN_MTU ETH_MIN_MTU
#define IONIC_MAX_MTU 9194
#define IONIC_MAX_TXRX_DESC 16384
#define IONIC_MIN_TXRX_DESC 16
#define IONIC_DEF_TXRX_DESC 4096
#define IONIC_LIFS_MAX 1024
#define IONIC_ITR_COAL_USEC_DEFAULT 64
#define IONIC_DEV_CMD_REG_VERSION 1
#define IONIC_DEV_INFO_REG_COUNT 32
#define IONIC_DEV_CMD_REG_COUNT 32
struct ionic_dev_bar {
void __iomem *vaddr;
phys_addr_t bus_addr;
unsigned long len;
int res_index;
};
/* Registers */
static_assert(sizeof(struct ionic_intr) == 32);
static_assert(sizeof(struct ionic_doorbell) == 8);
static_assert(sizeof(struct ionic_intr_status) == 8);
static_assert(sizeof(union ionic_dev_regs) == 4096);
static_assert(sizeof(union ionic_dev_info_regs) == 2048);
static_assert(sizeof(union ionic_dev_cmd_regs) == 2048);
static_assert(sizeof(struct ionic_lif_stats) == 1024);
static_assert(sizeof(struct ionic_admin_cmd) == 64);
static_assert(sizeof(struct ionic_admin_comp) == 16);
static_assert(sizeof(struct ionic_nop_cmd) == 64);
static_assert(sizeof(struct ionic_nop_comp) == 16);
/* Device commands */
static_assert(sizeof(struct ionic_dev_identify_cmd) == 64);
static_assert(sizeof(struct ionic_dev_identify_comp) == 16);
static_assert(sizeof(struct ionic_dev_init_cmd) == 64);
static_assert(sizeof(struct ionic_dev_init_comp) == 16);
static_assert(sizeof(struct ionic_dev_reset_cmd) == 64);
static_assert(sizeof(struct ionic_dev_reset_comp) == 16);
static_assert(sizeof(struct ionic_dev_getattr_cmd) == 64);
static_assert(sizeof(struct ionic_dev_getattr_comp) == 16);
static_assert(sizeof(struct ionic_dev_setattr_cmd) == 64);
static_assert(sizeof(struct ionic_dev_setattr_comp) == 16);
/* Port commands */
static_assert(sizeof(struct ionic_port_identify_cmd) == 64);
static_assert(sizeof(struct ionic_port_identify_comp) == 16);
static_assert(sizeof(struct ionic_port_init_cmd) == 64);
static_assert(sizeof(struct ionic_port_init_comp) == 16);
static_assert(sizeof(struct ionic_port_reset_cmd) == 64);
static_assert(sizeof(struct ionic_port_reset_comp) == 16);
static_assert(sizeof(struct ionic_port_getattr_cmd) == 64);
static_assert(sizeof(struct ionic_port_getattr_comp) == 16);
static_assert(sizeof(struct ionic_port_setattr_cmd) == 64);
static_assert(sizeof(struct ionic_port_setattr_comp) == 16);
/* LIF commands */
static_assert(sizeof(struct ionic_lif_init_cmd) == 64);
static_assert(sizeof(struct ionic_lif_init_comp) == 16);
static_assert(sizeof(struct ionic_lif_reset_cmd) == 64);
static_assert(sizeof(ionic_lif_reset_comp) == 16);
static_assert(sizeof(struct ionic_lif_getattr_cmd) == 64);
static_assert(sizeof(struct ionic_lif_getattr_comp) == 16);
static_assert(sizeof(struct ionic_lif_setattr_cmd) == 64);
static_assert(sizeof(struct ionic_lif_setattr_comp) == 16);
static_assert(sizeof(struct ionic_q_init_cmd) == 64);
static_assert(sizeof(struct ionic_q_init_comp) == 16);
static_assert(sizeof(struct ionic_q_control_cmd) == 64);
static_assert(sizeof(ionic_q_control_comp) == 16);
static_assert(sizeof(struct ionic_rx_mode_set_cmd) == 64);
static_assert(sizeof(ionic_rx_mode_set_comp) == 16);
static_assert(sizeof(struct ionic_rx_filter_add_cmd) == 64);
static_assert(sizeof(struct ionic_rx_filter_add_comp) == 16);
static_assert(sizeof(struct ionic_rx_filter_del_cmd) == 64);
static_assert(sizeof(ionic_rx_filter_del_comp) == 16);
/* RDMA commands */
static_assert(sizeof(struct ionic_rdma_reset_cmd) == 64);
static_assert(sizeof(struct ionic_rdma_queue_cmd) == 64);
/* Events */
static_assert(sizeof(struct ionic_notifyq_cmd) == 4);
static_assert(sizeof(union ionic_notifyq_comp) == 64);
static_assert(sizeof(struct ionic_notifyq_event) == 64);
static_assert(sizeof(struct ionic_link_change_event) == 64);
static_assert(sizeof(struct ionic_reset_event) == 64);
static_assert(sizeof(struct ionic_heartbeat_event) == 64);
static_assert(sizeof(struct ionic_log_event) == 64);
/* I/O */
static_assert(sizeof(struct ionic_txq_desc) == 16);
static_assert(sizeof(struct ionic_txq_sg_desc) == 128);
static_assert(sizeof(struct ionic_txq_comp) == 16);
static_assert(sizeof(struct ionic_rxq_desc) == 16);
static_assert(sizeof(struct ionic_rxq_sg_desc) == 128);
static_assert(sizeof(struct ionic_rxq_comp) == 16);
struct ionic_devinfo {
u8 asic_type;
u8 asic_rev;
char fw_version[IONIC_DEVINFO_FWVERS_BUFLEN + 1];
char serial_num[IONIC_DEVINFO_SERIAL_BUFLEN + 1];
};
struct ionic_dev {
union ionic_dev_info_regs __iomem *dev_info_regs;
union ionic_dev_cmd_regs __iomem *dev_cmd_regs;
u64 __iomem *db_pages;
dma_addr_t phy_db_pages;
struct ionic_intr __iomem *intr_ctrl;
u64 __iomem *intr_status;
u32 port_info_sz;
struct ionic_port_info *port_info;
dma_addr_t port_info_pa;
struct ionic_devinfo dev_info;
};
struct ionic_cq_info {
void *cq_desc;
struct ionic_cq_info *next;
unsigned int index;
bool last;
};
struct ionic_queue;
struct ionic_qcq;
struct ionic_desc_info;
typedef void (*ionic_desc_cb)(struct ionic_queue *q,
struct ionic_desc_info *desc_info,
struct ionic_cq_info *cq_info, void *cb_arg);
struct ionic_desc_info {
void *desc;
void *sg_desc;
struct ionic_desc_info *next;
unsigned int index;
unsigned int left;
ionic_desc_cb cb;
void *cb_arg;
};
#define QUEUE_NAME_MAX_SZ 32
struct ionic_queue {
u64 dbell_count;
u64 drop;
u64 stop;
u64 wake;
struct ionic_lif *lif;
struct ionic_desc_info *info;
struct ionic_desc_info *tail;
struct ionic_desc_info *head;
struct ionic_dev *idev;
unsigned int index;
unsigned int type;
unsigned int hw_index;
unsigned int hw_type;
u64 dbval;
void *base;
void *sg_base;
dma_addr_t base_pa;
dma_addr_t sg_base_pa;
unsigned int num_descs;
unsigned int desc_size;
unsigned int sg_desc_size;
unsigned int pid;
char name[QUEUE_NAME_MAX_SZ];
};
#define INTR_INDEX_NOT_ASSIGNED -1
#define INTR_NAME_MAX_SZ 32
struct ionic_intr_info {
char name[INTR_NAME_MAX_SZ];
unsigned int index;
unsigned int vector;
u64 rearm_count;
unsigned int cpu;
cpumask_t affinity_mask;
};
struct ionic_cq {
void *base;
dma_addr_t base_pa;
struct ionic_lif *lif;
struct ionic_cq_info *info;
struct ionic_cq_info *tail;
struct ionic_queue *bound_q;
struct ionic_intr_info *bound_intr;
bool done_color;
unsigned int num_descs;
u64 compl_count;
unsigned int desc_size;
};
struct ionic;
static inline void ionic_intr_init(struct ionic_dev *idev,
struct ionic_intr_info *intr,
unsigned long index)
{
ionic_intr_clean(idev->intr_ctrl, index);
intr->index = index;
}
static inline unsigned int ionic_q_space_avail(struct ionic_queue *q)
{
unsigned int avail = q->tail->index;
if (q->head->index >= avail)
avail += q->head->left - 1;
else
avail -= q->head->index + 1;
return avail;
}
static inline bool ionic_q_has_space(struct ionic_queue *q, unsigned int want)
{
return ionic_q_space_avail(q) >= want;
}
void ionic_init_devinfo(struct ionic *ionic);
int ionic_dev_setup(struct ionic *ionic);
void ionic_dev_teardown(struct ionic *ionic);
void ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd);
u8 ionic_dev_cmd_status(struct ionic_dev *idev);
bool ionic_dev_cmd_done(struct ionic_dev *idev);
void ionic_dev_cmd_comp(struct ionic_dev *idev, union ionic_dev_cmd_comp *comp);
void ionic_dev_cmd_identify(struct ionic_dev *idev, u8 ver);
void ionic_dev_cmd_init(struct ionic_dev *idev);
void ionic_dev_cmd_reset(struct ionic_dev *idev);
void ionic_dev_cmd_port_identify(struct ionic_dev *idev);
void ionic_dev_cmd_port_init(struct ionic_dev *idev);
void ionic_dev_cmd_port_reset(struct ionic_dev *idev);
void ionic_dev_cmd_port_state(struct ionic_dev *idev, u8 state);
void ionic_dev_cmd_port_speed(struct ionic_dev *idev, u32 speed);
void ionic_dev_cmd_port_autoneg(struct ionic_dev *idev, u8 an_enable);
void ionic_dev_cmd_port_fec(struct ionic_dev *idev, u8 fec_type);
void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type);
void ionic_dev_cmd_lif_identify(struct ionic_dev *idev, u8 type, u8 ver);
void ionic_dev_cmd_lif_init(struct ionic_dev *idev, u16 lif_index,
dma_addr_t addr);
void ionic_dev_cmd_lif_reset(struct ionic_dev *idev, u16 lif_index);
void ionic_dev_cmd_adminq_init(struct ionic_dev *idev, struct ionic_qcq *qcq,
u16 lif_index, u16 intr_index);
int ionic_db_page_num(struct ionic_lif *lif, int pid);
int ionic_cq_init(struct ionic_lif *lif, struct ionic_cq *cq,
struct ionic_intr_info *intr,
unsigned int num_descs, size_t desc_size);
void ionic_cq_map(struct ionic_cq *cq, void *base, dma_addr_t base_pa);
void ionic_cq_bind(struct ionic_cq *cq, struct ionic_queue *q);
typedef bool (*ionic_cq_cb)(struct ionic_cq *cq, struct ionic_cq_info *cq_info);
typedef void (*ionic_cq_done_cb)(void *done_arg);
unsigned int ionic_cq_service(struct ionic_cq *cq, unsigned int work_to_do,
ionic_cq_cb cb, ionic_cq_done_cb done_cb,
void *done_arg);
int ionic_q_init(struct ionic_lif *lif, struct ionic_dev *idev,
struct ionic_queue *q, unsigned int index, const char *name,
unsigned int num_descs, size_t desc_size,
size_t sg_desc_size, unsigned int pid);
void ionic_q_map(struct ionic_queue *q, void *base, dma_addr_t base_pa);
void ionic_q_sg_map(struct ionic_queue *q, void *base, dma_addr_t base_pa);
void ionic_q_post(struct ionic_queue *q, bool ring_doorbell, ionic_desc_cb cb,
void *cb_arg);
void ionic_q_rewind(struct ionic_queue *q, struct ionic_desc_info *start);
void ionic_q_service(struct ionic_queue *q, struct ionic_cq_info *cq_info,
unsigned int stop_index);
#endif /* _IONIC_DEV_H_ */
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
#include <linux/module.h>
#include <linux/netdevice.h>
#include "ionic.h"
#include "ionic_bus.h"
#include "ionic_lif.h"
#include "ionic_devlink.h"
static int ionic_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
struct netlink_ext_ack *extack)
{
struct ionic *ionic = devlink_priv(dl);
struct ionic_dev *idev = &ionic->idev;
char buf[16];
int err = 0;
err = devlink_info_driver_name_put(req, IONIC_DRV_NAME);
if (err)
goto info_out;
err = devlink_info_version_running_put(req,
DEVLINK_INFO_VERSION_GENERIC_FW,
idev->dev_info.fw_version);
if (err)
goto info_out;
snprintf(buf, sizeof(buf), "0x%x", idev->dev_info.asic_type);
err = devlink_info_version_fixed_put(req,
DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
buf);
if (err)
goto info_out;
snprintf(buf, sizeof(buf), "0x%x", idev->dev_info.asic_rev);
err = devlink_info_version_fixed_put(req,
DEVLINK_INFO_VERSION_GENERIC_ASIC_REV,
buf);
if (err)
goto info_out;
err = devlink_info_serial_number_put(req, idev->dev_info.serial_num);
info_out:
return err;
}
static const struct devlink_ops ionic_dl_ops = {
.info_get = ionic_dl_info_get,
};
struct ionic *ionic_devlink_alloc(struct device *dev)
{
struct devlink *dl;
dl = devlink_alloc(&ionic_dl_ops, sizeof(struct ionic));
return devlink_priv(dl);
}
void ionic_devlink_free(struct ionic *ionic)
{
struct devlink *dl = priv_to_devlink(ionic);
devlink_free(dl);
}
int ionic_devlink_register(struct ionic *ionic)
{
struct devlink *dl = priv_to_devlink(ionic);
int err;
err = devlink_register(dl, ionic->dev);
if (err) {
dev_warn(ionic->dev, "devlink_register failed: %d\n", err);
return err;
}
devlink_port_attrs_set(&ionic->dl_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
0, false, 0, NULL, 0);
err = devlink_port_register(dl, &ionic->dl_port, 0);
if (err)
dev_err(ionic->dev, "devlink_port_register failed: %d\n", err);
else
devlink_port_type_eth_set(&ionic->dl_port,
ionic->master_lif->netdev);
return err;
}
void ionic_devlink_unregister(struct ionic *ionic)
{
struct devlink *dl = priv_to_devlink(ionic);
devlink_port_unregister(&ionic->dl_port);
devlink_unregister(dl);
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
#ifndef _IONIC_DEVLINK_H_
#define _IONIC_DEVLINK_H_
#include <net/devlink.h>
struct ionic *ionic_devlink_alloc(struct device *dev);
void ionic_devlink_free(struct ionic *ionic);
int ionic_devlink_register(struct ionic *ionic);
void ionic_devlink_unregister(struct ionic *ionic);
#endif /* _IONIC_DEVLINK_H_ */
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
#ifndef _IONIC_ETHTOOL_H_
#define _IONIC_ETHTOOL_H_
void ionic_ethtool_set_ops(struct net_device *netdev);
#endif /* _IONIC_ETHTOOL_H_ */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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