DPDK-dev Archive on lore.kernel.org
 help / color / Atom feed
* [dpdk-dev] [PATCH 00/17] Series short description
@ 2019-10-12  0:26 Alfredo Cardigliano
  2019-10-12  0:26 ` [dpdk-dev] [PATCH 01/17] net/ionic: add skeleton Alfredo Cardigliano
                   ` (17 more replies)
  0 siblings, 18 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:26 UTC (permalink / raw)
  To: dev

The patch series provides an initial version of a
poll mode driver for Pensando network adapters.
The driver name is ionic.

---

Alfredo Cardigliano (17):
      net/ionic: add skeleton
      net/ionic: add hardware structures definitions
      net/ionic: add log
      net/ionic: register and initialize the adapter
      net/ionic: add port management commands
      net/ionic: add basic lif support
      net/ionic: add doorbells
      net/ionic: add adminq support
      net/ionic: add notifyq support
      net/ionic: add basic port operations
      net/ionic: add RX filters support
      net/ionic: net-ionic-add-flow-control-support
      net/ionic: add RSS support
      net/ionic: add RX and TX handling
      net/ionic: add stats
      net/ionic: add TX checksum support
      net/ionic: read fw version


 MAINTAINERS                                 |    6 
 config/common_base                          |    7 
 doc/guides/nics/features/ionic.ini          |   36 
 doc/guides/nics/index.rst                   |    1 
 doc/guides/nics/ionic.rst                   |   45 
 drivers/net/Makefile                        |    1 
 drivers/net/ionic/Makefile                  |   64 +
 drivers/net/ionic/ionic.h                   |   82 +
 drivers/net/ionic/ionic_dev.c               |  572 ++++++
 drivers/net/ionic/ionic_dev.h               |  281 +++
 drivers/net/ionic/ionic_ethdev.c            | 1335 ++++++++++++++
 drivers/net/ionic/ionic_ethdev.h            |   22 
 drivers/net/ionic/ionic_if.h                | 2491 +++++++++++++++++++++++++++
 drivers/net/ionic/ionic_lif.c               | 1713 +++++++++++++++++++
 drivers/net/ionic/ionic_lif.h               |  189 ++
 drivers/net/ionic/ionic_logs.h              |   46 
 drivers/net/ionic/ionic_mac_api.c           |   61 +
 drivers/net/ionic/ionic_mac_api.h           |   13 
 drivers/net/ionic/ionic_main.c              |  452 +++++
 drivers/net/ionic/ionic_osdep.h             |   81 +
 drivers/net/ionic/ionic_regs.h              |  142 ++
 drivers/net/ionic/ionic_rx_filter.c         |  140 ++
 drivers/net/ionic/ionic_rx_filter.h         |   47 +
 drivers/net/ionic/ionic_rxtx.c              | 1077 ++++++++++++
 drivers/net/ionic/ionic_rxtx.h              |   44 
 drivers/net/ionic/meson.build               |   15 
 drivers/net/ionic/rte_pmd_ionic_version.map |    5 
 mk/rte.app.mk                               |    1 
 28 files changed, 8969 insertions(+)
 create mode 100644 doc/guides/nics/features/ionic.ini
 create mode 100644 doc/guides/nics/ionic.rst
 create mode 100644 drivers/net/ionic/Makefile
 create mode 100644 drivers/net/ionic/ionic.h
 create mode 100644 drivers/net/ionic/ionic_dev.c
 create mode 100644 drivers/net/ionic/ionic_dev.h
 create mode 100644 drivers/net/ionic/ionic_ethdev.c
 create mode 100644 drivers/net/ionic/ionic_ethdev.h
 create mode 100644 drivers/net/ionic/ionic_if.h
 create mode 100644 drivers/net/ionic/ionic_lif.c
 create mode 100644 drivers/net/ionic/ionic_lif.h
 create mode 100644 drivers/net/ionic/ionic_logs.h
 create mode 100644 drivers/net/ionic/ionic_mac_api.c
 create mode 100644 drivers/net/ionic/ionic_mac_api.h
 create mode 100644 drivers/net/ionic/ionic_main.c
 create mode 100644 drivers/net/ionic/ionic_osdep.h
 create mode 100644 drivers/net/ionic/ionic_regs.h
 create mode 100644 drivers/net/ionic/ionic_rx_filter.c
 create mode 100644 drivers/net/ionic/ionic_rx_filter.h
 create mode 100644 drivers/net/ionic/ionic_rxtx.c
 create mode 100644 drivers/net/ionic/ionic_rxtx.h
 create mode 100644 drivers/net/ionic/meson.build
 create mode 100644 drivers/net/ionic/rte_pmd_ionic_version.map

--
Signature

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 01/17] net/ionic: add skeleton
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
@ 2019-10-12  0:26 ` Alfredo Cardigliano
  2019-10-12  0:26 ` [dpdk-dev] [PATCH 02/17] net/ionic: add hardware structures definitions Alfredo Cardigliano
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:26 UTC (permalink / raw)
  To: dev

Add makefile and config file options to compile the Pensando ionic PMD.
Add feature and version map file.
Update maintainers file.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 MAINTAINERS                                 |    6 +++
 config/common_base                          |    5 ++
 doc/guides/nics/features/ionic.ini          |    8 ++++
 doc/guides/nics/index.rst                   |    1 
 doc/guides/nics/ionic.rst                   |   45 +++++++++++++++++++++
 drivers/net/Makefile                        |    1 
 drivers/net/ionic/Makefile                  |   57 +++++++++++++++++++++++++++
 drivers/net/ionic/meson.build               |    8 ++++
 drivers/net/ionic/rte_pmd_ionic_version.map |    5 ++
 mk/rte.app.mk                               |    1 
 10 files changed, 137 insertions(+)
 create mode 100644 doc/guides/nics/features/ionic.ini
 create mode 100644 doc/guides/nics/ionic.rst
 create mode 100644 drivers/net/ionic/Makefile
 create mode 100644 drivers/net/ionic/meson.build
 create mode 100644 drivers/net/ionic/rte_pmd_ionic_version.map

diff --git a/MAINTAINERS b/MAINTAINERS
index 6adf20107..ff1fee06a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -787,6 +787,12 @@ F: drivers/net/enetc/
 F: doc/guides/nics/enetc.rst
 F: doc/guides/nics/features/enetc.ini
 
+Pensando ionic
+M: Alfredo Cardigliano <cardigliano@ntop.org>
+F: drivers/net/ionic/
+F: doc/guides/nics/ionic.rst
+F: doc/guides/nics/features/ionic.ini
+
 QLogic bnx2x
 M: Rasesh Mody <rmody@marvell.com>
 M: Shahed Shaikh <shshaikh@marvell.com>
diff --git a/config/common_base b/config/common_base
index 6a7e00d75..1c11fcae6 100644
--- a/config/common_base
+++ b/config/common_base
@@ -270,6 +270,11 @@ CONFIG_RTE_LIBRTE_E1000_DEBUG_TX=n
 CONFIG_RTE_LIBRTE_E1000_DEBUG_TX_FREE=n
 CONFIG_RTE_LIBRTE_E1000_PF_DISABLE_STRIP_CRC=n
 
+#
+# Compile Pensando IONIC PMD driver
+#
+CONFIG_RTE_LIBRTE_IONIC_PMD=y
+
 #
 # Compile burst-oriented HINIC PMD driver
 #
diff --git a/doc/guides/nics/features/ionic.ini b/doc/guides/nics/features/ionic.ini
new file mode 100644
index 000000000..3a92eedc7
--- /dev/null
+++ b/doc/guides/nics/features/ionic.ini
@@ -0,0 +1,8 @@
+;
+; Supported features of the 'ionic' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+x86-64               = Y
+Usage doc            = Y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index d477001d9..185457325 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -33,6 +33,7 @@ Network Interface Controller Drivers
     ice
     ifc
     igb
+    ionic
     ipn3ke
     ixgbe
     intel_vf
diff --git a/doc/guides/nics/ionic.rst b/doc/guides/nics/ionic.rst
new file mode 100644
index 000000000..aaf59981f
--- /dev/null
+++ b/doc/guides/nics/ionic.rst
@@ -0,0 +1,45 @@
+..  SPDX-License-Identifier: GPL-2.0
+    Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+
+IONIC Driver
+============
+
+The ionic driver provides support for Pensando server adapters.
+
+Identifying the Adapter
+-----------------------
+
+To find if one or more Pensando PCI Ethernet devices are installed 
+on the host, check for the PCI devices:
+
+   .. code-block:: console
+
+      lspci -d 1dd8:
+      b5:00.0 Ethernet controller: Device 1dd8:1002
+      b6:00.0 Ethernet controller: Device 1dd8:1002
+
+Pre-Installation Configuration
+------------------------------
+
+The following options can be modified in the ``config`` file.
+Please note that enabling debugging options may affect system performance.
+
+- ``CONFIG_RTE_LIBRTE_IONIC_PMD`` (default ``y``)
+
+  Toggle compilation of ionic PMD.
+
+- ``CONFIG_RTE_LIBRTE_IONIC_DEBUG_RX`` (default ``n``)
+
+  Toggle display of receive fast path run-time messages.
+
+- ``CONFIG_RTE_LIBRTE_IONIC_DEBUG_TX`` (default ``n``)
+
+  Toggle display of transmit fast path run-time messages.
+
+Building DPDK
+-------------
+
+The ionic PMD driver supports UIO and VFIO, please refer to the 
+:ref:`DPDK documentation that comes with the DPDK suite <linux_gsg>`
+for instructions on how to build DPDK. 
+
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 1770d8b23..cb7921c6f 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -34,6 +34,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3
 DIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e
 DIRS-$(CONFIG_RTE_LIBRTE_IAVF_PMD) += iavf
 DIRS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice
+DIRS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic
 DIRS-$(CONFIG_RTE_LIBRTE_IPN3KE_PMD) += ipn3ke
 DIRS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += ixgbe
 DIRS-$(CONFIG_RTE_LIBRTE_LIO_PMD) += liquidio
diff --git a/drivers/net/ionic/Makefile b/drivers/net/ionic/Makefile
new file mode 100644
index 000000000..3add24087
--- /dev/null
+++ b/drivers/net/ionic/Makefile
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_ionic.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_pmd_ionic_version.map
+
+LIBABIVER := 2
+
+ifeq ($(CONFIG_RTE_TOOLCHAIN_ICC),y)
+#
+# CFLAGS for icc
+#
+CFLAGS += -diag-disable 174 -diag-disable 593 -diag-disable 869
+CFLAGS += -diag-disable 981 -diag-disable 2259 -diag-disable 3656
+
+else ifeq ($(CONFIG_RTE_TOOLCHAIN_CLANG),y)
+#
+# CFLAGS for clang
+#
+CFLAGS += -Wno-unused-parameter -Wno-unused-value -Wno-strict-aliasing
+CFLAGS += -Wno-format-extra-args
+
+else
+#
+# CFLAGS for gcc
+#
+ifeq ($(shell test $(GCC_VERSION) -ge 44 && echo 1), 1)
+CFLAGS += -Wno-deprecated -Wno-unused-parameter -Wno-unused-value
+CFLAGS += -Wno-strict-aliasing -Wno-format-extra-args
+CFLAGS += -Wno-missing-field-initializers -Wno-pointer-arith
+endif
+
+ifeq ($(shell test $(GCC_VERSION) -ge 70 && echo 1), 1)
+CFLAGS += -Wno-implicit-fallthrough
+endif
+
+endif
+
+LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
+LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs -lrte_hash
+LDLIBS += -lrte_bus_pci
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) +=
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/ionic/meson.build b/drivers/net/ionic/meson.build
new file mode 100644
index 000000000..502076e3c
--- /dev/null
+++ b/drivers/net/ionic/meson.build
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2019 Pensando
+
+version = 1
+
+sources = files(
+)
+
diff --git a/drivers/net/ionic/rte_pmd_ionic_version.map b/drivers/net/ionic/rte_pmd_ionic_version.map
new file mode 100644
index 000000000..96f83bd6c
--- /dev/null
+++ b/drivers/net/ionic/rte_pmd_ionic_version.map
@@ -0,0 +1,5 @@
+DPDK_2.0 {
+
+	local: *;
+};
+
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 17b991604..d324078e3 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -176,6 +176,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_HNS3_PMD)       += -lrte_pmd_hns3
 _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IAVF_PMD)       += -lrte_pmd_iavf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ICE_PMD)        += -lrte_pmd_ice
+_LDLIBS-$(CONFIG_RTE_LIBRTE_IONIC_PMD)      += -lrte_pmd_ionic
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD)      += -lrte_pmd_ixgbe
 ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_KNI)        += -lrte_pmd_kni


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 02/17] net/ionic: add hardware structures definitions
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
  2019-10-12  0:26 ` [dpdk-dev] [PATCH 01/17] net/ionic: add skeleton Alfredo Cardigliano
@ 2019-10-12  0:26 ` Alfredo Cardigliano
  2019-10-12  0:26 ` [dpdk-dev] [PATCH 03/17] net/ionic: add log Alfredo Cardigliano
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:26 UTC (permalink / raw)
  To: dev

Add hardware structures and message commands definitions for
Pensando network adapters.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 drivers/net/ionic/ionic_if.h | 2491 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 2491 insertions(+)
 create mode 100644 drivers/net/ionic/ionic_if.h

diff --git a/drivers/net/ionic/ionic_if.h b/drivers/net/ionic/ionic_if.h
new file mode 100644
index 000000000..5f31ec034
--- /dev/null
+++ b/drivers/net/ionic/ionic_if.h
@@ -0,0 +1,2491 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB OR BSD-2-Clause */
+/* Copyright (c) 2017-2019 Pensando Systems, Inc.  All rights reserved. */
+
+#ifndef _IONIC_IF_H_
+#define _IONIC_IF_H_
+
+#pragma pack(push, 1)
+
+#define IONIC_DEV_INFO_SIGNATURE		0x44455649      /* 'DEVI' */
+#define IONIC_DEV_INFO_VERSION			1
+#define IONIC_IFNAMSIZ				16
+
+/**
+ * Commands
+ */
+enum ionic_cmd_opcode {
+	IONIC_CMD_NOP				= 0,
+
+	/* Device commands */
+	IONIC_CMD_IDENTIFY			= 1,
+	IONIC_CMD_INIT				= 2,
+	IONIC_CMD_RESET				= 3,
+	IONIC_CMD_GETATTR			= 4,
+	IONIC_CMD_SETATTR			= 5,
+
+	/* Port commands */
+	IONIC_CMD_PORT_IDENTIFY			= 10,
+	IONIC_CMD_PORT_INIT			= 11,
+	IONIC_CMD_PORT_RESET			= 12,
+	IONIC_CMD_PORT_GETATTR			= 13,
+	IONIC_CMD_PORT_SETATTR			= 14,
+
+	/* LIF commands */
+	IONIC_CMD_LIF_IDENTIFY			= 20,
+	IONIC_CMD_LIF_INIT			= 21,
+	IONIC_CMD_LIF_RESET			= 22,
+	IONIC_CMD_LIF_GETATTR			= 23,
+	IONIC_CMD_LIF_SETATTR			= 24,
+
+	IONIC_CMD_RX_MODE_SET			= 30,
+	IONIC_CMD_RX_FILTER_ADD			= 31,
+	IONIC_CMD_RX_FILTER_DEL			= 32,
+
+	/* Queue commands */
+	IONIC_CMD_Q_INIT			= 40,
+	IONIC_CMD_Q_CONTROL			= 41,
+
+	/* RDMA commands */
+	IONIC_CMD_RDMA_RESET_LIF		= 50,
+	IONIC_CMD_RDMA_CREATE_EQ		= 51,
+	IONIC_CMD_RDMA_CREATE_CQ		= 52,
+	IONIC_CMD_RDMA_CREATE_ADMINQ		= 53,
+
+	/* QoS commands */
+	IONIC_CMD_QOS_CLASS_IDENTIFY		= 240,
+	IONIC_CMD_QOS_CLASS_INIT		= 241,
+	IONIC_CMD_QOS_CLASS_RESET		= 242,
+
+	/* Firmware commands */
+	IONIC_CMD_FW_DOWNLOAD			= 254,
+	IONIC_CMD_FW_CONTROL			= 255,
+};
+
+/**
+ * Command Return codes
+ */
+enum ionic_status_code {
+	IONIC_RC_SUCCESS	= 0,	/* Success */
+	IONIC_RC_EVERSION	= 1,	/* Incorrect version for request */
+	IONIC_RC_EOPCODE	= 2,	/* Invalid cmd opcode */
+	IONIC_RC_EIO		= 3,	/* I/O error */
+	IONIC_RC_EPERM		= 4,	/* Permission denied */
+	IONIC_RC_EQID		= 5,	/* Bad qid */
+	IONIC_RC_EQTYPE		= 6,	/* Bad qtype */
+	IONIC_RC_ENOENT		= 7,	/* No such element */
+	IONIC_RC_EINTR		= 8,	/* operation interrupted */
+	IONIC_RC_EAGAIN		= 9,	/* Try again */
+	IONIC_RC_ENOMEM		= 10,	/* Out of memory */
+	IONIC_RC_EFAULT		= 11,	/* Bad address */
+	IONIC_RC_EBUSY		= 12,	/* Device or resource busy */
+	IONIC_RC_EEXIST		= 13,	/* object already exists */
+	IONIC_RC_EINVAL		= 14,	/* Invalid argument */
+	IONIC_RC_ENOSPC		= 15,	/* No space left or alloc failure */
+	IONIC_RC_ERANGE		= 16,	/* Parameter out of range */
+	IONIC_RC_BAD_ADDR	= 17,	/* Descriptor contains a bad ptr */
+	IONIC_RC_DEV_CMD	= 18,	/* Device cmd attempted on AdminQ */
+	IONIC_RC_ENOSUPP	= 19,	/* Operation not supported */
+	IONIC_RC_ERROR		= 29,	/* Generic error */
+
+	IONIC_RC_ERDMA		= 30,	/* Generic RDMA error */
+};
+
+enum ionic_notifyq_opcode {
+	IONIC_EVENT_LINK_CHANGE		= 1,
+	IONIC_EVENT_RESET		= 2,
+	IONIC_EVENT_HEARTBEAT		= 3,
+	IONIC_EVENT_LOG			= 4,
+};
+
+/**
+ * struct cmd - General admin command format
+ * @opcode:     Opcode for the command
+ * @lif_index:  LIF index
+ * @cmd_data:   Opcode-specific command bytes
+ */
+struct ionic_admin_cmd {
+	u8     opcode;
+	u8     rsvd;
+	__le16 lif_index;
+	u8     cmd_data[60];
+};
+
+/**
+ * struct ionic_admin_comp - General admin command completion format
+ * @status:     The status of the command (enum status_code)
+ * @comp_index: The index in the descriptor ring for which this
+ *              is the completion.
+ * @cmd_data:   Command-specific bytes.
+ * @color:      Color bit.  (Always 0 for commands issued to the
+ *              Device Cmd Registers.)
+ */
+struct ionic_admin_comp {
+	u8     status;
+	u8     rsvd;
+	__le16 comp_index;
+	u8     cmd_data[11];
+	u8     color;
+#define IONIC_COMP_COLOR_MASK  0x80
+};
+
+static inline u8 color_match(u8 color, u8 done_color)
+{
+	return (!!(color & IONIC_COMP_COLOR_MASK)) == done_color;
+}
+
+/**
+ * struct ionic_nop_cmd - NOP command
+ * @opcode: opcode
+ */
+struct ionic_nop_cmd {
+	u8 opcode;
+	u8 rsvd[63];
+};
+
+/**
+ * struct ionic_nop_comp - NOP command completion
+ * @status: The status of the command (enum status_code)
+ */
+struct ionic_nop_comp {
+	u8 status;
+	u8 rsvd[15];
+};
+
+/**
+ * struct ionic_dev_init_cmd - Device init command
+ * @opcode:    opcode
+ * @type:      device type
+ */
+struct ionic_dev_init_cmd {
+	u8     opcode;
+	u8     type;
+	u8     rsvd[62];
+};
+
+/**
+ * struct init_comp - Device init command completion
+ * @status: The status of the command (enum status_code)
+ */
+struct ionic_dev_init_comp {
+	u8 status;
+	u8 rsvd[15];
+};
+
+/**
+ * struct ionic_dev_reset_cmd - Device reset command
+ * @opcode: opcode
+ */
+struct ionic_dev_reset_cmd {
+	u8 opcode;
+	u8 rsvd[63];
+};
+
+/**
+ * struct reset_comp - Reset command completion
+ * @status: The status of the command (enum status_code)
+ */
+struct ionic_dev_reset_comp {
+	u8 status;
+	u8 rsvd[15];
+};
+
+#define IONIC_IDENTITY_VERSION_1	1
+
+/**
+ * struct ionic_dev_identify_cmd - Driver/device identify command
+ * @opcode:  opcode
+ * @ver:     Highest version of identify supported by driver
+ */
+struct ionic_dev_identify_cmd {
+	u8 opcode;
+	u8 ver;
+	u8 rsvd[62];
+};
+
+/**
+ * struct dev_identify_comp - Driver/device identify command completion
+ * @status: The status of the command (enum status_code)
+ * @ver:    Version of identify returned by device
+ */
+struct ionic_dev_identify_comp {
+	u8 status;
+	u8 ver;
+	u8 rsvd[14];
+};
+
+enum ionic_os_type {
+	IONIC_OS_TYPE_LINUX   = 1,
+	IONIC_OS_TYPE_WIN     = 2,
+	IONIC_OS_TYPE_DPDK    = 3,
+	IONIC_OS_TYPE_FREEBSD = 4,
+	IONIC_OS_TYPE_IPXE    = 5,
+	IONIC_OS_TYPE_ESXI    = 6,
+};
+
+/**
+ * union drv_identity - driver identity information
+ * @os_type:          OS type (see enum os_type)
+ * @os_dist:          OS distribution, numeric format
+ * @os_dist_str:      OS distribution, string format
+ * @kernel_ver:       Kernel version, numeric format
+ * @kernel_ver_str:   Kernel version, string format
+ * @driver_ver_str:   Driver version, string format
+ */
+union ionic_drv_identity {
+	struct {
+		__le32 os_type;
+		__le32 os_dist;
+		char   os_dist_str[128];
+		__le32 kernel_ver;
+		char   kernel_ver_str[32];
+		char   driver_ver_str[32];
+	};
+	__le32 words[512];
+};
+
+/**
+ * union dev_identity - device identity information
+ * @version:          Version of device identify
+ * @type:             Identify type (0 for now)
+ * @nports:           Number of ports provisioned
+ * @nlifs:            Number of LIFs provisioned
+ * @nintrs:           Number of interrupts provisioned
+ * @ndbpgs_per_lif:   Number of doorbell pages per LIF
+ * @intr_coal_mult:   Interrupt coalescing multiplication factor.
+ *                    Scale user-supplied interrupt coalescing
+ *                    value in usecs to device units using:
+ *                    device units = usecs * mult / div
+ * @intr_coal_div:    Interrupt coalescing division factor.
+ *                    Scale user-supplied interrupt coalescing
+ *                    value in usecs to device units using:
+ *                    device units = usecs * mult / div
+ *
+ */
+union ionic_dev_identity {
+	struct {
+		u8     version;
+		u8     type;
+		u8     rsvd[2];
+		u8     nports;
+		u8     rsvd2[3];
+		__le32 nlifs;
+		__le32 nintrs;
+		__le32 ndbpgs_per_lif;
+		__le32 intr_coal_mult;
+		__le32 intr_coal_div;
+	};
+	__le32 words[512];
+};
+
+enum ionic_lif_type {
+	IONIC_LIF_TYPE_CLASSIC = 0,
+	IONIC_LIF_TYPE_MACVLAN = 1,
+	IONIC_LIF_TYPE_NETQUEUE = 2,
+};
+
+/**
+ * struct ionic_lif_identify_cmd - lif identify command
+ * @opcode:  opcode
+ * @type:    lif type (enum lif_type)
+ * @ver:     version of identify returned by device
+ */
+struct ionic_lif_identify_cmd {
+	u8 opcode;
+	u8 type;
+	u8 ver;
+	u8 rsvd[61];
+};
+
+/**
+ * struct ionic_lif_identify_comp - lif identify command completion
+ * @status:  status of the command (enum status_code)
+ * @ver:     version of identify returned by device
+ */
+struct ionic_lif_identify_comp {
+	u8 status;
+	u8 ver;
+	u8 rsvd2[14];
+};
+
+enum ionic_lif_capability {
+	IONIC_LIF_CAP_ETH        = BIT(0),
+	IONIC_LIF_CAP_RDMA       = BIT(1),
+};
+
+/**
+ * Logical Queue Types
+ */
+enum ionic_logical_qtype {
+	IONIC_QTYPE_ADMINQ  = 0,
+	IONIC_QTYPE_NOTIFYQ = 1,
+	IONIC_QTYPE_RXQ     = 2,
+	IONIC_QTYPE_TXQ     = 3,
+	IONIC_QTYPE_EQ      = 4,
+	IONIC_QTYPE_MAX     = 16,
+};
+
+/**
+ * struct ionic_lif_logical_qtype - Descriptor of logical to hardware queue
+ * type.
+ * @qtype:          Hardware Queue Type.
+ * @qid_count:      Number of Queue IDs of the logical type.
+ * @qid_base:       Minimum Queue ID of the logical type.
+ */
+struct ionic_lif_logical_qtype {
+	u8     qtype;
+	u8     rsvd[3];
+	__le32 qid_count;
+	__le32 qid_base;
+};
+
+enum ionic_lif_state {
+	IONIC_LIF_DISABLE	= 0,
+	IONIC_LIF_ENABLE	= 1,
+	IONIC_LIF_HANG_RESET	= 2,
+};
+
+/**
+ * LIF configuration
+ * @state:          lif state (enum lif_state)
+ * @name:           lif name
+ * @mtu:            mtu
+ * @mac:            station mac address
+ * @features:       features (enum ionic_eth_hw_features)
+ * @queue_count:    queue counts per queue-type
+ */
+union ionic_lif_config {
+	struct {
+		u8     state;
+		u8     rsvd[3];
+		char   name[IONIC_IFNAMSIZ];
+		__le32 mtu;
+		u8     mac[6];
+		u8     rsvd2[2];
+		__le64 features;
+		__le32 queue_count[IONIC_QTYPE_MAX];
+	};
+	__le32 words[64];
+};
+
+/**
+ * struct ionic_lif_identity - lif identity information (type-specific)
+ *
+ * @capabilities    LIF capabilities
+ *
+ * Ethernet:
+ *     @version:          Ethernet identify structure version.
+ *     @features:         Ethernet features supported on this lif type.
+ *     @max_ucast_filters:  Number of perfect unicast addresses supported.
+ *     @max_mcast_filters:  Number of perfect multicast addresses supported.
+ *     @min_frame_size:   Minimum size of frames to be sent
+ *     @max_frame_size:   Maximim size of frames to be sent
+ *     @config:           LIF config struct with features, mtu, mac, q counts
+ *
+ * RDMA:
+ *     @version:         RDMA version of opcodes and queue descriptors.
+ *     @qp_opcodes:      Number of rdma queue pair opcodes supported.
+ *     @admin_opcodes:   Number of rdma admin opcodes supported.
+ *     @npts_per_lif:    Page table size per lif
+ *     @nmrs_per_lif:    Number of memory regions per lif
+ *     @nahs_per_lif:    Number of address handles per lif
+ *     @max_stride:      Max work request stride.
+ *     @cl_stride:       Cache line stride.
+ *     @pte_stride:      Page table entry stride.
+ *     @rrq_stride:      Remote RQ work request stride.
+ *     @rsq_stride:      Remote SQ work request stride.
+ *     @dcqcn_profiles:  Number of DCQCN profiles
+ *     @aq_qtype:        RDMA Admin Qtype.
+ *     @sq_qtype:        RDMA Send Qtype.
+ *     @rq_qtype:        RDMA Receive Qtype.
+ *     @cq_qtype:        RDMA Completion Qtype.
+ *     @eq_qtype:        RDMA Event Qtype.
+ */
+union ionic_lif_identity {
+	struct {
+		__le64 capabilities;
+
+		struct {
+			u8 version;
+			u8 rsvd[3];
+			__le32 max_ucast_filters;
+			__le32 max_mcast_filters;
+			__le16 rss_ind_tbl_sz;
+			__le32 min_frame_size;
+			__le32 max_frame_size;
+			u8 rsvd2[106];
+			union ionic_lif_config config;
+		} eth;
+
+		struct {
+			u8 version;
+			u8 qp_opcodes;
+			u8 admin_opcodes;
+			u8 rsvd;
+			__le32 npts_per_lif;
+			__le32 nmrs_per_lif;
+			__le32 nahs_per_lif;
+			u8 max_stride;
+			u8 cl_stride;
+			u8 pte_stride;
+			u8 rrq_stride;
+			u8 rsq_stride;
+			u8 dcqcn_profiles;
+			u8 rsvd_dimensions[10];
+			struct ionic_lif_logical_qtype aq_qtype;
+			struct ionic_lif_logical_qtype sq_qtype;
+			struct ionic_lif_logical_qtype rq_qtype;
+			struct ionic_lif_logical_qtype cq_qtype;
+			struct ionic_lif_logical_qtype eq_qtype;
+		} rdma;
+	};
+	__le32 words[512];
+};
+
+/**
+ * struct ionic_lif_init_cmd - LIF init command
+ * @opcode:       opcode
+ * @type:         LIF type (enum lif_type)
+ * @index:        LIF index
+ * @info_pa:      destination address for lif info (struct ionic_lif_info)
+ */
+struct ionic_lif_init_cmd {
+	u8     opcode;
+	u8     type;
+	__le16 index;
+	__le32 rsvd;
+	__le64 info_pa;
+	u8     rsvd2[48];
+};
+
+/**
+ * struct ionic_lif_init_comp - LIF init command completion
+ * @status: The status of the command (enum status_code)
+ */
+struct ionic_lif_init_comp {
+	u8 status;
+	u8 rsvd;
+	__le16 hw_index;
+	u8 rsvd2[12];
+};
+
+/**
+ * struct ionic_q_init_cmd - Queue init command
+ * @opcode:       opcode
+ * @type:         Logical queue type
+ * @ver:          Queue version (defines opcode/descriptor scope)
+ * @lif_index:    LIF index
+ * @index:        (lif, qtype) relative admin queue index
+ * @intr_index:   Interrupt control register index
+ * @pid:          Process ID
+ * @flags:
+ *    IRQ:        Interrupt requested on completion
+ *    ENA:        Enable the queue.  If ENA=0 the queue is initialized
+ *                but remains disabled, to be later enabled with the
+ *                Queue Enable command.  If ENA=1, then queue is
+ *                initialized and then enabled.
+ *    SG:         Enable Scatter-Gather on the queue.
+ *                in number of descs.  The actual ring size is
+ *                (1 << ring_size).  For example, to
+ *                select a ring size of 64 descriptors write
+ *                ring_size = 6.  The minimum ring_size value is 2
+ *                for a ring size of 4 descriptors.  The maximum
+ *                ring_size value is 16 for a ring size of 64k
+ *                descriptors.  Values of ring_size <2 and >16 are
+ *                reserved.
+ *    EQ:         Enable the Event Queue
+ * @cos:          Class of service for this queue.
+ * @ring_size:    Queue ring size, encoded as a log2(size)
+ * @ring_base:    Queue ring base address
+ * @cq_ring_base: Completion queue ring base address
+ * @sg_ring_base: Scatter/Gather ring base address
+ * @eq_index:	  Event queue index
+ */
+struct ionic_q_init_cmd {
+	u8     opcode;
+	u8     rsvd;
+	__le16 lif_index;
+	u8     type;
+	u8     ver;
+	u8     rsvd1[2];
+	__le32 index;
+	__le16 pid;
+	__le16 intr_index;
+	__le16 flags;
+#define IONIC_QINIT_F_IRQ	0x01	/* Request interrupt on completion */
+#define IONIC_QINIT_F_ENA	0x02	/* Enable the queue */
+#define IONIC_QINIT_F_SG	0x04	/* Enable scatter/gather on the queue */
+#define IONIC_QINIT_F_EQ	0x08	/* Enable event queue */
+#define IONIC_QINIT_F_DEBUG 0x80	/* Enable queue debugging */
+	u8     cos;
+	u8     ring_size;
+	__le64 ring_base;
+	__le64 cq_ring_base;
+	__le64 sg_ring_base;
+	__le32 eq_index;
+	u8     rsvd2[16];
+};
+
+/**
+ * struct ionic_q_init_comp - Queue init command completion
+ * @status:     The status of the command (enum status_code)
+ * @ver:        Queue version (defines opcode/descriptor scope)
+ * @comp_index: The index in the descriptor ring for which this
+ *              is the completion.
+ * @hw_index:   Hardware Queue ID
+ * @hw_type:    Hardware Queue type
+ * @color:      Color
+ */
+struct ionic_q_init_comp {
+	u8     status;
+	u8     ver;
+	__le16 comp_index;
+	__le32 hw_index;
+	u8     hw_type;
+	u8     rsvd2[6];
+	u8     color;
+};
+
+/* the device's internal addressing uses up to 52 bits */
+#define IONIC_ADDR_LEN		52
+#define IONIC_ADDR_MASK		(BIT_ULL(IONIC_ADDR_LEN) - 1)
+
+enum ionic_txq_desc_opcode {
+	IONIC_TXQ_DESC_OPCODE_CSUM_NONE = 0,
+	IONIC_TXQ_DESC_OPCODE_CSUM_PARTIAL = 1,
+	IONIC_TXQ_DESC_OPCODE_CSUM_HW = 2,
+	IONIC_TXQ_DESC_OPCODE_TSO = 3,
+};
+
+/**
+ * struct ionic_txq_desc - Ethernet Tx queue descriptor format
+ * @opcode:       Tx operation, see TXQ_DESC_OPCODE_*:
+ *
+ *                   IONIC_TXQ_DESC_OPCODE_CSUM_NONE:
+ *
+ *                      Non-offload send.  No segmentation,
+ *                      fragmentation or checksum calc/insertion is
+ *                      performed by device; packet is prepared
+ *                      to send by software stack and requires
+ *                      no further manipulation from device.
+ *
+ *                   IONIC_TXQ_DESC_OPCODE_CSUM_PARTIAL:
+ *
+ *                      Offload 16-bit L4 checksum
+ *                      calculation/insertion.  The device will
+ *                      calculate the L4 checksum value and
+ *                      insert the result in the packet's L4
+ *                      header checksum field.  The L4 checksum
+ *                      is calculated starting at @csum_start bytes
+ *                      into the packet to the end of the packet.
+ *                      The checksum insertion position is given
+ *                      in @csum_offset.  This feature is only
+ *                      applicable to protocols such as TCP, UDP
+ *                      and ICMP where a standard (i.e. the
+ *                      'IP-style' checksum) one's complement
+ *                      16-bit checksum is used, using an IP
+ *                      pseudo-header to seed the calculation.
+ *                      Software will preload the L4 checksum
+ *                      field with the IP pseudo-header checksum.
+ *
+ *                      For tunnel encapsulation, @csum_start and
+ *                      @csum_offset refer to the inner L4
+ *                      header.  Supported tunnels encapsulations
+ *                      are: IPIP, GRE, and UDP.  If the @encap
+ *                      is clear, no further processing by the
+ *                      device is required; software will
+ *                      calculate the outer header checksums.  If
+ *                      the @encap is set, the device will
+ *                      offload the outer header checksums using
+ *                      LCO (local checksum offload) (see
+ *                      Documentation/networking/checksum-
+ *                      offloads.txt for more info).
+ *
+ *                   IONIC_TXQ_DESC_OPCODE_CSUM_HW:
+ *
+ *                      Offload 16-bit checksum computation to hardware.
+ *                      If @csum_l3 is set then the packet's L3 checksum is
+ *                      updated. Similarly, if @csum_l4 is set the the L4
+ *                      checksum is updated. If @encap is set then encap header
+ *                      checksums are also updated.
+ *
+ *                   IONIC_TXQ_DESC_OPCODE_TSO:
+ *
+ *                      Device preforms TCP segmentation offload
+ *                      (TSO).  @hdr_len is the number of bytes
+ *                      to the end of TCP header (the offset to
+ *                      the TCP payload).  @mss is the desired
+ *                      MSS, the TCP payload length for each
+ *                      segment.  The device will calculate/
+ *                      insert IP (IPv4 only) and TCP checksums
+ *                      for each segment.  In the first data
+ *                      buffer containing the header template,
+ *                      the driver will set IPv4 checksum to 0
+ *                      and preload TCP checksum with the IP
+ *                      pseudo header calculated with IP length = 0.
+ *
+ *                      Supported tunnel encapsulations are IPIP,
+ *                      layer-3 GRE, and UDP. @hdr_len includes
+ *                      both outer and inner headers.  The driver
+ *                      will set IPv4 checksum to zero and
+ *                      preload TCP checksum with IP pseudo
+ *                      header on the inner header.
+ *
+ *                      TCP ECN offload is supported.  The device
+ *                      will set CWR flag in the first segment if
+ *                      CWR is set in the template header, and
+ *                      clear CWR in remaining segments.
+ * @flags:
+ *                vlan:
+ *                    Insert an L2 VLAN header using @vlan_tci.
+ *                encap:
+ *                    Calculate encap header checksum.
+ *                csum_l3:
+ *                    Compute L3 header checksum.
+ *                csum_l4:
+ *                    Compute L4 header checksum.
+ *                tso_sot:
+ *                    TSO start
+ *                tso_eot:
+ *                    TSO end
+ * @num_sg_elems: Number of scatter-gather elements in SG
+ *                descriptor
+ * @addr:         First data buffer's DMA address.
+ *                (Subsequent data buffers are on txq_sg_desc).
+ * @len:          First data buffer's length, in bytes
+ * @vlan_tci:     VLAN tag to insert in the packet (if requested
+ *                by @V-bit).  Includes .1p and .1q tags
+ * @hdr_len:      Length of packet headers, including
+ *                encapsulating outer header, if applicable.
+ *                Valid for opcodes TXQ_DESC_OPCODE_CALC_CSUM and
+ *                TXQ_DESC_OPCODE_TSO.  Should be set to zero for
+ *                all other modes.  For
+ *                TXQ_DESC_OPCODE_CALC_CSUM, @hdr_len is length
+ *                of headers up to inner-most L4 header.  For
+ *                TXQ_DESC_OPCODE_TSO, @hdr_len is up to
+ *                inner-most L4 payload, so inclusive of
+ *                inner-most L4 header.
+ * @mss:          Desired MSS value for TSO.  Only applicable for
+ *                TXQ_DESC_OPCODE_TSO.
+ * @csum_start:   Offset into inner-most L3 header of checksum
+ * @csum_offset:  Offset into inner-most L4 header of checksum
+ */
+
+#define IONIC_TXQ_DESC_OPCODE_MASK		0xf
+#define IONIC_TXQ_DESC_OPCODE_SHIFT		4
+#define IONIC_TXQ_DESC_FLAGS_MASK		0xf
+#define IONIC_TXQ_DESC_FLAGS_SHIFT		0
+#define IONIC_TXQ_DESC_NSGE_MASK		0xf
+#define IONIC_TXQ_DESC_NSGE_SHIFT		8
+#define IONIC_TXQ_DESC_ADDR_MASK		(BIT_ULL(IONIC_ADDR_LEN) - 1)
+#define IONIC_TXQ_DESC_ADDR_SHIFT		12
+
+/* common flags */
+#define IONIC_TXQ_DESC_FLAG_VLAN		0x1
+#define IONIC_TXQ_DESC_FLAG_ENCAP		0x2
+
+/* flags for csum_hw opcode */
+#define IONIC_TXQ_DESC_FLAG_CSUM_L3		0x4
+#define IONIC_TXQ_DESC_FLAG_CSUM_L4		0x8
+
+/* flags for tso opcode */
+#define IONIC_TXQ_DESC_FLAG_TSO_SOT		0x4
+#define IONIC_TXQ_DESC_FLAG_TSO_EOT		0x8
+
+struct ionic_txq_desc {
+	__le64  cmd;
+	__le16  len;
+	union {
+		__le16  vlan_tci;
+		__le16  hword0;
+	};
+	union {
+		__le16  csum_start;
+		__le16  hdr_len;
+		__le16  hword1;
+	};
+	union {
+		__le16  csum_offset;
+		__le16  mss;
+		__le16  hword2;
+	};
+};
+
+static inline u64 encode_txq_desc_cmd(u8 opcode, u8 flags,
+				      u8 nsge, u64 addr)
+{
+	u64 cmd;
+
+	cmd = (opcode & IONIC_TXQ_DESC_OPCODE_MASK) <<
+		IONIC_TXQ_DESC_OPCODE_SHIFT;
+	cmd |= (flags & IONIC_TXQ_DESC_FLAGS_MASK) <<
+		IONIC_TXQ_DESC_FLAGS_SHIFT;
+	cmd |= (nsge & IONIC_TXQ_DESC_NSGE_MASK) << IONIC_TXQ_DESC_NSGE_SHIFT;
+	cmd |= (addr & IONIC_TXQ_DESC_ADDR_MASK) << IONIC_TXQ_DESC_ADDR_SHIFT;
+
+	return cmd;
+};
+
+static inline void decode_txq_desc_cmd(u64 cmd, u8 *opcode, u8 *flags,
+				       u8 *nsge, u64 *addr)
+{
+	*opcode = (cmd >> IONIC_TXQ_DESC_OPCODE_SHIFT) &
+		IONIC_TXQ_DESC_OPCODE_MASK;
+	*flags = (cmd >> IONIC_TXQ_DESC_FLAGS_SHIFT) &
+		IONIC_TXQ_DESC_FLAGS_MASK;
+	*nsge = (cmd >> IONIC_TXQ_DESC_NSGE_SHIFT) & IONIC_TXQ_DESC_NSGE_MASK;
+	*addr = (cmd >> IONIC_TXQ_DESC_ADDR_SHIFT) & IONIC_TXQ_DESC_ADDR_MASK;
+};
+
+#define IONIC_TX_MAX_SG_ELEMS	8
+#define IONIC_RX_MAX_SG_ELEMS	8
+
+/**
+ * struct ionic_txq_sg_desc - Transmit scatter-gather (SG) list
+ * @addr:      DMA address of SG element data buffer
+ * @len:       Length of SG element data buffer, in bytes
+ */
+struct ionic_txq_sg_desc {
+	struct ionic_txq_sg_elem {
+		__le64 addr;
+		__le16 len;
+		__le16 rsvd[3];
+	} elems[IONIC_TX_MAX_SG_ELEMS];
+};
+
+/**
+ * struct ionic_txq_comp - Ethernet transmit queue completion descriptor
+ * @status:     The status of the command (enum status_code)
+ * @comp_index: The index in the descriptor ring for which this
+ *                 is the completion.
+ * @color:      Color bit.
+ */
+struct ionic_txq_comp {
+	u8     status;
+	u8     rsvd;
+	__le16 comp_index;
+	u8     rsvd2[11];
+	u8     color;
+};
+
+enum ionic_rxq_desc_opcode {
+	IONIC_RXQ_DESC_OPCODE_SIMPLE = 0,
+	IONIC_RXQ_DESC_OPCODE_SG = 1,
+};
+
+/**
+ * struct ionic_rxq_desc - Ethernet Rx queue descriptor format
+ * @opcode:       Rx operation, see RXQ_DESC_OPCODE_*:
+ *
+ *                   RXQ_DESC_OPCODE_SIMPLE:
+ *
+ *                      Receive full packet into data buffer
+ *                      starting at @addr.  Results of
+ *                      receive, including actual bytes received,
+ *                      are recorded in Rx completion descriptor.
+ *
+ * @len:          Data buffer's length, in bytes.
+ * @addr:         Data buffer's DMA address
+ */
+struct ionic_rxq_desc {
+	u8     opcode;
+	u8     rsvd[5];
+	__le16 len;
+	__le64 addr;
+};
+
+/**
+ * struct ionic_rxq_sg_desc - Receive scatter-gather (SG) list
+ * @addr:      DMA address of SG element data buffer
+ * @len:       Length of SG element data buffer, in bytes
+ */
+struct ionic_rxq_sg_desc {
+	struct ionic_rxq_sg_elem {
+		__le64 addr;
+		__le16 len;
+		__le16 rsvd[3];
+	} elems[IONIC_RX_MAX_SG_ELEMS];
+};
+
+/**
+ * struct ionic_rxq_comp - Ethernet receive queue completion descriptor
+ * @status:       The status of the command (enum status_code)
+ * @num_sg_elems: Number of SG elements used by this descriptor
+ * @comp_index:   The index in the descriptor ring for which this
+ *                is the completion.
+ * @rss_hash:     32-bit RSS hash
+ * @csum:         16-bit sum of the packet's L2 payload.
+ *                If the packet's L2 payload is odd length, an extra
+ *                zero-value byte is included in the @csum calculation but
+ *                not included in @len.
+ * @vlan_tci:     VLAN tag stripped from the packet.  Valid if @VLAN is
+ *                set.  Includes .1p and .1q tags.
+ * @len:          Received packet length, in bytes.  Excludes FCS.
+ * @csum_calc     L2 payload checksum is computed or not
+ * @csum_tcp_ok:  The TCP checksum calculated by the device
+ *                matched the checksum in the receive packet's
+ *                TCP header
+ * @csum_tcp_bad: The TCP checksum calculated by the device did
+ *                not match the checksum in the receive packet's
+ *                TCP header.
+ * @csum_udp_ok:  The UDP checksum calculated by the device
+ *                matched the checksum in the receive packet's
+ *                UDP header
+ * @csum_udp_bad: The UDP checksum calculated by the device did
+ *                not match the checksum in the receive packet's
+ *                UDP header.
+ * @csum_ip_ok:   The IPv4 checksum calculated by the device
+ *                matched the checksum in the receive packet's
+ *                first IPv4 header.  If the receive packet
+ *                contains both a tunnel IPv4 header and a
+ *                transport IPv4 header, the device validates the
+ *                checksum for the both IPv4 headers.
+ * @csum_ip_bad:  The IPv4 checksum calculated by the device did
+ *                not match the checksum in the receive packet's
+ *                first IPv4 header. If the receive packet
+ *                contains both a tunnel IPv4 header and a
+ *                transport IPv4 header, the device validates the
+ *                checksum for both IP headers.
+ * @VLAN:         VLAN header was stripped and placed in @vlan_tci.
+ * @pkt_type:     Packet type
+ * @color:        Color bit.
+ */
+struct ionic_rxq_comp {
+	u8     status;
+	u8     num_sg_elems;
+	__le16 comp_index;
+	__le32 rss_hash;
+	__le16 csum;
+	__le16 vlan_tci;
+	__le16 len;
+	u8     csum_flags;
+#define IONIC_RXQ_COMP_CSUM_F_TCP_OK	0x01
+#define IONIC_RXQ_COMP_CSUM_F_TCP_BAD	0x02
+#define IONIC_RXQ_COMP_CSUM_F_UDP_OK	0x04
+#define IONIC_RXQ_COMP_CSUM_F_UDP_BAD	0x08
+#define IONIC_RXQ_COMP_CSUM_F_IP_OK	0x10
+#define IONIC_RXQ_COMP_CSUM_F_IP_BAD	0x20
+#define IONIC_RXQ_COMP_CSUM_F_VLAN	0x40
+#define IONIC_RXQ_COMP_CSUM_F_CALC	0x80
+	u8     pkt_type_color;
+#define IONIC_RXQ_COMP_PKT_TYPE_MASK	0x0f
+};
+
+enum ionic_pkt_type {
+	IONIC_PKT_TYPE_NON_IP     = 0x000,
+	IONIC_PKT_TYPE_IPV4       = 0x001,
+	IONIC_PKT_TYPE_IPV4_TCP   = 0x003,
+	IONIC_PKT_TYPE_IPV4_UDP   = 0x005,
+	IONIC_PKT_TYPE_IPV6       = 0x008,
+	IONIC_PKT_TYPE_IPV6_TCP   = 0x018,
+	IONIC_PKT_TYPE_IPV6_UDP   = 0x028,
+};
+
+enum ionic_eth_hw_features {
+	IONIC_ETH_HW_VLAN_TX_TAG	= BIT(0),
+	IONIC_ETH_HW_VLAN_RX_STRIP	= BIT(1),
+	IONIC_ETH_HW_VLAN_RX_FILTER	= BIT(2),
+	IONIC_ETH_HW_RX_HASH		= BIT(3),
+	IONIC_ETH_HW_RX_CSUM		= BIT(4),
+	IONIC_ETH_HW_TX_SG		= BIT(5),
+	IONIC_ETH_HW_RX_SG		= BIT(6),
+	IONIC_ETH_HW_TX_CSUM		= BIT(7),
+	IONIC_ETH_HW_TSO		= BIT(8),
+	IONIC_ETH_HW_TSO_IPV6		= BIT(9),
+	IONIC_ETH_HW_TSO_ECN		= BIT(10),
+	IONIC_ETH_HW_TSO_GRE		= BIT(11),
+	IONIC_ETH_HW_TSO_GRE_CSUM	= BIT(12),
+	IONIC_ETH_HW_TSO_IPXIP4	= BIT(13),
+	IONIC_ETH_HW_TSO_IPXIP6	= BIT(14),
+	IONIC_ETH_HW_TSO_UDP		= BIT(15),
+	IONIC_ETH_HW_TSO_UDP_CSUM	= BIT(16),
+};
+
+/**
+ * struct ionic_q_control_cmd - Queue control command
+ * @opcode:     opcode
+ * @type:       Queue type
+ * @lif_index:  LIF index
+ * @index:      Queue index
+ * @oper:       Operation (enum q_control_oper)
+ */
+struct ionic_q_control_cmd {
+	u8     opcode;
+	u8     type;
+	__le16 lif_index;
+	__le32 index;
+	u8     oper;
+	u8     rsvd[55];
+};
+
+typedef struct ionic_admin_comp ionic_q_control_comp;
+
+enum q_control_oper {
+	IONIC_Q_DISABLE		= 0,
+	IONIC_Q_ENABLE		= 1,
+	IONIC_Q_HANG_RESET	= 2,
+};
+
+/**
+ * Physical connection type
+ */
+enum ionic_phy_type {
+	IONIC_PHY_TYPE_NONE	= 0,
+	IONIC_PHY_TYPE_COPPER	= 1,
+	IONIC_PHY_TYPE_FIBER	= 2,
+};
+
+/**
+ * Transceiver status
+ */
+enum ionic_xcvr_state {
+	IONIC_XCVR_STATE_REMOVED	 = 0,
+	IONIC_XCVR_STATE_INSERTED	 = 1,
+	IONIC_XCVR_STATE_PENDING	 = 2,
+	IONIC_XCVR_STATE_SPROM_READ	 = 3,
+	IONIC_XCVR_STATE_SPROM_READ_ERR  = 4,
+};
+
+/**
+ * Supported link modes
+ */
+enum ionic_xcvr_pid {
+	IONIC_XCVR_PID_UNKNOWN           = 0,
+
+	/* CU */
+	IONIC_XCVR_PID_QSFP_100G_CR4     = 1,
+	IONIC_XCVR_PID_QSFP_40GBASE_CR4  = 2,
+	IONIC_XCVR_PID_SFP_25GBASE_CR_S  = 3,
+	IONIC_XCVR_PID_SFP_25GBASE_CR_L  = 4,
+	IONIC_XCVR_PID_SFP_25GBASE_CR_N  = 5,
+
+	/* Fiber */
+	IONIC_XCVR_PID_QSFP_100G_AOC    = 50,
+	IONIC_XCVR_PID_QSFP_100G_ACC    = 51,
+	IONIC_XCVR_PID_QSFP_100G_SR4    = 52,
+	IONIC_XCVR_PID_QSFP_100G_LR4    = 53,
+	IONIC_XCVR_PID_QSFP_100G_ER4    = 54,
+	IONIC_XCVR_PID_QSFP_40GBASE_ER4 = 55,
+	IONIC_XCVR_PID_QSFP_40GBASE_SR4 = 56,
+	IONIC_XCVR_PID_QSFP_40GBASE_LR4 = 57,
+	IONIC_XCVR_PID_QSFP_40GBASE_AOC = 58,
+	IONIC_XCVR_PID_SFP_25GBASE_SR   = 59,
+	IONIC_XCVR_PID_SFP_25GBASE_LR   = 60,
+	IONIC_XCVR_PID_SFP_25GBASE_ER   = 61,
+	IONIC_XCVR_PID_SFP_25GBASE_AOC  = 62,
+	IONIC_XCVR_PID_SFP_10GBASE_SR   = 63,
+	IONIC_XCVR_PID_SFP_10GBASE_LR   = 64,
+	IONIC_XCVR_PID_SFP_10GBASE_LRM  = 65,
+	IONIC_XCVR_PID_SFP_10GBASE_ER   = 66,
+	IONIC_XCVR_PID_SFP_10GBASE_AOC  = 67,
+	IONIC_XCVR_PID_SFP_10GBASE_CU   = 68,
+	IONIC_XCVR_PID_QSFP_100G_CWDM4  = 69,
+	IONIC_XCVR_PID_QSFP_100G_PSM4   = 70,
+};
+
+/**
+ * Port types
+ */
+enum ionic_port_type {
+	IONIC_PORT_TYPE_NONE = 0,  /* port type not configured */
+	IONIC_PORT_TYPE_ETH  = 1,  /* port carries ethernet traffic (inband) */
+	IONIC_PORT_TYPE_MGMT = 2,  /* port carries mgmt traffic (out-of-band) */
+};
+
+/**
+ * Port config state
+ */
+enum ionic_port_admin_state {
+	IONIC_PORT_ADMIN_STATE_NONE = 0,   /* port admin state not configured */
+	IONIC_PORT_ADMIN_STATE_DOWN = 1,   /* port is admin disabled */
+	IONIC_PORT_ADMIN_STATE_UP   = 2,   /* port is admin enabled */
+};
+
+/**
+ * Port operational status
+ */
+enum ionic_port_oper_status {
+	IONIC_PORT_OPER_STATUS_NONE  = 0,	/* port is disabled */
+	IONIC_PORT_OPER_STATUS_UP    = 1,	/* port is linked up */
+	IONIC_PORT_OPER_STATUS_DOWN  = 2,	/* port link status is down */
+};
+
+/**
+ * Ethernet Forward error correction (fec) modes
+ */
+enum ionic_port_fec_type {
+	IONIC_PORT_FEC_TYPE_NONE = 0,		/* Disabled */
+	IONIC_PORT_FEC_TYPE_FC   = 1,		/* FireCode */
+	IONIC_PORT_FEC_TYPE_RS   = 2,		/* ReedSolomon */
+};
+
+/**
+ * Ethernet pause (flow control) modes
+ */
+enum ionic_port_pause_type {
+	IONIC_PORT_PAUSE_TYPE_NONE = 0,	/* Disable Pause */
+	IONIC_PORT_PAUSE_TYPE_LINK = 1,	/* Link level pause */
+	IONIC_PORT_PAUSE_TYPE_PFC  = 2,	/* Priority-Flow control */
+};
+
+/**
+ * Loopback modes
+ */
+enum ionic_port_loopback_mode {
+	IONIC_PORT_LOOPBACK_MODE_NONE = 0,	/* Disable loopback */
+	IONIC_PORT_LOOPBACK_MODE_MAC  = 1,	/* MAC loopback */
+	IONIC_PORT_LOOPBACK_MODE_PHY  = 2,	/* PHY/Serdes loopback */
+};
+
+/**
+ * Transceiver Status information
+ * @state:    Transceiver status (enum ionic_xcvr_state)
+ * @phy:      Physical connection type (enum ionic_phy_type)
+ * @pid:      Transceiver link mode (enum pid)
+ * @sprom:    Transceiver sprom contents
+ */
+struct ionic_xcvr_status {
+	u8     state;
+	u8     phy;
+	__le16 pid;
+	u8     sprom[256];
+};
+
+/**
+ * Port configuration
+ * @speed:              port speed (in Mbps)
+ * @mtu:                mtu
+ * @state:              port admin state (enum port_admin_state)
+ * @an_enable:          autoneg enable
+ * @fec_type:           fec type (enum ionic_port_fec_type)
+ * @pause_type:         pause type (enum ionic_port_pause_type)
+ * @loopback_mode:      loopback mode (enum ionic_port_loopback_mode)
+ */
+union ionic_port_config {
+	struct {
+#define IONIC_SPEED_100G	100000	/* 100G in Mbps */
+#define IONIC_SPEED_50G		50000	/* 50G in Mbps */
+#define IONIC_SPEED_40G		40000	/* 40G in Mbps */
+#define IONIC_SPEED_25G		25000	/* 25G in Mbps */
+#define IONIC_SPEED_10G		10000	/* 10G in Mbps */
+#define IONIC_SPEED_1G		1000	/* 1G in Mbps */
+		__le32 speed;
+		__le32 mtu;
+		u8     state;
+		u8     an_enable;
+		u8     fec_type;
+#define IONIC_PAUSE_TYPE_MASK		0x0f
+#define IONIC_PAUSE_FLAGS_MASK		0xf0
+#define IONIC_PAUSE_F_TX		0x10
+#define IONIC_PAUSE_F_RX		0x20
+		u8     pause_type;
+		u8     loopback_mode;
+	};
+	__le32 words[64];
+};
+
+/**
+ * Port Status information
+ * @status:             link status (enum ionic_port_oper_status)
+ * @id:                 port id
+ * @speed:              link speed (in Mbps)
+ * @xcvr:               tranceiver status
+ */
+struct ionic_port_status {
+	__le32 id;
+	__le32 speed;
+	u8     status;
+	u8     rsvd[51];
+	struct ionic_xcvr_status  xcvr;
+};
+
+/**
+ * struct ionic_port_identify_cmd - Port identify command
+ * @opcode:     opcode
+ * @index:      port index
+ * @ver:        Highest version of identify supported by driver
+ */
+struct ionic_port_identify_cmd {
+	u8 opcode;
+	u8 index;
+	u8 ver;
+	u8 rsvd[61];
+};
+
+/**
+ * struct ionic_port_identify_comp - Port identify command completion
+ * @status: The status of the command (enum status_code)
+ * @ver:    Version of identify returned by device
+ */
+struct ionic_port_identify_comp {
+	u8 status;
+	u8 ver;
+	u8 rsvd[14];
+};
+
+/**
+ * struct ionic_port_init_cmd - Port initialization command
+ * @opcode:     opcode
+ * @index:      port index
+ * @info_pa:    destination address for port info (struct ionic_port_info)
+ */
+struct ionic_port_init_cmd {
+	u8     opcode;
+	u8     index;
+	u8     rsvd[6];
+	__le64 info_pa;
+	u8     rsvd2[48];
+};
+
+/**
+ * struct ionic_port_init_comp - Port initialization command completion
+ * @status: The status of the command (enum status_code)
+ */
+struct ionic_port_init_comp {
+	u8 status;
+	u8 rsvd[15];
+};
+
+/**
+ * struct ionic_port_reset_cmd - Port reset command
+ * @opcode:     opcode
+ * @index:      port index
+ */
+struct ionic_port_reset_cmd {
+	u8 opcode;
+	u8 index;
+	u8 rsvd[62];
+};
+
+/**
+ * struct ionic_port_reset_comp - Port reset command completion
+ * @status: The status of the command (enum status_code)
+ */
+struct ionic_port_reset_comp {
+	u8 status;
+	u8 rsvd[15];
+};
+
+/**
+ * enum stats_ctl_cmd - List of commands for stats control
+ */
+enum ionic_stats_ctl_cmd {
+	IONIC_STATS_CTL_RESET		= 0,
+};
+
+
+/**
+ * enum ionic_port_attr - List of device attributes
+ */
+enum ionic_port_attr {
+	IONIC_PORT_ATTR_STATE		= 0,
+	IONIC_PORT_ATTR_SPEED		= 1,
+	IONIC_PORT_ATTR_MTU		= 2,
+	IONIC_PORT_ATTR_AUTONEG		= 3,
+	IONIC_PORT_ATTR_FEC		= 4,
+	IONIC_PORT_ATTR_PAUSE		= 5,
+	IONIC_PORT_ATTR_LOOPBACK	= 6,
+	IONIC_PORT_ATTR_STATS_CTRL	= 7,
+};
+
+/**
+ * struct ionic_port_setattr_cmd - Set port attributes on the NIC
+ * @opcode:     Opcode
+ * @index:      port index
+ * @attr:       Attribute type (enum ionic_port_attr)
+ */
+struct ionic_port_setattr_cmd {
+	u8     opcode;
+	u8     index;
+	u8     attr;
+	u8     rsvd;
+	union {
+		u8      state;
+		__le32  speed;
+		__le32  mtu;
+		u8      an_enable;
+		u8      fec_type;
+		u8      pause_type;
+		u8      loopback_mode;
+		u8	stats_ctl;
+		u8      rsvd2[60];
+	};
+};
+
+/**
+ * struct ionic_port_setattr_comp - Port set attr command completion
+ * @status:     The status of the command (enum status_code)
+ * @color:      Color bit
+ */
+struct ionic_port_setattr_comp {
+	u8     status;
+	u8     rsvd[14];
+	u8     color;
+};
+
+/**
+ * struct ionic_port_getattr_cmd - Get port attributes from the NIC
+ * @opcode:     Opcode
+ * @index:      port index
+ * @attr:       Attribute type (enum ionic_port_attr)
+ */
+struct ionic_port_getattr_cmd {
+	u8     opcode;
+	u8     index;
+	u8     attr;
+	u8     rsvd[61];
+};
+
+/**
+ * struct ionic_port_getattr_comp - Port get attr command completion
+ * @status:     The status of the command (enum status_code)
+ * @color:      Color bit
+ */
+struct ionic_port_getattr_comp {
+	u8     status;
+	u8     rsvd[3];
+	union {
+		u8      state;
+		__le32  speed;
+		__le32  mtu;
+		u8      an_enable;
+		u8      fec_type;
+		u8      pause_type;
+		u8      loopback_mode;
+		u8      rsvd2[11];
+	};
+	u8     color;
+};
+
+/**
+ * struct ionic_lif_status - Lif status register
+ * @eid:             most recent NotifyQ event id
+ * @port_num:        port the lif is connected to
+ * @link_status:     port status (enum ionic_port_oper_status)
+ * @link_speed:      speed of link in Mbps
+ * @link_down_count: number of times link status changes
+ */
+struct ionic_lif_status {
+	__le64 eid;
+	u8     port_num;
+	u8     rsvd;
+	__le16 link_status;
+	__le32 link_speed;		/* units of 1Mbps: eg 10000 = 10Gbps */
+	__le16 link_down_count;
+	u8      rsvd2[46];
+};
+
+/**
+ * struct ionic_lif_reset_cmd - LIF reset command
+ * @opcode:    opcode
+ * @index:     LIF index
+ */
+struct ionic_lif_reset_cmd {
+	u8     opcode;
+	u8     rsvd;
+	__le16 index;
+	__le32 rsvd2[15];
+};
+
+typedef struct ionic_admin_comp ionic_lif_reset_comp;
+
+enum ionic_dev_state {
+	IONIC_DEV_DISABLE	= 0,
+	IONIC_DEV_ENABLE	= 1,
+	IONIC_DEV_HANG_RESET	= 2,
+};
+
+/**
+ * enum ionic_dev_attr - List of device attributes
+ */
+enum ionic_dev_attr {
+	IONIC_DEV_ATTR_STATE    = 0,
+	IONIC_DEV_ATTR_NAME     = 1,
+	IONIC_DEV_ATTR_FEATURES = 2,
+};
+
+/**
+ * struct ionic_dev_setattr_cmd - Set Device attributes on the NIC
+ * @opcode:     Opcode
+ * @attr:       Attribute type (enum ionic_dev_attr)
+ * @state:      Device state (enum ionic_dev_state)
+ * @name:       The bus info, e.g. PCI slot-device-function, 0 terminated
+ * @features:   Device features
+ */
+struct ionic_dev_setattr_cmd {
+	u8     opcode;
+	u8     attr;
+	__le16 rsvd;
+	union {
+		u8      state;
+		char    name[IONIC_IFNAMSIZ];
+		__le64  features;
+		u8      rsvd2[60];
+	};
+};
+
+/**
+ * struct ionic_dev_setattr_comp - Device set attr command completion
+ * @status:     The status of the command (enum status_code)
+ * @features:   Device features
+ * @color:      Color bit
+ */
+struct ionic_dev_setattr_comp {
+	u8     status;
+	u8     rsvd[3];
+	union {
+		__le64  features;
+		u8      rsvd2[11];
+	};
+	u8     color;
+};
+
+/**
+ * struct ionic_dev_getattr_cmd - Get Device attributes from the NIC
+ * @opcode:     opcode
+ * @attr:       Attribute type (enum ionic_dev_attr)
+ */
+struct ionic_dev_getattr_cmd {
+	u8     opcode;
+	u8     attr;
+	u8     rsvd[62];
+};
+
+/**
+ * struct ionic_dev_setattr_comp - Device set attr command completion
+ * @status:     The status of the command (enum status_code)
+ * @features:   Device features
+ * @color:      Color bit
+ */
+struct ionic_dev_getattr_comp {
+	u8     status;
+	u8     rsvd[3];
+	union {
+		__le64  features;
+		u8      rsvd2[11];
+	};
+	u8     color;
+};
+
+/**
+ * RSS parameters
+ */
+#define IONIC_RSS_HASH_KEY_SIZE		40
+
+enum ionic_rss_hash_types {
+	IONIC_RSS_TYPE_IPV4	= BIT(0),
+	IONIC_RSS_TYPE_IPV4_TCP	= BIT(1),
+	IONIC_RSS_TYPE_IPV4_UDP	= BIT(2),
+	IONIC_RSS_TYPE_IPV6	= BIT(3),
+	IONIC_RSS_TYPE_IPV6_TCP	= BIT(4),
+	IONIC_RSS_TYPE_IPV6_UDP	= BIT(5),
+};
+
+/**
+ * enum ionic_lif_attr - List of LIF attributes
+ */
+enum ionic_lif_attr {
+	IONIC_LIF_ATTR_STATE        = 0,
+	IONIC_LIF_ATTR_NAME         = 1,
+	IONIC_LIF_ATTR_MTU          = 2,
+	IONIC_LIF_ATTR_MAC          = 3,
+	IONIC_LIF_ATTR_FEATURES     = 4,
+	IONIC_LIF_ATTR_RSS          = 5,
+	IONIC_LIF_ATTR_STATS_CTRL   = 6,
+};
+
+/**
+ * struct ionic_lif_setattr_cmd - Set LIF attributes on the NIC
+ * @opcode:     Opcode
+ * @type:       Attribute type (enum ionic_lif_attr)
+ * @index:      LIF index
+ * @state:      lif state (enum lif_state)
+ * @name:       The netdev name string, 0 terminated
+ * @mtu:        Mtu
+ * @mac:        Station mac
+ * @features:   Features (enum ionic_eth_hw_features)
+ * @rss:        RSS properties
+ *              @types:     The hash types to enable (see rss_hash_types).
+ *              @key:       The hash secret key.
+ *              @addr:      Address for the indirection table shared memory.
+ * @stats_ctl:  stats control commands (enum stats_ctl_cmd)
+ */
+struct ionic_lif_setattr_cmd {
+	u8     opcode;
+	u8     attr;
+	__le16 index;
+	union {
+		u8      state;
+		char    name[IONIC_IFNAMSIZ];
+		__le32  mtu;
+		u8      mac[6];
+		__le64  features;
+		struct {
+			__le16 types;
+			u8     key[IONIC_RSS_HASH_KEY_SIZE];
+			u8     rsvd[6];
+			__le64 addr;
+		} rss;
+		u8	stats_ctl;
+		u8      rsvd[60];
+	};
+};
+
+/**
+ * struct ionic_lif_setattr_comp - LIF set attr command completion
+ * @status:     The status of the command (enum status_code)
+ * @comp_index: The index in the descriptor ring for which this
+ *              is the completion.
+ * @features:   features (enum ionic_eth_hw_features)
+ * @color:      Color bit
+ */
+struct ionic_lif_setattr_comp {
+	u8     status;
+	u8     rsvd;
+	__le16 comp_index;
+	union {
+		__le64  features;
+		u8      rsvd2[11];
+	};
+	u8     color;
+};
+
+/**
+ * struct ionic_lif_getattr_cmd - Get LIF attributes from the NIC
+ * @opcode:     Opcode
+ * @attr:       Attribute type (enum ionic_lif_attr)
+ * @index:      LIF index
+ */
+struct ionic_lif_getattr_cmd {
+	u8     opcode;
+	u8     attr;
+	__le16 index;
+	u8     rsvd[60];
+};
+
+/**
+ * struct ionic_lif_getattr_comp - LIF get attr command completion
+ * @status:     The status of the command (enum status_code)
+ * @comp_index: The index in the descriptor ring for which this
+ *              is the completion.
+ * @state:      lif state (enum lif_state)
+ * @name:       The netdev name string, 0 terminated
+ * @mtu:        Mtu
+ * @mac:        Station mac
+ * @features:   Features (enum ionic_eth_hw_features)
+ * @color:      Color bit
+ */
+struct ionic_lif_getattr_comp {
+	u8     status;
+	u8     rsvd;
+	__le16 comp_index;
+	union {
+		u8      state;
+		__le32  mtu;
+		u8      mac[6];
+		__le64  features;
+		u8      rsvd2[11];
+	};
+	u8     color;
+};
+
+enum ionic_rx_mode {
+	IONIC_RX_MODE_F_UNICAST    = BIT(0),
+	IONIC_RX_MODE_F_MULTICAST  = BIT(1),
+	IONIC_RX_MODE_F_BROADCAST  = BIT(2),
+	IONIC_RX_MODE_F_PROMISC    = BIT(3),
+	IONIC_RX_MODE_F_ALLMULTI   = BIT(4),
+};
+
+/**
+ * struct ionic_rx_mode_set_cmd - Set LIF's Rx mode command
+ * @opcode:     opcode
+ * @lif_index:  LIF index
+ * @rx_mode:    Rx mode flags:
+ *                  IONIC_RX_MODE_F_UNICAST: Accept known unicast packets.
+ *                  IONIC_RX_MODE_F_MULTICAST: Accept known multicast packets.
+ *                  IONIC_RX_MODE_F_BROADCAST: Accept broadcast packets.
+ *                  IONIC_RX_MODE_F_PROMISC: Accept any packets.
+ *                  IONIC_RX_MODE_F_ALLMULTI: Accept any multicast packets.
+ */
+struct ionic_rx_mode_set_cmd {
+	u8     opcode;
+	u8     rsvd;
+	__le16 lif_index;
+	__le16 rx_mode;
+	__le16 rsvd2[29];
+};
+
+typedef struct ionic_admin_comp ionic_rx_mode_set_comp;
+
+enum ionic_rx_filter_match_type {
+	IONIC_RX_FILTER_MATCH_VLAN = 0,
+	IONIC_RX_FILTER_MATCH_MAC,
+	IONIC_RX_FILTER_MATCH_MAC_VLAN,
+};
+
+/**
+ * struct ionic_rx_filter_add_cmd - Add LIF Rx filter command
+ * @opcode:     opcode
+ * @qtype:      Queue type
+ * @lif_index:  LIF index
+ * @qid:        Queue ID
+ * @match:      Rx filter match type.  (See IONIC_RX_FILTER_MATCH_xxx)
+ * @vlan:       VLAN ID
+ * @addr:       MAC address (network-byte order)
+ */
+struct ionic_rx_filter_add_cmd {
+	u8     opcode;
+	u8     qtype;
+	__le16 lif_index;
+	__le32 qid;
+	__le16 match;
+	union {
+		struct {
+			__le16 vlan;
+		} vlan;
+		struct {
+			u8     addr[6];
+		} mac;
+		struct {
+			__le16 vlan;
+			u8     addr[6];
+		} mac_vlan;
+		u8 rsvd[54];
+	};
+};
+
+/**
+ * struct ionic_rx_filter_add_comp - Add LIF Rx filter command completion
+ * @status:     The status of the command (enum status_code)
+ * @comp_index: The index in the descriptor ring for which this
+ *              is the completion.
+ * @filter_id:  Filter ID
+ * @color:      Color bit.
+ */
+struct ionic_rx_filter_add_comp {
+	u8     status;
+	u8     rsvd;
+	__le16 comp_index;
+	__le32 filter_id;
+	u8     rsvd2[7];
+	u8     color;
+};
+
+/**
+ * struct ionic_rx_filter_del_cmd - Delete LIF Rx filter command
+ * @opcode:     opcode
+ * @lif_index:  LIF index
+ * @filter_id:  Filter ID
+ */
+struct ionic_rx_filter_del_cmd {
+	u8     opcode;
+	u8     rsvd;
+	__le16 lif_index;
+	__le32 filter_id;
+	u8     rsvd2[56];
+};
+
+typedef struct ionic_admin_comp ionic_rx_filter_del_comp;
+
+/**
+ * struct ionic_qos_identify_cmd - QoS identify command
+ * @opcode:    opcode
+ * @ver:     Highest version of identify supported by driver
+ *
+ */
+struct ionic_qos_identify_cmd {
+	u8 opcode;
+	u8 ver;
+	u8 rsvd[62];
+};
+
+/**
+ * struct ionic_qos_identify_comp - QoS identify command completion
+ * @status: The status of the command (enum status_code)
+ * @ver:    Version of identify returned by device
+ */
+struct ionic_qos_identify_comp {
+	u8 status;
+	u8 ver;
+	u8 rsvd[14];
+};
+
+#define IONIC_QOS_CLASS_MAX		7
+#define IONIC_QOS_CLASS_NAME_SZ		32
+#define IONIC_QOS_DSCP_MAX_VALUES	64
+
+/**
+ * enum ionic_qos_class
+ */
+enum ionic_qos_class {
+	IONIC_QOS_CLASS_DEFAULT		= 0,
+	IONIC_QOS_CLASS_USER_DEFINED_1	= 1,
+	IONIC_QOS_CLASS_USER_DEFINED_2	= 2,
+	IONIC_QOS_CLASS_USER_DEFINED_3	= 3,
+	IONIC_QOS_CLASS_USER_DEFINED_4	= 4,
+	IONIC_QOS_CLASS_USER_DEFINED_5	= 5,
+	IONIC_QOS_CLASS_USER_DEFINED_6	= 6,
+};
+
+/**
+ * enum ionic_qos_class_type - Traffic classification criteria
+ */
+enum ionic_qos_class_type {
+	IONIC_QOS_CLASS_TYPE_NONE	= 0,
+	IONIC_QOS_CLASS_TYPE_PCP	= 1,	/* Dot1Q pcp */
+	IONIC_QOS_CLASS_TYPE_DSCP	= 2,	/* IP dscp */
+};
+
+/**
+ * enum ionic_qos_sched_type - Qos class scheduling type
+ */
+enum ionic_qos_sched_type {
+	/* Strict priority */
+	IONIC_QOS_SCHED_TYPE_STRICT	= 0,
+	/* Deficit weighted round-robin */
+	IONIC_QOS_SCHED_TYPE_DWRR	= 1,
+};
+
+/**
+ * union ionic_qos_config - Qos configuration structure
+ * @flags:		Configuration flags
+ *	IONIC_QOS_CONFIG_F_ENABLE		enable
+ *	IONIC_QOS_CONFIG_F_DROP			drop/nodrop
+ *	IONIC_QOS_CONFIG_F_RW_DOT1Q_PCP		enable dot1q pcp rewrite
+ *	IONIC_QOS_CONFIG_F_RW_IP_DSCP		enable ip dscp rewrite
+ * @sched_type:		Qos class scheduling type (enum ionic_qos_sched_type)
+ * @class_type:		Qos class type (enum ionic_qos_class_type)
+ * @pause_type:		Qos pause type (enum qos_pause_type)
+ * @name:		Qos class name
+ * @mtu:		MTU of the class
+ * @pfc_dot1q_pcp:	Pcp value for pause frames (valid iff F_NODROP)
+ * @dwrr_weight:	Qos class scheduling weight
+ * @strict_rlmt:	Rate limit for strict priority scheduling
+ * @rw_dot1q_pcp:	Rewrite dot1q pcp to this value
+ *			(valid iff F_RW_DOT1Q_PCP)
+ * @rw_ip_dscp:		Rewrite ip dscp to this value
+ *			(valid iff F_RW_IP_DSCP)
+ * @dot1q_pcp:		Dot1q pcp value
+ * @ndscp:		Number of valid dscp values in the ip_dscp field
+ * @ip_dscp:		IP dscp values
+ */
+union ionic_qos_config {
+	struct {
+#define IONIC_QOS_CONFIG_F_ENABLE		BIT(0)
+#define IONIC_QOS_CONFIG_F_DROP			BIT(1)
+#define IONIC_QOS_CONFIG_F_RW_DOT1Q_PCP		BIT(2)
+#define IONIC_QOS_CONFIG_F_RW_IP_DSCP		BIT(3)
+		u8      flags;
+		u8      sched_type;
+		u8      class_type;
+		u8      pause_type;
+		char    name[IONIC_QOS_CLASS_NAME_SZ];
+		__le32  mtu;
+		/* flow control */
+		u8      pfc_cos;
+		/* scheduler */
+		union {
+			u8      dwrr_weight;
+			__le64  strict_rlmt;
+		};
+		/* marking */
+		union {
+			u8      rw_dot1q_pcp;
+			u8      rw_ip_dscp;
+		};
+		/* classification */
+		union {
+			u8      dot1q_pcp;
+			struct {
+				u8      ndscp;
+				u8      ip_dscp[IONIC_QOS_DSCP_MAX_VALUES];
+			};
+		};
+	};
+	__le32  words[64];
+};
+
+/**
+ * union ionic_qos_identity - QoS identity structure
+ * @version:	Version of the identify structure
+ * @type:	QoS system type
+ * @nclasses:	Number of usable QoS classes
+ * @config:	Current configuration of classes
+ */
+union ionic_qos_identity {
+	struct {
+		u8     version;
+		u8     type;
+		u8     rsvd[62];
+		union  ionic_qos_config config[IONIC_QOS_CLASS_MAX];
+	};
+	__le32 words[512];
+};
+
+/**
+ * struct qos_init_cmd - QoS config init command
+ * @opcode:	Opcode
+ * @group:	Qos class id
+ * @info_pa:	destination address for qos info
+ */
+struct ionic_qos_init_cmd {
+	u8     opcode;
+	u8     group;
+	u8     rsvd[6];
+	__le64 info_pa;
+	u8     rsvd1[48];
+};
+
+typedef struct ionic_admin_comp ionic_qos_init_comp;
+
+/**
+ * struct ionic_qos_reset_cmd - Qos config reset command
+ * @opcode:	Opcode
+ */
+struct ionic_qos_reset_cmd {
+	u8    opcode;
+	u8    group;
+	u8    rsvd[62];
+};
+
+typedef struct ionic_admin_comp ionic_qos_reset_comp;
+
+/**
+ * struct ionic_fw_download_cmd - Firmware download command
+ * @opcode:	opcode
+ * @addr:	dma address of the firmware buffer
+ * @offset:	offset of the firmware buffer within the full image
+ * @length:	number of valid bytes in the firmware buffer
+ */
+struct ionic_fw_download_cmd {
+	u8     opcode;
+	u8     rsvd[3];
+	__le32 offset;
+	__le64 addr;
+	__le32 length;
+};
+
+typedef struct ionic_admin_comp ionic_fw_download_comp;
+
+enum ionic_fw_control_oper {
+	IONIC_FW_RESET		= 0,	/* Reset firmware */
+	IONIC_FW_INSTALL	= 1,	/* Install firmware */
+	IONIC_FW_ACTIVATE	= 2,	/* Activate firmware */
+};
+
+/**
+ * struct ionic_fw_control_cmd - Firmware control command
+ * @opcode:    opcode
+ * @oper:      firmware control operation (enum ionic_fw_control_oper)
+ * @slot:      slot to activate
+ */
+struct ionic_fw_control_cmd {
+	u8  opcode;
+	u8  rsvd[3];
+	u8  oper;
+	u8  slot;
+	u8  rsvd1[58];
+};
+
+/**
+ * struct ionic_fw_control_comp - Firmware control copletion
+ * @opcode:    opcode
+ * @slot:      slot where the firmware was installed
+ */
+struct ionic_fw_control_comp {
+	u8     status;
+	u8     rsvd;
+	__le16 comp_index;
+	u8     slot;
+	u8     rsvd1[10];
+	u8     color;
+};
+
+/******************************************************************
+ ******************* RDMA Commands ********************************
+ ******************************************************************/
+
+/**
+ * struct ionic_rdma_reset_cmd - Reset RDMA LIF cmd
+ * @opcode:        opcode
+ * @lif_index:     lif index
+ *
+ * There is no rdma specific dev command completion struct.  Completion uses
+ * the common struct ionic_admin_comp.  Only the status is indicated.
+ * Nonzero status means the LIF does not support rdma.
+ **/
+struct ionic_rdma_reset_cmd {
+	u8     opcode;
+	u8     rsvd;
+	__le16 lif_index;
+	u8     rsvd2[60];
+};
+
+/**
+ * struct ionic_rdma_queue_cmd - Create RDMA Queue command
+ * @opcode:        opcode, 52, 53
+ * @lif_index      lif index
+ * @qid_ver:       (qid | (rdma version << 24))
+ * @cid:           intr, eq_id, or cq_id
+ * @dbid:          doorbell page id
+ * @depth_log2:    log base two of queue depth
+ * @stride_log2:   log base two of queue stride
+ * @dma_addr:      address of the queue memory
+ * @xxx_table_index: temporary, but should not need pgtbl for contig. queues.
+ *
+ * The same command struct is used to create an rdma event queue, completion
+ * queue, or rdma admin queue.  The cid is an interrupt number for an event
+ * queue, an event queue id for a completion queue, or a completion queue id
+ * for an rdma admin queue.
+ *
+ * The queue created via a dev command must be contiguous in dma space.
+ *
+ * The dev commands are intended only to be used during driver initialization,
+ * to create queues supporting the rdma admin queue.  Other queues, and other
+ * types of rdma resources like memory regions, will be created and registered
+ * via the rdma admin queue, and will support a more complete interface
+ * providing scatter gather lists for larger, scattered queue buffers and
+ * memory registration.
+ *
+ * There is no rdma specific dev command completion struct.  Completion uses
+ * the common struct ionic_admin_comp.  Only the status is indicated.
+ **/
+struct ionic_rdma_queue_cmd {
+	u8     opcode;
+	u8     rsvd;
+	__le16 lif_index;
+	__le32 qid_ver;
+	__le32 cid;
+	__le16 dbid;
+	u8     depth_log2;
+	u8     stride_log2;
+	__le64 dma_addr;
+	u8     rsvd2[36];
+	__le32 xxx_table_index;
+};
+
+/******************************************************************
+ ******************* Notify Events ********************************
+ ******************************************************************/
+
+/**
+ * struct ionic_notifyq_event
+ * @eid:   event number
+ * @ecode: event code
+ * @data:  unspecified data about the event
+ *
+ * This is the generic event report struct from which the other
+ * actual events will be formed.
+ */
+struct ionic_notifyq_event {
+	__le64 eid;
+	__le16 ecode;
+	u8     data[54];
+};
+
+/**
+ * struct ionic_link_change_event
+ * @eid:		event number
+ * @ecode:		event code = EVENT_OPCODE_LINK_CHANGE
+ * @link_status:	link up or down, with error bits (enum port_status)
+ * @link_speed:		speed of the network link
+ *
+ * Sent when the network link state changes between UP and DOWN
+ */
+struct ionic_link_change_event {
+	__le64 eid;
+	__le16 ecode;
+	__le16 link_status;
+	__le32 link_speed;	/* units of 1Mbps: e.g. 10000 = 10Gbps */
+	u8     rsvd[48];
+};
+
+/**
+ * struct ionic_reset_event
+ * @eid:		event number
+ * @ecode:		event code = EVENT_OPCODE_RESET
+ * @reset_code:		reset type
+ * @state:		0=pending, 1=complete, 2=error
+ *
+ * Sent when the NIC or some subsystem is going to be or
+ * has been reset.
+ */
+struct ionic_reset_event {
+	__le64 eid;
+	__le16 ecode;
+	u8     reset_code;
+	u8     state;
+	u8     rsvd[52];
+};
+
+/**
+ * struct ionic_heartbeat_event
+ * @eid:	event number
+ * @ecode:	event code = EVENT_OPCODE_HEARTBEAT
+ *
+ * Sent periodically by the NIC to indicate continued health
+ */
+struct ionic_heartbeat_event {
+	__le64 eid;
+	__le16 ecode;
+	u8     rsvd[54];
+};
+
+/**
+ * struct ionic_log_event
+ * @eid:	event number
+ * @ecode:	event code = EVENT_OPCODE_LOG
+ * @data:	log data
+ *
+ * Sent to notify the driver of an internal error.
+ */
+struct ionic_log_event {
+	__le64 eid;
+	__le16 ecode;
+	u8     data[54];
+};
+
+/**
+ * struct ionic_port_stats
+ */
+struct ionic_port_stats {
+	__le64 frames_rx_ok;
+	__le64 frames_rx_all;
+	__le64 frames_rx_bad_fcs;
+	__le64 frames_rx_bad_all;
+	__le64 octets_rx_ok;
+	__le64 octets_rx_all;
+	__le64 frames_rx_unicast;
+	__le64 frames_rx_multicast;
+	__le64 frames_rx_broadcast;
+	__le64 frames_rx_pause;
+	__le64 frames_rx_bad_length;
+	__le64 frames_rx_undersized;
+	__le64 frames_rx_oversized;
+	__le64 frames_rx_fragments;
+	__le64 frames_rx_jabber;
+	__le64 frames_rx_pripause;
+	__le64 frames_rx_stomped_crc;
+	__le64 frames_rx_too_long;
+	__le64 frames_rx_vlan_good;
+	__le64 frames_rx_dropped;
+	__le64 frames_rx_less_than_64b;
+	__le64 frames_rx_64b;
+	__le64 frames_rx_65b_127b;
+	__le64 frames_rx_128b_255b;
+	__le64 frames_rx_256b_511b;
+	__le64 frames_rx_512b_1023b;
+	__le64 frames_rx_1024b_1518b;
+	__le64 frames_rx_1519b_2047b;
+	__le64 frames_rx_2048b_4095b;
+	__le64 frames_rx_4096b_8191b;
+	__le64 frames_rx_8192b_9215b;
+	__le64 frames_rx_other;
+	__le64 frames_tx_ok;
+	__le64 frames_tx_all;
+	__le64 frames_tx_bad;
+	__le64 octets_tx_ok;
+	__le64 octets_tx_total;
+	__le64 frames_tx_unicast;
+	__le64 frames_tx_multicast;
+	__le64 frames_tx_broadcast;
+	__le64 frames_tx_pause;
+	__le64 frames_tx_pripause;
+	__le64 frames_tx_vlan;
+	__le64 frames_tx_less_than_64b;
+	__le64 frames_tx_64b;
+	__le64 frames_tx_65b_127b;
+	__le64 frames_tx_128b_255b;
+	__le64 frames_tx_256b_511b;
+	__le64 frames_tx_512b_1023b;
+	__le64 frames_tx_1024b_1518b;
+	__le64 frames_tx_1519b_2047b;
+	__le64 frames_tx_2048b_4095b;
+	__le64 frames_tx_4096b_8191b;
+	__le64 frames_tx_8192b_9215b;
+	__le64 frames_tx_other;
+	__le64 frames_tx_pri_0;
+	__le64 frames_tx_pri_1;
+	__le64 frames_tx_pri_2;
+	__le64 frames_tx_pri_3;
+	__le64 frames_tx_pri_4;
+	__le64 frames_tx_pri_5;
+	__le64 frames_tx_pri_6;
+	__le64 frames_tx_pri_7;
+	__le64 frames_rx_pri_0;
+	__le64 frames_rx_pri_1;
+	__le64 frames_rx_pri_2;
+	__le64 frames_rx_pri_3;
+	__le64 frames_rx_pri_4;
+	__le64 frames_rx_pri_5;
+	__le64 frames_rx_pri_6;
+	__le64 frames_rx_pri_7;
+	__le64 tx_pripause_0_1us_count;
+	__le64 tx_pripause_1_1us_count;
+	__le64 tx_pripause_2_1us_count;
+	__le64 tx_pripause_3_1us_count;
+	__le64 tx_pripause_4_1us_count;
+	__le64 tx_pripause_5_1us_count;
+	__le64 tx_pripause_6_1us_count;
+	__le64 tx_pripause_7_1us_count;
+	__le64 rx_pripause_0_1us_count;
+	__le64 rx_pripause_1_1us_count;
+	__le64 rx_pripause_2_1us_count;
+	__le64 rx_pripause_3_1us_count;
+	__le64 rx_pripause_4_1us_count;
+	__le64 rx_pripause_5_1us_count;
+	__le64 rx_pripause_6_1us_count;
+	__le64 rx_pripause_7_1us_count;
+	__le64 rx_pause_1us_count;
+	__le64 frames_tx_truncated;
+};
+
+struct ionic_mgmt_port_stats {
+	__le64 frames_rx_ok;
+	__le64 frames_rx_all;
+	__le64 frames_rx_bad_fcs;
+	__le64 frames_rx_bad_all;
+	__le64 octets_rx_ok;
+	__le64 octets_rx_all;
+	__le64 frames_rx_unicast;
+	__le64 frames_rx_multicast;
+	__le64 frames_rx_broadcast;
+	__le64 frames_rx_pause;
+	__le64 frames_rx_bad_length0;
+	__le64 frames_rx_undersized1;
+	__le64 frames_rx_oversized2;
+	__le64 frames_rx_fragments3;
+	__le64 frames_rx_jabber4;
+	__le64 frames_rx_64b5;
+	__le64 frames_rx_65b_127b6;
+	__le64 frames_rx_128b_255b7;
+	__le64 frames_rx_256b_511b8;
+	__le64 frames_rx_512b_1023b9;
+	__le64 frames_rx_1024b_1518b0;
+	__le64 frames_rx_gt_1518b1;
+	__le64 frames_rx_fifo_full2;
+	__le64 frames_tx_ok3;
+	__le64 frames_tx_all4;
+	__le64 frames_tx_bad5;
+	__le64 octets_tx_ok6;
+	__le64 octets_tx_total7;
+	__le64 frames_tx_unicast8;
+	__le64 frames_tx_multicast9;
+	__le64 frames_tx_broadcast0;
+	__le64 frames_tx_pause1;
+};
+
+/**
+ * struct ionic_port_identity - port identity structure
+ * @version:        identity structure version
+ * @type:           type of port (enum port_type)
+ * @num_lanes:      number of lanes for the port
+ * @autoneg:        autoneg supported
+ * @min_frame_size: minimum frame size supported
+ * @max_frame_size: maximum frame size supported
+ * @fec_type:       supported fec types
+ * @pause_type:     supported pause types
+ * @loopback_mode:  supported loopback mode
+ * @speeds:         supported speeds
+ * @config:         current port configuration
+ */
+union ionic_port_identity {
+	struct {
+		u8     version;
+		u8     type;
+		u8     num_lanes;
+		u8     autoneg;
+		__le32 min_frame_size;
+		__le32 max_frame_size;
+		u8     fec_type[4];
+		u8     pause_type[2];
+		u8     loopback_mode[2];
+		__le32 speeds[16];
+		u8     rsvd2[44];
+		union ionic_port_config config;
+	};
+	__le32 words[512];
+};
+
+/**
+ * struct ionic_port_info - port info structure
+ * @port_status:     port status
+ * @port_stats:      port stats
+ */
+struct ionic_port_info {
+	union ionic_port_config config;
+	struct ionic_port_status status;
+	struct ionic_port_stats stats;
+};
+
+/**
+ * struct ionic_lif_stats
+ */
+struct ionic_lif_stats {
+	/* RX */
+	__le64 rx_ucast_bytes;
+	__le64 rx_ucast_packets;
+	__le64 rx_mcast_bytes;
+	__le64 rx_mcast_packets;
+	__le64 rx_bcast_bytes;
+	__le64 rx_bcast_packets;
+	__le64 rsvd0;
+	__le64 rsvd1;
+	/* RX drops */
+	__le64 rx_ucast_drop_bytes;
+	__le64 rx_ucast_drop_packets;
+	__le64 rx_mcast_drop_bytes;
+	__le64 rx_mcast_drop_packets;
+	__le64 rx_bcast_drop_bytes;
+	__le64 rx_bcast_drop_packets;
+	__le64 rx_dma_error;
+	__le64 rsvd2;
+	/* TX */
+	__le64 tx_ucast_bytes;
+	__le64 tx_ucast_packets;
+	__le64 tx_mcast_bytes;
+	__le64 tx_mcast_packets;
+	__le64 tx_bcast_bytes;
+	__le64 tx_bcast_packets;
+	__le64 rsvd3;
+	__le64 rsvd4;
+	/* TX drops */
+	__le64 tx_ucast_drop_bytes;
+	__le64 tx_ucast_drop_packets;
+	__le64 tx_mcast_drop_bytes;
+	__le64 tx_mcast_drop_packets;
+	__le64 tx_bcast_drop_bytes;
+	__le64 tx_bcast_drop_packets;
+	__le64 tx_dma_error;
+	__le64 rsvd5;
+	/* Rx Queue/Ring drops */
+	__le64 rx_queue_disabled;
+	__le64 rx_queue_empty;
+	__le64 rx_queue_error;
+	__le64 rx_desc_fetch_error;
+	__le64 rx_desc_data_error;
+	__le64 rsvd6;
+	__le64 rsvd7;
+	__le64 rsvd8;
+	/* Tx Queue/Ring drops */
+	__le64 tx_queue_disabled;
+	__le64 tx_queue_error;
+	__le64 tx_desc_fetch_error;
+	__le64 tx_desc_data_error;
+	__le64 rsvd9;
+	__le64 rsvd10;
+	__le64 rsvd11;
+	__le64 rsvd12;
+
+	/* RDMA/ROCE TX */
+	__le64 tx_rdma_ucast_bytes;
+	__le64 tx_rdma_ucast_packets;
+	__le64 tx_rdma_mcast_bytes;
+	__le64 tx_rdma_mcast_packets;
+	__le64 tx_rdma_cnp_packets;
+	__le64 rsvd13;
+	__le64 rsvd14;
+	__le64 rsvd15;
+
+	/* RDMA/ROCE RX */
+	__le64 rx_rdma_ucast_bytes;
+	__le64 rx_rdma_ucast_packets;
+	__le64 rx_rdma_mcast_bytes;
+	__le64 rx_rdma_mcast_packets;
+	__le64 rx_rdma_cnp_packets;
+	__le64 rx_rdma_ecn_packets;
+	__le64 rsvd16;
+	__le64 rsvd17;
+
+	__le64 rsvd18;
+	__le64 rsvd19;
+	__le64 rsvd20;
+	__le64 rsvd21;
+	__le64 rsvd22;
+	__le64 rsvd23;
+	__le64 rsvd24;
+	__le64 rsvd25;
+
+	__le64 rsvd26;
+	__le64 rsvd27;
+	__le64 rsvd28;
+	__le64 rsvd29;
+	__le64 rsvd30;
+	__le64 rsvd31;
+	__le64 rsvd32;
+	__le64 rsvd33;
+
+	__le64 rsvd34;
+	__le64 rsvd35;
+	__le64 rsvd36;
+	__le64 rsvd37;
+	__le64 rsvd38;
+	__le64 rsvd39;
+	__le64 rsvd40;
+	__le64 rsvd41;
+
+	__le64 rsvd42;
+	__le64 rsvd43;
+	__le64 rsvd44;
+	__le64 rsvd45;
+	__le64 rsvd46;
+	__le64 rsvd47;
+	__le64 rsvd48;
+	__le64 rsvd49;
+
+	/* RDMA/ROCE REQ Error/Debugs (768 - 895) */
+	__le64 rdma_req_rx_pkt_seq_err;
+	__le64 rdma_req_rx_rnr_retry_err;
+	__le64 rdma_req_rx_remote_access_err;
+	__le64 rdma_req_rx_remote_inv_req_err;
+	__le64 rdma_req_rx_remote_oper_err;
+	__le64 rdma_req_rx_implied_nak_seq_err;
+	__le64 rdma_req_rx_cqe_err;
+	__le64 rdma_req_rx_cqe_flush_err;
+
+	__le64 rdma_req_rx_dup_responses;
+	__le64 rdma_req_rx_invalid_packets;
+	__le64 rdma_req_tx_local_access_err;
+	__le64 rdma_req_tx_local_oper_err;
+	__le64 rdma_req_tx_memory_mgmt_err;
+	__le64 rsvd52;
+	__le64 rsvd53;
+	__le64 rsvd54;
+
+	/* RDMA/ROCE RESP Error/Debugs (896 - 1023) */
+	__le64 rdma_resp_rx_dup_requests;
+	__le64 rdma_resp_rx_out_of_buffer;
+	__le64 rdma_resp_rx_out_of_seq_pkts;
+	__le64 rdma_resp_rx_cqe_err;
+	__le64 rdma_resp_rx_cqe_flush_err;
+	__le64 rdma_resp_rx_local_len_err;
+	__le64 rdma_resp_rx_inv_request_err;
+	__le64 rdma_resp_rx_local_qp_oper_err;
+
+	__le64 rdma_resp_rx_out_of_atomic_resource;
+	__le64 rdma_resp_tx_pkt_seq_err;
+	__le64 rdma_resp_tx_remote_inv_req_err;
+	__le64 rdma_resp_tx_remote_access_err;
+	__le64 rdma_resp_tx_remote_oper_err;
+	__le64 rdma_resp_tx_rnr_retry_err;
+	__le64 rsvd57;
+	__le64 rsvd58;
+};
+
+/**
+ * struct ionic_lif_info - lif info structure
+ */
+struct ionic_lif_info {
+	union ionic_lif_config config;
+	struct ionic_lif_status status;
+	struct ionic_lif_stats stats;
+};
+
+union ionic_dev_cmd {
+	u32 words[16];
+	struct ionic_admin_cmd cmd;
+	struct ionic_nop_cmd nop;
+
+	struct ionic_dev_identify_cmd identify;
+	struct ionic_dev_init_cmd init;
+	struct ionic_dev_reset_cmd reset;
+	struct ionic_dev_getattr_cmd getattr;
+	struct ionic_dev_setattr_cmd setattr;
+
+	struct ionic_port_identify_cmd port_identify;
+	struct ionic_port_init_cmd port_init;
+	struct ionic_port_reset_cmd port_reset;
+	struct ionic_port_getattr_cmd port_getattr;
+	struct ionic_port_setattr_cmd port_setattr;
+
+	struct ionic_lif_identify_cmd lif_identify;
+	struct ionic_lif_init_cmd lif_init;
+	struct ionic_lif_reset_cmd lif_reset;
+
+	struct ionic_qos_identify_cmd qos_identify;
+	struct ionic_qos_init_cmd qos_init;
+	struct ionic_qos_reset_cmd qos_reset;
+
+	struct ionic_q_init_cmd q_init;
+};
+
+union ionic_dev_cmd_comp {
+	u32 words[4];
+	u8 status;
+	struct ionic_admin_comp comp;
+	struct ionic_nop_comp nop;
+
+	struct ionic_dev_identify_comp identify;
+	struct ionic_dev_init_comp init;
+	struct ionic_dev_reset_comp reset;
+	struct ionic_dev_getattr_comp getattr;
+	struct ionic_dev_setattr_comp setattr;
+
+	struct ionic_port_identify_comp port_identify;
+	struct ionic_port_init_comp port_init;
+	struct ionic_port_reset_comp port_reset;
+	struct ionic_port_getattr_comp port_getattr;
+	struct ionic_port_setattr_comp port_setattr;
+
+	struct ionic_lif_identify_comp lif_identify;
+	struct ionic_lif_init_comp lif_init;
+	ionic_lif_reset_comp lif_reset;
+
+	struct ionic_qos_identify_comp qos_identify;
+	ionic_qos_init_comp qos_init;
+	ionic_qos_reset_comp qos_reset;
+
+	struct ionic_q_init_comp q_init;
+};
+
+/**
+ * union dev_info - Device info register format (read-only)
+ * @signature:       Signature value of 0x44455649 ('DEVI').
+ * @version:         Current version of info.
+ * @asic_type:       Asic type.
+ * @asic_rev:        Asic revision.
+ * @fw_status:       Firmware status.
+ * @fw_heartbeat:    Firmware heartbeat counter.
+ * @serial_num:      Serial number.
+ * @fw_version:      Firmware version.
+ */
+union ionic_dev_info_regs {
+#define IONIC_DEVINFO_FWVERS_BUFLEN 32
+#define IONIC_DEVINFO_SERIAL_BUFLEN 32
+	struct {
+		u32    signature;
+		u8     version;
+		u8     asic_type;
+		u8     asic_rev;
+		u8     fw_status;
+		u32    fw_heartbeat;
+		char   fw_version[IONIC_DEVINFO_FWVERS_BUFLEN];
+		char   serial_num[IONIC_DEVINFO_SERIAL_BUFLEN];
+	};
+	u32 words[512];
+};
+
+/**
+ * union ionic_dev_cmd_regs - Device command register format (read-write)
+ * @doorbell:        Device Cmd Doorbell, write-only.
+ *                   Write a 1 to signal device to process cmd,
+ *                   poll done for completion.
+ * @done:            Done indicator, bit 0 == 1 when command is complete.
+ * @cmd:             Opcode-specific command bytes
+ * @comp:            Opcode-specific response bytes
+ * @data:            Opcode-specific side-data
+ */
+union ionic_dev_cmd_regs {
+	struct {
+		u32                   doorbell;
+		u32                   done;
+		union ionic_dev_cmd         cmd;
+		union ionic_dev_cmd_comp    comp;
+		u8                    rsvd[48];
+		u32                   data[478];
+	};
+	u32 words[512];
+};
+
+/**
+ * union ionic_dev_regs - Device register format in for bar 0 page 0
+ * @info:            Device info registers
+ * @devcmd:          Device command registers
+ */
+union ionic_dev_regs {
+	struct {
+		union ionic_dev_info_regs info;
+		union ionic_dev_cmd_regs  devcmd;
+	};
+	__le32 words[1024];
+};
+
+union ionic_adminq_cmd {
+	struct ionic_admin_cmd cmd;
+	struct ionic_nop_cmd nop;
+	struct ionic_q_init_cmd q_init;
+	struct ionic_q_control_cmd q_control;
+	struct ionic_lif_setattr_cmd lif_setattr;
+	struct ionic_lif_getattr_cmd lif_getattr;
+	struct ionic_rx_mode_set_cmd rx_mode_set;
+	struct ionic_rx_filter_add_cmd rx_filter_add;
+	struct ionic_rx_filter_del_cmd rx_filter_del;
+	struct ionic_rdma_reset_cmd rdma_reset;
+	struct ionic_rdma_queue_cmd rdma_queue;
+	struct ionic_fw_download_cmd fw_download;
+	struct ionic_fw_control_cmd fw_control;
+};
+
+union ionic_adminq_comp {
+	struct ionic_admin_comp comp;
+	struct ionic_nop_comp nop;
+	struct ionic_q_init_comp q_init;
+	struct ionic_lif_setattr_comp lif_setattr;
+	struct ionic_lif_getattr_comp lif_getattr;
+	struct ionic_rx_filter_add_comp rx_filter_add;
+	struct ionic_fw_control_comp fw_control;
+};
+
+#define IONIC_BARS_MAX			6
+#define IONIC_PCI_BAR_DBELL		1
+
+/* BAR0 */
+#define IONIC_BAR0_SIZE				0x8000
+
+#define IONIC_BAR0_DEV_INFO_REGS_OFFSET		0x0000
+#define IONIC_BAR0_DEV_CMD_REGS_OFFSET		0x0800
+#define IONIC_BAR0_DEV_CMD_DATA_REGS_OFFSET	0x0c00
+#define IONIC_BAR0_INTR_STATUS_OFFSET		0x1000
+#define IONIC_BAR0_INTR_CTRL_OFFSET		0x2000
+#define IONIC_DEV_CMD_DONE			0x00000001
+
+#define IONIC_ASIC_TYPE_CAPRI			0
+
+/**
+ * struct ionic_doorbell - Doorbell register layout
+ * @p_index: Producer index
+ * @ring:    Selects the specific ring of the queue to update.
+ *           Type-specific meaning:
+ *              ring=0: Default producer/consumer queue.
+ *              ring=1: (CQ, EQ) Re-Arm queue.  RDMA CQs
+ *              send events to EQs when armed.  EQs send
+ *              interrupts when armed.
+ * @qid:     The queue id selects the queue destination for the
+ *           producer index and flags.
+ */
+struct ionic_doorbell {
+	__le16 p_index;
+	u8     ring;
+	u8     qid_lo;
+	__le16 qid_hi;
+	u16    rsvd2;
+};
+
+struct ionic_intr_status {
+	u32 status[2];
+};
+
+struct ionic_notifyq_cmd {
+	__le32 data;	/* Not used but needed for qcq structure */
+};
+
+union ionic_notifyq_comp {
+	struct ionic_notifyq_event event;
+	struct ionic_link_change_event link_change;
+	struct ionic_reset_event reset;
+	struct ionic_heartbeat_event heartbeat;
+	struct ionic_log_event log;
+};
+
+/* Deprecate */
+struct ionic_identity {
+	union ionic_drv_identity drv;
+	union ionic_dev_identity dev;
+	union ionic_lif_identity lif;
+	union ionic_port_identity port;
+	union ionic_qos_identity qos;
+};
+
+#pragma pack(pop)
+
+#endif /* _IONIC_IF_H_ */


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 03/17] net/ionic: add log
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
  2019-10-12  0:26 ` [dpdk-dev] [PATCH 01/17] net/ionic: add skeleton Alfredo Cardigliano
  2019-10-12  0:26 ` [dpdk-dev] [PATCH 02/17] net/ionic: add hardware structures definitions Alfredo Cardigliano
@ 2019-10-12  0:26 ` Alfredo Cardigliano
  2019-10-12 15:23   ` Stephen Hemminger
  2019-10-12  0:26 ` [dpdk-dev] [PATCH 04/17] net/ionic: register and initialize the adapter Alfredo Cardigliano
                   ` (14 subsequent siblings)
  17 siblings, 1 reply; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:26 UTC (permalink / raw)
  To: dev

Add debug options to the config file.
Define macros used for logs and make use of config file options
to enable them.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 config/common_base               |    2 ++
 drivers/net/ionic/Makefile       |    2 +-
 drivers/net/ionic/ionic_ethdev.c |   21 +++++++++++++++++
 drivers/net/ionic/ionic_logs.h   |   46 ++++++++++++++++++++++++++++++++++++++
 drivers/net/ionic/meson.build    |    1 +
 5 files changed, 71 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ionic/ionic_ethdev.c
 create mode 100644 drivers/net/ionic/ionic_logs.h

diff --git a/config/common_base b/config/common_base
index 1c11fcae6..c1b556fc1 100644
--- a/config/common_base
+++ b/config/common_base
@@ -274,6 +274,8 @@ CONFIG_RTE_LIBRTE_E1000_PF_DISABLE_STRIP_CRC=n
 # Compile Pensando IONIC PMD driver
 #
 CONFIG_RTE_LIBRTE_IONIC_PMD=y
+CONFIG_RTE_LIBRTE_IONIC_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_IONIC_DEBUG_TX=n
 
 #
 # Compile burst-oriented HINIC PMD driver
diff --git a/drivers/net/ionic/Makefile b/drivers/net/ionic/Makefile
index 3add24087..2f3296a15 100644
--- a/drivers/net/ionic/Makefile
+++ b/drivers/net/ionic/Makefile
@@ -52,6 +52,6 @@ LDLIBS += -lrte_bus_pci
 #
 # all source are stored in SRCS-y
 #
-SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) +=
+SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_ethdev.c
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
new file mode 100644
index 000000000..863d20d19
--- /dev/null
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#include "ionic_logs.h"
+
+int ionic_logtype_init;
+int ionic_logtype_driver;
+
+RTE_INIT(ionic_init_log)
+{
+	ionic_logtype_init = rte_log_register("pmd.net.ionic.init");
+
+	if (ionic_logtype_init >= 0)
+		rte_log_set_level(ionic_logtype_init, RTE_LOG_NOTICE);
+
+	ionic_logtype_driver = rte_log_register("pmd.net.ionic.driver");
+
+	if (ionic_logtype_driver >= 0)
+		rte_log_set_level(ionic_logtype_driver, RTE_LOG_NOTICE);
+}
diff --git a/drivers/net/ionic/ionic_logs.h b/drivers/net/ionic/ionic_logs.h
new file mode 100644
index 000000000..a4a9af888
--- /dev/null
+++ b/drivers/net/ionic/ionic_logs.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#ifndef _IONIC_LOGS_H_
+#define _IONIC_LOGS_H_
+
+#include <rte_log.h>
+
+extern int ionic_logtype_init;
+extern int ionic_logtype_driver;
+
+#define ionic_init_print(level, fmt, args...) rte_log(RTE_LOG_ ## level, \
+		ionic_logtype_init, "%s(): " fmt "\n", __func__, ##args)
+
+#define ionic_init_print_call() ionic_init_print(DEBUG, " >>")
+
+#ifndef IONIC_WARN_ON
+#define IONIC_WARN_ON(x) do { \
+	int ret = !!(x); \
+	if (unlikely(ret)) \
+		ionic_init_print(WARNING, "WARN_ON: \"" #x "\" at %s:%d\n", \
+				__func__, __LINE__); \
+} while (0)
+#endif
+
+#ifdef RTE_LIBRTE_IONIC_DEBUG_RX
+#define ionic_rx_print(level, fmt, args...) RTE_LOG(level, PMD, \
+		"%s(): " fmt "\n", __func__, ## args)
+#else
+#define ionic_rx_print(level, fmt, args...) do { } while (0)
+#endif
+
+#ifdef RTE_LIBRTE_IONIC_DEBUG_TX
+#define ionic_tx_print(level, fmt, args...) RTE_LOG(level, PMD, \
+		"%s(): " fmt "\n", __func__, ## args)
+#else
+#define ionic_tx_print(level, fmt, args...) do { } while (0)
+#endif
+
+#define ionic_drv_print(level, fmt, args...) rte_log(RTE_LOG_ ## level, \
+		ionic_logtype_driver, "%s(): " fmt "\n", __func__, ## args)
+
+#define ionic_drv_print_call() ionic_drv_print(DEBUG, " >>")
+
+#endif /* _IONIC_LOGS_H_ */
diff --git a/drivers/net/ionic/meson.build b/drivers/net/ionic/meson.build
index 502076e3c..5534ad6c3 100644
--- a/drivers/net/ionic/meson.build
+++ b/drivers/net/ionic/meson.build
@@ -4,5 +4,6 @@
 version = 1
 
 sources = files(
+	'ionic_ethdev.c'
 )
 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 04/17] net/ionic: register and initialize the adapter
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
                   ` (2 preceding siblings ...)
  2019-10-12  0:26 ` [dpdk-dev] [PATCH 03/17] net/ionic: add log Alfredo Cardigliano
@ 2019-10-12  0:26 ` Alfredo Cardigliano
  2019-10-12  0:26 ` [dpdk-dev] [PATCH 05/17] net/ionic: add port management commands Alfredo Cardigliano
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:26 UTC (permalink / raw)
  To: dev

Register the Pensando ionic PMD (net_ionic) and define initial probe
and remove callbacks with adapter initialization.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 doc/guides/nics/features/ionic.ini |    2 +
 drivers/net/ionic/Makefile         |    3 +
 drivers/net/ionic/ionic.h          |   63 ++++++++++++++++
 drivers/net/ionic/ionic_dev.c      |  128 ++++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_dev.h      |  138 +++++++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_ethdev.c   |  138 +++++++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_mac_api.c  |   61 +++++++++++++++
 drivers/net/ionic/ionic_mac_api.h  |   13 +++
 drivers/net/ionic/ionic_main.c     |  133 ++++++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_osdep.h    |   79 ++++++++++++++++++++
 drivers/net/ionic/ionic_regs.h     |  142 ++++++++++++++++++++++++++++++++++++
 drivers/net/ionic/meson.build      |    4 +
 12 files changed, 904 insertions(+)
 create mode 100644 drivers/net/ionic/ionic.h
 create mode 100644 drivers/net/ionic/ionic_dev.c
 create mode 100644 drivers/net/ionic/ionic_dev.h
 create mode 100644 drivers/net/ionic/ionic_mac_api.c
 create mode 100644 drivers/net/ionic/ionic_mac_api.h
 create mode 100644 drivers/net/ionic/ionic_main.c
 create mode 100644 drivers/net/ionic/ionic_osdep.h
 create mode 100644 drivers/net/ionic/ionic_regs.h

diff --git a/doc/guides/nics/features/ionic.ini b/doc/guides/nics/features/ionic.ini
index 3a92eedc7..6915d9c42 100644
--- a/doc/guides/nics/features/ionic.ini
+++ b/doc/guides/nics/features/ionic.ini
@@ -4,5 +4,7 @@
 ; Refer to default.ini for the full list of available PMD features.
 ;
 [Features]
+Linux UIO            = Y
+Linux VFIO           = Y
 x86-64               = Y
 Usage doc            = Y
diff --git a/drivers/net/ionic/Makefile b/drivers/net/ionic/Makefile
index 2f3296a15..4d42e3778 100644
--- a/drivers/net/ionic/Makefile
+++ b/drivers/net/ionic/Makefile
@@ -52,6 +52,9 @@ LDLIBS += -lrte_bus_pci
 #
 # all source are stored in SRCS-y
 #
+SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_mac_api.c
+SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_dev.c
 SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_main.c
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/ionic/ionic.h b/drivers/net/ionic/ionic.h
new file mode 100644
index 000000000..1f91e0a10
--- /dev/null
+++ b/drivers/net/ionic/ionic.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#ifndef _IONIC_H_
+#define _IONIC_H_
+
+#include <stdint.h>
+
+#include "ionic_dev.h"
+#include "ionic_if.h"
+#include "ionic_osdep.h"
+
+#define IONIC_DRV_NAME			"ionic"
+#define IONIC_DRV_DESCRIPTION		"Pensando Ethernet NIC Driver"
+#define IONIC_DRV_VERSION		"0.11.0-49"
+
+/* Vendor ID */
+#define IONIC_PENSANDO_VENDOR_ID	0x1dd8
+
+/* Device IDs */
+#define IONIC_DEV_ID_ETH_PF		0x1002
+#define IONIC_DEV_ID_ETH_VF		0x1003
+#define IONIC_DEV_ID_ETH_MGMT		0x1004
+
+enum ionic_mac_type {
+	IONIC_MAC_UNKNOWN = 0,
+	IONIC_MAC_CAPRI,
+	IONIC_NUM_MACS
+};
+
+struct ionic_mac_info {
+	enum ionic_mac_type type;
+};
+
+struct ionic_hw {
+	struct ionic_mac_info mac;
+	uint16_t device_id;
+	uint16_t vendor_id;
+};
+
+/*
+ * Structure to store private data for each driver instance (for each adapter).
+ */
+struct ionic_adapter {
+	struct ionic_hw hw;
+	struct ionic_dev idev;
+	struct ionic_dev_bar bars[IONIC_BARS_MAX];
+	struct ionic_identity	ident;
+	uint32_t num_bars;
+	bool is_mgmt_nic;
+	struct rte_pci_device *pci_dev;
+	LIST_ENTRY(ionic_adapter) pci_adapters;
+};
+
+int ionic_dev_cmd_wait_check(struct ionic_dev *idev, unsigned long max_wait);
+int ionic_setup(struct ionic_adapter *adapter);
+
+int ionic_identify(struct ionic_adapter *adapter);
+int ionic_init(struct ionic_adapter *adapter);
+int ionic_reset(struct ionic_adapter *adapter);
+
+#endif /* _IONIC_H_ */
diff --git a/drivers/net/ionic/ionic_dev.c b/drivers/net/ionic/ionic_dev.c
new file mode 100644
index 000000000..5cdcaa104
--- /dev/null
+++ b/drivers/net/ionic/ionic_dev.c
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#include <rte_malloc.h>
+
+#include "ionic_dev.h"
+#include "ionic.h"
+
+int
+ionic_dev_setup(struct ionic_adapter *adapter)
+{
+	struct ionic_dev_bar *bar = adapter->bars;
+	unsigned int num_bars = adapter->num_bars;
+	struct ionic_dev *idev = &adapter->idev;
+	uint32_t sig;
+
+	/* BAR0: dev_cmd and interrupts */
+	if (num_bars < 1) {
+		ionic_init_print(ERR, "No bars found, aborting\n");
+		return -EFAULT;
+	}
+
+	if (bar->len < IONIC_BAR0_SIZE) {
+		ionic_init_print(ERR,
+			"Resource bar size %lu too small, aborting\n",
+			bar->len);
+		return -EFAULT;
+	}
+
+	idev->dev_info = bar->vaddr + IONIC_BAR0_DEV_INFO_REGS_OFFSET;
+	idev->dev_cmd = bar->vaddr + IONIC_BAR0_DEV_CMD_REGS_OFFSET;
+	idev->intr_status = bar->vaddr + IONIC_BAR0_INTR_STATUS_OFFSET;
+	idev->intr_ctrl = bar->vaddr + IONIC_BAR0_INTR_CTRL_OFFSET;
+
+	sig = ioread32(&idev->dev_info->signature);
+	if (sig != IONIC_DEV_INFO_SIGNATURE) {
+		ionic_init_print(ERR, "Incompatible firmware signature %x",
+			sig);
+		return -EFAULT;
+	}
+
+	/* BAR1: doorbells */
+	bar++;
+	if (num_bars < 2) {
+		ionic_init_print(ERR, "Doorbell bar missing, aborting\n");
+		return -EFAULT;
+	}
+
+	idev->db_pages = bar->vaddr;
+	idev->phy_db_pages = bar->bus_addr;
+
+	return 0;
+}
+
+/* Devcmd Interface */
+
+uint8_t
+ionic_dev_cmd_status(struct ionic_dev *idev)
+{
+	return ioread8(&idev->dev_cmd->comp.comp.status);
+}
+
+bool
+ionic_dev_cmd_done(struct ionic_dev *idev)
+{
+	return ioread32(&idev->dev_cmd->done) & IONIC_DEV_CMD_DONE;
+}
+
+void
+ionic_dev_cmd_comp(struct ionic_dev *idev, void *mem)
+{
+	union ionic_dev_cmd_comp *comp = mem;
+	unsigned int i;
+	uint32_t comp_size = sizeof(comp->words) /
+		sizeof(comp->words[0]);
+
+	for (i = 0; i < comp_size; i++)
+		comp->words[i] = ioread32(&idev->dev_cmd->comp.words[i]);
+}
+
+void
+ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd)
+{
+	unsigned int i;
+	uint32_t cmd_size = sizeof(cmd->words) /
+		sizeof(cmd->words[0]);
+
+	for (i = 0; i < cmd_size; i++)
+		iowrite32(cmd->words[i], &idev->dev_cmd->cmd.words[i]);
+
+	iowrite32(0, &idev->dev_cmd->done);
+	iowrite32(1, &idev->dev_cmd->doorbell);
+}
+
+/* Device commands */
+
+void
+ionic_dev_cmd_identify(struct ionic_dev *idev, uint8_t ver)
+{
+	union ionic_dev_cmd cmd = {
+		.identify.opcode = IONIC_CMD_IDENTIFY,
+		.identify.ver = ver,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+void
+ionic_dev_cmd_init(struct ionic_dev *idev)
+{
+	union ionic_dev_cmd cmd = {
+		.init.opcode = IONIC_CMD_INIT,
+		.init.type = 0,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+void
+ionic_dev_cmd_reset(struct ionic_dev *idev)
+{
+	union ionic_dev_cmd cmd = {
+		.reset.opcode = IONIC_CMD_RESET,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
diff --git a/drivers/net/ionic/ionic_dev.h b/drivers/net/ionic/ionic_dev.h
new file mode 100644
index 000000000..a157e4175
--- /dev/null
+++ b/drivers/net/ionic/ionic_dev.h
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#ifndef _IONIC_DEV_H_
+#define _IONIC_DEV_H_
+
+#include "ionic_osdep.h"
+#include "ionic_if.h"
+#include "ionic_regs.h"
+
+/** IONIC_API_VERSION - Version number of this interface.
+ *
+ * Any interface changes to this interface must also change the version.
+ *
+ * If drivers are compiled from different sources,
+ * they are compatible only if IONIC_API_VERSION is statically the same in both
+ * sources.  Drivers must have matching values of IONIC_API_VERSION at compile
+ * time, to be considered compatible at run time.
+ */
+#define IONIC_API_VERSION		"3"
+
+#define IONIC_DEVCMD_TIMEOUT	30 /* devcmd_timeout */
+
+struct ionic_adapter;
+
+struct ionic_dev_bar {
+	void __iomem *vaddr;
+	rte_iova_t bus_addr;
+	unsigned long len;
+};
+
+static inline void ionic_struct_size_checks(void)
+{
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_doorbell) != 8);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_intr) != 32);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_intr_status) != 8);
+
+	RTE_BUILD_BUG_ON(sizeof(union ionic_dev_regs) != 4096);
+	RTE_BUILD_BUG_ON(sizeof(union ionic_dev_info_regs) != 2048);
+	RTE_BUILD_BUG_ON(sizeof(union ionic_dev_cmd_regs) != 2048);
+
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_stats) != 1024);
+
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_admin_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_admin_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_nop_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_nop_comp) != 16);
+
+	/* Device commands */
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_identify_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_identify_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_init_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_init_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_reset_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_reset_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_getattr_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_getattr_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_setattr_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_dev_setattr_comp) != 16);
+
+	/* Port commands */
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_identify_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_identify_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_init_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_init_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_reset_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_reset_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_getattr_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_getattr_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_setattr_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_port_setattr_comp) != 16);
+
+	/* LIF commands */
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_init_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_init_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_reset_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_getattr_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_getattr_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_setattr_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_lif_setattr_comp) != 16);
+
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_q_init_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_q_init_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_q_control_cmd) != 64);
+
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rx_mode_set_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rx_filter_add_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rx_filter_add_comp) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rx_filter_del_cmd) != 64);
+
+	/* RDMA commands */
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rdma_reset_cmd) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rdma_queue_cmd) != 64);
+
+	/* Events */
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_notifyq_cmd) != 4);
+	RTE_BUILD_BUG_ON(sizeof(union ionic_notifyq_comp) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_notifyq_event) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_link_change_event) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_reset_event) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_heartbeat_event) != 64);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_log_event) != 64);
+
+	/* I/O */
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_txq_desc) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_txq_sg_desc) != 128);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_txq_comp) != 16);
+
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rxq_desc) != 16);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rxq_sg_desc) != 128);
+	RTE_BUILD_BUG_ON(sizeof(struct ionic_rxq_comp) != 16);
+}
+
+struct ionic_dev {
+	union ionic_dev_info_regs __iomem *dev_info;
+	union ionic_dev_cmd_regs __iomem *dev_cmd;
+
+	struct ionic_doorbell __iomem *db_pages;
+	rte_iova_t phy_db_pages;
+
+	struct ionic_intr __iomem *intr_ctrl;
+
+	struct ionic_intr_status __iomem *intr_status;
+};
+
+int ionic_dev_setup(struct ionic_adapter *adapter);
+
+void ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd);
+uint8_t 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, void *mem);
+
+void ionic_dev_cmd_identify(struct ionic_dev *idev, uint8_t ver);
+void ionic_dev_cmd_init(struct ionic_dev *idev);
+void ionic_dev_cmd_reset(struct ionic_dev *idev);
+
+#endif /* _IONIC_DEV_H_ */
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index 863d20d19..148d6f236 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -2,11 +2,147 @@
  * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
  */
 
+#include <rte_pci.h>
+#include <rte_bus_pci.h>
+#include <rte_ethdev.h>
+#include <rte_ethdev_driver.h>
+#include <rte_malloc.h>
+
 #include "ionic_logs.h"
+#include "ionic.h"
+#include "ionic_dev.h"
+#include "ionic_mac_api.h"
 
 int ionic_logtype_init;
 int ionic_logtype_driver;
 
+static const struct rte_pci_id pci_id_ionic_map[] = {
+	{ RTE_PCI_DEVICE(IONIC_PENSANDO_VENDOR_ID, IONIC_DEV_ID_ETH_PF) },
+	{ RTE_PCI_DEVICE(IONIC_PENSANDO_VENDOR_ID, IONIC_DEV_ID_ETH_VF) },
+	{ RTE_PCI_DEVICE(IONIC_PENSANDO_VENDOR_ID, IONIC_DEV_ID_ETH_MGMT) },
+	{ .vendor_id = 0, /* sentinel */ },
+};
+
+/*
+ * There is no room in struct rte_pci_driver to keep a reference
+ * to the adapter, using a static list for the time being.
+ */
+static LIST_HEAD(ionic_pci_adapters_list, ionic_adapter) ionic_pci_adapters =
+		LIST_HEAD_INITIALIZER(ionic_pci_adapters);
+static rte_spinlock_t ionic_pci_adapters_lock = RTE_SPINLOCK_INITIALIZER;
+
+static int
+eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+		struct rte_pci_device *pci_dev)
+{
+	struct rte_mem_resource *resource;
+	struct ionic_adapter *adapter;
+	struct ionic_hw *hw;
+	unsigned long i;
+	int err;
+
+	/* Multi-process not supported */
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return -EPERM;
+
+	ionic_init_print(DEBUG, "Initializing device %s %s",
+			pci_dev->device.name,
+			rte_eal_process_type() == RTE_PROC_SECONDARY ?
+			"[SECONDARY]" : "");
+
+	adapter = rte_zmalloc("ionic", sizeof(*adapter), 0);
+
+	if (!adapter) {
+		ionic_init_print(ERR, "OOM");
+		return -ENOMEM;
+	}
+
+	adapter->pci_dev = pci_dev;
+	hw = &adapter->hw;
+
+	hw->device_id = pci_dev->id.device_id;
+	hw->vendor_id = pci_dev->id.vendor_id;
+
+	err = ionic_init_mac(hw);
+	if (err != 0) {
+		ionic_init_print(ERR, "Mac init failed: %d", err);
+		return -EIO;
+	}
+
+	adapter->is_mgmt_nic = (pci_dev->id.device_id == IONIC_DEV_ID_ETH_MGMT);
+
+	adapter->num_bars = 0;
+	for (i = 0; i < PCI_MAX_RESOURCE && i < IONIC_BARS_MAX; i++) {
+		resource = &pci_dev->mem_resource[i];
+		if (resource->phys_addr == 0 || resource->len == 0)
+			continue;
+		adapter->bars[adapter->num_bars].vaddr = resource->addr;
+		adapter->bars[adapter->num_bars].bus_addr = resource->phys_addr;
+		adapter->bars[adapter->num_bars].len = resource->len;
+		adapter->num_bars++;
+	}
+
+	/* Discover ionic dev resources */
+
+	err = ionic_setup(adapter);
+	if (err) {
+		ionic_init_print(ERR, "Cannot setup device: %d, aborting", err);
+		return err;
+	}
+
+	err = ionic_identify(adapter);
+	if (err) {
+		ionic_init_print(ERR, "Cannot identify device: %d, aborting",
+				err);
+		return err;
+	}
+
+	err = ionic_init(adapter);
+	if (err) {
+		ionic_init_print(ERR, "Cannot init device: %d, aborting", err);
+		return err;
+	}
+
+	rte_spinlock_lock(&ionic_pci_adapters_lock);
+	LIST_INSERT_HEAD(&ionic_pci_adapters, adapter, pci_adapters);
+	rte_spinlock_unlock(&ionic_pci_adapters_lock);
+
+	return 0;
+}
+
+static int
+eth_ionic_pci_remove(struct rte_pci_device *pci_dev)
+{
+	struct ionic_adapter *adapter = NULL;
+
+	rte_spinlock_lock(&ionic_pci_adapters_lock);
+	LIST_FOREACH(adapter, &ionic_pci_adapters, pci_adapters) {
+		if (adapter->pci_dev == pci_dev)
+			break;
+
+		adapter = NULL;
+	}
+	if (adapter)
+		LIST_REMOVE(adapter, pci_adapters);
+	rte_spinlock_unlock(&ionic_pci_adapters_lock);
+
+	if (adapter)
+		rte_free(adapter);
+
+	return 0;
+}
+
+static struct rte_pci_driver rte_ionic_pmd = {
+	.id_table = pci_id_ionic_map,
+	.drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
+	.probe = eth_ionic_pci_probe,
+	.remove = eth_ionic_pci_remove,
+};
+
+RTE_PMD_REGISTER_PCI(net_ionic, rte_ionic_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_ionic, pci_id_ionic_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_ionic, "* igb_uio | uio_pci_generic | vfio-pci");
+
 RTE_INIT(ionic_init_log)
 {
 	ionic_logtype_init = rte_log_register("pmd.net.ionic.init");
@@ -14,6 +150,8 @@ RTE_INIT(ionic_init_log)
 	if (ionic_logtype_init >= 0)
 		rte_log_set_level(ionic_logtype_init, RTE_LOG_NOTICE);
 
+	ionic_struct_size_checks();
+
 	ionic_logtype_driver = rte_log_register("pmd.net.ionic.driver");
 
 	if (ionic_logtype_driver >= 0)
diff --git a/drivers/net/ionic/ionic_mac_api.c b/drivers/net/ionic/ionic_mac_api.c
new file mode 100644
index 000000000..5413afa93
--- /dev/null
+++ b/drivers/net/ionic/ionic_mac_api.c
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#include "ionic_mac_api.h"
+
+int32_t
+ionic_init_mac(struct ionic_hw *hw)
+{
+	int err = 0;
+
+	ionic_drv_print_call();
+
+	/*
+	 * Set the mac type
+	 */
+	ionic_set_mac_type(hw);
+
+	switch (hw->mac.type) {
+	case IONIC_MAC_CAPRI:
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+int32_t
+ionic_set_mac_type(struct ionic_hw *hw)
+{
+	int err = 0;
+
+	ionic_drv_print_call();
+
+	if (hw->vendor_id != IONIC_PENSANDO_VENDOR_ID) {
+		ionic_drv_print(ERR, "Unsupported vendor id: %x",
+				hw->vendor_id);
+		return -EINVAL;
+	}
+
+	switch (hw->device_id) {
+	case IONIC_DEV_ID_ETH_PF:
+	case IONIC_DEV_ID_ETH_VF:
+	case IONIC_DEV_ID_ETH_MGMT:
+		hw->mac.type = IONIC_MAC_CAPRI;
+		break;
+	default:
+		err = -EINVAL;
+		ionic_drv_print(ERR, "Unsupported device id: %x",
+				hw->device_id);
+		break;
+	}
+
+	ionic_drv_print(INFO, "Mac: %d (%d)\n",
+			hw->mac.type, err);
+
+	return err;
+}
+
diff --git a/drivers/net/ionic/ionic_mac_api.h b/drivers/net/ionic/ionic_mac_api.h
new file mode 100644
index 000000000..41f9328f3
--- /dev/null
+++ b/drivers/net/ionic/ionic_mac_api.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#ifndef _IONIC_API_H_
+#define _IONIC_API_H_
+
+#include "ionic.h"
+
+int32_t ionic_init_mac(struct ionic_hw *hw);
+int32_t ionic_set_mac_type(struct ionic_hw *hw);
+
+#endif /* _IONIC_API_H_ */
diff --git a/drivers/net/ionic/ionic_main.c b/drivers/net/ionic/ionic_main.c
new file mode 100644
index 000000000..79a141140
--- /dev/null
+++ b/drivers/net/ionic/ionic_main.c
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#include "ionic.h"
+
+static int
+ionic_dev_cmd_wait(struct ionic_dev *idev, unsigned long max_wait)
+{
+	unsigned long step_msec = 100;
+	unsigned int max_wait_msec = max_wait * 1000;
+	unsigned long elapsed_msec = 0;
+	int done;
+
+	/* Wait for dev cmd to complete.. but no more than max_wait sec */
+
+	do {
+		done = ionic_dev_cmd_done(idev);
+
+		if (done) {
+			ionic_drv_print(DEBUG, "DEVCMD %d done took %ld msecs\n",
+					idev->dev_cmd->cmd.cmd.opcode,
+					elapsed_msec);
+			return 0;
+		}
+
+		msec_delay(step_msec);
+
+		elapsed_msec += step_msec;
+	} while (elapsed_msec < max_wait_msec);
+
+	ionic_drv_print(DEBUG, "DEVCMD %d timeout after %ld msecs\n",
+			idev->dev_cmd->cmd.cmd.opcode,
+			elapsed_msec);
+
+	return -ETIMEDOUT;
+}
+
+static int
+ionic_dev_cmd_check_error(struct ionic_dev *idev)
+{
+	uint8_t status;
+
+	status = ionic_dev_cmd_status(idev);
+
+	if (status == 0)
+		return 0;
+
+	return -EIO;
+}
+
+int
+ionic_dev_cmd_wait_check(struct ionic_dev *idev, unsigned long max_wait)
+{
+	int err;
+
+	err = ionic_dev_cmd_wait(idev, max_wait);
+
+	if (err)
+		return err;
+
+	return ionic_dev_cmd_check_error(idev);
+}
+
+int
+ionic_setup(struct ionic_adapter *adapter)
+{
+	return ionic_dev_setup(adapter);
+}
+
+int
+ionic_identify(struct ionic_adapter *adapter)
+{
+	struct ionic_dev *idev = &adapter->idev;
+	struct ionic_identity *ident = &adapter->ident;
+	int err = 0;
+	uint32_t i;
+	unsigned int nwords;
+	uint32_t drv_size = sizeof(ident->drv.words) /
+		sizeof(ident->drv.words[0]);
+	uint32_t cmd_size = sizeof(idev->dev_cmd->data) /
+		sizeof(idev->dev_cmd->data[0]);
+	uint32_t dev_size = sizeof(ident->dev.words) /
+		sizeof(ident->dev.words[0]);
+
+	memset(ident, 0, sizeof(*ident));
+
+	ident->drv.os_type = IONIC_OS_TYPE_LINUX;
+	ident->drv.os_dist = 0;
+	snprintf(ident->drv.os_dist_str,
+		sizeof(ident->drv.os_dist_str), "Unknown");
+	ident->drv.kernel_ver = 0;
+	snprintf(ident->drv.kernel_ver_str,
+		sizeof(ident->drv.kernel_ver_str), "DPDK");
+	strncpy(ident->drv.driver_ver_str, IONIC_DRV_VERSION,
+		sizeof(ident->drv.driver_ver_str) - 1);
+
+	nwords = RTE_MIN(drv_size, cmd_size);
+	for (i = 0; i < nwords; i++)
+		iowrite32(ident->drv.words[i], &idev->dev_cmd->data[i]);
+
+	ionic_dev_cmd_identify(idev, IONIC_IDENTITY_VERSION_1);
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+	if (!err) {
+		nwords = RTE_MIN(dev_size, cmd_size);
+		for (i = 0; i < nwords; i++)
+			ident->dev.words[i] = ioread32(&idev->dev_cmd->data[i]);
+	}
+
+	return err;
+}
+
+int
+ionic_init(struct ionic_adapter *adapter)
+{
+	struct ionic_dev *idev = &adapter->idev;
+	int err;
+
+	ionic_dev_cmd_init(idev);
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+	return err;
+}
+
+int
+ionic_reset(struct ionic_adapter *adapter)
+{
+	struct ionic_dev *idev = &adapter->idev;
+	int err;
+
+	ionic_dev_cmd_reset(idev);
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+	return err;
+}
diff --git a/drivers/net/ionic/ionic_osdep.h b/drivers/net/ionic/ionic_osdep.h
new file mode 100644
index 000000000..5b8baa67b
--- /dev/null
+++ b/drivers/net/ionic/ionic_osdep.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#ifndef _IONIC_OSDEP_
+#define _IONIC_OSDEP_
+
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_log.h>
+#include <rte_byteorder.h>
+#include <rte_io.h>
+#include <rte_memory.h>
+
+#include "ionic_logs.h"
+
+#define DELAY(x) rte_delay_us(x)
+#define usec_delay(x) DELAY(x)
+#define msec_delay(x) DELAY(1000 * (x))
+
+#define BIT(nr)            (1UL << (nr))
+#define BIT_ULL(nr)        (1ULL << (nr))
+#define BITS_TO_LONGS(nr)  div_round_up(nr, 8 * sizeof(long))
+
+#ifndef PAGE_SHIFT
+#define PAGE_SHIFT      12
+#define PAGE_SIZE       (1 << PAGE_SHIFT)
+#endif
+
+#define __iomem
+
+typedef uint8_t	 u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+typedef uint16_t __le16;
+typedef uint32_t __le32;
+typedef uint64_t __le64;
+
+#ifndef __cplusplus
+typedef uint8_t bool;
+#define false   0
+#define true    1
+#endif
+
+static inline uint32_t div_round_up(uint32_t n, uint32_t d)
+{
+	return (n + d - 1) / d;
+}
+
+static inline uint16_t ilog2(uint32_t n)
+{
+	uint16_t logv = -1;
+
+	if (n == 0)
+		return 0;
+
+	while (n) {
+		logv++;
+		n >>= 1;
+	}
+
+	return logv;
+}
+
+#define ioread8(reg)		rte_read8(reg)
+#define ioread32(reg)		rte_read32(reg)
+#define iowrite8(value, reg)	rte_write8(value, reg)
+#define iowrite32(value, reg)	rte_write32(value, reg)
+#define writeq(value, reg)	rte_write64(value, reg)
+
+#endif
diff --git a/drivers/net/ionic/ionic_regs.h b/drivers/net/ionic/ionic_regs.h
new file mode 100644
index 000000000..e213062c9
--- /dev/null
+++ b/drivers/net/ionic/ionic_regs.h
@@ -0,0 +1,142 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#ifndef _IONIC_REGS_H_
+#define _IONIC_REGS_H_
+
+/** struct ionic_intr - interrupt control register set.
+ * @coal_init:			coalesce timer initial value.
+ * @mask:			interrupt mask value.
+ * @credits:			interrupt credit count and return.
+ * @mask_assert:		interrupt mask value on assert.
+ * @coal:			coalesce timer time remaining.
+ */
+struct ionic_intr {
+	uint32_t coal_init;
+	uint32_t mask;
+	uint32_t credits;
+	uint32_t mask_assert;
+	uint32_t coal;
+	uint32_t rsvd[3];
+};
+
+#define IONIC_INTR_CTRL_REGS_MAX	2048
+#define IONIC_INTR_CTRL_COAL_MAX	0x3F
+
+/** enum ionic_intr_mask_vals - valid values for mask and mask_assert.
+ * @IONIC_INTR_MASK_CLEAR:	unmask interrupt.
+ * @IONIC_INTR_MASK_SET:	mask interrupt.
+ */
+enum ionic_intr_mask_vals {
+	IONIC_INTR_MASK_CLEAR		= 0,
+	IONIC_INTR_MASK_SET		= 1,
+};
+
+/** enum ionic_intr_credits_bits - bitwise composition of credits values.
+ * @IONIC_INTR_CRED_COUNT:	bit mask of credit count, no shift needed.
+ * @IONIC_INTR_CRED_COUNT_SIGNED: bit mask of credit count, including sign bit.
+ * @IONIC_INTR_CRED_UNMASK:	unmask the interrupt.
+ * @IONIC_INTR_CRED_RESET_COALESCE: reset the coalesce timer.
+ * @IONIC_INTR_CRED_REARM:	unmask the and reset the timer.
+ */
+enum ionic_intr_credits_bits {
+	IONIC_INTR_CRED_COUNT		= 0x7fffu,
+	IONIC_INTR_CRED_COUNT_SIGNED	= 0xffffu,
+	IONIC_INTR_CRED_UNMASK		= 0x10000u,
+	IONIC_INTR_CRED_RESET_COALESCE	= 0x20000u,
+	IONIC_INTR_CRED_REARM		= (IONIC_INTR_CRED_UNMASK |
+					   IONIC_INTR_CRED_RESET_COALESCE),
+};
+
+static inline void
+ionic_intr_coal_init(struct ionic_intr __iomem *intr_ctrl,
+		int intr_idx, uint32_t coal)
+{
+	iowrite32(coal, &intr_ctrl[intr_idx].coal_init);
+}
+
+static inline void
+ionic_intr_mask(struct ionic_intr __iomem *intr_ctrl,
+		int intr_idx, uint32_t mask)
+{
+	iowrite32(mask, &intr_ctrl[intr_idx].mask);
+}
+
+static inline void
+ionic_intr_credits(struct ionic_intr __iomem *intr_ctrl,
+		int intr_idx, uint32_t cred, uint32_t flags)
+{
+	if (cred > IONIC_INTR_CRED_COUNT) {
+		IONIC_WARN_ON(cred > IONIC_INTR_CRED_COUNT);
+		cred = ioread32(&intr_ctrl[intr_idx].credits);
+		cred &= IONIC_INTR_CRED_COUNT_SIGNED;
+	}
+
+	iowrite32(cred | flags, &intr_ctrl[intr_idx].credits);
+}
+
+static inline void
+ionic_intr_clean(struct ionic_intr __iomem *intr_ctrl,
+		int intr_idx)
+{
+	uint32_t cred;
+
+	cred = ioread32(&intr_ctrl[intr_idx].credits);
+	cred &= IONIC_INTR_CRED_COUNT_SIGNED;
+	cred |= IONIC_INTR_CRED_RESET_COALESCE;
+	iowrite32(cred, &intr_ctrl[intr_idx].credits);
+}
+
+static inline void
+ionic_intr_mask_assert(struct ionic_intr __iomem *intr_ctrl,
+		int intr_idx, uint32_t mask)
+{
+	iowrite32(mask, &intr_ctrl[intr_idx].mask_assert);
+}
+
+/** enum ionic_dbell_bits - bitwise composition of dbell values.
+ *
+ * @IONIC_DBELL_QID_MASK:	unshifted mask of valid queue id bits.
+ * @IONIC_DBELL_QID_SHIFT:	queue id shift amount in dbell value.
+ * @IONIC_DBELL_QID:		macro to build QID component of dbell value.
+ *
+ * @IONIC_DBELL_RING_MASK:	unshifted mask of valid ring bits.
+ * @IONIC_DBELL_RING_SHIFT:	ring shift amount in dbell value.
+ * @IONIC_DBELL_RING:		macro to build ring component of dbell value.
+ *
+ * @IONIC_DBELL_RING_0:		ring zero dbell component value.
+ * @IONIC_DBELL_RING_1:		ring one dbell component value.
+ * @IONIC_DBELL_RING_2:		ring two dbell component value.
+ * @IONIC_DBELL_RING_3:		ring three dbell component value.
+ *
+ * @IONIC_DBELL_INDEX_MASK:	bit mask of valid index bits, no shift needed.
+ */
+enum ionic_dbell_bits {
+	IONIC_DBELL_QID_MASK		= 0xffffff,
+	IONIC_DBELL_QID_SHIFT		= 24,
+
+#define IONIC_DBELL_QID(n) \
+	(((u64)(n) & IONIC_DBELL_QID_MASK) << IONIC_DBELL_QID_SHIFT)
+
+	IONIC_DBELL_RING_MASK		= 0x7,
+	IONIC_DBELL_RING_SHIFT		= 16,
+
+#define IONIC_DBELL_RING(n) \
+	(((u64)(n) & IONIC_DBELL_RING_MASK) << IONIC_DBELL_RING_SHIFT)
+
+	IONIC_DBELL_RING_0		= 0,
+	IONIC_DBELL_RING_1		= IONIC_DBELL_RING(1),
+	IONIC_DBELL_RING_2		= IONIC_DBELL_RING(2),
+	IONIC_DBELL_RING_3		= IONIC_DBELL_RING(3),
+
+	IONIC_DBELL_INDEX_MASK		= 0xffff,
+};
+
+static inline void
+ionic_dbell_ring(u64 __iomem *db_page, int qtype, u64 val)
+{
+	writeq(val, &db_page[qtype]);
+}
+
+#endif /* _IONIC_REGS_H_ */
diff --git a/drivers/net/ionic/meson.build b/drivers/net/ionic/meson.build
index 5534ad6c3..bd63e6136 100644
--- a/drivers/net/ionic/meson.build
+++ b/drivers/net/ionic/meson.build
@@ -4,6 +4,10 @@
 version = 1
 
 sources = files(
+	'ionic_mac_api.c',
+	'ionic_dev.c',
+	'ionic_ethdev.c',
+	'ionic_main.c',
 	'ionic_ethdev.c'
 )
 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 05/17] net/ionic: add port management commands
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
                   ` (3 preceding siblings ...)
  2019-10-12  0:26 ` [dpdk-dev] [PATCH 04/17] net/ionic: register and initialize the adapter Alfredo Cardigliano
@ 2019-10-12  0:26 ` Alfredo Cardigliano
  2019-10-12  0:26 ` [dpdk-dev] [PATCH 06/17] net/ionic: add basic lif support Alfredo Cardigliano
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:26 UTC (permalink / raw)
  To: dev

Add port management commands that apply to the physical
ports associated with the PCI device, which might be
shared among several logical interfaces.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 drivers/net/ionic/ionic.h        |    6 ++
 drivers/net/ionic/ionic_dev.c    |  127 +++++++++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_dev.h    |   18 +++++
 drivers/net/ionic/ionic_ethdev.c |   16 +++++
 drivers/net/ionic/ionic_main.c   |  131 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 298 insertions(+)

diff --git a/drivers/net/ionic/ionic.h b/drivers/net/ionic/ionic.h
index 1f91e0a10..c15dc6b44 100644
--- a/drivers/net/ionic/ionic.h
+++ b/drivers/net/ionic/ionic.h
@@ -7,6 +7,8 @@
 
 #include <stdint.h>
 
+#include <rte_bus_pci.h>
+
 #include "ionic_dev.h"
 #include "ionic_if.h"
 #include "ionic_osdep.h"
@@ -60,4 +62,8 @@ int ionic_identify(struct ionic_adapter *adapter);
 int ionic_init(struct ionic_adapter *adapter);
 int ionic_reset(struct ionic_adapter *adapter);
 
+int ionic_port_identify(struct ionic_adapter *adapter);
+int ionic_port_init(struct ionic_adapter *adapter);
+int ionic_port_reset(struct ionic_adapter *adapter);
+
 #endif /* _IONIC_H_ */
diff --git a/drivers/net/ionic/ionic_dev.c b/drivers/net/ionic/ionic_dev.c
index 5cdcaa104..7a9890175 100644
--- a/drivers/net/ionic/ionic_dev.c
+++ b/drivers/net/ionic/ionic_dev.c
@@ -126,3 +126,130 @@ ionic_dev_cmd_reset(struct ionic_dev *idev)
 
 	ionic_dev_cmd_go(idev, &cmd);
 }
+
+/* Port commands */
+
+void
+ionic_dev_cmd_port_identify(struct ionic_dev *idev)
+{
+	union ionic_dev_cmd cmd = {
+		.port_init.opcode = IONIC_CMD_PORT_IDENTIFY,
+		.port_init.index = 0,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+void
+ionic_dev_cmd_port_init(struct ionic_dev *idev)
+{
+	union ionic_dev_cmd cmd = {
+		.port_init.opcode = IONIC_CMD_PORT_INIT,
+		.port_init.index = 0,
+		.port_init.info_pa = idev->port_info_pa,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+void
+ionic_dev_cmd_port_reset(struct ionic_dev *idev)
+{
+	union ionic_dev_cmd cmd = {
+		.port_reset.opcode = IONIC_CMD_PORT_RESET,
+		.port_reset.index = 0,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+void
+ionic_dev_cmd_port_state(struct ionic_dev *idev, uint8_t state)
+{
+	union ionic_dev_cmd cmd = {
+		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
+		.port_setattr.index = 0,
+		.port_setattr.attr = IONIC_PORT_ATTR_STATE,
+		.port_setattr.state = state,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+void
+ionic_dev_cmd_port_speed(struct ionic_dev *idev, uint32_t speed)
+{
+	union ionic_dev_cmd cmd = {
+		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
+		.port_setattr.index = 0,
+		.port_setattr.attr = IONIC_PORT_ATTR_SPEED,
+		.port_setattr.speed = speed,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+void
+ionic_dev_cmd_port_mtu(struct ionic_dev *idev, uint32_t mtu)
+{
+	union ionic_dev_cmd cmd = {
+		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
+		.port_setattr.index = 0,
+		.port_setattr.attr = IONIC_PORT_ATTR_MTU,
+		.port_setattr.mtu = mtu,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+void
+ionic_dev_cmd_port_autoneg(struct ionic_dev *idev, uint8_t an_enable)
+{
+	union ionic_dev_cmd cmd = {
+		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
+		.port_setattr.index = 0,
+		.port_setattr.attr = IONIC_PORT_ATTR_AUTONEG,
+		.port_setattr.an_enable = an_enable,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+void
+ionic_dev_cmd_port_fec(struct ionic_dev *idev, uint8_t fec_type)
+{
+	union ionic_dev_cmd cmd = {
+		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
+		.port_setattr.index = 0,
+		.port_setattr.attr = IONIC_PORT_ATTR_FEC,
+		.port_setattr.fec_type = fec_type,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+void
+ionic_dev_cmd_port_pause(struct ionic_dev *idev, uint8_t pause_type)
+{
+	union ionic_dev_cmd cmd = {
+		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
+		.port_setattr.index = 0,
+		.port_setattr.attr = IONIC_PORT_ATTR_PAUSE,
+		.port_setattr.pause_type = pause_type,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+void
+ionic_dev_cmd_port_loopback(struct ionic_dev *idev, uint8_t loopback_mode)
+{
+	union ionic_dev_cmd cmd = {
+		.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
+		.port_setattr.index = 0,
+		.port_setattr.attr = IONIC_PORT_ATTR_LOOPBACK,
+		.port_setattr.loopback_mode = loopback_mode,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
diff --git a/drivers/net/ionic/ionic_dev.h b/drivers/net/ionic/ionic_dev.h
index a157e4175..aaa031980 100644
--- a/drivers/net/ionic/ionic_dev.h
+++ b/drivers/net/ionic/ionic_dev.h
@@ -21,6 +21,7 @@
 #define IONIC_API_VERSION		"3"
 
 #define IONIC_DEVCMD_TIMEOUT	30 /* devcmd_timeout */
+#define	IONIC_ALIGN             4096
 
 struct ionic_adapter;
 
@@ -122,6 +123,11 @@ struct ionic_dev {
 	struct ionic_intr __iomem *intr_ctrl;
 
 	struct ionic_intr_status __iomem *intr_status;
+
+	struct ionic_port_info *port_info;
+	const struct rte_memzone *port_info_z;
+	rte_iova_t port_info_pa;
+	uint32_t port_info_sz;
 };
 
 int ionic_dev_setup(struct ionic_adapter *adapter);
@@ -135,4 +141,16 @@ void ionic_dev_cmd_identify(struct ionic_dev *idev, uint8_t 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, uint8_t state);
+void ionic_dev_cmd_port_speed(struct ionic_dev *idev, uint32_t speed);
+void ionic_dev_cmd_port_mtu(struct ionic_dev *idev, uint32_t mtu);
+void ionic_dev_cmd_port_autoneg(struct ionic_dev *idev, uint8_t an_enable);
+void ionic_dev_cmd_port_fec(struct ionic_dev *idev, uint8_t fec_type);
+void ionic_dev_cmd_port_pause(struct ionic_dev *idev, uint8_t pause_type);
+void ionic_dev_cmd_port_loopback(struct ionic_dev *idev,
+		uint8_t loopback_mode);
+
 #endif /* _IONIC_DEV_H_ */
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index 148d6f236..61999bf1d 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -103,6 +103,22 @@ eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 		return err;
 	}
 
+	/* Configure the ports */
+	err = ionic_port_identify(adapter);
+
+	if (err) {
+		ionic_init_print(ERR, "Cannot identify port: %d, aborting\n",
+				err);
+		return err;
+	}
+
+	err = ionic_port_init(adapter);
+
+	if (err) {
+		ionic_init_print(ERR, "Cannot init port: %d, aborting\n", err);
+		return err;
+	}
+
 	rte_spinlock_lock(&ionic_pci_adapters_lock);
 	LIST_INSERT_HEAD(&ionic_pci_adapters, adapter, pci_adapters);
 	rte_spinlock_unlock(&ionic_pci_adapters_lock);
diff --git a/drivers/net/ionic/ionic_main.c b/drivers/net/ionic/ionic_main.c
index 79a141140..0feb713a9 100644
--- a/drivers/net/ionic/ionic_main.c
+++ b/drivers/net/ionic/ionic_main.c
@@ -2,6 +2,8 @@
  * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
  */
 
+#include <rte_memzone.h>
+
 #include "ionic.h"
 
 static int
@@ -131,3 +133,132 @@ ionic_reset(struct ionic_adapter *adapter)
 	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
 	return err;
 }
+
+int
+ionic_port_identify(struct ionic_adapter *adapter)
+{
+	struct ionic_dev *idev = &adapter->idev;
+	struct ionic_identity *ident = &adapter->ident;
+	unsigned int port_words = sizeof(ident->port.words) /
+		sizeof(ident->port.words[0]);
+	unsigned int cmd_words = sizeof(idev->dev_cmd->data) /
+		sizeof(idev->dev_cmd->data[0]);
+	unsigned int i;
+	unsigned int nwords;
+	int err;
+
+	ionic_dev_cmd_port_identify(idev);
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+	if (!err) {
+		nwords = RTE_MIN(port_words, cmd_words);
+		for (i = 0; i < nwords; i++)
+			ident->port.words[i] =
+					ioread32(&idev->dev_cmd->data[i]);
+	}
+
+	ionic_init_print(INFO, "speed %d ", ident->port.config.speed);
+	ionic_init_print(INFO, "mtu %d ", ident->port.config.mtu);
+	ionic_init_print(INFO, "state %d ", ident->port.config.state);
+	ionic_init_print(INFO, "an_enable %d ", ident->port.config.an_enable);
+	ionic_init_print(INFO, "fec_type %d ", ident->port.config.fec_type);
+	ionic_init_print(INFO, "pause_type %d ", ident->port.config.pause_type);
+	ionic_init_print(INFO, "loopback_mode %d",
+			ident->port.config.loopback_mode);
+
+	return err;
+}
+
+static const struct rte_memzone *
+ionic_memzone_reserve(const char *name, uint32_t len, int socket_id)
+{
+	const struct rte_memzone *mz;
+
+	mz = rte_memzone_lookup(name);
+	if (mz)
+		return mz;
+
+	mz = rte_memzone_reserve_aligned(name, len, socket_id,
+			RTE_MEMZONE_IOVA_CONTIG, IONIC_ALIGN);
+	return mz;
+}
+
+int
+ionic_port_init(struct ionic_adapter *adapter)
+{
+	struct ionic_dev *idev = &adapter->idev;
+	struct ionic_identity *ident = &adapter->ident;
+	char z_name[RTE_MEMZONE_NAMESIZE];
+	unsigned int config_words = sizeof(ident->port.config.words) /
+		sizeof(ident->port.config.words[0]);
+	unsigned int cmd_words = sizeof(idev->dev_cmd->data) /
+		sizeof(idev->dev_cmd->data[0]);
+	unsigned int nwords;
+	unsigned int i;
+	int err;
+
+	if (idev->port_info)
+		return 0;
+
+	idev->port_info_sz = RTE_ALIGN(sizeof(*idev->port_info), PAGE_SIZE);
+
+	snprintf(z_name, sizeof(z_name), "%s_port_%s_info",
+			IONIC_DRV_NAME,
+			adapter->pci_dev->device.name);
+
+	idev->port_info_z = ionic_memzone_reserve(z_name, idev->port_info_sz,
+			SOCKET_ID_ANY);
+
+	if (!idev->port_info_z) {
+		ionic_init_print(ERR, "Cannot reserve port info DMA memory");
+		return -ENOMEM;
+	}
+
+	idev->port_info = idev->port_info_z->addr;
+	idev->port_info_pa = idev->port_info_z->iova;
+
+	nwords = RTE_MIN(config_words, cmd_words);
+
+	for (i = 0; i < nwords; i++)
+		iowrite32(ident->port.config.words[i], &idev->dev_cmd->data[i]);
+
+	ionic_dev_cmd_port_init(idev);
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+
+	if (err) {
+		ionic_init_print(ERR, "Failed to init port\n");
+		return err;
+	}
+
+	ionic_dev_cmd_port_state(idev, IONIC_PORT_ADMIN_STATE_UP);
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+
+	if (err) {
+		ionic_init_print(WARNING, "Failed to bring port UP\n");
+		return err;
+	}
+
+	return 0;
+}
+
+int
+ionic_port_reset(struct ionic_adapter *adapter)
+{
+	struct ionic_dev *idev = &adapter->idev;
+	int err;
+
+	if (!idev->port_info)
+		return 0;
+
+	ionic_dev_cmd_port_reset(idev);
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+
+	if (err) {
+		ionic_init_print(ERR, "Failed to reset port\n");
+		return err;
+	}
+
+	idev->port_info = NULL;
+	idev->port_info_pa = 0;
+
+	return 0;
+}


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 06/17] net/ionic: add basic lif support
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
                   ` (4 preceding siblings ...)
  2019-10-12  0:26 ` [dpdk-dev] [PATCH 05/17] net/ionic: add port management commands Alfredo Cardigliano
@ 2019-10-12  0:26 ` Alfredo Cardigliano
  2019-10-12 15:26   ` Stephen Hemminger
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 07/17] net/ionic: add doorbells Alfredo Cardigliano
                   ` (11 subsequent siblings)
  17 siblings, 1 reply; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:26 UTC (permalink / raw)
  To: dev

Initialize LIFs (Logical Interfaces) which represents
external connections. The NIC can multiplex many LIFs
to a single port, but in most setups, LIF0 is the
primary control for the port.
Create a device for each LIF.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 drivers/net/ionic/Makefile       |    2 +
 drivers/net/ionic/ionic.h        |    5 +
 drivers/net/ionic/ionic_dev.c    |   38 ++++++++++
 drivers/net/ionic/ionic_dev.h    |    8 ++
 drivers/net/ionic/ionic_ethdev.c |  119 ++++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_ethdev.h |   14 ++++
 drivers/net/ionic/ionic_lif.c    |  142 ++++++++++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_lif.h    |   49 +++++++++++++
 drivers/net/ionic/meson.build    |    4 +
 9 files changed, 378 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/ionic/ionic_ethdev.h
 create mode 100644 drivers/net/ionic/ionic_lif.c
 create mode 100644 drivers/net/ionic/ionic_lif.h

diff --git a/drivers/net/ionic/Makefile b/drivers/net/ionic/Makefile
index 4d42e3778..a1378bdbe 100644
--- a/drivers/net/ionic/Makefile
+++ b/drivers/net/ionic/Makefile
@@ -37,6 +37,7 @@ ifeq ($(shell test $(GCC_VERSION) -ge 44 && echo 1), 1)
 CFLAGS += -Wno-deprecated -Wno-unused-parameter -Wno-unused-value
 CFLAGS += -Wno-strict-aliasing -Wno-format-extra-args
 CFLAGS += -Wno-missing-field-initializers -Wno-pointer-arith
+CFLAGS += -Wno-deprecated-declarations
 endif
 
 ifeq ($(shell test $(GCC_VERSION) -ge 70 && echo 1), 1)
@@ -55,6 +56,7 @@ LDLIBS += -lrte_bus_pci
 SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_mac_api.c
 SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_dev.c
 SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_lif.c
 SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_main.c
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/ionic/ionic.h b/drivers/net/ionic/ionic.h
index c15dc6b44..a30e1cf20 100644
--- a/drivers/net/ionic/ionic.h
+++ b/drivers/net/ionic/ionic.h
@@ -49,7 +49,12 @@ struct ionic_adapter {
 	struct ionic_dev idev;
 	struct ionic_dev_bar bars[IONIC_BARS_MAX];
 	struct ionic_identity	ident;
+	struct ionic_lif *lifs[IONIC_LIFS_MAX];
 	uint32_t num_bars;
+	uint32_t nlifs;
+	uint32_t max_ntxqs_per_lif;
+	uint32_t max_nrxqs_per_lif;
+	uint32_t nintrs;
 	bool is_mgmt_nic;
 	struct rte_pci_device *pci_dev;
 	LIST_ENTRY(ionic_adapter) pci_adapters;
diff --git a/drivers/net/ionic/ionic_dev.c b/drivers/net/ionic/ionic_dev.c
index 7a9890175..9d25c5e15 100644
--- a/drivers/net/ionic/ionic_dev.c
+++ b/drivers/net/ionic/ionic_dev.c
@@ -253,3 +253,41 @@ ionic_dev_cmd_port_loopback(struct ionic_dev *idev, uint8_t loopback_mode)
 
 	ionic_dev_cmd_go(idev, &cmd);
 }
+
+/* LIF commands */
+
+void
+ionic_dev_cmd_lif_identify(struct ionic_dev *idev, uint8_t type, uint8_t ver)
+{
+	union ionic_dev_cmd cmd = {
+		.lif_identify.opcode = IONIC_CMD_LIF_IDENTIFY,
+		.lif_identify.type = type,
+		.lif_identify.ver = ver,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+void
+ionic_dev_cmd_lif_init(struct ionic_dev *idev, uint16_t lif_index,
+		       rte_iova_t info_pa)
+{
+	union ionic_dev_cmd cmd = {
+		.lif_init.opcode = IONIC_CMD_LIF_INIT,
+		.lif_init.index = lif_index,
+		.lif_init.info_pa = info_pa,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+void
+ionic_dev_cmd_lif_reset(struct ionic_dev *idev, uint16_t lif_index)
+{
+	union ionic_dev_cmd cmd = {
+		.lif_init.opcode = IONIC_CMD_LIF_RESET,
+		.lif_init.index = lif_index,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
diff --git a/drivers/net/ionic/ionic_dev.h b/drivers/net/ionic/ionic_dev.h
index aaa031980..9ab482c8a 100644
--- a/drivers/net/ionic/ionic_dev.h
+++ b/drivers/net/ionic/ionic_dev.h
@@ -20,6 +20,8 @@
  */
 #define IONIC_API_VERSION		"3"
 
+#define IONIC_LIFS_MAX			1024
+
 #define IONIC_DEVCMD_TIMEOUT	30 /* devcmd_timeout */
 #define	IONIC_ALIGN             4096
 
@@ -153,4 +155,10 @@ void ionic_dev_cmd_port_pause(struct ionic_dev *idev, uint8_t pause_type);
 void ionic_dev_cmd_port_loopback(struct ionic_dev *idev,
 		uint8_t loopback_mode);
 
+void ionic_dev_cmd_lif_identify(struct ionic_dev *idev, uint8_t type,
+		uint8_t ver);
+void ionic_dev_cmd_lif_init(struct ionic_dev *idev, uint16_t lif_index,
+		rte_iova_t addr);
+void ionic_dev_cmd_lif_reset(struct ionic_dev *idev, uint16_t lif_index);
+
 #endif /* _IONIC_DEV_H_ */
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index 61999bf1d..a0a788ab3 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -7,11 +7,17 @@
 #include <rte_ethdev.h>
 #include <rte_ethdev_driver.h>
 #include <rte_malloc.h>
+#include <rte_ethdev_pci.h>
 
 #include "ionic_logs.h"
 #include "ionic.h"
 #include "ionic_dev.h"
 #include "ionic_mac_api.h"
+#include "ionic_lif.h"
+#include "ionic_ethdev.h"
+
+static int  eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void *init_params);
+static int  eth_ionic_dev_uninit(struct rte_eth_dev *eth_dev);
 
 int ionic_logtype_init;
 int ionic_logtype_driver;
@@ -23,6 +29,9 @@ static const struct rte_pci_id pci_id_ionic_map[] = {
 	{ .vendor_id = 0, /* sentinel */ },
 };
 
+static const struct eth_dev_ops ionic_eth_dev_ops = {
+};
+
 /*
  * There is no room in struct rte_pci_driver to keep a reference
  * to the adapter, using a static list for the time being.
@@ -31,10 +40,75 @@ static LIST_HEAD(ionic_pci_adapters_list, ionic_adapter) ionic_pci_adapters =
 		LIST_HEAD_INITIALIZER(ionic_pci_adapters);
 static rte_spinlock_t ionic_pci_adapters_lock = RTE_SPINLOCK_INITIALIZER;
 
+static int
+eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void *init_params)
+{
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_adapter *adapter = (struct ionic_adapter *)init_params;
+	int err;
+
+	ionic_init_print_call();
+
+	eth_dev->dev_ops = &ionic_eth_dev_ops;
+
+	/* Multi-process not supported, primary does initialization anyway */
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return 0;
+
+	rte_eth_copy_pci_info(eth_dev, pci_dev);
+
+	lif->index = adapter->nlifs;
+	lif->eth_dev = eth_dev;
+	lif->adapter = adapter;
+	adapter->lifs[adapter->nlifs] = lif;
+
+	err = ionic_lif_alloc(lif);
+
+	if (err) {
+		ionic_init_print(ERR, "Cannot allocate LIFs: %d, aborting",
+				err);
+		return err;
+	}
+
+	err = ionic_lif_init(lif);
+
+	if (err) {
+		ionic_init_print(ERR, "Cannot init LIFs: %d, aborting", err);
+		return err;
+	}
+
+	ionic_init_print(DEBUG, "Port %u initialized", eth_dev->data->port_id);
+
+	return 0;
+}
+
+static int
+eth_ionic_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_adapter *adapter = lif->adapter;
+
+	ionic_init_print_call();
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return 0;
+
+	adapter->lifs[lif->index] = NULL;
+
+	ionic_lif_deinit(lif);
+	ionic_lif_free(lif);
+
+	eth_dev->dev_ops = NULL;
+
+	return 0;
+}
+
 static int
 eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 		struct rte_pci_device *pci_dev)
 {
+	char name[RTE_ETH_NAME_MAX_LEN];
 	struct rte_mem_resource *resource;
 	struct ionic_adapter *adapter;
 	struct ionic_hw *hw;
@@ -119,6 +193,41 @@ eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 		return err;
 	}
 
+	/* Configure LIFs */
+	err = ionic_lif_identify(adapter);
+
+	if (err) {
+		ionic_init_print(ERR, "Cannot identify lif: %d, aborting", err);
+		return err;
+	}
+
+	/* Allocate and init LIFs */
+	err = ionic_lifs_size(adapter);
+
+	if (err) {
+		ionic_init_print(ERR, "Cannot size LIFs: %d, aborting", err);
+		return err;
+	}
+
+	adapter->nlifs = 0;
+	for (i = 0; i < adapter->ident.dev.nlifs; i++) {
+		snprintf(name, sizeof(name), "net_%s_lif_%lu",
+			pci_dev->device.name, i);
+
+		err = rte_eth_dev_create(&pci_dev->device, name,
+			sizeof(struct ionic_lif),
+			NULL, NULL,
+			eth_ionic_dev_init, adapter);
+
+		if (err) {
+			ionic_init_print(ERR, "Cannot create eth device for "
+					"ionic lif %s", name);
+			break;
+		}
+
+		adapter->nlifs++;
+	}
+
 	rte_spinlock_lock(&ionic_pci_adapters_lock);
 	LIST_INSERT_HEAD(&ionic_pci_adapters, adapter, pci_adapters);
 	rte_spinlock_unlock(&ionic_pci_adapters_lock);
@@ -130,6 +239,8 @@ static int
 eth_ionic_pci_remove(struct rte_pci_device *pci_dev)
 {
 	struct ionic_adapter *adapter = NULL;
+	struct ionic_lif *lif;
+	uint32_t i;
 
 	rte_spinlock_lock(&ionic_pci_adapters_lock);
 	LIST_FOREACH(adapter, &ionic_pci_adapters, pci_adapters) {
@@ -142,8 +253,14 @@ eth_ionic_pci_remove(struct rte_pci_device *pci_dev)
 		LIST_REMOVE(adapter, pci_adapters);
 	rte_spinlock_unlock(&ionic_pci_adapters_lock);
 
-	if (adapter)
+	if (adapter) {
+		for (i = 0; i < adapter->nlifs; i++) {
+			lif = adapter->lifs[i];
+			rte_eth_dev_destroy(lif->eth_dev, eth_ionic_dev_uninit);
+		}
+
 		rte_free(adapter);
+	}
 
 	return 0;
 }
diff --git a/drivers/net/ionic/ionic_ethdev.h b/drivers/net/ionic/ionic_ethdev.h
new file mode 100644
index 000000000..9f1c0320d
--- /dev/null
+++ b/drivers/net/ionic/ionic_ethdev.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#ifndef _IONIC_ETHDEV_H_
+#define _IONIC_ETHDEV_H_
+
+#define IONIC_ETH_DEV_TO_LIF(eth_dev) ((struct ionic_lif *) \
+		eth_dev->data->dev_private)
+#define IONIC_ETH_DEV_TO_ADAPTER(eth_dev) \
+		(IONIC_ETH_DEV_TO_LIF(eth_dev)->adapter)
+
+#endif /* _IONIC_ETHDEV_H_ */
+
diff --git a/drivers/net/ionic/ionic_lif.c b/drivers/net/ionic/ionic_lif.c
new file mode 100644
index 000000000..c67619d85
--- /dev/null
+++ b/drivers/net/ionic/ionic_lif.c
@@ -0,0 +1,142 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#include <rte_malloc.h>
+#include <rte_ethdev_driver.h>
+
+#include "ionic.h"
+#include "ionic_logs.h"
+#include "ionic_lif.h"
+#include "ionic_ethdev.h"
+
+int
+ionic_lif_alloc(struct ionic_lif *lif)
+{
+	uint32_t socket_id = rte_socket_id();
+
+	snprintf(lif->name, sizeof(lif->name), "lif%u", lif->index);
+
+	ionic_init_print(DEBUG, "Allocating Lif Info");
+
+	lif->info_sz = RTE_ALIGN(sizeof(*lif->info), PAGE_SIZE);
+
+	lif->info_z = rte_eth_dma_zone_reserve(lif->eth_dev,
+		"lif_info", 0 /* queue_idx*/,
+		lif->info_sz, IONIC_ALIGN, socket_id);
+
+	if (!lif->info_z) {
+		ionic_init_print(ERR, "Cannot allocate lif info memory");
+		return -ENOMEM;
+	}
+
+	lif->info = lif->info_z->addr;
+	lif->info_pa = lif->info_z->iova;
+
+	return 0;
+}
+
+void
+ionic_lif_free(struct ionic_lif *lif)
+{
+	if (lif->info)
+		rte_memzone_free(lif->info_z);
+}
+
+int
+ionic_lif_init(struct ionic_lif *lif)
+{
+	struct ionic_dev *idev = &lif->adapter->idev;
+	struct ionic_q_init_comp comp;
+	int err;
+
+	ionic_dev_cmd_lif_init(idev, lif->index, lif->info_pa);
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+	ionic_dev_cmd_comp(idev, &comp);
+	if (err)
+		return err;
+
+	lif->hw_index = comp.hw_index;
+
+	lif->state |= IONIC_LIF_F_INITED;
+
+	return 0;
+}
+
+void
+ionic_lif_deinit(struct ionic_lif *lif)
+{
+	if (!(lif->state & IONIC_LIF_F_INITED))
+		return;
+
+	lif->state &= ~IONIC_LIF_F_INITED;
+}
+
+int
+ionic_lif_identify(struct ionic_adapter *adapter)
+{
+	struct ionic_dev *idev = &adapter->idev;
+	struct ionic_identity *ident = &adapter->ident;
+	int err;
+	unsigned int i;
+	unsigned int lif_words = sizeof(ident->lif.words) /
+		sizeof(ident->lif.words[0]);
+	unsigned int cmd_words = sizeof(idev->dev_cmd->data) /
+		sizeof(idev->dev_cmd->data[0]);
+	unsigned int nwords;
+
+	ionic_dev_cmd_lif_identify(idev, IONIC_LIF_TYPE_CLASSIC,
+		IONIC_IDENTITY_VERSION_1);
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+	if (err)
+		return (err);
+
+	nwords = RTE_MIN(lif_words, cmd_words);
+	for (i = 0; i < nwords; i++)
+		ident->lif.words[i] = ioread32(&idev->dev_cmd->data[i]);
+
+	ionic_init_print(INFO, "capabilities 0x%lx ", ident->lif.capabilities);
+
+	ionic_init_print(INFO, "eth.max_ucast_filters 0x%x ",
+		ident->lif.eth.max_ucast_filters);
+	ionic_init_print(INFO, "eth.max_mcast_filters 0x%x ",
+		ident->lif.eth.max_mcast_filters);
+
+	ionic_init_print(INFO, "eth.features 0x%lx ",
+		ident->lif.eth.config.features);
+	ionic_init_print(INFO, "eth.queue_count[IONIC_QTYPE_ADMINQ] 0x%x ",
+		ident->lif.eth.config.queue_count[IONIC_QTYPE_ADMINQ]);
+	ionic_init_print(INFO, "eth.queue_count[IONIC_QTYPE_NOTIFYQ] 0x%x ",
+		ident->lif.eth.config.queue_count[IONIC_QTYPE_NOTIFYQ]);
+	ionic_init_print(INFO, "eth.queue_count[IONIC_QTYPE_RXQ] 0x%x ",
+		ident->lif.eth.config.queue_count[IONIC_QTYPE_RXQ]);
+	ionic_init_print(INFO, "eth.queue_count[IONIC_QTYPE_TXQ] 0x%x ",
+		ident->lif.eth.config.queue_count[IONIC_QTYPE_TXQ]);
+
+	return 0;
+}
+
+int
+ionic_lifs_size(struct ionic_adapter *adapter)
+{
+	struct ionic_identity *ident = &adapter->ident;
+	uint32_t nlifs = ident->dev.nlifs;
+	uint32_t nintrs, dev_nintrs = ident->dev.nintrs;
+
+	adapter->max_ntxqs_per_lif =
+			ident->lif.eth.config.queue_count[IONIC_QTYPE_TXQ];
+	adapter->max_nrxqs_per_lif =
+			ident->lif.eth.config.queue_count[IONIC_QTYPE_RXQ];
+
+	nintrs = nlifs * 1 /* notifyq */;
+
+	if (nintrs > dev_nintrs) {
+		ionic_init_print(ERR, "At most %d intr queues supported, minimum required is %u",
+				dev_nintrs, nintrs);
+		return -ENOSPC;
+	}
+
+	adapter->nintrs = nintrs;
+
+	return 0;
+}
diff --git a/drivers/net/ionic/ionic_lif.h b/drivers/net/ionic/ionic_lif.h
new file mode 100644
index 000000000..374cebd05
--- /dev/null
+++ b/drivers/net/ionic/ionic_lif.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#ifndef _IONIC_LIF_H_
+#define _IONIC_LIF_H_
+
+#include <inttypes.h>
+
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+
+#include "ionic_osdep.h"
+#include "ionic_dev.h"
+
+#define IONIC_LIF_F_INITED		BIT(0)
+
+#define IONIC_LIF_NAME_MAX_SZ		(32)
+
+struct ionic_lif {
+	struct ionic_adapter *adapter;
+	struct rte_eth_dev *eth_dev;
+	uint16_t port_id;  /**< Device port identifier */
+	uint32_t index;
+	uint32_t hw_index;
+	char name[IONIC_LIF_NAME_MAX_SZ];
+	uint32_t state;
+	uint32_t info_sz;
+	struct ionic_lif_info *info;
+	rte_iova_t info_pa;
+	const struct rte_memzone *info_z;
+};
+
+int ionic_lif_identify(struct ionic_adapter *adapter);
+int ionic_lifs_size(struct ionic_adapter *ionic);
+
+int ionic_lif_alloc(struct ionic_lif *lif);
+void ionic_lif_free(struct ionic_lif *lif);
+
+int ionic_lif_init(struct ionic_lif *lif);
+void ionic_lif_deinit(struct ionic_lif *lif);
+
+int ionic_lif_start(struct ionic_lif *lif);
+int ionic_lif_stop(struct ionic_lif *lif);
+
+int ionic_lif_configure(struct ionic_lif *lif);
+void ionic_lif_reset(struct ionic_lif *lif);
+
+#endif /* _IONIC_LIF_H_ */
diff --git a/drivers/net/ionic/meson.build b/drivers/net/ionic/meson.build
index bd63e6136..0cf5a0cc7 100644
--- a/drivers/net/ionic/meson.build
+++ b/drivers/net/ionic/meson.build
@@ -7,7 +7,7 @@ sources = files(
 	'ionic_mac_api.c',
 	'ionic_dev.c',
 	'ionic_ethdev.c',
-	'ionic_main.c',
-	'ionic_ethdev.c'
+	'ionic_lif.c',
+	'ionic_main.c'
 )
 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 07/17] net/ionic: add doorbells
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
                   ` (5 preceding siblings ...)
  2019-10-12  0:26 ` [dpdk-dev] [PATCH 06/17] net/ionic: add basic lif support Alfredo Cardigliano
@ 2019-10-12  0:27 ` Alfredo Cardigliano
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 08/17] net/ionic: add adminq support Alfredo Cardigliano
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:27 UTC (permalink / raw)
  To: dev

Doorbell registers are used by the driver to signal to the NIC
that requests are waiting on the message queues.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 drivers/net/ionic/ionic_dev.c |   15 +++++++++++++++
 drivers/net/ionic/ionic_dev.h |   19 +++++++++++++++++++
 drivers/net/ionic/ionic_lif.c |   24 ++++++++++++++++++++++++
 drivers/net/ionic/ionic_lif.h |    4 +++-
 4 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ionic/ionic_dev.c b/drivers/net/ionic/ionic_dev.c
index 9d25c5e15..d0a4d5268 100644
--- a/drivers/net/ionic/ionic_dev.c
+++ b/drivers/net/ionic/ionic_dev.c
@@ -5,6 +5,7 @@
 #include <rte_malloc.h>
 
 #include "ionic_dev.h"
+#include "ionic_lif.h"
 #include "ionic.h"
 
 int
@@ -291,3 +292,17 @@ ionic_dev_cmd_lif_reset(struct ionic_dev *idev, uint16_t lif_index)
 
 	ionic_dev_cmd_go(idev, &cmd);
 }
+
+int
+ionic_db_page_num(struct ionic_lif *lif, int pid)
+{
+	return (lif->index * 0) + pid;
+}
+
+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;
+}
diff --git a/drivers/net/ionic/ionic_dev.h b/drivers/net/ionic/ionic_dev.h
index 9ab482c8a..812d800d9 100644
--- a/drivers/net/ionic/ionic_dev.h
+++ b/drivers/net/ionic/ionic_dev.h
@@ -132,6 +132,23 @@ struct ionic_dev {
 	uint32_t port_info_sz;
 };
 
+#define IONIC_INTR_INDEX_NOT_ASSIGNED	(-1)
+#define IONIC_INTR_NAME_MAX_SZ		(32)
+
+struct ionic_intr_info {
+	char name[IONIC_INTR_NAME_MAX_SZ];
+	int index;
+	uint32_t vector;
+	struct ionic_intr __iomem *ctrl;
+	uint64_t rearm_count;
+};
+
+struct ionic_lif;
+struct ionic_adapter;
+
+void ionic_intr_init(struct ionic_dev *idev, struct ionic_intr_info *intr,
+		unsigned long index);
+
 int ionic_dev_setup(struct ionic_adapter *adapter);
 
 void ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd);
@@ -161,4 +178,6 @@ void ionic_dev_cmd_lif_init(struct ionic_dev *idev, uint16_t lif_index,
 		rte_iova_t addr);
 void ionic_dev_cmd_lif_reset(struct ionic_dev *idev, uint16_t lif_index);
 
+int ionic_db_page_num(struct ionic_lif *lif, int pid);
+
 #endif /* _IONIC_DEV_H_ */
diff --git a/drivers/net/ionic/ionic_lif.c b/drivers/net/ionic/ionic_lif.c
index c67619d85..c36bb6bc3 100644
--- a/drivers/net/ionic/ionic_lif.c
+++ b/drivers/net/ionic/ionic_lif.c
@@ -10,15 +10,39 @@
 #include "ionic_lif.h"
 #include "ionic_ethdev.h"
 
+static void *
+ionic_bus_map_dbpage(struct ionic_adapter *adapter, int page_num)
+{
+	char *vaddr = adapter->bars[IONIC_PCI_BAR_DBELL].vaddr;
+
+	if (adapter->num_bars <= IONIC_PCI_BAR_DBELL)
+		return NULL;
+
+	return (void *)&vaddr[page_num << PAGE_SHIFT];
+}
+
 int
 ionic_lif_alloc(struct ionic_lif *lif)
 {
+	struct ionic_adapter *adapter = lif->adapter;
 	uint32_t socket_id = rte_socket_id();
+	int dbpage_num;
 
 	snprintf(lif->name, sizeof(lif->name), "lif%u", lif->index);
 
 	ionic_init_print(DEBUG, "Allocating Lif Info");
 
+	lif->kern_pid = 0;
+
+	dbpage_num = ionic_db_page_num(lif, 0);
+
+	lif->kern_dbpage = ionic_bus_map_dbpage(adapter, dbpage_num);
+
+	if (!lif->kern_dbpage) {
+		ionic_init_print(ERR, "Cannot map dbpage, aborting");
+		return -ENOMEM;
+	}
+
 	lif->info_sz = RTE_ALIGN(sizeof(*lif->info), PAGE_SIZE);
 
 	lif->info_z = rte_eth_dma_zone_reserve(lif->eth_dev,
diff --git a/drivers/net/ionic/ionic_lif.h b/drivers/net/ionic/ionic_lif.h
index 374cebd05..6b912efa0 100644
--- a/drivers/net/ionic/ionic_lif.h
+++ b/drivers/net/ionic/ionic_lif.h
@@ -23,8 +23,10 @@ struct ionic_lif {
 	uint16_t port_id;  /**< Device port identifier */
 	uint32_t index;
 	uint32_t hw_index;
-	char name[IONIC_LIF_NAME_MAX_SZ];
 	uint32_t state;
+	uint32_t kern_pid;
+	struct ionic_doorbell __iomem *kern_dbpage;
+	char name[IONIC_LIF_NAME_MAX_SZ];
 	uint32_t info_sz;
 	struct ionic_lif_info *info;
 	rte_iova_t info_pa;


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 08/17] net/ionic: add adminq support
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
                   ` (6 preceding siblings ...)
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 07/17] net/ionic: add doorbells Alfredo Cardigliano
@ 2019-10-12  0:27 ` Alfredo Cardigliano
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 09/17] net/ionic: add notifyq support Alfredo Cardigliano
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:27 UTC (permalink / raw)
  To: dev

Add support for the admin queue, which is used for most
of the NIC configurations.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 drivers/net/ionic/ionic.h      |    4 
 drivers/net/ionic/ionic_dev.c  |  256 +++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_dev.h  |   96 +++++++++++
 drivers/net/ionic/ionic_lif.c  |  356 ++++++++++++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_lif.h  |   36 ++++
 drivers/net/ionic/ionic_main.c |  188 +++++++++++++++++++++
 6 files changed, 934 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ionic/ionic.h b/drivers/net/ionic/ionic.h
index a30e1cf20..3a9bb7b22 100644
--- a/drivers/net/ionic/ionic.h
+++ b/drivers/net/ionic/ionic.h
@@ -55,11 +55,15 @@ struct ionic_adapter {
 	uint32_t max_ntxqs_per_lif;
 	uint32_t max_nrxqs_per_lif;
 	uint32_t nintrs;
+	bool intrs[IONIC_INTR_CTRL_REGS_MAX];
 	bool is_mgmt_nic;
 	struct rte_pci_device *pci_dev;
 	LIST_ENTRY(ionic_adapter) pci_adapters;
 };
 
+int ionic_adminq_check_err(struct ionic_lif *lif, struct ionic_admin_ctx *ctx,
+		bool timeout);
+int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx);
 int ionic_dev_cmd_wait_check(struct ionic_dev *idev, unsigned long max_wait);
 int ionic_setup(struct ionic_adapter *adapter);
 
diff --git a/drivers/net/ionic/ionic_dev.c b/drivers/net/ionic/ionic_dev.c
index d0a4d5268..fc165d0a8 100644
--- a/drivers/net/ionic/ionic_dev.c
+++ b/drivers/net/ionic/ionic_dev.c
@@ -293,6 +293,12 @@ ionic_dev_cmd_lif_reset(struct ionic_dev *idev, uint16_t lif_index)
 	ionic_dev_cmd_go(idev, &cmd);
 }
 
+struct ionic_doorbell *
+ionic_db_map(struct ionic_lif *lif, struct ionic_queue *q)
+{
+	return lif->kern_dbpage + q->hw_type;
+}
+
 int
 ionic_db_page_num(struct ionic_lif *lif, int pid)
 {
@@ -306,3 +312,253 @@ ionic_intr_init(struct ionic_dev *idev, struct ionic_intr_info *intr,
 	ionic_intr_clean(idev->intr_ctrl, index);
 	intr->index = index;
 }
+
+void
+ionic_dev_cmd_adminq_init(struct ionic_dev *idev,
+			  struct ionic_qcq *qcq,
+			  uint16_t lif_index, uint16_t intr_index)
+{
+	struct ionic_queue *q = &qcq->q;
+	struct ionic_cq *cq = &qcq->cq;
+
+	union ionic_dev_cmd cmd = {
+		.q_init.opcode = IONIC_CMD_Q_INIT,
+		.q_init.lif_index = lif_index,
+		.q_init.type = q->type,
+		.q_init.index = q->index,
+		.q_init.flags = IONIC_QINIT_F_ENA,
+		.q_init.pid = q->pid,
+		.q_init.intr_index = intr_index,
+		.q_init.ring_size = ilog2(q->num_descs),
+		.q_init.ring_base = q->base_pa,
+		.q_init.cq_ring_base = cq->base_pa,
+	};
+
+	ionic_dev_cmd_go(idev, &cmd);
+}
+
+int
+ionic_cq_init(struct ionic_lif *lif, struct ionic_cq *cq,
+		struct ionic_intr_info *intr,
+		uint32_t num_descs, size_t desc_size)
+{
+	if (desc_size == 0) {
+		ionic_init_print(ERR, "Descriptor size is %lu", desc_size);
+		return -EINVAL;
+	}
+
+	if (!rte_is_power_of_2(num_descs) ||
+	    num_descs < IONIC_MIN_RING_DESC ||
+	    num_descs > IONIC_MAX_RING_DESC) {
+		ionic_init_print(ERR, "%u descriptors (min: %u max: %u)",
+			num_descs, IONIC_MIN_RING_DESC, IONIC_MAX_RING_DESC);
+		return -EINVAL;
+	}
+
+	cq->lif = lif;
+	cq->bound_intr = intr;
+	cq->num_descs = num_descs;
+	cq->desc_size = desc_size;
+	cq->tail_idx = 0;
+	cq->done_color = 1;
+
+	return 0;
+}
+
+void
+ionic_cq_map(struct ionic_cq *cq, void *base, rte_iova_t base_pa)
+{
+	cq->base = base;
+	cq->base_pa = base_pa;
+}
+
+void
+ionic_cq_bind(struct ionic_cq *cq, struct ionic_queue *q)
+{
+	cq->bound_q = q;
+	q->bound_cq = cq;
+}
+
+uint32_t
+ionic_cq_service(struct ionic_cq *cq, uint32_t work_to_do,
+		 ionic_cq_cb cb, void *cb_arg)
+{
+	uint32_t work_done = 0;
+
+	if (work_to_do == 0)
+		return 0;
+
+	while (cb(cq, cq->tail_idx, cb_arg)) {
+		cq->tail_idx = (cq->tail_idx + 1) & (cq->num_descs - 1);
+		if (cq->tail_idx == 0)
+			cq->done_color = !cq->done_color;
+
+		if (++work_done == work_to_do)
+			break;
+	}
+
+	return work_done;
+}
+
+int
+ionic_q_init(struct ionic_lif *lif, struct ionic_dev *idev,
+	     struct ionic_queue *q,
+	     uint32_t index, const char *base, uint32_t num_descs,
+	     size_t desc_size, size_t sg_desc_size, uint32_t pid)
+{
+	uint32_t ring_size;
+
+	if (desc_size == 0 || !rte_is_power_of_2(num_descs))
+		return -EINVAL;
+
+	ring_size = ilog2(num_descs);
+
+	if (ring_size < 2 || ring_size > 16)
+		return -EINVAL;
+
+	q->lif = lif;
+	q->idev = idev;
+	q->index = index;
+	q->num_descs = num_descs;
+	q->desc_size = desc_size;
+	q->sg_desc_size = sg_desc_size;
+	q->head_idx = 0;
+	q->tail_idx = 0;
+	q->pid = pid;
+
+	return 0;
+}
+
+void
+ionic_q_map(struct ionic_queue *q, void *base, rte_iova_t base_pa)
+{
+	q->base = base;
+	q->base_pa = base_pa;
+}
+
+void
+ionic_q_sg_map(struct ionic_queue *q, void *base, rte_iova_t base_pa)
+{
+	q->sg_base = base;
+	q->sg_base_pa = base_pa;
+}
+
+void
+ionic_q_flush(struct ionic_queue *q)
+{
+	writeq(IONIC_DBELL_QID(q->hw_index) | q->head_idx, q->db);
+}
+
+void
+ionic_q_post(struct ionic_queue *q, bool ring_doorbell, desc_cb cb,
+	     void *cb_arg)
+{
+	struct ionic_desc_info *head = &q->info[q->head_idx];
+
+	head->cb = cb;
+	head->cb_arg = cb_arg;
+
+	q->head_idx = (q->head_idx + 1) & (q->num_descs - 1);
+
+	if (ring_doorbell)
+		ionic_q_flush(q);
+}
+
+uint32_t
+ionic_q_space_avail(struct ionic_queue *q)
+{
+	uint32_t avail = q->tail_idx;
+
+	if (q->head_idx >= avail)
+		avail += q->num_descs - q->head_idx - 1;
+	else
+		avail -= q->head_idx + 1;
+
+	return avail;
+}
+
+bool
+ionic_q_has_space(struct ionic_queue *q, uint32_t want)
+{
+	return ionic_q_space_avail(q) >= want;
+}
+
+void
+ionic_q_service(struct ionic_queue *q, uint32_t cq_desc_index,
+		uint32_t stop_index, void *service_cb_arg)
+{
+	struct ionic_desc_info *desc_info;
+	uint32_t curr_q_tail_idx;
+
+	do {
+		desc_info = &q->info[q->tail_idx];
+
+		if (desc_info->cb)
+			desc_info->cb(q, q->tail_idx, cq_desc_index,
+				      desc_info->cb_arg, service_cb_arg);
+
+		desc_info->cb = NULL;
+		desc_info->cb_arg = NULL;
+
+		curr_q_tail_idx = q->tail_idx;
+		q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
+
+	} while (curr_q_tail_idx != stop_index);
+}
+
+static void
+ionic_adminq_cb(struct ionic_queue *q,
+		uint32_t q_desc_index, uint32_t cq_desc_index,
+		void *cb_arg, void *service_cb_arg __rte_unused)
+{
+	struct ionic_admin_ctx *ctx = cb_arg;
+	struct ionic_admin_comp *cq_desc_base = q->bound_cq->base;
+	struct ionic_admin_comp *cq_desc = &cq_desc_base[cq_desc_index];
+
+	if (unlikely(cq_desc->comp_index != q_desc_index)) {
+		IONIC_WARN_ON(cq_desc->comp_index != q_desc_index);
+		return;
+	}
+
+	memcpy(&ctx->comp, cq_desc, sizeof(*cq_desc));
+
+	ctx->pending_work = false; /* done */
+}
+
+/** ionic_adminq_post - Post an admin command.
+ * @lif:		Handle to lif.
+ * @cmd_ctx:		Api admin command context.
+ *
+ * Post the command to an admin queue in the ethernet driver.  If this command
+ * succeeds, then the command has been posted, but that does not indicate a
+ * completion.  If this command returns success, then the completion callback
+ * will eventually be called.
+ *
+ * Return: zero or negative error status.
+ */
+int
+ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
+{
+	struct ionic_queue *adminq = &lif->adminqcq->q;
+	struct ionic_admin_cmd *q_desc_base = adminq->base;
+	struct ionic_admin_cmd *q_desc;
+	int err = 0;
+
+	rte_spinlock_lock(&lif->adminq_lock);
+
+	if (!ionic_q_has_space(adminq, 1)) {
+		err = -ENOSPC;
+		goto err_out;
+	}
+
+	q_desc = &q_desc_base[adminq->head_idx];
+
+	memcpy(q_desc, &ctx->cmd, sizeof(ctx->cmd));
+
+	ionic_q_post(adminq, true, ionic_adminq_cb, ctx);
+
+err_out:
+	rte_spinlock_unlock(&lif->adminq_lock);
+
+	return err;
+}
diff --git a/drivers/net/ionic/ionic_dev.h b/drivers/net/ionic/ionic_dev.h
index 812d800d9..ada07edff 100644
--- a/drivers/net/ionic/ionic_dev.h
+++ b/drivers/net/ionic/ionic_dev.h
@@ -20,6 +20,9 @@
  */
 #define IONIC_API_VERSION		"3"
 
+#define IONIC_MAX_RING_DESC		32768
+#define IONIC_MIN_RING_DESC		16
+
 #define IONIC_LIFS_MAX			1024
 
 #define IONIC_DEVCMD_TIMEOUT	30 /* devcmd_timeout */
@@ -132,6 +135,44 @@ struct ionic_dev {
 	uint32_t port_info_sz;
 };
 
+struct ionic_queue;
+struct ionic_desc_info;
+
+typedef void (*desc_cb)(struct ionic_queue *q,
+			uint32_t q_desc_index,
+			uint32_t cq_desc_index,
+			void *cb_arg, void *service_cb_arg);
+
+struct ionic_desc_info {
+	desc_cb cb;
+	void *cb_arg;
+};
+
+struct ionic_queue {
+	struct ionic_dev *idev;
+	struct ionic_lif *lif;
+	struct ionic_cq *bound_cq;
+	uint32_t index;
+	uint32_t type;
+	uint32_t hw_index;
+	uint32_t hw_type;
+	void *base;
+	void *sg_base;
+	rte_iova_t base_pa;
+	rte_iova_t sg_base_pa;
+	struct ionic_desc_info *info;
+	uint32_t tail_idx;
+	uint32_t head_idx;
+	uint32_t num_descs;
+	uint32_t desc_size;
+	uint32_t sg_desc_size;
+	uint32_t pid;
+	uint32_t qid;
+	uint32_t qtype;
+	struct ionic_doorbell __iomem *db;
+	void *nop_desc;
+};
+
 #define IONIC_INTR_INDEX_NOT_ASSIGNED	(-1)
 #define IONIC_INTR_NAME_MAX_SZ		(32)
 
@@ -140,11 +181,34 @@ struct ionic_intr_info {
 	int index;
 	uint32_t vector;
 	struct ionic_intr __iomem *ctrl;
-	uint64_t rearm_count;
+};
+
+struct ionic_cq {
+	struct ionic_lif *lif;
+	struct ionic_queue *bound_q;
+	uint32_t tail_idx;
+	uint32_t num_descs;
+	uint32_t desc_size;
+	bool done_color;
+	void *base;
+	rte_iova_t base_pa;
+	struct ionic_intr_info *bound_intr;
+};
+
+/** ionic_admin_ctx - Admin command context.
+ * @pending_work:	Flag that indicates a completion.
+ * @cmd:		Admin command (64B) to be copied to the queue.
+ * @comp:		Admin completion (16B) copied from the queue.
+ */
+struct ionic_admin_ctx {
+	bool pending_work;
+	union ionic_adminq_cmd cmd;
+	union ionic_adminq_comp comp;
 };
 
 struct ionic_lif;
 struct ionic_adapter;
+struct ionic_qcq;
 
 void ionic_intr_init(struct ionic_dev *idev, struct ionic_intr_info *intr,
 		unsigned long index);
@@ -177,7 +241,37 @@ void ionic_dev_cmd_lif_identify(struct ionic_dev *idev, uint8_t type,
 void ionic_dev_cmd_lif_init(struct ionic_dev *idev, uint16_t lif_index,
 		rte_iova_t addr);
 void ionic_dev_cmd_lif_reset(struct ionic_dev *idev, uint16_t lif_index);
+void ionic_dev_cmd_adminq_init(struct ionic_dev *idev, struct ionic_qcq *qcq,
+		uint16_t lif_index, uint16_t intr_index);
 
+struct ionic_doorbell __iomem *ionic_db_map(struct ionic_lif *lif,
+		struct ionic_queue *q);
 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, uint32_t num_descs,
+		size_t desc_size);
+void ionic_cq_map(struct ionic_cq *cq, void *base, rte_iova_t base_pa);
+void ionic_cq_bind(struct ionic_cq *cq, struct ionic_queue *q);
+typedef bool (*ionic_cq_cb)(struct ionic_cq *cq, uint32_t cq_desc_index,
+		void *cb_arg);
+uint32_t ionic_cq_service(struct ionic_cq *cq, uint32_t work_to_do,
+		ionic_cq_cb cb, void *cb_arg);
+
+int ionic_q_init(struct ionic_lif *lif, struct ionic_dev *idev,
+		struct ionic_queue *q,
+		uint32_t index, const char *base, uint32_t num_descs,
+		size_t desc_size, size_t sg_desc_size, uint32_t pid);
+void ionic_q_map(struct ionic_queue *q, void *base, rte_iova_t base_pa);
+void ionic_q_sg_map(struct ionic_queue *q, void *base, rte_iova_t base_pa);
+void ionic_q_flush(struct ionic_queue *q);
+void ionic_q_post(struct ionic_queue *q, bool ring_doorbell, desc_cb cb,
+		void *cb_arg);
+uint32_t ionic_q_space_avail(struct ionic_queue *q);
+bool ionic_q_has_space(struct ionic_queue *q, uint32_t want);
+void ionic_q_service(struct ionic_queue *q, uint32_t cq_desc_index,
+		uint32_t stop_index, void *service_cb_arg);
+
+int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx);
+
 #endif /* _IONIC_DEV_H_ */
diff --git a/drivers/net/ionic/ionic_lif.c b/drivers/net/ionic/ionic_lif.c
index c36bb6bc3..f2ede6d23 100644
--- a/drivers/net/ionic/ionic_lif.c
+++ b/drivers/net/ionic/ionic_lif.c
@@ -10,6 +10,259 @@
 #include "ionic_lif.h"
 #include "ionic_ethdev.h"
 
+int
+ionic_qcq_enable(struct ionic_qcq *qcq)
+{
+	struct ionic_queue *q = &qcq->q;
+	struct ionic_lif *lif = q->lif;
+	struct ionic_dev *idev = &lif->adapter->idev;
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.q_control = {
+			.opcode = IONIC_CMD_Q_CONTROL,
+			.lif_index = lif->index,
+			.type = q->type,
+			.index = q->index,
+			.oper = IONIC_Q_ENABLE,
+		},
+	};
+
+	if (qcq->flags & IONIC_QCQ_F_INTR) {
+		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
+				IONIC_INTR_MASK_CLEAR);
+	}
+
+	return ionic_adminq_post_wait(lif, &ctx);
+}
+
+int
+ionic_qcq_disable(struct ionic_qcq *qcq)
+{
+	struct ionic_queue *q = &qcq->q;
+	struct ionic_lif *lif = q->lif;
+	struct ionic_dev *idev = &lif->adapter->idev;
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.q_control = {
+			.opcode = IONIC_CMD_Q_CONTROL,
+			.lif_index = lif->index,
+			.type = q->type,
+			.index = q->index,
+			.oper = IONIC_Q_DISABLE,
+		},
+	};
+
+	if (qcq->flags & IONIC_QCQ_F_INTR) {
+		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
+				IONIC_INTR_MASK_SET);
+	}
+
+	return ionic_adminq_post_wait(lif, &ctx);
+}
+
+int
+ionic_intr_alloc(struct ionic_lif *lif, struct ionic_intr_info *intr)
+{
+	struct ionic_adapter *adapter = lif->adapter;
+	struct ionic_dev *idev = &adapter->idev;
+	unsigned long index;
+
+	/*
+	 * Note: interrupt handler is called for index = 0 only
+	 * (we use interrupts for the notifyq only anyway,
+	 * which hash index = 0)
+	 */
+
+	for (index = 0; index < adapter->nintrs; index++)
+		if (!adapter->intrs[index])
+			break;
+
+	if (index == adapter->nintrs)
+		return -ENOSPC;
+
+	adapter->intrs[index] = true;
+
+	ionic_intr_init(idev, intr, index);
+
+	return 0;
+}
+
+void
+ionic_intr_free(struct ionic_lif *lif, struct ionic_intr_info *intr)
+{
+	if (intr->index != IONIC_INTR_INDEX_NOT_ASSIGNED)
+		lif->adapter->intrs[intr->index] = false;
+}
+
+static int
+ionic_qcq_alloc(struct ionic_lif *lif, uint8_t type,
+		uint32_t index,
+		const char *base, uint32_t flags,
+		uint32_t num_descs,
+		uint32_t desc_size,
+		uint32_t cq_desc_size,
+		uint32_t sg_desc_size,
+		uint32_t pid, struct ionic_qcq **qcq)
+{
+	struct ionic_dev *idev = &lif->adapter->idev;
+	struct ionic_qcq *new;
+	uint32_t q_size, cq_size, sg_size, total_size;
+	void *q_base, *cq_base, *sg_base;
+	rte_iova_t q_base_pa = 0;
+	rte_iova_t cq_base_pa = 0;
+	rte_iova_t sg_base_pa = 0;
+	uint32_t socket_id = rte_socket_id();
+	int err;
+
+	*qcq = NULL;
+
+	q_size  = num_descs * desc_size;
+	cq_size = num_descs * cq_desc_size;
+	sg_size = num_descs * sg_desc_size;
+
+	total_size = RTE_ALIGN(q_size, PAGE_SIZE) +
+			RTE_ALIGN(cq_size, PAGE_SIZE);
+	/*
+	 * Note: aligning q_size/cq_size is not enough due to cq_base address
+	 * aligning as q_base could be not aligned to the page.
+	 * Adding PAGE_SIZE.
+	 */
+	total_size += PAGE_SIZE;
+
+	if (flags & IONIC_QCQ_F_SG) {
+		total_size += RTE_ALIGN(sg_size, PAGE_SIZE);
+		total_size += PAGE_SIZE;
+	}
+
+	new = rte_zmalloc("ionic", sizeof(*new), 0);
+
+	if (!new) {
+		ionic_init_print(ERR, "Cannot allocate queue structure");
+		return -ENOMEM;
+	}
+
+	new->lif = lif;
+	new->flags = flags;
+
+	new->q.info = rte_zmalloc("ionic", sizeof(*new->q.info) * num_descs, 0);
+
+	if (!new->q.info) {
+		ionic_init_print(ERR, "Cannot allocate queue info");
+		return -ENOMEM;
+	}
+
+	new->q.type = type;
+
+	err = ionic_q_init(lif, idev, &new->q, index, base, num_descs,
+			desc_size, sg_desc_size, pid);
+
+	if (err) {
+		ionic_init_print(ERR, "Queue initialization failed");
+		return err;
+	}
+
+	if (flags & IONIC_QCQ_F_INTR) {
+		err = ionic_intr_alloc(lif, &new->intr);
+		if (err)
+			return err;
+
+		ionic_intr_mask_assert(idev->intr_ctrl, new->intr.index,
+				IONIC_INTR_MASK_SET);
+	} else {
+		new->intr.index = IONIC_INTR_INDEX_NOT_ASSIGNED;
+	}
+
+	err = ionic_cq_init(lif, &new->cq, &new->intr,
+			num_descs, cq_desc_size);
+	if (err) {
+		ionic_init_print(ERR, "Completion queue initialization failed");
+		goto err_out_free_intr;
+	}
+
+	new->base_z = rte_eth_dma_zone_reserve(lif->eth_dev,
+			base /* name */, index /* queue_idx */,
+			total_size, IONIC_ALIGN, socket_id);
+
+	if (!new->base_z) {
+		ionic_init_print(ERR, "Cannot reserve queue DMA memory");
+		err = -ENOMEM;
+		goto err_out_free_intr;
+	}
+
+	new->base = new->base_z->addr;
+	new->base_pa = new->base_z->iova;
+	new->total_size = total_size;
+
+	q_base = new->base;
+	q_base_pa = new->base_pa;
+
+	cq_base = (void *)RTE_ALIGN((uintptr_t)q_base + q_size, PAGE_SIZE);
+	cq_base_pa = RTE_ALIGN(q_base_pa + q_size, PAGE_SIZE);
+
+	if (flags & IONIC_QCQ_F_SG) {
+		sg_base = (void *)RTE_ALIGN((uintptr_t)cq_base + cq_size,
+				PAGE_SIZE);
+		sg_base_pa = RTE_ALIGN(cq_base_pa + cq_size, PAGE_SIZE);
+		ionic_q_sg_map(&new->q, sg_base, sg_base_pa);
+	}
+
+	ionic_init_print(DEBUG, "Q-Base-PA = %ju CQ-Base-PA = %ju "
+			"SG-base-PA = %ju",
+			q_base_pa, cq_base_pa, sg_base_pa);
+
+	ionic_q_map(&new->q, q_base, q_base_pa);
+	ionic_cq_map(&new->cq, cq_base, cq_base_pa);
+	ionic_cq_bind(&new->cq, &new->q);
+
+	*qcq = new;
+
+	return 0;
+
+err_out_free_intr:
+	if (flags & IONIC_QCQ_F_INTR)
+		ionic_intr_free(lif, &new->intr);
+
+	return err;
+}
+
+void
+ionic_qcq_free(struct ionic_qcq *qcq)
+{
+	if (qcq->base_z) {
+		qcq->base = NULL;
+		qcq->base_pa = 0;
+		rte_memzone_free(qcq->base_z);
+		qcq->base_z = NULL;
+	}
+
+	if (qcq->q.info) {
+		rte_free(qcq->q.info);
+		qcq->q.info = NULL;
+	}
+
+	rte_free(qcq);
+}
+
+static int
+ionic_admin_qcq_alloc(struct ionic_lif *lif)
+{
+	uint32_t flags;
+	int err = -ENOMEM;
+
+	flags = 0;
+	err = ionic_qcq_alloc(lif, IONIC_QTYPE_ADMINQ, 0, "admin", flags,
+			IONIC_ADMINQ_LENGTH,
+			sizeof(struct ionic_admin_cmd),
+			sizeof(struct ionic_admin_comp),
+			0,
+			lif->kern_pid, &lif->adminqcq);
+
+	if (err)
+		return err;
+
+	return 0;
+}
+
 static void *
 ionic_bus_map_dbpage(struct ionic_adapter *adapter, int page_num)
 {
@@ -27,10 +280,12 @@ ionic_lif_alloc(struct ionic_lif *lif)
 	struct ionic_adapter *adapter = lif->adapter;
 	uint32_t socket_id = rte_socket_id();
 	int dbpage_num;
+	int err;
 
 	snprintf(lif->name, sizeof(lif->name), "lif%u", lif->index);
 
-	ionic_init_print(DEBUG, "Allocating Lif Info");
+	rte_spinlock_init(&lif->adminq_lock);
+	rte_spinlock_init(&lif->adminq_service_lock);
 
 	lif->kern_pid = 0;
 
@@ -43,6 +298,17 @@ ionic_lif_alloc(struct ionic_lif *lif)
 		return -ENOMEM;
 	}
 
+	ionic_init_print(DEBUG, "Allocating Admin Queue");
+
+	err = ionic_admin_qcq_alloc(lif);
+
+	if (err) {
+		ionic_init_print(ERR, "Cannot allocate admin queue");
+		return err;
+	}
+
+	ionic_init_print(DEBUG, "Allocating Lif Info");
+
 	lif->info_sz = RTE_ALIGN(sizeof(*lif->info), PAGE_SIZE);
 
 	lif->info_z = rte_eth_dma_zone_reserve(lif->eth_dev,
@@ -63,10 +329,91 @@ ionic_lif_alloc(struct ionic_lif *lif)
 void
 ionic_lif_free(struct ionic_lif *lif)
 {
+	if (lif->adminqcq) {
+		ionic_qcq_free(lif->adminqcq);
+		lif->adminqcq = NULL;
+	}
+
 	if (lif->info)
 		rte_memzone_free(lif->info_z);
 }
 
+static void
+ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
+{
+	struct ionic_dev *idev = &lif->adapter->idev;
+
+	if (!(qcq->flags & IONIC_QCQ_F_INITED))
+		return;
+
+	if (qcq->flags & IONIC_QCQ_F_INTR)
+		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
+				IONIC_INTR_MASK_SET);
+
+	qcq->flags &= ~IONIC_QCQ_F_INITED;
+}
+
+bool
+ionic_adminq_service(struct ionic_cq *cq, uint32_t cq_desc_index,
+		void *cb_arg __rte_unused)
+{
+	struct ionic_admin_comp *cq_desc_base = cq->base;
+	struct ionic_admin_comp *cq_desc = &cq_desc_base[cq_desc_index];
+
+	if (!color_match(cq_desc->color, cq->done_color))
+		return false;
+
+	ionic_q_service(cq->bound_q, cq_desc_index, cq_desc->comp_index, NULL);
+
+	return true;
+}
+
+/* This acts like ionic_napi */
+int
+ionic_qcq_service(struct ionic_qcq *qcq, int budget, ionic_cq_cb cb,
+		void *cb_arg)
+{
+	struct ionic_cq *cq = &qcq->cq;
+	uint32_t work_done;
+
+	work_done = ionic_cq_service(cq, budget, cb, cb_arg);
+
+	return work_done;
+}
+
+static int
+ionic_lif_adminq_init(struct ionic_lif *lif)
+{
+	struct ionic_dev *idev = &lif->adapter->idev;
+	struct ionic_qcq *qcq = lif->adminqcq;
+	struct ionic_queue *q = &qcq->q;
+	struct ionic_q_init_comp comp;
+	int err;
+
+	ionic_dev_cmd_adminq_init(idev, qcq, lif->index, qcq->intr.index);
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+	if (err)
+		return err;
+
+	ionic_dev_cmd_comp(idev, &comp);
+
+	q->hw_type = comp.hw_type;
+	q->hw_index = comp.hw_index;
+	q->db = ionic_db_map(lif, q);
+
+	ionic_init_print(DEBUG, "adminq->hw_type %d\n", q->hw_type);
+	ionic_init_print(DEBUG, "adminq->hw_index %d\n", q->hw_index);
+	ionic_init_print(DEBUG, "adminq->db %p\n", q->db);
+
+	if (qcq->flags & IONIC_QCQ_F_INTR)
+		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
+				IONIC_INTR_MASK_CLEAR);
+
+	qcq->flags |= IONIC_QCQ_F_INITED;
+
+	return 0;
+}
+
 int
 ionic_lif_init(struct ionic_lif *lif)
 {
@@ -82,6 +429,11 @@ ionic_lif_init(struct ionic_lif *lif)
 
 	lif->hw_index = comp.hw_index;
 
+	err = ionic_lif_adminq_init(lif);
+
+	if (err)
+		return err;
+
 	lif->state |= IONIC_LIF_F_INITED;
 
 	return 0;
@@ -93,6 +445,8 @@ ionic_lif_deinit(struct ionic_lif *lif)
 	if (!(lif->state & IONIC_LIF_F_INITED))
 		return;
 
+	ionic_lif_qcq_deinit(lif, lif->adminqcq);
+
 	lif->state &= ~IONIC_LIF_F_INITED;
 }
 
diff --git a/drivers/net/ionic/ionic_lif.h b/drivers/net/ionic/ionic_lif.h
index 6b912efa0..cedd8a721 100644
--- a/drivers/net/ionic/ionic_lif.h
+++ b/drivers/net/ionic/ionic_lif.h
@@ -13,6 +13,26 @@
 #include "ionic_osdep.h"
 #include "ionic_dev.h"
 
+#define IONIC_ADMINQ_LENGTH	16	/* must be a power of two */
+
+#define IONIC_QCQ_F_INITED	BIT(0)
+#define IONIC_QCQ_F_SG		BIT(1)
+#define IONIC_QCQ_F_INTR	BIT(2)
+
+/* Queue / Completion Queue */
+struct ionic_qcq {
+	struct ionic_queue q;        /**< Queue */
+	struct ionic_cq cq;          /**< Completion Queue */
+	struct ionic_lif *lif;       /**< LIF */
+	struct rte_mempool *mb_pool; /**< mbuf pool to populate the RX ring */
+	const struct rte_memzone *base_z;
+	void *base;
+	rte_iova_t base_pa;
+	uint32_t total_size;
+	uint32_t flags;
+	struct ionic_intr_info intr;
+};
+
 #define IONIC_LIF_F_INITED		BIT(0)
 
 #define IONIC_LIF_NAME_MAX_SZ		(32)
@@ -25,6 +45,9 @@ struct ionic_lif {
 	uint32_t hw_index;
 	uint32_t state;
 	uint32_t kern_pid;
+	rte_spinlock_t adminq_lock;
+	rte_spinlock_t adminq_service_lock;
+	struct ionic_qcq *adminqcq;
 	struct ionic_doorbell __iomem *kern_dbpage;
 	char name[IONIC_LIF_NAME_MAX_SZ];
 	uint32_t info_sz;
@@ -48,4 +71,17 @@ int ionic_lif_stop(struct ionic_lif *lif);
 int ionic_lif_configure(struct ionic_lif *lif);
 void ionic_lif_reset(struct ionic_lif *lif);
 
+int ionic_intr_alloc(struct ionic_lif *lif, struct ionic_intr_info *intr);
+void ionic_intr_free(struct ionic_lif *lif, struct ionic_intr_info *intr);
+
+bool ionic_adminq_service(struct ionic_cq *cq, uint32_t cq_desc_index,
+		void *cb_arg);
+int ionic_qcq_service(struct ionic_qcq *qcq, int budget, ionic_cq_cb cb,
+		void *cb_arg);
+
+void ionic_qcq_free(struct ionic_qcq *qcq);
+
+int ionic_qcq_enable(struct ionic_qcq *qcq);
+int ionic_qcq_disable(struct ionic_qcq *qcq);
+
 #endif /* _IONIC_LIF_H_ */
diff --git a/drivers/net/ionic/ionic_main.c b/drivers/net/ionic/ionic_main.c
index 0feb713a9..45a6dc26c 100644
--- a/drivers/net/ionic/ionic_main.c
+++ b/drivers/net/ionic/ionic_main.c
@@ -5,6 +5,194 @@
 #include <rte_memzone.h>
 
 #include "ionic.h"
+#include "ionic_ethdev.h"
+#include "ionic_lif.h"
+
+static const char *
+ionic_error_to_str(enum ionic_status_code code)
+{
+	switch (code) {
+	case IONIC_RC_SUCCESS:
+		return "IONIC_RC_SUCCESS";
+	case IONIC_RC_EVERSION:
+		return "IONIC_RC_EVERSION";
+	case IONIC_RC_EOPCODE:
+		return "IONIC_RC_EOPCODE";
+	case IONIC_RC_EIO:
+		return "IONIC_RC_EIO";
+	case IONIC_RC_EPERM:
+		return "IONIC_RC_EPERM";
+	case IONIC_RC_EQID:
+		return "IONIC_RC_EQID";
+	case IONIC_RC_EQTYPE:
+		return "IONIC_RC_EQTYPE";
+	case IONIC_RC_ENOENT:
+		return "IONIC_RC_ENOENT";
+	case IONIC_RC_EINTR:
+		return "IONIC_RC_EINTR";
+	case IONIC_RC_EAGAIN:
+		return "IONIC_RC_EAGAIN";
+	case IONIC_RC_ENOMEM:
+		return "IONIC_RC_ENOMEM";
+	case IONIC_RC_EFAULT:
+		return "IONIC_RC_EFAULT";
+	case IONIC_RC_EBUSY:
+		return "IONIC_RC_EBUSY";
+	case IONIC_RC_EEXIST:
+		return "IONIC_RC_EEXIST";
+	case IONIC_RC_EINVAL:
+		return "IONIC_RC_EINVAL";
+	case IONIC_RC_ENOSPC:
+		return "IONIC_RC_ENOSPC";
+	case IONIC_RC_ERANGE:
+		return "IONIC_RC_ERANGE";
+	case IONIC_RC_BAD_ADDR:
+		return "IONIC_RC_BAD_ADDR";
+	case IONIC_RC_DEV_CMD:
+		return "IONIC_RC_DEV_CMD";
+	case IONIC_RC_ERROR:
+		return "IONIC_RC_ERROR";
+	case IONIC_RC_ERDMA:
+		return "IONIC_RC_ERDMA";
+	default:
+		return "IONIC_RC_UNKNOWN";
+	}
+}
+
+static const char *
+ionic_opcode_to_str(enum ionic_cmd_opcode opcode)
+{
+	switch (opcode) {
+	case IONIC_CMD_NOP:
+		return "IONIC_CMD_NOP";
+	case IONIC_CMD_INIT:
+		return "IONIC_CMD_INIT";
+	case IONIC_CMD_RESET:
+		return "IONIC_CMD_RESET";
+	case IONIC_CMD_IDENTIFY:
+		return "IONIC_CMD_IDENTIFY";
+	case IONIC_CMD_GETATTR:
+		return "IONIC_CMD_GETATTR";
+	case IONIC_CMD_SETATTR:
+		return "IONIC_CMD_SETATTR";
+	case IONIC_CMD_PORT_IDENTIFY:
+		return "IONIC_CMD_PORT_IDENTIFY";
+	case IONIC_CMD_PORT_INIT:
+		return "IONIC_CMD_PORT_INIT";
+	case IONIC_CMD_PORT_RESET:
+		return "IONIC_CMD_PORT_RESET";
+	case IONIC_CMD_PORT_GETATTR:
+		return "IONIC_CMD_PORT_GETATTR";
+	case IONIC_CMD_PORT_SETATTR:
+		return "IONIC_CMD_PORT_SETATTR";
+	case IONIC_CMD_LIF_INIT:
+		return "IONIC_CMD_LIF_INIT";
+	case IONIC_CMD_LIF_RESET:
+		return "IONIC_CMD_LIF_RESET";
+	case IONIC_CMD_LIF_IDENTIFY:
+		return "IONIC_CMD_LIF_IDENTIFY";
+	case IONIC_CMD_LIF_SETATTR:
+		return "IONIC_CMD_LIF_SETATTR";
+	case IONIC_CMD_LIF_GETATTR:
+		return "IONIC_CMD_LIF_GETATTR";
+	case IONIC_CMD_RX_MODE_SET:
+		return "IONIC_CMD_RX_MODE_SET";
+	case IONIC_CMD_RX_FILTER_ADD:
+		return "IONIC_CMD_RX_FILTER_ADD";
+	case IONIC_CMD_RX_FILTER_DEL:
+		return "IONIC_CMD_RX_FILTER_DEL";
+	case IONIC_CMD_Q_INIT:
+		return "IONIC_CMD_Q_INIT";
+	case IONIC_CMD_Q_CONTROL:
+		return "IONIC_CMD_Q_CONTROL";
+	case IONIC_CMD_RDMA_RESET_LIF:
+		return "IONIC_CMD_RDMA_RESET_LIF";
+	case IONIC_CMD_RDMA_CREATE_EQ:
+		return "IONIC_CMD_RDMA_CREATE_EQ";
+	case IONIC_CMD_RDMA_CREATE_CQ:
+		return "IONIC_CMD_RDMA_CREATE_CQ";
+	case IONIC_CMD_RDMA_CREATE_ADMINQ:
+		return "IONIC_CMD_RDMA_CREATE_ADMINQ";
+	default:
+		return "DEVCMD_UNKNOWN";
+	}
+}
+
+int
+ionic_adminq_check_err(struct ionic_lif *lif, struct ionic_admin_ctx *ctx,
+		bool timeout)
+{
+	const char *name;
+	const char *status;
+
+	if (ctx->comp.comp.status || timeout) {
+		name = ionic_opcode_to_str(ctx->cmd.cmd.opcode);
+		status = ionic_error_to_str(ctx->comp.comp.status);
+		ionic_init_print(ERR, "%s (%d) failed: %s (%d)\n",
+				name,
+				ctx->cmd.cmd.opcode,
+				timeout ? "TIMEOUT" : status,
+				timeout ? -1 : ctx->comp.comp.status);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int
+ionic_wait_ctx_for_completion(struct ionic_lif *lif, struct ionic_qcq *qcq,
+		struct ionic_admin_ctx *ctx, unsigned long max_wait)
+{
+	unsigned long step_msec = 1;
+	unsigned int max_wait_msec = max_wait * 1000;
+	unsigned long elapsed_msec = 0;
+	int budget = 8;
+
+	while (ctx->pending_work && elapsed_msec < max_wait_msec) {
+		/*
+		 * Locking here as adminq is served inline (this could be called
+		 * from multiple places)
+		 */
+		rte_spinlock_lock(&lif->adminq_service_lock);
+
+		ionic_qcq_service(qcq, budget, ionic_adminq_service, NULL);
+
+		rte_spinlock_unlock(&lif->adminq_service_lock);
+
+		msec_delay(step_msec);
+		elapsed_msec += step_msec;
+	}
+
+	return (!ctx->pending_work);
+}
+
+int
+ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
+{
+	struct ionic_qcq *qcq = lif->adminqcq;
+	bool done;
+	int err;
+
+	ionic_init_print(DEBUG, "Sending %s to the admin queue",
+		ionic_opcode_to_str(ctx->cmd.cmd.opcode));
+
+	err = ionic_adminq_post(lif, ctx);
+
+	if (err) {
+		ionic_init_print(ERR, "Failure posting to the admin queue %d "
+				"(%d)\n",
+				ctx->cmd.cmd.opcode, err);
+
+		return err;
+	}
+
+	done = ionic_wait_ctx_for_completion(lif, qcq, ctx,
+			IONIC_DEVCMD_TIMEOUT);
+
+	err = ionic_adminq_check_err(lif, ctx, !done /* timed out */);
+
+	return err;
+}
 
 static int
 ionic_dev_cmd_wait(struct ionic_dev *idev, unsigned long max_wait)


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 09/17] net/ionic: add notifyq support
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
                   ` (7 preceding siblings ...)
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 08/17] net/ionic: add adminq support Alfredo Cardigliano
@ 2019-10-12  0:27 ` Alfredo Cardigliano
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 10/17] net/ionic: add basic port operations Alfredo Cardigliano
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:27 UTC (permalink / raw)
  To: dev

Add support for the notify queue, which is used for events
published by the NIC.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 drivers/net/ionic/ionic.h        |    2 
 drivers/net/ionic/ionic_ethdev.c |   97 +++++++++++++++++++
 drivers/net/ionic/ionic_lif.c    |  192 ++++++++++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_lif.h    |    7 +
 4 files changed, 298 insertions(+)

diff --git a/drivers/net/ionic/ionic.h b/drivers/net/ionic/ionic.h
index 3a9bb7b22..53836be64 100644
--- a/drivers/net/ionic/ionic.h
+++ b/drivers/net/ionic/ionic.h
@@ -54,9 +54,11 @@ struct ionic_adapter {
 	uint32_t nlifs;
 	uint32_t max_ntxqs_per_lif;
 	uint32_t max_nrxqs_per_lif;
+	uint32_t link_speed;
 	uint32_t nintrs;
 	bool intrs[IONIC_INTR_CTRL_REGS_MAX];
 	bool is_mgmt_nic;
+	bool link_up;
 	struct rte_pci_device *pci_dev;
 	LIST_ENTRY(ionic_adapter) pci_adapters;
 };
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index a0a788ab3..6e435fe89 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -40,6 +40,30 @@ static LIST_HEAD(ionic_pci_adapters_list, ionic_adapter) ionic_pci_adapters =
 		LIST_HEAD_INITIALIZER(ionic_pci_adapters);
 static rte_spinlock_t ionic_pci_adapters_lock = RTE_SPINLOCK_INITIALIZER;
 
+/**
+ * Interrupt handler triggered by NIC for handling
+ * specific interrupt.
+ *
+ * @param param
+ *  The address of parameter regsitered before.
+ *
+ * @return
+ *  void
+ */
+static void
+ionic_dev_interrupt_handler(void *param)
+{
+	struct ionic_adapter *adapter = (struct ionic_adapter *) param;
+	uint32_t i;
+
+	ionic_drv_print(DEBUG, "->");
+
+	for (i = 0; i < adapter->nlifs; i++) {
+		if (adapter->lifs[i])
+			ionic_notifyq_handler(adapter->lifs[i], -1);
+	}
+}
+
 static int
 eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void *init_params)
 {
@@ -104,6 +128,70 @@ eth_ionic_dev_uninit(struct rte_eth_dev *eth_dev)
 	return 0;
 }
 
+static int
+ionic_configure_intr(struct ionic_adapter *adapter)
+{
+	struct rte_pci_device *pci_dev = adapter->pci_dev;
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+	int err;
+
+	ionic_init_print(DEBUG, "Configuring %u intrs", adapter->nintrs);
+
+	if (rte_intr_efd_enable(intr_handle, adapter->nintrs)) {
+		ionic_init_print(ERR, "Fail to create eventfd");
+		return -1;
+	}
+
+	if (rte_intr_dp_is_en(intr_handle))
+		ionic_init_print(DEBUG, 
+				"Packet I/O interrupt on datapath is enabled");
+
+	if (!intr_handle->intr_vec) {
+		intr_handle->intr_vec = rte_zmalloc("intr_vec",
+			adapter->nintrs * sizeof(int), 0);
+
+		if (!intr_handle->intr_vec) {
+			ionic_init_print(ERR, "Failed to allocate %u vectors",
+				adapter->nintrs);
+			return -ENOMEM;
+		}
+	}
+
+	err = rte_intr_callback_register(intr_handle,
+			ionic_dev_interrupt_handler,
+			adapter);
+
+	if (err) {
+		ionic_init_print(ERR,
+				"Failure registering interrupts handler (%d)",
+				err);
+		return err;
+	}
+
+	/* enable intr mapping */
+	err = rte_intr_enable(intr_handle);
+
+	if (err) {
+		ionic_init_print(ERR, "Failure enabling interrupts (%d)", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static void
+ionic_unconfigure_intr(struct ionic_adapter *adapter)
+{
+	struct rte_pci_device *pci_dev = adapter->pci_dev;
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+
+	rte_intr_disable(intr_handle);
+
+	rte_intr_callback_unregister(intr_handle,
+			ionic_dev_interrupt_handler,
+			adapter);
+}
+
 static int
 eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 		struct rte_pci_device *pci_dev)
@@ -228,6 +316,13 @@ eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 		adapter->nlifs++;
 	}
 
+	err = ionic_configure_intr(adapter);
+
+	if (err) {
+		ionic_init_print(ERR, "Failed to configure interrupts");
+		return err;
+	}
+
 	rte_spinlock_lock(&ionic_pci_adapters_lock);
 	LIST_INSERT_HEAD(&ionic_pci_adapters, adapter, pci_adapters);
 	rte_spinlock_unlock(&ionic_pci_adapters_lock);
@@ -254,6 +349,8 @@ eth_ionic_pci_remove(struct rte_pci_device *pci_dev)
 	rte_spinlock_unlock(&ionic_pci_adapters_lock);
 
 	if (adapter) {
+		ionic_unconfigure_intr(adapter);
+
 		for (i = 0; i < adapter->nlifs; i++) {
 			lif = adapter->lifs[i];
 			rte_eth_dev_destroy(lif->eth_dev, eth_ionic_dev_uninit);
diff --git a/drivers/net/ionic/ionic_lif.c b/drivers/net/ionic/ionic_lif.c
index f2ede6d23..491db56d4 100644
--- a/drivers/net/ionic/ionic_lif.c
+++ b/drivers/net/ionic/ionic_lif.c
@@ -263,6 +263,28 @@ ionic_admin_qcq_alloc(struct ionic_lif *lif)
 	return 0;
 }
 
+static int
+ionic_notify_qcq_alloc(struct ionic_lif *lif)
+{
+	uint32_t flags;
+	int err = -ENOMEM;
+
+	flags = IONIC_QCQ_F_NOTIFYQ | IONIC_QCQ_F_INTR;
+
+	err = ionic_qcq_alloc(lif, IONIC_QTYPE_NOTIFYQ, 0, "notify",
+			flags,
+			IONIC_NOTIFYQ_LENGTH,
+			sizeof(struct ionic_notifyq_cmd),
+			sizeof(union ionic_notifyq_comp),
+			0,
+			lif->kern_pid, &lif->notifyqcq);
+
+	if (err)
+		return err;
+
+	return 0;
+}
+
 static void *
 ionic_bus_map_dbpage(struct ionic_adapter *adapter, int page_num)
 {
@@ -298,6 +320,15 @@ ionic_lif_alloc(struct ionic_lif *lif)
 		return -ENOMEM;
 	}
 
+	ionic_init_print(DEBUG, "Allocating Notify Queue");
+
+	err = ionic_notify_qcq_alloc(lif);
+
+	if (err) {
+		ionic_init_print(ERR, "Cannot allocate notify queue");
+		return err;
+	}
+
 	ionic_init_print(DEBUG, "Allocating Admin Queue");
 
 	err = ionic_admin_qcq_alloc(lif);
@@ -329,6 +360,11 @@ ionic_lif_alloc(struct ionic_lif *lif)
 void
 ionic_lif_free(struct ionic_lif *lif)
 {
+	if (lif->notifyqcq) {
+		ionic_qcq_free(lif->notifyqcq);
+		lif->notifyqcq = NULL;
+	}
+
 	if (lif->adminqcq) {
 		ionic_qcq_free(lif->adminqcq);
 		lif->adminqcq = NULL;
@@ -381,6 +417,99 @@ ionic_qcq_service(struct ionic_qcq *qcq, int budget, ionic_cq_cb cb,
 	return work_done;
 }
 
+static void
+ionic_link_status_check(struct ionic_lif *lif)
+{
+	struct ionic_adapter *adapter = lif->adapter;
+	bool link_up;
+
+	lif->state &= ~IONIC_LIF_F_LINK_CHECK_NEEDED;
+
+	if (!lif->info)
+		return;
+
+	link_up = (lif->info->status.link_status == IONIC_PORT_OPER_STATUS_UP);
+
+	if ((link_up  && adapter->link_up) ||
+	    (!link_up && !adapter->link_up))
+		return;
+
+	if (link_up) {
+		ionic_drv_print(DEBUG, "Link up - %d Gbps",
+			lif->info->status.link_speed);
+		adapter->link_speed = lif->info->status.link_speed;
+	} else {
+		ionic_drv_print(DEBUG, "Link down");
+	}
+
+	adapter->link_up = link_up;
+}
+
+static bool
+ionic_notifyq_cb(struct ionic_cq *cq, uint32_t cq_desc_index, void *cb_arg)
+{
+	union ionic_notifyq_comp *cq_desc_base = cq->base;
+	union ionic_notifyq_comp *cq_desc = &cq_desc_base[cq_desc_index];
+	struct ionic_lif *lif = cb_arg;
+
+	ionic_drv_print(DEBUG, "Notifyq callback eid = %jd ecode = %d",
+		cq_desc->event.eid, cq_desc->event.ecode);
+
+	/* Have we run out of new completions to process? */
+	if (!(cq_desc->event.eid > lif->last_eid))
+		return false;
+
+	lif->last_eid = cq_desc->event.eid;
+
+	switch (cq_desc->event.ecode) {
+	case IONIC_EVENT_LINK_CHANGE:
+		ionic_drv_print(DEBUG,
+				"Notifyq IONIC_EVENT_LINK_CHANGE eid=%jd link_status=%d link_speed=%d",
+				cq_desc->event.eid,
+				cq_desc->link_change.link_status,
+				cq_desc->link_change.link_speed);
+
+		lif->state |= IONIC_LIF_F_LINK_CHECK_NEEDED;
+
+		break;
+	default:
+		ionic_drv_print(WARNING, "Notifyq bad event ecode=%d eid=%jd",
+				cq_desc->event.ecode, cq_desc->event.eid);
+		break;
+	}
+
+	return true;
+}
+
+int
+ionic_notifyq_handler(struct ionic_lif *lif, int budget)
+{
+	struct ionic_dev *idev = &lif->adapter->idev;
+	struct ionic_qcq *qcq = lif->notifyqcq;
+	uint32_t work_done;
+
+	if (!(qcq->flags & IONIC_QCQ_F_INITED)) {
+		ionic_drv_print(DEBUG, "Notifyq not yet initialized");
+		return -1;
+	}
+
+	ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
+			IONIC_INTR_MASK_SET);
+
+	work_done = ionic_qcq_service(qcq, budget, ionic_notifyq_cb, lif);
+
+	if (lif->state & IONIC_LIF_F_LINK_CHECK_NEEDED)
+		ionic_link_status_check(lif);
+
+	ionic_intr_credits(idev->intr_ctrl, qcq->intr.index,
+			work_done, IONIC_INTR_CRED_RESET_COALESCE);
+
+	ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
+			IONIC_INTR_MASK_CLEAR);
+
+	return 0;
+}
+
 static int
 ionic_lif_adminq_init(struct ionic_lif *lif)
 {
@@ -414,6 +543,58 @@ ionic_lif_adminq_init(struct ionic_lif *lif)
 	return 0;
 }
 
+static int
+ionic_lif_notifyq_init(struct ionic_lif *lif)
+{
+	struct ionic_dev *idev = &lif->adapter->idev;
+	struct ionic_qcq *qcq = lif->notifyqcq;
+	struct ionic_queue *q = &qcq->q;
+	int err;
+
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.q_init = {
+			.opcode = IONIC_CMD_Q_INIT,
+			.lif_index = lif->index,
+			.type = q->type,
+			.index = q->index,
+			.flags = (IONIC_QINIT_F_IRQ | IONIC_QINIT_F_ENA),
+			.intr_index = qcq->intr.index,
+			.pid = q->pid,
+			.ring_size = ilog2(q->num_descs),
+			.ring_base = q->base_pa,
+		}
+	};
+
+	ionic_init_print(DEBUG, "notifyq_init.pid %d\n", ctx.cmd.q_init.pid);
+	ionic_init_print(DEBUG, "notifyq_init.index %d\n",
+			ctx.cmd.q_init.index);
+	ionic_init_print(DEBUG, "notifyq_init.ring_base 0x%lx\n",
+			ctx.cmd.q_init.ring_base);
+	ionic_init_print(DEBUG, "notifyq_init.ring_size %d\n",
+			ctx.cmd.q_init.ring_size);
+
+	err = ionic_adminq_post_wait(lif, &ctx);
+	if (err)
+		return err;
+
+	q->hw_type = ctx.comp.q_init.hw_type;
+	q->hw_index = ctx.comp.q_init.hw_index;
+	q->db = NULL;
+
+	ionic_init_print(DEBUG, "notifyq->hw_type %d\n", q->hw_type);
+	ionic_init_print(DEBUG, "notifyq->hw_index %d\n", q->hw_index);
+	ionic_init_print(DEBUG, "notifyq->db %p\n", q->db);
+
+	if (qcq->flags & IONIC_QCQ_F_INTR)
+		ionic_intr_mask(idev->intr_ctrl, qcq->intr.index,
+				IONIC_INTR_MASK_CLEAR);
+
+	qcq->flags |= IONIC_QCQ_F_INITED;
+
+	return 0;
+}
+
 int
 ionic_lif_init(struct ionic_lif *lif)
 {
@@ -434,9 +615,19 @@ ionic_lif_init(struct ionic_lif *lif)
 	if (err)
 		return err;
 
+	err = ionic_lif_notifyq_init(lif);
+
+	if (err)
+		goto err_out_adminq_deinit;
+
 	lif->state |= IONIC_LIF_F_INITED;
 
 	return 0;
+
+err_out_adminq_deinit:
+	ionic_lif_qcq_deinit(lif, lif->adminqcq);
+
+	return err;
 }
 
 void
@@ -445,6 +636,7 @@ ionic_lif_deinit(struct ionic_lif *lif)
 	if (!(lif->state & IONIC_LIF_F_INITED))
 		return;
 
+	ionic_lif_qcq_deinit(lif, lif->notifyqcq);
 	ionic_lif_qcq_deinit(lif, lif->adminqcq);
 
 	lif->state &= ~IONIC_LIF_F_INITED;
diff --git a/drivers/net/ionic/ionic_lif.h b/drivers/net/ionic/ionic_lif.h
index cedd8a721..326cb17d5 100644
--- a/drivers/net/ionic/ionic_lif.h
+++ b/drivers/net/ionic/ionic_lif.h
@@ -14,10 +14,12 @@
 #include "ionic_dev.h"
 
 #define IONIC_ADMINQ_LENGTH	16	/* must be a power of two */
+#define IONIC_NOTIFYQ_LENGTH	64	/* must be a power of two */
 
 #define IONIC_QCQ_F_INITED	BIT(0)
 #define IONIC_QCQ_F_SG		BIT(1)
 #define IONIC_QCQ_F_INTR	BIT(2)
+#define IONIC_QCQ_F_NOTIFYQ	BIT(3)
 
 /* Queue / Completion Queue */
 struct ionic_qcq {
@@ -34,6 +36,7 @@ struct ionic_qcq {
 };
 
 #define IONIC_LIF_F_INITED		BIT(0)
+#define IONIC_LIF_F_LINK_CHECK_NEEDED	BIT(1)
 
 #define IONIC_LIF_NAME_MAX_SZ		(32)
 
@@ -48,7 +51,9 @@ struct ionic_lif {
 	rte_spinlock_t adminq_lock;
 	rte_spinlock_t adminq_service_lock;
 	struct ionic_qcq *adminqcq;
+	struct ionic_qcq *notifyqcq;
 	struct ionic_doorbell __iomem *kern_dbpage;
+	uint64_t last_eid;
 	char name[IONIC_LIF_NAME_MAX_SZ];
 	uint32_t info_sz;
 	struct ionic_lif_info *info;
@@ -84,4 +89,6 @@ void ionic_qcq_free(struct ionic_qcq *qcq);
 int ionic_qcq_enable(struct ionic_qcq *qcq);
 int ionic_qcq_disable(struct ionic_qcq *qcq);
 
+int ionic_notifyq_handler(struct ionic_lif *lif, int budget);
+
 #endif /* _IONIC_LIF_H_ */


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 10/17] net/ionic: add basic port operations
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
                   ` (8 preceding siblings ...)
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 09/17] net/ionic: add notifyq support Alfredo Cardigliano
@ 2019-10-12  0:27 ` Alfredo Cardigliano
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 11/17] net/ionic: add RX filters support Alfredo Cardigliano
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:27 UTC (permalink / raw)
  To: dev

Add support for port start/stop and handle basic features
including mtu and link up/down.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 doc/guides/nics/features/ionic.ini |    4 
 drivers/net/ionic/ionic.h          |    1 
 drivers/net/ionic/ionic_dev.h      |    3 
 drivers/net/ionic/ionic_ethdev.c   |  315 ++++++++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_lif.c      |  268 +++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_lif.h      |    9 +
 drivers/net/ionic/ionic_osdep.h    |    2 
 7 files changed, 602 insertions(+)

diff --git a/doc/guides/nics/features/ionic.ini b/doc/guides/nics/features/ionic.ini
index 6915d9c42..c69e5cbed 100644
--- a/doc/guides/nics/features/ionic.ini
+++ b/doc/guides/nics/features/ionic.ini
@@ -4,6 +4,10 @@
 ; Refer to default.ini for the full list of available PMD features.
 ;
 [Features]
+Speed capabilities   = Y
+Link status          = Y
+Link status event    = Y
+MTU update           = Y
 Linux UIO            = Y
 Linux VFIO           = Y
 x86-64               = Y
diff --git a/drivers/net/ionic/ionic.h b/drivers/net/ionic/ionic.h
index 53836be64..05f1df061 100644
--- a/drivers/net/ionic/ionic.h
+++ b/drivers/net/ionic/ionic.h
@@ -54,6 +54,7 @@ struct ionic_adapter {
 	uint32_t nlifs;
 	uint32_t max_ntxqs_per_lif;
 	uint32_t max_nrxqs_per_lif;
+	uint32_t max_mac_addrs;
 	uint32_t link_speed;
 	uint32_t nintrs;
 	bool intrs[IONIC_INTR_CTRL_REGS_MAX];
diff --git a/drivers/net/ionic/ionic_dev.h b/drivers/net/ionic/ionic_dev.h
index ada07edff..02fcfdee8 100644
--- a/drivers/net/ionic/ionic_dev.h
+++ b/drivers/net/ionic/ionic_dev.h
@@ -20,6 +20,9 @@
  */
 #define IONIC_API_VERSION		"3"
 
+#define IONIC_MIN_MTU			RTE_ETHER_MIN_MTU
+#define IONIC_MAX_MTU			9194
+
 #define IONIC_MAX_RING_DESC		32768
 #define IONIC_MIN_RING_DESC		16
 
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index 6e435fe89..fed332750 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -18,6 +18,17 @@
 
 static int  eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void *init_params);
 static int  eth_ionic_dev_uninit(struct rte_eth_dev *eth_dev);
+static int  ionic_dev_info_get(struct rte_eth_dev *eth_dev,
+		struct rte_eth_dev_info *dev_info);
+static int  ionic_dev_configure(struct rte_eth_dev *dev);
+static int  ionic_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
+static int  ionic_dev_start(struct rte_eth_dev *dev);
+static void ionic_dev_stop(struct rte_eth_dev *dev);
+static void ionic_dev_close(struct rte_eth_dev *dev);
+static int  ionic_dev_set_link_up(struct rte_eth_dev *dev);
+static int  ionic_dev_set_link_down(struct rte_eth_dev *dev);
+static int  ionic_dev_link_update(struct rte_eth_dev *eth_dev,
+		int wait_to_complete);
 
 int ionic_logtype_init;
 int ionic_logtype_driver;
@@ -30,6 +41,15 @@ static const struct rte_pci_id pci_id_ionic_map[] = {
 };
 
 static const struct eth_dev_ops ionic_eth_dev_ops = {
+	.dev_infos_get          = ionic_dev_info_get,
+	.dev_configure          = ionic_dev_configure,
+	.mtu_set                = ionic_dev_mtu_set,
+	.dev_start              = ionic_dev_start,
+	.dev_stop               = ionic_dev_stop,
+	.dev_close              = ionic_dev_close,
+	.link_update            = ionic_dev_link_update,
+	.dev_set_link_up        = ionic_dev_set_link_up,
+	.dev_set_link_down      = ionic_dev_set_link_down,
 };
 
 /*
@@ -40,6 +60,104 @@ static LIST_HEAD(ionic_pci_adapters_list, ionic_adapter) ionic_pci_adapters =
 		LIST_HEAD_INITIALIZER(ionic_pci_adapters);
 static rte_spinlock_t ionic_pci_adapters_lock = RTE_SPINLOCK_INITIALIZER;
 
+/*
+ * Set device link up, enable tx.
+ */
+static int
+ionic_dev_set_link_up(struct rte_eth_dev *eth_dev)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_adapter *adapter = lif->adapter;
+	struct ionic_dev *idev = &adapter->idev;
+	int err;
+
+	ionic_init_print_call();
+
+	ionic_dev_cmd_port_state(idev, IONIC_PORT_ADMIN_STATE_UP);
+
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+
+	if (err) {
+		ionic_init_print(WARNING, "Failed to bring port UP\n");
+		return err;
+	}
+
+	return 0;
+}
+
+/*
+ * Set device link down, disable tx.
+ */
+static int
+ionic_dev_set_link_down(struct rte_eth_dev *eth_dev)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_adapter *adapter = lif->adapter;
+	struct ionic_dev *idev = &adapter->idev;
+	int err;
+
+	ionic_init_print_call();
+
+	ionic_dev_cmd_port_state(idev, IONIC_PORT_ADMIN_STATE_DOWN);
+
+	err = ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+
+	if (err) {
+		ionic_init_print(WARNING, "Failed to bring port DOWN\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int
+ionic_dev_link_update(struct rte_eth_dev *eth_dev,
+		int wait_to_complete __rte_unused)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_adapter *adapter = lif->adapter;
+	struct rte_eth_link link;
+
+	ionic_init_print_call();
+
+	/* Initialize */
+	memset(&link, 0, sizeof(link));
+	link.link_autoneg = ETH_LINK_AUTONEG;
+
+	if (!adapter->link_up) {
+		/* Interface is down */
+		link.link_status = ETH_LINK_DOWN;
+		link.link_duplex = ETH_LINK_HALF_DUPLEX;
+		link.link_speed = ETH_SPEED_NUM_NONE;
+	} else {
+		/* Interface is up */
+		link.link_status = ETH_LINK_UP;
+		link.link_duplex = ETH_LINK_FULL_DUPLEX;
+		switch (adapter->link_speed) {
+		case  10000:
+			link.link_speed = ETH_SPEED_NUM_10G;
+			break;
+		case  25000:
+			link.link_speed = ETH_SPEED_NUM_25G;
+			break;
+		case  40000:
+			link.link_speed = ETH_SPEED_NUM_40G;
+			break;
+		case  50000:
+			link.link_speed = ETH_SPEED_NUM_50G;
+			break;
+		case 100000:
+			link.link_speed = ETH_SPEED_NUM_100G;
+			break;
+		default:
+			link.link_speed = ETH_SPEED_NUM_NONE;
+			break;
+		}
+	}
+
+	return rte_eth_linkstatus_set(eth_dev, &link);
+}
+
 /**
  * Interrupt handler triggered by NIC for handling
  * specific interrupt.
@@ -64,6 +182,183 @@ ionic_dev_interrupt_handler(void *param)
 	}
 }
 
+static int
+ionic_dev_mtu_set(struct rte_eth_dev *eth_dev, uint16_t mtu)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	/*
+	 * Size = MTU + Ethernet header + VLAN + QinQ
+	 * Also add ETHER_CRC_LEN if the adapter is able to keep CRC
+	 */
+	uint32_t frame_size = mtu + RTE_ETHER_HDR_LEN + 4 + 4;
+	int err;
+
+	ionic_init_print_call();
+
+	/* Check that mtu is within the allowed range */
+	if (mtu < IONIC_MIN_MTU || mtu > IONIC_MAX_MTU)
+		return -EINVAL;
+
+	err = ionic_lif_change_mtu(lif, mtu);
+
+	if (err)
+		return err;
+
+	/* Update max frame size */
+	eth_dev->data->dev_conf.rxmode.max_rx_pkt_len = frame_size;
+
+	return 0;
+}
+
+static int
+ionic_dev_info_get(struct rte_eth_dev *eth_dev,
+		struct rte_eth_dev_info *dev_info)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_adapter *adapter = lif->adapter;
+	struct ionic_identity *ident = &adapter->ident;
+
+	ionic_init_print_call();
+
+	dev_info->max_rx_queues = (uint16_t)
+		ident->lif.eth.config.queue_count[IONIC_QTYPE_RXQ];
+	dev_info->max_tx_queues = (uint16_t)
+		ident->lif.eth.config.queue_count[IONIC_QTYPE_TXQ];
+	/* Also add ETHER_CRC_LEN if the adapter is able to keep CRC */
+	dev_info->min_rx_bufsize = IONIC_MIN_MTU + RTE_ETHER_HDR_LEN;
+	dev_info->max_rx_pktlen = IONIC_MAX_MTU + RTE_ETHER_HDR_LEN;
+	dev_info->max_mac_addrs = adapter->max_mac_addrs;
+
+	dev_info->speed_capa =
+		ETH_LINK_SPEED_10G |
+		ETH_LINK_SPEED_25G |
+		ETH_LINK_SPEED_40G |
+		ETH_LINK_SPEED_50G |
+		ETH_LINK_SPEED_100G;
+
+	return 0;
+}
+
+static int
+ionic_dev_configure(struct rte_eth_dev *eth_dev)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	int err;
+
+	ionic_init_print_call();
+
+	err = ionic_lif_configure(lif);
+
+	if (err) {
+		ionic_drv_print(ERR, "Cannot configure LIF: %d", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static inline uint32_t
+ionic_parse_link_speeds(uint16_t link_speeds)
+{
+	if (link_speeds & ETH_LINK_SPEED_100G)
+		return 100000;
+	else if (link_speeds & ETH_LINK_SPEED_50G)
+		return 50000;
+	else if (link_speeds & ETH_LINK_SPEED_40G)
+		return 40000;
+	else if (link_speeds & ETH_LINK_SPEED_25G)
+		return 25000;
+	else if (link_speeds & ETH_LINK_SPEED_10G)
+		return 10000;
+	else
+		return 0;
+}
+
+/*
+ * Configure device link speed and setup link.
+ * It returns 0 on success.
+ */
+static int
+ionic_dev_start(struct rte_eth_dev *eth_dev)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_adapter *adapter = lif->adapter;
+	struct ionic_dev *idev = &adapter->idev;
+	uint32_t allowed_speeds;
+	int err;
+
+	ionic_init_print_call();
+
+	err = ionic_lif_start(lif);
+
+	if (err) {
+		ionic_drv_print(ERR, "Cannot start LIF: %d", err);
+		return err;
+	}
+
+	if (eth_dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED) {
+		uint32_t speed = ionic_parse_link_speeds(eth_dev->data->dev_conf.link_speeds);
+
+		if (speed)
+			ionic_dev_cmd_port_speed(idev, speed);
+	}
+
+	allowed_speeds =
+		ETH_LINK_SPEED_FIXED |
+		ETH_LINK_SPEED_10G |
+		ETH_LINK_SPEED_25G |
+		ETH_LINK_SPEED_40G |
+		ETH_LINK_SPEED_50G |
+		ETH_LINK_SPEED_100G;
+
+	if (eth_dev->data->dev_conf.link_speeds & ~allowed_speeds) {
+		ionic_init_print(ERR, "Invalid link setting");
+		return -EINVAL;
+	}
+
+	ionic_dev_link_update(eth_dev, 0);
+
+	return 0;
+}
+
+/*
+ * Stop device: disable rx and tx functions to allow for reconfiguring.
+ */
+static void
+ionic_dev_stop(struct rte_eth_dev *eth_dev)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	int err;
+
+	ionic_init_print_call();
+
+	err = ionic_lif_stop(lif);
+
+	if (err) {
+		ionic_drv_print(ERR, "Cannot stop LIF: %d", err);
+		return;
+	}
+}
+
+/*
+ * Reset and stop device.
+ */
+static void
+ionic_dev_close(struct rte_eth_dev *eth_dev)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	int err;
+
+	ionic_init_print_call();
+
+	err = ionic_lif_stop(lif);
+
+	if (err) {
+		ionic_drv_print(ERR, "Cannot stop LIF: %d", err);
+		return;
+	}
+}
+
 static int
 eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void *init_params)
 {
@@ -87,6 +382,20 @@ eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void *init_params)
 	lif->adapter = adapter;
 	adapter->lifs[adapter->nlifs] = lif;
 
+	ionic_init_print(DEBUG, "Up to %u MAC addresses supported",
+			adapter->max_mac_addrs);
+
+	/* Allocate memory for storing MAC addresses */
+	eth_dev->data->mac_addrs = rte_zmalloc("ionic",
+			RTE_ETHER_ADDR_LEN * adapter->max_mac_addrs, 0);
+
+	if (eth_dev->data->mac_addrs == NULL) {
+		ionic_init_print(ERR, "Failed to allocate %u bytes needed to "
+				"store MAC addresses",
+				RTE_ETHER_ADDR_LEN * adapter->max_mac_addrs);
+		return -ENOMEM;
+	}
+
 	err = ionic_lif_alloc(lif);
 
 	if (err) {
@@ -102,6 +411,10 @@ eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void *init_params)
 		return err;
 	}
 
+	/* Copy the MAC address */
+	rte_ether_addr_copy((struct rte_ether_addr *)lif->mac_addr,
+			&eth_dev->data->mac_addrs[0]);
+
 	ionic_init_print(DEBUG, "Port %u initialized", eth_dev->data->port_id);
 
 	return 0;
@@ -297,6 +610,8 @@ eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 		return err;
 	}
 
+	adapter->max_mac_addrs = adapter->ident.lif.eth.max_ucast_filters;
+
 	adapter->nlifs = 0;
 	for (i = 0; i < adapter->ident.dev.nlifs; i++) {
 		snprintf(name, sizeof(name), "net_%s_lif_%lu",
diff --git a/drivers/net/ionic/ionic_lif.c b/drivers/net/ionic/ionic_lif.c
index 491db56d4..b6b730cef 100644
--- a/drivers/net/ionic/ionic_lif.c
+++ b/drivers/net/ionic/ionic_lif.c
@@ -10,6 +10,9 @@
 #include "ionic_lif.h"
 #include "ionic_ethdev.h"
 
+static int ionic_lif_addr_add(struct ionic_lif *lif, const uint8_t *addr);
+static int ionic_lif_addr_del(struct ionic_lif *lif, const uint8_t *addr);
+
 int
 ionic_qcq_enable(struct ionic_qcq *qcq)
 {
@@ -60,6 +63,105 @@ ionic_qcq_disable(struct ionic_qcq *qcq)
 	return ionic_adminq_post_wait(lif, &ctx);
 }
 
+int
+ionic_lif_stop(struct ionic_lif *lif)
+{
+	/* Carrier OFF here */
+
+	return 0;
+}
+
+void
+ionic_lif_reset(struct ionic_lif *lif)
+{
+	struct ionic_dev *idev = &lif->adapter->idev;
+
+	ionic_drv_print_call();
+
+	ionic_dev_cmd_lif_reset(idev, lif->index);
+	ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
+}
+
+static int
+ionic_lif_addr_add(struct ionic_lif *lif, const uint8_t *addr)
+{
+	ionic_init_print(INFO, "%s: stubbed\n", __func__);
+
+	return 0;
+}
+
+static int
+ionic_lif_addr_del(struct ionic_lif *lif, const uint8_t *addr)
+{
+	ionic_init_print(INFO, "%s: stubbed\n", __func__);
+
+	return 0;
+}
+
+static void
+ionic_lif_rx_mode(struct ionic_lif *lif, uint32_t rx_mode)
+{
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.rx_mode_set = {
+			.opcode = IONIC_CMD_RX_MODE_SET,
+			.lif_index = lif->index,
+			.rx_mode = rx_mode,
+		},
+	};
+	int err;
+
+	if (rx_mode & IONIC_RX_MODE_F_UNICAST)
+		ionic_init_print(DEBUG, "rx_mode IONIC_RX_MODE_F_UNICAST");
+	if (rx_mode & IONIC_RX_MODE_F_MULTICAST)
+		ionic_init_print(DEBUG, "rx_mode IONIC_RX_MODE_F_MULTICAST");
+	if (rx_mode & IONIC_RX_MODE_F_BROADCAST)
+		ionic_init_print(DEBUG, "rx_mode IONIC_RX_MODE_F_BROADCAST");
+	if (rx_mode & IONIC_RX_MODE_F_PROMISC)
+		ionic_init_print(DEBUG, "rx_mode IONIC_RX_MODE_F_PROMISC");
+	if (rx_mode & IONIC_RX_MODE_F_ALLMULTI)
+		ionic_init_print(DEBUG, "rx_mode IONIC_RX_MODE_F_ALLMULTI");
+
+	err = ionic_adminq_post_wait(lif, &ctx);
+
+	if (err)
+		ionic_init_print(ERR, "Failure setting RX mode");
+}
+
+static void
+ionic_set_rx_mode(struct ionic_lif *lif, uint32_t rx_mode)
+{
+	if (lif->rx_mode != rx_mode) {
+		lif->rx_mode = rx_mode;
+		ionic_lif_rx_mode(lif, rx_mode);
+	}
+}
+
+
+int
+ionic_lif_change_mtu(struct ionic_lif *lif, int new_mtu)
+{
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.lif_setattr = {
+			.opcode = IONIC_CMD_LIF_SETATTR,
+			.index = lif->index,
+			.attr = IONIC_LIF_ATTR_MTU,
+			.mtu = new_mtu,
+		},
+	};
+	int err;
+
+	err = ionic_adminq_post_wait(lif, &ctx);
+
+	if (err)
+		return err;
+
+	lif->mtu = new_mtu;
+
+	return 0;
+}
+
 int
 ionic_intr_alloc(struct ionic_lif *lif, struct ionic_intr_info *intr)
 {
@@ -595,6 +697,124 @@ ionic_lif_notifyq_init(struct ionic_lif *lif)
 	return 0;
 }
 
+int
+ionic_lif_set_features(struct ionic_lif *lif)
+{
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.lif_setattr = {
+			.opcode = IONIC_CMD_LIF_SETATTR,
+			.index = lif->index,
+			.attr = IONIC_LIF_ATTR_FEATURES,
+			.features = lif->features,
+		},
+	};
+	int err;
+
+	err = ionic_adminq_post_wait(lif, &ctx);
+	if (err)
+		return err;
+
+	lif->hw_features = (ctx.cmd.lif_setattr.features &
+			ctx.comp.lif_setattr.features);
+
+	if (lif->hw_features & IONIC_ETH_HW_VLAN_TX_TAG)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_VLAN_TX_TAG");
+	if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_STRIP)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_VLAN_RX_STRIP");
+	if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_FILTER)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_VLAN_RX_FILTER");
+	if (lif->hw_features & IONIC_ETH_HW_RX_HASH)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_RX_HASH");
+	if (lif->hw_features & IONIC_ETH_HW_TX_SG)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TX_SG");
+	if (lif->hw_features & IONIC_ETH_HW_RX_SG)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_RX_SG");
+	if (lif->hw_features & IONIC_ETH_HW_TX_CSUM)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TX_CSUM");
+	if (lif->hw_features & IONIC_ETH_HW_RX_CSUM)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_RX_CSUM");
+	if (lif->hw_features & IONIC_ETH_HW_TSO)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO");
+	if (lif->hw_features & IONIC_ETH_HW_TSO_IPV6)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_IPV6");
+	if (lif->hw_features & IONIC_ETH_HW_TSO_ECN)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_ECN");
+	if (lif->hw_features & IONIC_ETH_HW_TSO_GRE)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_GRE");
+	if (lif->hw_features & IONIC_ETH_HW_TSO_GRE_CSUM)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_GRE_CSUM");
+	if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP4)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_IPXIP4");
+	if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP6)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_IPXIP6");
+	if (lif->hw_features & IONIC_ETH_HW_TSO_UDP)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_UDP");
+	if (lif->hw_features & IONIC_ETH_HW_TSO_UDP_CSUM)
+		ionic_init_print(DEBUG, "feature IONIC_ETH_HW_TSO_UDP_CSUM");
+
+	return 0;
+}
+
+static int
+ionic_station_set(struct ionic_lif *lif)
+{
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.lif_getattr = {
+			.opcode = IONIC_CMD_LIF_GETATTR,
+			.index = lif->index,
+			.attr = IONIC_LIF_ATTR_MAC,
+		},
+	};
+	int err;
+
+	ionic_init_print_call();
+
+	err = ionic_adminq_post_wait(lif, &ctx);
+
+	if (err)
+		return err;
+
+	if (!rte_is_zero_ether_addr((struct rte_ether_addr *)
+			lif->mac_addr)) {
+		ionic_init_print(INFO, "deleting station MAC addr");
+
+		ionic_lif_addr_del(lif, lif->mac_addr);
+	}
+
+	memcpy(lif->mac_addr, ctx.comp.lif_getattr.mac, ETH_ALEN);
+
+	if (rte_is_zero_ether_addr((struct rte_ether_addr *)lif->mac_addr)) {
+		ionic_init_print(NOTICE, "empty MAC addr (VF?)");
+		return 0;
+	}
+
+	ionic_init_print(DEBUG, "adding station MAC addr");
+
+	ionic_lif_addr_add(lif, lif->mac_addr);
+
+	return 0;
+}
+
+static void
+ionic_lif_set_name(struct ionic_lif *lif)
+{
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.lif_setattr = {
+			.opcode = IONIC_CMD_LIF_SETATTR,
+			.index = lif->index,
+			.attr = IONIC_LIF_ATTR_NAME,
+		},
+	};
+
+	snprintf(ctx.cmd.lif_setattr.name, sizeof(ctx.cmd.lif_setattr.name),
+		"%d", lif->port_id);
+
+	ionic_adminq_post_wait(lif, &ctx);
+}
+
 int
 ionic_lif_init(struct ionic_lif *lif)
 {
@@ -620,10 +840,27 @@ ionic_lif_init(struct ionic_lif *lif)
 	if (err)
 		goto err_out_adminq_deinit;
 
+	lif->features = 0;
+
+	err = ionic_lif_set_features(lif);
+
+	if (err)
+		goto err_out_notifyq_deinit;
+
+	err = ionic_station_set(lif);
+
+	if (err)
+		goto err_out_notifyq_deinit;
+
+	ionic_lif_set_name(lif);
+
 	lif->state |= IONIC_LIF_F_INITED;
 
 	return 0;
 
+err_out_notifyq_deinit:
+	ionic_lif_qcq_deinit(lif, lif->notifyqcq);
+
 err_out_adminq_deinit:
 	ionic_lif_qcq_deinit(lif, lif->adminqcq);
 
@@ -642,6 +879,37 @@ ionic_lif_deinit(struct ionic_lif *lif)
 	lif->state &= ~IONIC_LIF_F_INITED;
 }
 
+int
+ionic_lif_configure(struct ionic_lif *lif)
+{
+	lif->port_id = lif->eth_dev->data->port_id;
+
+	return 0;
+}
+
+int
+ionic_lif_start(struct ionic_lif *lif)
+{
+	uint32_t rx_mode = 0;
+
+	ionic_init_print(DEBUG, "Setting RX mode on port %u",
+		lif->port_id);
+
+	rx_mode |= IONIC_RX_MODE_F_UNICAST;
+	rx_mode |= IONIC_RX_MODE_F_MULTICAST;
+	rx_mode |= IONIC_RX_MODE_F_BROADCAST;
+
+	lif->rx_mode = 0; /* set by ionic_set_rx_mode */
+
+	ionic_set_rx_mode(lif, rx_mode);
+
+	ionic_link_status_check(lif);
+
+	/* Carrier ON here */
+
+	return 0;
+}
+
 int
 ionic_lif_identify(struct ionic_adapter *adapter)
 {
diff --git a/drivers/net/ionic/ionic_lif.h b/drivers/net/ionic/ionic_lif.h
index 326cb17d5..f7c51c9ec 100644
--- a/drivers/net/ionic/ionic_lif.h
+++ b/drivers/net/ionic/ionic_lif.h
@@ -44,6 +44,7 @@ struct ionic_lif {
 	struct ionic_adapter *adapter;
 	struct rte_eth_dev *eth_dev;
 	uint16_t port_id;  /**< Device port identifier */
+	uint16_t mtu;
 	uint32_t index;
 	uint32_t hw_index;
 	uint32_t state;
@@ -54,7 +55,11 @@ struct ionic_lif {
 	struct ionic_qcq *notifyqcq;
 	struct ionic_doorbell __iomem *kern_dbpage;
 	uint64_t last_eid;
+	uint64_t features;
+	uint32_t hw_features;
+	uint32_t rx_mode;
 	char name[IONIC_LIF_NAME_MAX_SZ];
+	uint8_t mac_addr[ETH_ALEN];
 	uint32_t info_sz;
 	struct ionic_lif_info *info;
 	rte_iova_t info_pa;
@@ -84,11 +89,15 @@ bool ionic_adminq_service(struct ionic_cq *cq, uint32_t cq_desc_index,
 int ionic_qcq_service(struct ionic_qcq *qcq, int budget, ionic_cq_cb cb,
 		void *cb_arg);
 
+int ionic_lif_change_mtu(struct ionic_lif *lif, int new_mtu);
+
 void ionic_qcq_free(struct ionic_qcq *qcq);
 
 int ionic_qcq_enable(struct ionic_qcq *qcq);
 int ionic_qcq_disable(struct ionic_qcq *qcq);
 
+int ionic_lif_set_features(struct ionic_lif *lif);
+
 int ionic_notifyq_handler(struct ionic_lif *lif, int budget);
 
 #endif /* _IONIC_LIF_H_ */
diff --git a/drivers/net/ionic/ionic_osdep.h b/drivers/net/ionic/ionic_osdep.h
index 5b8baa67b..39a9cefa9 100644
--- a/drivers/net/ionic/ionic_osdep.h
+++ b/drivers/net/ionic/ionic_osdep.h
@@ -28,6 +28,8 @@
 #define BIT_ULL(nr)        (1ULL << (nr))
 #define BITS_TO_LONGS(nr)  div_round_up(nr, 8 * sizeof(long))
 
+#define ETH_ALEN        6
+
 #ifndef PAGE_SHIFT
 #define PAGE_SHIFT      12
 #define PAGE_SIZE       (1 << PAGE_SHIFT)


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 11/17] net/ionic: add RX filters support
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
                   ` (9 preceding siblings ...)
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 10/17] net/ionic: add basic port operations Alfredo Cardigliano
@ 2019-10-12  0:27 ` Alfredo Cardigliano
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 12/17] net/ionic: net-ionic-add-flow-control-support Alfredo Cardigliano
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:27 UTC (permalink / raw)
  To: dev

Add support for managing RX filters based on MAC and VLAN.
Hardware cannot provide the list of filters, thus we keep
a local list.
Add support for promisc and allmulticast modes.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 doc/guides/nics/features/ionic.ini  |    4 +
 drivers/net/ionic/Makefile          |    1 
 drivers/net/ionic/ionic_ethdev.c    |    8 +
 drivers/net/ionic/ionic_lif.c       |  255 ++++++++++++++++++++++++++++++++++-
 drivers/net/ionic/ionic_lif.h       |   16 ++
 drivers/net/ionic/ionic_rx_filter.c |  140 +++++++++++++++++++
 drivers/net/ionic/ionic_rx_filter.h |   47 ++++++
 drivers/net/ionic/meson.build       |    1 
 8 files changed, 468 insertions(+), 4 deletions(-)
 create mode 100644 drivers/net/ionic/ionic_rx_filter.c
 create mode 100644 drivers/net/ionic/ionic_rx_filter.h

diff --git a/doc/guides/nics/features/ionic.ini b/doc/guides/nics/features/ionic.ini
index c69e5cbed..3dd5dab45 100644
--- a/doc/guides/nics/features/ionic.ini
+++ b/doc/guides/nics/features/ionic.ini
@@ -8,6 +8,10 @@ Speed capabilities   = Y
 Link status          = Y
 Link status event    = Y
 MTU update           = Y
+Promiscuous mode     = Y
+Allmulticast mode    = Y
+Unicast MAC filter   = Y
+VLAN filter          = Y
 Linux UIO            = Y
 Linux VFIO           = Y
 x86-64               = Y
diff --git a/drivers/net/ionic/Makefile b/drivers/net/ionic/Makefile
index a1378bdbe..7827e2b69 100644
--- a/drivers/net/ionic/Makefile
+++ b/drivers/net/ionic/Makefile
@@ -54,6 +54,7 @@ LDLIBS += -lrte_bus_pci
 # all source are stored in SRCS-y
 #
 SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_mac_api.c
+SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_rx_filter.c
 SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_dev.c
 SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_lif.c
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index fed332750..ee9feb9ef 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -50,6 +50,14 @@ static const struct eth_dev_ops ionic_eth_dev_ops = {
 	.link_update            = ionic_dev_link_update,
 	.dev_set_link_up        = ionic_dev_set_link_up,
 	.dev_set_link_down      = ionic_dev_set_link_down,
+	.mac_addr_add           = ionic_dev_add_mac,
+	.mac_addr_remove        = ionic_dev_remove_mac,
+	.mac_addr_set           = ionic_dev_set_mac,
+	.vlan_filter_set        = ionic_dev_vlan_filter_set,
+	.promiscuous_enable     = ionic_dev_promiscuous_enable,
+	.promiscuous_disable    = ionic_dev_promiscuous_disable,
+	.allmulticast_enable    = ionic_dev_allmulticast_enable,
+	.allmulticast_disable   = ionic_dev_allmulticast_disable,
 };
 
 /*
diff --git a/drivers/net/ionic/ionic_lif.c b/drivers/net/ionic/ionic_lif.c
index b6b730cef..0ab0f9e5e 100644
--- a/drivers/net/ionic/ionic_lif.c
+++ b/drivers/net/ionic/ionic_lif.c
@@ -9,6 +9,7 @@
 #include "ionic_logs.h"
 #include "ionic_lif.h"
 #include "ionic_ethdev.h"
+#include "ionic_rx_filter.h"
 
 static int ionic_lif_addr_add(struct ionic_lif *lif, const uint8_t *addr);
 static int ionic_lif_addr_del(struct ionic_lif *lif, const uint8_t *addr);
@@ -85,19 +86,203 @@ ionic_lif_reset(struct ionic_lif *lif)
 static int
 ionic_lif_addr_add(struct ionic_lif *lif, const uint8_t *addr)
 {
-	ionic_init_print(INFO, "%s: stubbed\n", __func__);
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.rx_filter_add = {
+			.opcode = IONIC_CMD_RX_FILTER_ADD,
+			.match = IONIC_RX_FILTER_MATCH_MAC,
+		},
+	};
+	int err;
 
-	return 0;
+	memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, ETH_ALEN);
+
+	err = ionic_adminq_post_wait(lif, &ctx);
+
+	if (err)
+		return err;
+
+	ionic_init_print(INFO, "rx_filter add (id %d)",
+			ctx.comp.rx_filter_add.filter_id);
+
+	return ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx);
 }
 
 static int
 ionic_lif_addr_del(struct ionic_lif *lif, const uint8_t *addr)
 {
-	ionic_init_print(INFO, "%s: stubbed\n", __func__);
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.rx_filter_del = {
+			.opcode = IONIC_CMD_RX_FILTER_DEL,
+		},
+	};
+	struct ionic_rx_filter *f;
+	int err;
+
+	ionic_init_print_call();
+
+	rte_spinlock_lock(&lif->rx_filters.lock);
+
+	f = ionic_rx_filter_by_addr(lif, addr);
+
+	if (!f) {
+		rte_spinlock_unlock(&lif->rx_filters.lock);
+		return -ENOENT;
+	}
+
+	ctx.cmd.rx_filter_del.filter_id = f->filter_id;
+	ionic_rx_filter_free(lif, f);
+
+	rte_spinlock_unlock(&lif->rx_filters.lock);
+
+	err = ionic_adminq_post_wait(lif, &ctx);
+
+	if (err)
+		return err;
+
+	ionic_init_print(INFO, "rx_filter del (id %d)",
+			ctx.cmd.rx_filter_del.filter_id);
 
 	return 0;
 }
 
+int
+ionic_dev_add_mac(struct rte_eth_dev *eth_dev,
+		struct rte_ether_addr *mac_addr,
+		uint32_t index __rte_unused, uint32_t pool __rte_unused)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+
+	ionic_init_print_call();
+
+	return ionic_lif_addr_add(lif, (const uint8_t *)mac_addr);
+}
+
+void
+ionic_dev_remove_mac(struct rte_eth_dev *eth_dev, uint32_t index __rte_unused)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_adapter *adapter = lif->adapter;
+
+	ionic_init_print_call();
+
+	if (index >= adapter->max_mac_addrs) {
+		ionic_init_print(WARNING,
+				"Index %u is above MAC filter limit %u",
+				index, adapter->max_mac_addrs);
+		return;
+	}
+
+	if (!rte_is_valid_assigned_ether_addr(&eth_dev->data->mac_addrs[index]))
+		return;
+
+	ionic_lif_addr_del(lif, (const uint8_t *)
+			&eth_dev->data->mac_addrs[index]);
+}
+
+int
+ionic_dev_set_mac(struct rte_eth_dev *eth_dev, struct rte_ether_addr *mac_addr)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+
+	ionic_init_print_call();
+
+	if (mac_addr == NULL) {
+		ionic_init_print(NOTICE, "New mac is null");
+		return -1;
+	}
+
+	if (!rte_is_zero_ether_addr((struct rte_ether_addr *)lif->mac_addr)) {
+		ionic_init_print(INFO, "Deleting mac addr %pM",
+				lif->mac_addr);
+		ionic_lif_addr_del(lif, lif->mac_addr);
+		memset(lif->mac_addr, 0, ETH_ALEN);
+	}
+
+	ionic_init_print(INFO, "Updating mac addr");
+
+	rte_ether_addr_copy(mac_addr, (struct rte_ether_addr *)lif->mac_addr);
+
+	return ionic_lif_addr_add(lif, (const uint8_t *)mac_addr);
+}
+
+static int
+ionic_vlan_rx_add_vid(struct ionic_lif *lif, uint16_t vid)
+{
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.rx_filter_add = {
+			.opcode = IONIC_CMD_RX_FILTER_ADD,
+			.match = IONIC_RX_FILTER_MATCH_VLAN,
+			.vlan.vlan = vid,
+		},
+	};
+	int err;
+
+	err = ionic_adminq_post_wait(lif, &ctx);
+
+	if (err)
+		return err;
+
+	ionic_init_print(INFO, "rx_filter add VLAN %d (id %d)", vid,
+			ctx.comp.rx_filter_add.filter_id);
+
+	return ionic_rx_filter_save(lif, 0, IONIC_RXQ_INDEX_ANY, 0, &ctx);
+}
+
+static int
+ionic_vlan_rx_kill_vid(struct ionic_lif *lif, uint16_t vid)
+{
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.rx_filter_del = {
+			.opcode = IONIC_CMD_RX_FILTER_DEL,
+		},
+	};
+	struct ionic_rx_filter *f;
+	int err;
+
+	ionic_init_print_call();
+
+	rte_spinlock_lock(&lif->rx_filters.lock);
+
+	f = ionic_rx_filter_by_vlan(lif, vid);
+	if (!f) {
+		rte_spinlock_unlock(&lif->rx_filters.lock);
+		return -ENOENT;
+	}
+
+	ctx.cmd.rx_filter_del.filter_id = f->filter_id;
+	ionic_rx_filter_free(lif, f);
+	rte_spinlock_unlock(&lif->rx_filters.lock);
+
+	err = ionic_adminq_post_wait(lif, &ctx);
+
+	if (err)
+		return err;
+
+	ionic_init_print(INFO, "rx_filter del VLAN %d (id %d)", vid,
+			ctx.cmd.rx_filter_del.filter_id);
+
+	return 0;
+}
+
+int
+ionic_dev_vlan_filter_set(struct rte_eth_dev *eth_dev, uint16_t vlan_id,
+		int on)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	int err;
+
+	if (on)
+		err = ionic_vlan_rx_add_vid(lif, vlan_id);
+	else
+		err = ionic_vlan_rx_kill_vid(lif, vlan_id);
+
+	return err;
+}
+
 static void
 ionic_lif_rx_mode(struct ionic_lif *lif, uint32_t rx_mode)
 {
@@ -137,6 +322,59 @@ ionic_set_rx_mode(struct ionic_lif *lif, uint32_t rx_mode)
 	}
 }
 
+int
+ionic_dev_promiscuous_enable(struct rte_eth_dev *eth_dev)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	uint32_t rx_mode = lif->rx_mode;
+
+	ionic_init_print_call();
+
+	rx_mode |= IONIC_RX_MODE_F_PROMISC;
+
+	ionic_set_rx_mode(lif, rx_mode);
+
+	return 0;
+}
+
+int
+ionic_dev_promiscuous_disable(struct rte_eth_dev *eth_dev)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	uint32_t rx_mode = lif->rx_mode;
+
+	rx_mode &= ~IONIC_RX_MODE_F_PROMISC;
+
+	ionic_set_rx_mode(lif, rx_mode);
+
+	return 0;
+}
+
+int
+ionic_dev_allmulticast_enable(struct rte_eth_dev *eth_dev)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	uint32_t rx_mode = lif->rx_mode;
+
+	rx_mode |= IONIC_RX_MODE_F_ALLMULTI;
+
+	ionic_set_rx_mode(lif, rx_mode);
+
+	return 0;
+}
+
+int
+ionic_dev_allmulticast_disable(struct rte_eth_dev *eth_dev)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	uint32_t rx_mode = lif->rx_mode;
+
+	rx_mode &= ~IONIC_RX_MODE_F_ALLMULTI;
+
+	ionic_set_rx_mode(lif, rx_mode);
+
+	return 0;
+}
 
 int
 ionic_lif_change_mtu(struct ionic_lif *lif, int new_mtu)
@@ -847,17 +1085,25 @@ ionic_lif_init(struct ionic_lif *lif)
 	if (err)
 		goto err_out_notifyq_deinit;
 
-	err = ionic_station_set(lif);
+	err = ionic_rx_filters_init(lif);
 
 	if (err)
 		goto err_out_notifyq_deinit;
 
+	err = ionic_station_set(lif);
+
+	if (err)
+		goto err_out_rx_filter_deinit;
+
 	ionic_lif_set_name(lif);
 
 	lif->state |= IONIC_LIF_F_INITED;
 
 	return 0;
 
+err_out_rx_filter_deinit:
+	ionic_rx_filters_deinit(lif);
+
 err_out_notifyq_deinit:
 	ionic_lif_qcq_deinit(lif, lif->notifyqcq);
 
@@ -873,6 +1119,7 @@ ionic_lif_deinit(struct ionic_lif *lif)
 	if (!(lif->state & IONIC_LIF_F_INITED))
 		return;
 
+	ionic_rx_filters_deinit(lif);
 	ionic_lif_qcq_deinit(lif, lif->notifyqcq);
 	ionic_lif_qcq_deinit(lif, lif->adminqcq);
 
diff --git a/drivers/net/ionic/ionic_lif.h b/drivers/net/ionic/ionic_lif.h
index f7c51c9ec..e192186a6 100644
--- a/drivers/net/ionic/ionic_lif.h
+++ b/drivers/net/ionic/ionic_lif.h
@@ -12,6 +12,7 @@
 
 #include "ionic_osdep.h"
 #include "ionic_dev.h"
+#include "ionic_rx_filter.h"
 
 #define IONIC_ADMINQ_LENGTH	16	/* must be a power of two */
 #define IONIC_NOTIFYQ_LENGTH	64	/* must be a power of two */
@@ -53,6 +54,7 @@ struct ionic_lif {
 	rte_spinlock_t adminq_service_lock;
 	struct ionic_qcq *adminqcq;
 	struct ionic_qcq *notifyqcq;
+	struct ionic_rx_filters rx_filters;
 	struct ionic_doorbell __iomem *kern_dbpage;
 	uint64_t last_eid;
 	uint64_t features;
@@ -91,6 +93,20 @@ int ionic_qcq_service(struct ionic_qcq *qcq, int budget, ionic_cq_cb cb,
 
 int ionic_lif_change_mtu(struct ionic_lif *lif, int new_mtu);
 
+int ionic_dev_add_mac(struct rte_eth_dev *eth_dev,
+		struct rte_ether_addr *mac_addr,
+		uint32_t index __rte_unused, uint32_t pool __rte_unused);
+void ionic_dev_remove_mac(struct rte_eth_dev *eth_dev,
+		uint32_t index __rte_unused);
+int ionic_dev_set_mac(struct rte_eth_dev *eth_dev,
+		struct rte_ether_addr *mac_addr);
+int ionic_dev_vlan_filter_set(struct rte_eth_dev *eth_dev, uint16_t vlan_id,
+		int on);
+int ionic_dev_promiscuous_enable(struct rte_eth_dev *dev);
+int ionic_dev_promiscuous_disable(struct rte_eth_dev *dev);
+int ionic_dev_allmulticast_enable(struct rte_eth_dev *dev);
+int ionic_dev_allmulticast_disable(struct rte_eth_dev *dev);
+
 void ionic_qcq_free(struct ionic_qcq *qcq);
 
 int ionic_qcq_enable(struct ionic_qcq *qcq);
diff --git a/drivers/net/ionic/ionic_rx_filter.c b/drivers/net/ionic/ionic_rx_filter.c
new file mode 100644
index 000000000..901f172dc
--- /dev/null
+++ b/drivers/net/ionic/ionic_rx_filter.c
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#include <errno.h>
+
+#include <rte_malloc.h>
+
+#include "ionic_lif.h"
+#include "ionic_rx_filter.h"
+
+void
+ionic_rx_filter_free(struct ionic_lif *lif, struct ionic_rx_filter *f)
+{
+	LIST_REMOVE(f, by_id);
+	LIST_REMOVE(f, by_hash);
+	rte_free(f);
+}
+
+int
+ionic_rx_filter_del(struct ionic_lif *lif, struct ionic_rx_filter *f)
+{
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.rx_filter_del = {
+			.opcode = IONIC_CMD_RX_FILTER_DEL,
+			.filter_id = f->filter_id,
+		},
+	};
+
+	return ionic_adminq_post(lif, &ctx);
+}
+
+int
+ionic_rx_filters_init(struct ionic_lif *lif)
+{
+	uint32_t i;
+
+	rte_spinlock_init(&lif->rx_filters.lock);
+
+	for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
+		LIST_INIT(&lif->rx_filters.by_hash[i]);
+		LIST_INIT(&lif->rx_filters.by_id[i]);
+	}
+
+	return 0;
+}
+
+void
+ionic_rx_filters_deinit(struct ionic_lif *lif)
+{
+	struct ionic_rx_filter *f;
+	uint32_t i;
+
+	for (i = 0; i < IONIC_RX_FILTER_HLISTS; i++) {
+		while (!LIST_EMPTY(&lif->rx_filters.by_id[i])) {
+			f = LIST_FIRST(&lif->rx_filters.by_id[i]);
+			ionic_rx_filter_free(lif, f);
+		}
+	}
+}
+
+int
+ionic_rx_filter_save(struct ionic_lif *lif, uint32_t flow_id,
+		uint16_t rxq_index,
+		uint32_t hash, struct ionic_admin_ctx *ctx)
+{
+	struct ionic_rx_filter *f;
+	uint32_t key;
+
+	f = rte_zmalloc("ionic", sizeof(*f), 0);
+
+	if (!f)
+		return -ENOMEM;
+
+	f->flow_id = flow_id;
+	f->filter_id = ctx->comp.rx_filter_add.filter_id;
+	f->rxq_index = rxq_index;
+	memcpy(&f->cmd, &ctx->cmd, sizeof(f->cmd));
+
+	switch (f->cmd.match) {
+	case IONIC_RX_FILTER_MATCH_VLAN:
+		key = f->cmd.vlan.vlan & IONIC_RX_FILTER_HLISTS_MASK;
+		break;
+	case IONIC_RX_FILTER_MATCH_MAC:
+		key = *(uint32_t *)f->cmd.mac.addr &
+				IONIC_RX_FILTER_HLISTS_MASK;
+		break;
+	case IONIC_RX_FILTER_MATCH_MAC_VLAN:
+		key = f->cmd.mac_vlan.vlan & IONIC_RX_FILTER_HLISTS_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	rte_spinlock_lock(&lif->rx_filters.lock);
+
+	LIST_INSERT_HEAD(&lif->rx_filters.by_hash[key], f, by_hash);
+
+	key = f->filter_id & IONIC_RX_FILTER_HLISTS_MASK;
+
+	LIST_INSERT_HEAD(&lif->rx_filters.by_id[key], f, by_id);
+
+	rte_spinlock_unlock(&lif->rx_filters.lock);
+
+	return 0;
+}
+
+struct ionic_rx_filter *
+ionic_rx_filter_by_vlan(struct ionic_lif *lif, uint16_t vid)
+{
+	uint32_t key = vid & IONIC_RX_FILTER_HLISTS_MASK;
+	struct ionic_rx_filter *f;
+
+	LIST_FOREACH(f, &lif->rx_filters.by_hash[key], by_hash) {
+		if (f->cmd.match != IONIC_RX_FILTER_MATCH_VLAN)
+			continue;
+		if (f->cmd.vlan.vlan == vid)
+			return f;
+	}
+
+	return NULL;
+}
+
+struct ionic_rx_filter *
+ionic_rx_filter_by_addr(struct ionic_lif *lif, const uint8_t *addr)
+{
+	const uint32_t key = *(const uint32_t *)addr &
+			IONIC_RX_FILTER_HLISTS_MASK;
+	struct ionic_rx_filter *f;
+
+	LIST_FOREACH(f, &lif->rx_filters.by_hash[key], by_hash) {
+		if (f->cmd.match != IONIC_RX_FILTER_MATCH_MAC)
+			continue;
+		if (memcmp(addr, f->cmd.mac.addr, ETH_ALEN) == 0)
+			return f;
+	}
+
+	return NULL;
+}
diff --git a/drivers/net/ionic/ionic_rx_filter.h b/drivers/net/ionic/ionic_rx_filter.h
new file mode 100644
index 000000000..be56f0222
--- /dev/null
+++ b/drivers/net/ionic/ionic_rx_filter.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#ifndef _IONIC_RX_FILTER_H_
+#define _IONIC_RX_FILTER_H_
+
+#include <rte_spinlock.h>
+
+#include "ionic_osdep.h"
+#include "ionic_if.h"
+
+#define IONIC_RXQ_INDEX_ANY		(0xFFFF)
+struct ionic_rx_filter {
+	uint32_t flow_id;
+	uint32_t filter_id;
+	uint16_t rxq_index;
+	struct ionic_rx_filter_add_cmd cmd;
+	LIST_ENTRY(ionic_rx_filter) by_hash;
+	LIST_ENTRY(ionic_rx_filter) by_id;
+};
+
+#define IONIC_RX_FILTER_HLISTS	(1 << 10)
+#define IONIC_RX_FILTER_HLISTS_MASK	(IONIC_RX_FILTER_HLISTS - 1)
+struct ionic_rx_filters {
+	rte_spinlock_t lock;
+	LIST_HEAD(rx_filters_by_hash, ionic_rx_filter)
+			by_hash[IONIC_RX_FILTER_HLISTS]; /* by pkt hash */
+	LIST_HEAD(rx_filters_by_id,   ionic_rx_filter)
+			by_id[IONIC_RX_FILTER_HLISTS];   /* by filter_id */
+};
+
+struct ionic_admin_ctx;
+struct ionic_lif;
+
+void ionic_rx_filter_free(struct ionic_lif *lif, struct ionic_rx_filter *f);
+int ionic_rx_filter_del(struct ionic_lif *lif, struct ionic_rx_filter *f);
+int ionic_rx_filters_init(struct ionic_lif *lif);
+void ionic_rx_filters_deinit(struct ionic_lif *lif);
+int ionic_rx_filter_save(struct ionic_lif *lif, uint32_t flow_id,
+		uint16_t rxq_index, uint32_t hash, struct ionic_admin_ctx *ctx);
+struct ionic_rx_filter *ionic_rx_filter_by_vlan(struct ionic_lif *lif,
+		uint16_t vid);
+struct ionic_rx_filter *ionic_rx_filter_by_addr(struct ionic_lif *lif,
+		const uint8_t *addr);
+
+#endif /* _IONIC_RX_FILTER_H_ */
diff --git a/drivers/net/ionic/meson.build b/drivers/net/ionic/meson.build
index 0cf5a0cc7..ef202af7f 100644
--- a/drivers/net/ionic/meson.build
+++ b/drivers/net/ionic/meson.build
@@ -5,6 +5,7 @@ version = 1
 
 sources = files(
 	'ionic_mac_api.c',
+	'ionic_rx_filter.c',
 	'ionic_dev.c',
 	'ionic_ethdev.c',
 	'ionic_lif.c',


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 12/17] net/ionic: net-ionic-add-flow-control-support
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
                   ` (10 preceding siblings ...)
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 11/17] net/ionic: add RX filters support Alfredo Cardigliano
@ 2019-10-12  0:27 ` Alfredo Cardigliano
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 13/17] net/ionic: add RSS support Alfredo Cardigliano
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:27 UTC (permalink / raw)
  To: dev

Add support for managing Flow Control.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 doc/guides/nics/features/ionic.ini |    1 +
 drivers/net/ionic/ionic_ethdev.c   |   56 ++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+)

diff --git a/doc/guides/nics/features/ionic.ini b/doc/guides/nics/features/ionic.ini
index 3dd5dab45..05bdb2d98 100644
--- a/doc/guides/nics/features/ionic.ini
+++ b/doc/guides/nics/features/ionic.ini
@@ -12,6 +12,7 @@ Promiscuous mode     = Y
 Allmulticast mode    = Y
 Unicast MAC filter   = Y
 VLAN filter          = Y
+Flow control         = Y
 Linux UIO            = Y
 Linux VFIO           = Y
 x86-64               = Y
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index ee9feb9ef..46cdee7be 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -29,6 +29,10 @@ static int  ionic_dev_set_link_up(struct rte_eth_dev *dev);
 static int  ionic_dev_set_link_down(struct rte_eth_dev *dev);
 static int  ionic_dev_link_update(struct rte_eth_dev *eth_dev,
 		int wait_to_complete);
+static int  ionic_flow_ctrl_get(struct rte_eth_dev *eth_dev,
+		struct rte_eth_fc_conf *fc_conf);
+static int  ionic_flow_ctrl_set(struct rte_eth_dev *eth_dev,
+		struct rte_eth_fc_conf *fc_conf);
 
 int ionic_logtype_init;
 int ionic_logtype_driver;
@@ -58,6 +62,8 @@ static const struct eth_dev_ops ionic_eth_dev_ops = {
 	.promiscuous_disable    = ionic_dev_promiscuous_disable,
 	.allmulticast_enable    = ionic_dev_allmulticast_enable,
 	.allmulticast_disable   = ionic_dev_allmulticast_disable,
+	.flow_ctrl_get          = ionic_flow_ctrl_get,
+	.flow_ctrl_set          = ionic_flow_ctrl_set,
 };
 
 /*
@@ -247,6 +253,56 @@ ionic_dev_info_get(struct rte_eth_dev *eth_dev,
 	return 0;
 }
 
+static int
+ionic_flow_ctrl_get(struct rte_eth_dev *eth_dev,
+		struct rte_eth_fc_conf *fc_conf)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_adapter *adapter = lif->adapter;
+	struct ionic_dev *idev = &adapter->idev;
+
+	if (idev->port_info) {
+		fc_conf->autoneg = idev->port_info->config.an_enable;
+
+		if (idev->port_info->config.pause_type)
+			fc_conf->mode = RTE_FC_FULL;
+		else
+			fc_conf->mode = RTE_FC_NONE;
+	}
+
+	return 0;
+}
+
+static int
+ionic_flow_ctrl_set(struct rte_eth_dev *eth_dev,
+		struct rte_eth_fc_conf *fc_conf)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_adapter *adapter = lif->adapter;
+	struct ionic_dev *idev = &adapter->idev;
+	uint8_t pause_type = IONIC_PORT_PAUSE_TYPE_NONE;
+	uint8_t an_enable;
+
+	switch (fc_conf->mode) {
+		case RTE_FC_NONE:
+			pause_type = IONIC_PORT_PAUSE_TYPE_NONE;
+			break;
+		case RTE_FC_FULL:
+			pause_type = IONIC_PORT_PAUSE_TYPE_LINK;
+			break;
+		case RTE_FC_RX_PAUSE:
+		case RTE_FC_TX_PAUSE:
+			return -ENOTSUP;
+	}
+
+	an_enable = fc_conf->autoneg;
+
+	ionic_dev_cmd_port_pause(idev, pause_type);
+	ionic_dev_cmd_port_autoneg(idev, an_enable);
+
+	return 0;
+}
+
 static int
 ionic_dev_configure(struct rte_eth_dev *eth_dev)
 {


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 13/17] net/ionic: add RSS support
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
                   ` (11 preceding siblings ...)
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 12/17] net/ionic: net-ionic-add-flow-control-support Alfredo Cardigliano
@ 2019-10-12  0:27 ` Alfredo Cardigliano
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 14/17] net/ionic: add RX and TX handling Alfredo Cardigliano
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:27 UTC (permalink / raw)
  To: dev

Add code to manipulate the RSS configuration
used by the adapter.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 doc/guides/nics/features/ionic.ini |    3 +
 drivers/net/ionic/ionic_ethdev.c   |  175 ++++++++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_ethdev.h   |    8 ++
 drivers/net/ionic/ionic_lif.c      |  120 +++++++++++++++++++++++++
 drivers/net/ionic/ionic_lif.h      |   18 ++++
 5 files changed, 324 insertions(+)

diff --git a/doc/guides/nics/features/ionic.ini b/doc/guides/nics/features/ionic.ini
index 05bdb2d98..b3f6c3497 100644
--- a/doc/guides/nics/features/ionic.ini
+++ b/doc/guides/nics/features/ionic.ini
@@ -11,6 +11,9 @@ MTU update           = Y
 Promiscuous mode     = Y
 Allmulticast mode    = Y
 Unicast MAC filter   = Y
+RSS hash             = Y
+RSS key update       = Y
+RSS reta update      = Y
 VLAN filter          = Y
 Flow control         = Y
 Linux UIO            = Y
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index 46cdee7be..196113089 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -33,6 +33,14 @@ static int  ionic_flow_ctrl_get(struct rte_eth_dev *eth_dev,
 		struct rte_eth_fc_conf *fc_conf);
 static int  ionic_flow_ctrl_set(struct rte_eth_dev *eth_dev,
 		struct rte_eth_fc_conf *fc_conf);
+static int  ionic_dev_rss_reta_update(struct rte_eth_dev *eth_dev,
+		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size);
+static int  ionic_dev_rss_reta_query(struct rte_eth_dev *eth_dev,
+		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size);
+static int  ionic_dev_rss_hash_conf_get(struct rte_eth_dev *eth_dev,
+		struct rte_eth_rss_conf *rss_conf);
+static int  ionic_dev_rss_hash_update(struct rte_eth_dev *eth_dev,
+		struct rte_eth_rss_conf *rss_conf);
 
 int ionic_logtype_init;
 int ionic_logtype_driver;
@@ -64,6 +72,10 @@ static const struct eth_dev_ops ionic_eth_dev_ops = {
 	.allmulticast_disable   = ionic_dev_allmulticast_disable,
 	.flow_ctrl_get          = ionic_flow_ctrl_get,
 	.flow_ctrl_set          = ionic_flow_ctrl_set,
+	.reta_update            = ionic_dev_rss_reta_update,
+	.reta_query             = ionic_dev_rss_reta_query,
+	.rss_hash_conf_get      = ionic_dev_rss_hash_conf_get,
+	.rss_hash_update        = ionic_dev_rss_hash_update,
 };
 
 /*
@@ -243,6 +255,10 @@ ionic_dev_info_get(struct rte_eth_dev *eth_dev,
 	dev_info->max_rx_pktlen = IONIC_MAX_MTU + RTE_ETHER_HDR_LEN;
 	dev_info->max_mac_addrs = adapter->max_mac_addrs;
 
+	dev_info->hash_key_size = IONIC_RSS_HASH_KEY_SIZE;
+	dev_info->reta_size = ident->lif.eth.rss_ind_tbl_sz;
+	dev_info->flow_type_rss_offloads = IONIC_ETH_RSS_OFFLOAD_ALL;
+
 	dev_info->speed_capa =
 		ETH_LINK_SPEED_10G |
 		ETH_LINK_SPEED_25G |
@@ -303,6 +319,165 @@ ionic_flow_ctrl_set(struct rte_eth_dev *eth_dev,
 	return 0;
 }
 
+static int
+ionic_dev_rss_reta_update(struct rte_eth_dev *eth_dev,
+		struct rte_eth_rss_reta_entry64 *reta_conf,
+		uint16_t reta_size)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_adapter *adapter = lif->adapter;
+	struct ionic_identity *ident = &adapter->ident;
+	uint32_t i, j, index, num;
+
+	ionic_init_print_call();
+
+	if (!lif->rss_ind_tbl) {
+		ionic_drv_print(ERR, "RSS RETA not initialized, "
+				"can't update the table");
+		return -EINVAL;
+	}
+
+	if (reta_size != ident->lif.eth.rss_ind_tbl_sz) {
+		ionic_drv_print(ERR, "The size of hash lookup table configured "
+			"(%d) doesn't match the number hardware can supported "
+			"(%d)",
+			reta_size, ident->lif.eth.rss_ind_tbl_sz);
+		return -EINVAL;
+	}
+
+	num = lif->adapter->ident.lif.eth.rss_ind_tbl_sz / RTE_RETA_GROUP_SIZE;
+
+	for (i = 0; i < num; i++) {
+		for (j = 0; j < RTE_RETA_GROUP_SIZE; j++) {
+			if (reta_conf[i].mask & ((uint64_t)1 << j)) {
+				index = (i * RTE_RETA_GROUP_SIZE) + j;
+				lif->rss_ind_tbl[index] = reta_conf[i].reta[j];
+			}
+		}
+	}
+
+	return ionic_lif_rss_config(lif, lif->rss_types, NULL, NULL);
+}
+
+static int
+ionic_dev_rss_reta_query(struct rte_eth_dev *eth_dev,
+		struct rte_eth_rss_reta_entry64 *reta_conf,
+		uint16_t reta_size)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_adapter *adapter = lif->adapter;
+	struct ionic_identity *ident = &adapter->ident;
+	int i, num;
+
+	ionic_init_print_call();
+
+	if (reta_size != ident->lif.eth.rss_ind_tbl_sz) {
+		ionic_drv_print(ERR, "The size of hash lookup table configured "
+			"(%d) doesn't match the number hardware can supported "
+			"(%d)",
+			reta_size, ident->lif.eth.rss_ind_tbl_sz);
+		return -EINVAL;
+	}
+
+	if (!lif->rss_ind_tbl) {
+		ionic_drv_print(ERR, "RSS RETA has not been built yet");
+		return -EINVAL;
+	}
+
+	num = reta_size / RTE_RETA_GROUP_SIZE;
+
+	for (i = 0; i < num; i++) {
+		memcpy(reta_conf->reta,
+			&lif->rss_ind_tbl[i * RTE_RETA_GROUP_SIZE],
+			RTE_RETA_GROUP_SIZE);
+		reta_conf++;
+	}
+
+	return 0;
+}
+
+static int
+ionic_dev_rss_hash_conf_get(struct rte_eth_dev *eth_dev,
+		struct rte_eth_rss_conf *rss_conf)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	uint64_t rss_hf = 0;
+
+	ionic_init_print_call();
+
+	if (!lif->rss_ind_tbl) {
+		ionic_drv_print(NOTICE, "RSS not enabled");
+		return 0;
+	}
+
+	/* Get key value (if not null, rss_key is 40-byte) */
+	if (rss_conf->rss_key != NULL &&
+			rss_conf->rss_key_len >= IONIC_RSS_HASH_KEY_SIZE)
+		memcpy(rss_conf->rss_key, lif->rss_hash_key,
+				IONIC_RSS_HASH_KEY_SIZE);
+
+	if (lif->rss_types & IONIC_RSS_TYPE_IPV4)
+		rss_hf |= ETH_RSS_IPV4;
+	if (lif->rss_types & IONIC_RSS_TYPE_IPV4_TCP)
+		rss_hf |= ETH_RSS_NONFRAG_IPV4_TCP;
+	if (lif->rss_types & IONIC_RSS_TYPE_IPV4_UDP)
+		rss_hf |= ETH_RSS_NONFRAG_IPV4_UDP;
+	if (lif->rss_types & IONIC_RSS_TYPE_IPV6)
+		rss_hf |= ETH_RSS_IPV6;
+	if (lif->rss_types & IONIC_RSS_TYPE_IPV6_TCP)
+		rss_hf |= ETH_RSS_NONFRAG_IPV6_TCP;
+	if (lif->rss_types & IONIC_RSS_TYPE_IPV6_UDP)
+		rss_hf |= ETH_RSS_NONFRAG_IPV6_UDP;
+
+	rss_conf->rss_hf = rss_hf;
+
+	return 0;
+}
+
+static int
+ionic_dev_rss_hash_update(struct rte_eth_dev *eth_dev,
+		struct rte_eth_rss_conf *rss_conf)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	uint32_t rss_types = 0;
+	uint8_t *key = NULL;
+
+	ionic_init_print_call();
+
+	if (rss_conf->rss_key)
+		key = rss_conf->rss_key;
+
+	if ((rss_conf->rss_hf & IONIC_ETH_RSS_OFFLOAD_ALL) == 0) {
+		/*
+		 * Can't disable rss through hash flags,
+		 * if it is enabled by default during init
+		 */
+		if (lif->rss_ind_tbl)
+			return -EINVAL;
+	} else {
+		/* Can't enable rss if disabled by default during init */
+		if (!lif->rss_ind_tbl)
+			return -EINVAL;
+
+		if (rss_conf->rss_hf & ETH_RSS_IPV4)
+			rss_types |= IONIC_RSS_TYPE_IPV4;
+		if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_TCP)
+			rss_types |= IONIC_RSS_TYPE_IPV4_TCP;
+		if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV4_UDP)
+			rss_types |= IONIC_RSS_TYPE_IPV4_UDP;
+		if (rss_conf->rss_hf & ETH_RSS_IPV6)
+			rss_types |= IONIC_RSS_TYPE_IPV6;
+		if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV6_TCP)
+			rss_types |= IONIC_RSS_TYPE_IPV6_TCP;
+		if (rss_conf->rss_hf & ETH_RSS_NONFRAG_IPV6_UDP)
+			rss_types |= IONIC_RSS_TYPE_IPV6_UDP;
+
+		ionic_lif_rss_config(lif, rss_types, key, NULL);
+	}
+
+	return 0;
+}
+
 static int
 ionic_dev_configure(struct rte_eth_dev *eth_dev)
 {
diff --git a/drivers/net/ionic/ionic_ethdev.h b/drivers/net/ionic/ionic_ethdev.h
index 9f1c0320d..914e36dfb 100644
--- a/drivers/net/ionic/ionic_ethdev.h
+++ b/drivers/net/ionic/ionic_ethdev.h
@@ -5,6 +5,14 @@
 #ifndef _IONIC_ETHDEV_H_
 #define _IONIC_ETHDEV_H_
 
+#define IONIC_ETH_RSS_OFFLOAD_ALL ( \
+	ETH_RSS_IPV4 | \
+	ETH_RSS_NONFRAG_IPV4_TCP | \
+	ETH_RSS_NONFRAG_IPV4_UDP | \
+	ETH_RSS_IPV6 | \
+	ETH_RSS_NONFRAG_IPV6_TCP | \
+	ETH_RSS_NONFRAG_IPV6_UDP)
+
 #define IONIC_ETH_DEV_TO_LIF(eth_dev) ((struct ionic_lif *) \
 		eth_dev->data->dev_private)
 #define IONIC_ETH_DEV_TO_ADAPTER(eth_dev) \
diff --git a/drivers/net/ionic/ionic_lif.c b/drivers/net/ionic/ionic_lif.c
index 0ab0f9e5e..045994787 100644
--- a/drivers/net/ionic/ionic_lif.c
+++ b/drivers/net/ionic/ionic_lif.c
@@ -714,6 +714,97 @@ ionic_lif_free(struct ionic_lif *lif)
 		rte_memzone_free(lif->info_z);
 }
 
+int
+ionic_lif_rss_config(struct ionic_lif *lif,
+		const uint16_t types, const uint8_t *key, const uint32_t *indir)
+{
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.lif_setattr = {
+			.opcode = IONIC_CMD_LIF_SETATTR,
+			.attr = IONIC_LIF_ATTR_RSS,
+			.rss.types = types,
+			.rss.addr = lif->rss_ind_tbl_pa,
+		},
+	};
+	unsigned int i;
+
+	ionic_init_print_call();
+
+	lif->rss_types = types;
+
+	if (key)
+		memcpy(lif->rss_hash_key, key, IONIC_RSS_HASH_KEY_SIZE);
+
+	if (indir)
+		for (i = 0; i < lif->adapter->ident.lif.eth.rss_ind_tbl_sz; i++)
+			lif->rss_ind_tbl[i] = indir[i];
+
+	memcpy(ctx.cmd.lif_setattr.rss.key, lif->rss_hash_key,
+	       IONIC_RSS_HASH_KEY_SIZE);
+
+	return ionic_adminq_post_wait(lif, &ctx);
+}
+
+static int
+ionic_lif_rss_setup(struct ionic_lif *lif)
+{
+	size_t tbl_size = sizeof(*lif->rss_ind_tbl) *
+			lif->adapter->ident.lif.eth.rss_ind_tbl_sz;
+	static const uint8_t toeplitz_symmetric_key[] = {
+		0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
+		0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
+		0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
+		0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
+		0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
+	};
+	uint32_t socket_id = rte_socket_id();
+	uint32_t i;
+	int err;
+
+	ionic_init_print_call();
+
+	lif->rss_ind_tbl_z = rte_eth_dma_zone_reserve(lif->eth_dev,
+			"rss_ind_tbl",
+			0 /* queue_idx*/, tbl_size, IONIC_ALIGN, socket_id);
+
+	if (!lif->rss_ind_tbl_z) {
+		ionic_init_print(ERR, "OOM");
+		return -ENOMEM;
+	}
+
+	lif->rss_ind_tbl = lif->rss_ind_tbl_z->addr;
+	lif->rss_ind_tbl_pa = lif->rss_ind_tbl_z->iova;
+
+	/* Fill indirection table with 'default' values */
+	for (i = 0; i < lif->adapter->ident.lif.eth.rss_ind_tbl_sz; i++)
+		lif->rss_ind_tbl[i] = i % lif->nrxqcqs;
+
+	err = ionic_lif_rss_config(lif, IONIC_RSS_OFFLOAD_ALL,
+			toeplitz_symmetric_key, NULL);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static void
+ionic_lif_rss_teardown(struct ionic_lif *lif)
+{
+	if (!lif->rss_ind_tbl)
+		return;
+
+	if (lif->rss_ind_tbl_z) {
+		/* Disable RSS on the NIC */
+		ionic_lif_rss_config(lif, 0x0, NULL, NULL);
+
+		lif->rss_ind_tbl = NULL;
+		lif->rss_ind_tbl_pa = 0;
+		rte_memzone_free(lif->rss_ind_tbl_z);
+		lif->rss_ind_tbl_z = NULL;
+	}
+}
+
 static void
 ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
 {
@@ -1120,6 +1211,7 @@ ionic_lif_deinit(struct ionic_lif *lif)
 		return;
 
 	ionic_rx_filters_deinit(lif);
+	ionic_lif_rss_teardown(lif);
 	ionic_lif_qcq_deinit(lif, lif->notifyqcq);
 	ionic_lif_qcq_deinit(lif, lif->adminqcq);
 
@@ -1129,8 +1221,28 @@ ionic_lif_deinit(struct ionic_lif *lif)
 int
 ionic_lif_configure(struct ionic_lif *lif)
 {
+	struct ionic_identity *ident = &lif->adapter->ident;
+	uint32_t ntxqs_per_lif =
+			ident->lif.eth.config.queue_count[IONIC_QTYPE_TXQ];
+	uint32_t nrxqs_per_lif =
+			ident->lif.eth.config.queue_count[IONIC_QTYPE_RXQ];
+	uint32_t nrxqs = lif->eth_dev->data->nb_rx_queues;
+	uint32_t ntxqs = lif->eth_dev->data->nb_tx_queues;
+
 	lif->port_id = lif->eth_dev->data->port_id;
 
+	ionic_init_print(DEBUG, "Configuring LIF on port %u",
+		lif->port_id);
+
+	if (nrxqs > 0)
+		nrxqs_per_lif = RTE_MIN(nrxqs_per_lif, nrxqs);
+
+	if (ntxqs > 0)
+		ntxqs_per_lif = RTE_MIN(ntxqs_per_lif, ntxqs);
+
+	lif->nrxqcqs = nrxqs_per_lif;
+	lif->ntxqcqs = ntxqs_per_lif;
+
 	return 0;
 }
 
@@ -1138,6 +1250,14 @@ int
 ionic_lif_start(struct ionic_lif *lif)
 {
 	uint32_t rx_mode = 0;
+	int err;
+
+	ionic_init_print(DEBUG, "Setting RSS configuration on port %u",
+		lif->port_id);
+
+	err = ionic_lif_rss_setup(lif);
+	if (err)
+		return err;
 
 	ionic_init_print(DEBUG, "Setting RX mode on port %u",
 		lif->port_id);
diff --git a/drivers/net/ionic/ionic_lif.h b/drivers/net/ionic/ionic_lif.h
index e192186a6..faf2f6294 100644
--- a/drivers/net/ionic/ionic_lif.h
+++ b/drivers/net/ionic/ionic_lif.h
@@ -17,6 +17,14 @@
 #define IONIC_ADMINQ_LENGTH	16	/* must be a power of two */
 #define IONIC_NOTIFYQ_LENGTH	64	/* must be a power of two */
 
+#define IONIC_RSS_OFFLOAD_ALL ( \
+	IONIC_RSS_TYPE_IPV4 | \
+	IONIC_RSS_TYPE_IPV4_TCP | \
+	IONIC_RSS_TYPE_IPV4_UDP | \
+	IONIC_RSS_TYPE_IPV6 | \
+	IONIC_RSS_TYPE_IPV6_TCP | \
+	IONIC_RSS_TYPE_IPV6_UDP)
+
 #define IONIC_QCQ_F_INITED	BIT(0)
 #define IONIC_QCQ_F_SG		BIT(1)
 #define IONIC_QCQ_F_INTR	BIT(2)
@@ -49,6 +57,8 @@ struct ionic_lif {
 	uint32_t index;
 	uint32_t hw_index;
 	uint32_t state;
+	uint32_t ntxqcqs;
+	uint32_t nrxqcqs;
 	uint32_t kern_pid;
 	rte_spinlock_t adminq_lock;
 	rte_spinlock_t adminq_service_lock;
@@ -62,6 +72,11 @@ struct ionic_lif {
 	uint32_t rx_mode;
 	char name[IONIC_LIF_NAME_MAX_SZ];
 	uint8_t mac_addr[ETH_ALEN];
+	uint16_t rss_types;
+	uint8_t rss_hash_key[IONIC_RSS_HASH_KEY_SIZE];
+	uint8_t *rss_ind_tbl;
+	rte_iova_t rss_ind_tbl_pa;
+	const struct rte_memzone *rss_ind_tbl_z;
 	uint32_t info_sz;
 	struct ionic_lif_info *info;
 	rte_iova_t info_pa;
@@ -112,6 +127,9 @@ void ionic_qcq_free(struct ionic_qcq *qcq);
 int ionic_qcq_enable(struct ionic_qcq *qcq);
 int ionic_qcq_disable(struct ionic_qcq *qcq);
 
+int ionic_lif_rss_config(struct ionic_lif *lif, const uint16_t types,
+		const uint8_t *key, const uint32_t *indir);
+
 int ionic_lif_set_features(struct ionic_lif *lif);
 
 int ionic_notifyq_handler(struct ionic_lif *lif, int budget);


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 14/17] net/ionic: add RX and TX handling
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
                   ` (12 preceding siblings ...)
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 13/17] net/ionic: add RSS support Alfredo Cardigliano
@ 2019-10-12  0:27 ` Alfredo Cardigliano
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 15/17] net/ionic: add stats Alfredo Cardigliano
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:27 UTC (permalink / raw)
  To: dev

Add RX and TX queues setup and handling.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 doc/guides/nics/features/ionic.ini |   10 
 drivers/net/ionic/Makefile         |    1 
 drivers/net/ionic/ionic_dev.h      |    1 
 drivers/net/ionic/ionic_ethdev.c   |  114 ++++
 drivers/net/ionic/ionic_lif.c      |  218 ++++++++
 drivers/net/ionic/ionic_lif.h      |   42 ++
 drivers/net/ionic/ionic_rxtx.c     |  993 ++++++++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_rxtx.h     |   44 ++
 drivers/net/ionic/meson.build      |    1 
 9 files changed, 1423 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ionic/ionic_rxtx.c
 create mode 100644 drivers/net/ionic/ionic_rxtx.h

diff --git a/doc/guides/nics/features/ionic.ini b/doc/guides/nics/features/ionic.ini
index b3f6c3497..59f0753db 100644
--- a/doc/guides/nics/features/ionic.ini
+++ b/doc/guides/nics/features/ionic.ini
@@ -7,7 +7,12 @@
 Speed capabilities   = Y
 Link status          = Y
 Link status event    = Y
+Queue start/stop     = Y
 MTU update           = Y
+Jumbo frame          = Y
+Scattered Rx         = Y
+LRO                  = Y
+TSO                  = Y
 Promiscuous mode     = Y
 Allmulticast mode    = Y
 Unicast MAC filter   = Y
@@ -16,6 +21,11 @@ RSS key update       = Y
 RSS reta update      = Y
 VLAN filter          = Y
 Flow control         = Y
+CRC offload          = Y
+VLAN offload         = Y
+L3 checksum offload  = Y
+L4 checksum offload  = Y
+Packet type parsing  = Y
 Linux UIO            = Y
 Linux VFIO           = Y
 x86-64               = Y
diff --git a/drivers/net/ionic/Makefile b/drivers/net/ionic/Makefile
index 7827e2b69..7649d674d 100644
--- a/drivers/net/ionic/Makefile
+++ b/drivers/net/ionic/Makefile
@@ -55,6 +55,7 @@ LDLIBS += -lrte_bus_pci
 #
 SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_mac_api.c
 SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_rx_filter.c
+SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_rxtx.c
 SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_dev.c
 SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_IONIC_PMD) += ionic_lif.c
diff --git a/drivers/net/ionic/ionic_dev.h b/drivers/net/ionic/ionic_dev.h
index 02fcfdee8..7bbb944b3 100644
--- a/drivers/net/ionic/ionic_dev.h
+++ b/drivers/net/ionic/ionic_dev.h
@@ -25,6 +25,7 @@
 
 #define IONIC_MAX_RING_DESC		32768
 #define IONIC_MIN_RING_DESC		16
+#define IONIC_DEF_TXRX_DESC		4096
 
 #define IONIC_LIFS_MAX			1024
 
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index 196113089..d91513bc8 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -15,6 +15,7 @@
 #include "ionic_mac_api.h"
 #include "ionic_lif.h"
 #include "ionic_ethdev.h"
+#include "ionic_rxtx.h"
 
 static int  eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void *init_params);
 static int  eth_ionic_dev_uninit(struct rte_eth_dev *eth_dev);
@@ -41,6 +42,7 @@ static int  ionic_dev_rss_hash_conf_get(struct rte_eth_dev *eth_dev,
 		struct rte_eth_rss_conf *rss_conf);
 static int  ionic_dev_rss_hash_update(struct rte_eth_dev *eth_dev,
 		struct rte_eth_rss_conf *rss_conf);
+static int  ionic_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask);
 
 int ionic_logtype_init;
 int ionic_logtype_driver;
@@ -52,6 +54,20 @@ static const struct rte_pci_id pci_id_ionic_map[] = {
 	{ .vendor_id = 0, /* sentinel */ },
 };
 
+static const struct rte_eth_desc_lim rx_desc_lim = {
+	.nb_max = IONIC_MAX_RING_DESC,
+	.nb_min = IONIC_MIN_RING_DESC,
+	.nb_align = 1,
+};
+
+static const struct rte_eth_desc_lim tx_desc_lim = {
+	.nb_max = IONIC_MAX_RING_DESC,
+	.nb_min = IONIC_MIN_RING_DESC,
+	.nb_align = 1,
+	.nb_seg_max = IONIC_TX_MAX_SG_ELEMS,
+	.nb_mtu_seg_max = IONIC_TX_MAX_SG_ELEMS,
+};
+
 static const struct eth_dev_ops ionic_eth_dev_ops = {
 	.dev_infos_get          = ionic_dev_info_get,
 	.dev_configure          = ionic_dev_configure,
@@ -76,6 +92,17 @@ static const struct eth_dev_ops ionic_eth_dev_ops = {
 	.reta_query             = ionic_dev_rss_reta_query,
 	.rss_hash_conf_get      = ionic_dev_rss_hash_conf_get,
 	.rss_hash_update        = ionic_dev_rss_hash_update,
+	.rxq_info_get           = ionic_rxq_info_get,
+	.txq_info_get           = ionic_txq_info_get,
+	.rx_queue_setup         = ionic_dev_rx_queue_setup,
+	.rx_queue_release       = ionic_dev_rx_queue_release,
+	.rx_queue_start	        = ionic_dev_rx_queue_start,
+	.rx_queue_stop          = ionic_dev_rx_queue_stop,
+	.tx_queue_setup         = ionic_dev_tx_queue_setup,
+	.tx_queue_release       = ionic_dev_tx_queue_release,
+	.tx_queue_start	        = ionic_dev_tx_queue_start,
+	.tx_queue_stop          = ionic_dev_tx_queue_stop,
+	.vlan_offload_set       = ionic_vlan_offload_set,
 };
 
 /*
@@ -266,6 +293,50 @@ ionic_dev_info_get(struct rte_eth_dev *eth_dev,
 		ETH_LINK_SPEED_50G |
 		ETH_LINK_SPEED_100G;
 
+	/*
+	 * Per-queue capabilities. Actually most of the offloads are enabled
+	 * by default on the port and can be used on selected queues (by adding
+	 * packet flags at runtime when required)
+	 */
+
+	dev_info->rx_queue_offload_capa =
+		DEV_RX_OFFLOAD_IPV4_CKSUM |
+		DEV_RX_OFFLOAD_UDP_CKSUM |
+		DEV_RX_OFFLOAD_TCP_CKSUM |
+		0;
+
+	dev_info->tx_queue_offload_capa =
+		DEV_TX_OFFLOAD_VLAN_INSERT |
+		0;
+
+	/*
+	 * Per-port capabilities
+	 * See ionic_set_features to request and check supported features
+	 */
+
+	dev_info->rx_offload_capa = dev_info->rx_queue_offload_capa |
+		DEV_RX_OFFLOAD_JUMBO_FRAME |
+		DEV_RX_OFFLOAD_VLAN_FILTER |
+		DEV_RX_OFFLOAD_VLAN_STRIP |
+		DEV_RX_OFFLOAD_SCATTER |
+		0;
+
+	dev_info->tx_offload_capa = dev_info->tx_queue_offload_capa |
+		DEV_TX_OFFLOAD_MULTI_SEGS |
+		DEV_TX_OFFLOAD_TCP_TSO |
+		0;
+
+	dev_info->rx_desc_lim = rx_desc_lim;
+	dev_info->tx_desc_lim = tx_desc_lim;
+
+	/* Driver-preferred Rx/Tx parameters */
+	dev_info->default_rxportconf.burst_size = 32;
+	dev_info->default_txportconf.burst_size = 32;
+	dev_info->default_rxportconf.nb_queues = 1;
+	dev_info->default_txportconf.nb_queues = 1;
+	dev_info->default_rxportconf.ring_size = IONIC_DEF_TXRX_DESC;
+	dev_info->default_txportconf.ring_size = IONIC_DEF_TXRX_DESC;
+
 	return 0;
 }
 
@@ -478,6 +549,44 @@ ionic_dev_rss_hash_update(struct rte_eth_dev *eth_dev,
 	return 0;
 }
 
+static int
+ionic_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct rte_eth_rxmode *rxmode;
+	rxmode = &eth_dev->data->dev_conf.rxmode;
+	int i;
+
+	if (mask & ETH_VLAN_STRIP_MASK) {
+		if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_STRIP) {
+			for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
+				struct ionic_qcq *rxq =
+						eth_dev->data->rx_queues[i];
+				rxq->offloads |= DEV_RX_OFFLOAD_VLAN_STRIP;
+			}
+			lif->features |= IONIC_ETH_HW_VLAN_RX_STRIP;
+		} else {
+			for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
+				struct ionic_qcq *rxq =
+						eth_dev->data->rx_queues[i];
+				rxq->offloads &= ~DEV_RX_OFFLOAD_VLAN_STRIP;
+			}
+			lif->features &= ~IONIC_ETH_HW_VLAN_RX_STRIP;
+		}
+	}
+
+	if (mask & ETH_VLAN_FILTER_MASK) {
+		if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_FILTER)
+			lif->features |= IONIC_ETH_HW_VLAN_RX_FILTER;
+		else
+			lif->features &= ~IONIC_ETH_HW_VLAN_RX_FILTER;
+	}
+
+	ionic_lif_set_features(lif);
+
+	return 0;
+}
+
 static int
 ionic_dev_configure(struct rte_eth_dev *eth_dev)
 {
@@ -609,6 +718,9 @@ eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void *init_params)
 	ionic_init_print_call();
 
 	eth_dev->dev_ops = &ionic_eth_dev_ops;
+	eth_dev->rx_pkt_burst = &ionic_recv_pkts;
+	eth_dev->tx_pkt_burst = &ionic_xmit_pkts;
+	eth_dev->tx_pkt_prepare = &ionic_prep_pkts;
 
 	/* Multi-process not supported, primary does initialization anyway */
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
@@ -676,6 +788,8 @@ eth_ionic_dev_uninit(struct rte_eth_dev *eth_dev)
 	ionic_lif_free(lif);
 
 	eth_dev->dev_ops = NULL;
+	eth_dev->rx_pkt_burst = NULL;
+	eth_dev->tx_pkt_burst = NULL;
 
 	return 0;
 }
diff --git a/drivers/net/ionic/ionic_lif.c b/drivers/net/ionic/ionic_lif.c
index 045994787..a8eed76bd 100644
--- a/drivers/net/ionic/ionic_lif.c
+++ b/drivers/net/ionic/ionic_lif.c
@@ -10,6 +10,7 @@
 #include "ionic_lif.h"
 #include "ionic_ethdev.h"
 #include "ionic_rx_filter.h"
+#include "ionic_rxtx.h"
 
 static int ionic_lif_addr_add(struct ionic_lif *lif, const uint8_t *addr);
 static int ionic_lif_addr_del(struct ionic_lif *lif, const uint8_t *addr);
@@ -583,6 +584,52 @@ ionic_qcq_free(struct ionic_qcq *qcq)
 	rte_free(qcq);
 }
 
+int
+ionic_rx_qcq_alloc(struct ionic_lif *lif, uint32_t index, uint16_t nrxq_descs,
+		struct ionic_qcq **qcq)
+{
+	uint32_t flags;
+	int err = -ENOMEM;
+
+	flags = IONIC_QCQ_F_SG;
+	err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, index, "rx", flags,
+			nrxq_descs,
+			sizeof(struct ionic_rxq_desc),
+			sizeof(struct ionic_rxq_comp),
+			sizeof(struct ionic_rxq_sg_desc),
+			lif->kern_pid, &lif->rxqcqs[index]);
+
+	if (err)
+		return err;
+
+	*qcq = lif->rxqcqs[index];
+
+	return 0;
+}
+
+int
+ionic_tx_qcq_alloc(struct ionic_lif *lif, uint32_t index, uint16_t ntxq_descs,
+		struct ionic_qcq **qcq)
+{
+	uint32_t flags;
+	int err = -ENOMEM;
+
+	flags = IONIC_QCQ_F_SG;
+	err = ionic_qcq_alloc(lif, IONIC_QTYPE_TXQ, index, "tx", flags,
+			ntxq_descs,
+			sizeof(struct ionic_txq_desc),
+			sizeof(struct ionic_txq_comp),
+			sizeof(struct ionic_txq_sg_desc),
+			lif->kern_pid, &lif->txqcqs[index]);
+
+	if (err)
+		return err;
+
+	*qcq = lif->txqcqs[index];
+
+	return 0;
+}
+
 static int
 ionic_admin_qcq_alloc(struct ionic_lif *lif)
 {
@@ -660,6 +707,22 @@ ionic_lif_alloc(struct ionic_lif *lif)
 		return -ENOMEM;
 	}
 
+	lif->txqcqs = rte_zmalloc("ionic", sizeof(*lif->txqcqs) *
+			adapter->max_ntxqs_per_lif, 0);
+
+	if (!lif->txqcqs) {
+		ionic_init_print(ERR, "Cannot allocate tx queues array");
+		return -ENOMEM;
+	}
+
+	lif->rxqcqs = rte_zmalloc("ionic", sizeof(*lif->rxqcqs) *
+			adapter->max_nrxqs_per_lif, 0);
+
+	if (!lif->rxqcqs) {
+		ionic_init_print(ERR, "Cannot allocate rx queues array");
+		return -ENOMEM;
+	}
+
 	ionic_init_print(DEBUG, "Allocating Notify Queue");
 
 	err = ionic_notify_qcq_alloc(lif);
@@ -710,6 +773,16 @@ ionic_lif_free(struct ionic_lif *lif)
 		lif->adminqcq = NULL;
 	}
 
+	if (lif->txqcqs) {
+		rte_free(lif->txqcqs);
+		lif->txqcqs = NULL;
+	}
+
+	if (lif->rxqcqs) {
+		rte_free(lif->rxqcqs);
+		lif->rxqcqs = NULL;
+	}
+
 	if (lif->info)
 		rte_memzone_free(lif->info_z);
 }
@@ -820,6 +893,18 @@ ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq)
 	qcq->flags &= ~IONIC_QCQ_F_INITED;
 }
 
+void
+ionic_lif_txq_deinit(struct ionic_qcq *qcq)
+{
+	ionic_lif_qcq_deinit(qcq->lif, qcq);
+}
+
+void
+ionic_lif_rxq_deinit(struct ionic_qcq *qcq)
+{
+	ionic_lif_qcq_deinit(qcq->lif, qcq);
+}
+
 bool
 ionic_adminq_service(struct ionic_cq *cq, uint32_t cq_desc_index,
 		void *cb_arg __rte_unused)
@@ -1085,6 +1170,102 @@ ionic_lif_set_features(struct ionic_lif *lif)
 	return 0;
 }
 
+int
+ionic_lif_txq_init(struct ionic_qcq *qcq)
+{
+	struct ionic_queue *q = &qcq->q;
+	struct ionic_lif *lif = qcq->lif;
+	struct ionic_cq *cq = &qcq->cq;
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.q_init = {
+			.opcode = IONIC_CMD_Q_INIT,
+			.lif_index = lif->index,
+			.type = q->type,
+			.index = q->index,
+			.flags = IONIC_QINIT_F_SG,
+			.intr_index = cq->bound_intr->index,
+			.pid = q->pid,
+			.ring_size = ilog2(q->num_descs),
+			.ring_base = q->base_pa,
+			.cq_ring_base = cq->base_pa,
+			.sg_ring_base = q->sg_base_pa,
+		},
+	};
+	int err;
+
+	ionic_init_print(DEBUG, "txq_init.pid %d", ctx.cmd.q_init.pid);
+	ionic_init_print(DEBUG, "txq_init.index %d", ctx.cmd.q_init.index);
+	ionic_init_print(DEBUG, "txq_init.ring_base 0x%lx",
+			ctx.cmd.q_init.ring_base);
+	ionic_init_print(DEBUG, "txq_init.ring_size %d",
+			ctx.cmd.q_init.ring_size);
+
+	err = ionic_adminq_post_wait(qcq->lif, &ctx);
+	if (err)
+		return err;
+
+	q->hw_type = ctx.comp.q_init.hw_type;
+	q->hw_index = ctx.comp.q_init.hw_index;
+	q->db = ionic_db_map(lif, q);
+
+	ionic_init_print(DEBUG, "txq->hw_type %d", q->hw_type);
+	ionic_init_print(DEBUG, "txq->hw_index %d", q->hw_index);
+	ionic_init_print(DEBUG, "txq->db %p", q->db);
+
+	qcq->flags |= IONIC_QCQ_F_INITED;
+
+	return 0;
+}
+
+int
+ionic_lif_rxq_init(struct ionic_qcq *qcq)
+{
+	struct ionic_queue *q = &qcq->q;
+	struct ionic_lif *lif = qcq->lif;
+	struct ionic_cq *cq = &qcq->cq;
+	struct ionic_admin_ctx ctx = {
+		.pending_work = true,
+		.cmd.q_init = {
+			.opcode = IONIC_CMD_Q_INIT,
+			.lif_index = lif->index,
+			.type = q->type,
+			.index = q->index,
+			.flags = IONIC_QINIT_F_SG,
+			.intr_index = cq->bound_intr->index,
+			.pid = q->pid,
+			.ring_size = ilog2(q->num_descs),
+			.ring_base = q->base_pa,
+			.cq_ring_base = cq->base_pa,
+			.sg_ring_base = q->sg_base_pa,
+		},
+	};
+	int err;
+
+	ionic_init_print(DEBUG, "rxq_init.pid %d\n", ctx.cmd.q_init.pid);
+	ionic_init_print(DEBUG, "rxq_init.index %d\n", ctx.cmd.q_init.index);
+	ionic_init_print(DEBUG, "rxq_init.ring_base 0x%lx\n",
+			ctx.cmd.q_init.ring_base);
+	ionic_init_print(DEBUG, "rxq_init.ring_size %d\n",
+			ctx.cmd.q_init.ring_size);
+
+	err = ionic_adminq_post_wait(qcq->lif, &ctx);
+	if (err)
+		return err;
+
+	q->hw_type = ctx.comp.q_init.hw_type;
+	q->hw_index = ctx.comp.q_init.hw_index;
+	q->db = ionic_db_map(lif, q);
+
+	qcq->flags |= IONIC_QCQ_F_INITED;
+
+	ionic_init_print(DEBUG, "rxq->hw_type %d", q->hw_type);
+	ionic_init_print(DEBUG, "rxq->hw_index %d", q->hw_index);
+	ionic_init_print(DEBUG, "rxq->db %p", q->db);
+
+	return 0;
+}
+
 static int
 ionic_station_set(struct ionic_lif *lif)
 {
@@ -1169,7 +1350,17 @@ ionic_lif_init(struct ionic_lif *lif)
 	if (err)
 		goto err_out_adminq_deinit;
 
-	lif->features = 0;
+	lif->features =
+                  IONIC_ETH_HW_VLAN_TX_TAG
+		| IONIC_ETH_HW_VLAN_RX_STRIP
+		| IONIC_ETH_HW_VLAN_RX_FILTER
+		| IONIC_ETH_HW_RX_HASH
+		| IONIC_ETH_HW_TX_SG
+		| IONIC_ETH_HW_RX_SG
+		| IONIC_ETH_HW_RX_CSUM
+		| IONIC_ETH_HW_TSO
+		| IONIC_ETH_HW_TSO_IPV6
+		| IONIC_ETH_HW_TSO_ECN;
 
 	err = ionic_lif_set_features(lif);
 
@@ -1250,6 +1441,7 @@ int
 ionic_lif_start(struct ionic_lif *lif)
 {
 	uint32_t rx_mode = 0;
+	uint32_t i;
 	int err;
 
 	ionic_init_print(DEBUG, "Setting RSS configuration on port %u",
@@ -1270,6 +1462,30 @@ ionic_lif_start(struct ionic_lif *lif)
 
 	ionic_set_rx_mode(lif, rx_mode);
 
+	ionic_init_print(DEBUG, "Starting %u RX queues and %u TX queues "
+			"on port %u",
+			lif->nrxqcqs, lif->ntxqcqs, lif->port_id);
+
+	for (i = 0; i < lif->nrxqcqs; i++) {
+		struct ionic_qcq *rxq = lif->rxqcqs[i];
+		if (!rxq->deferred_start) {
+			err = ionic_dev_rx_queue_start(lif->eth_dev, i);
+
+			if (err)
+				return err;
+		}
+	}
+
+	for (i = 0; i < lif->ntxqcqs; i++) {
+		struct ionic_qcq *txq = lif->txqcqs[i];
+		if (!txq->deferred_start) {
+			err = ionic_dev_tx_queue_start(lif->eth_dev, i);
+
+			if (err)
+				return err;
+		}
+	}
+
 	ionic_link_status_check(lif);
 
 	/* Carrier ON here */
diff --git a/drivers/net/ionic/ionic_lif.h b/drivers/net/ionic/ionic_lif.h
index faf2f6294..a72196de8 100644
--- a/drivers/net/ionic/ionic_lif.h
+++ b/drivers/net/ionic/ionic_lif.h
@@ -25,6 +25,26 @@
 	IONIC_RSS_TYPE_IPV6_TCP | \
 	IONIC_RSS_TYPE_IPV6_UDP)
 
+#define IONIC_GET_SG_CNTR_IDX(num_sg_elems)	(num_sg_elems)
+
+struct ionic_tx_stats {
+	uint64_t packets;
+	uint64_t bytes;
+	uint64_t drop;
+	uint64_t stop;
+	uint64_t tso;
+	uint64_t frags;
+};
+
+struct ionic_rx_stats {
+	uint64_t packets;
+	uint64_t bytes;
+	uint64_t no_cb_arg;
+	uint64_t bad_cq_status;
+	uint64_t no_room;
+	uint64_t bad_len;
+};
+
 #define IONIC_QCQ_F_INITED	BIT(0)
 #define IONIC_QCQ_F_SG		BIT(1)
 #define IONIC_QCQ_F_INTR	BIT(2)
@@ -32,18 +52,28 @@
 
 /* Queue / Completion Queue */
 struct ionic_qcq {
+	uint64_t offloads;
 	struct ionic_queue q;        /**< Queue */
 	struct ionic_cq cq;          /**< Completion Queue */
 	struct ionic_lif *lif;       /**< LIF */
 	struct rte_mempool *mb_pool; /**< mbuf pool to populate the RX ring */
+	union {
+		struct ionic_tx_stats tx;
+		struct ionic_rx_stats rx;
+	} stats;
 	const struct rte_memzone *base_z;
 	void *base;
 	rte_iova_t base_pa;
 	uint32_t total_size;
 	uint32_t flags;
 	struct ionic_intr_info intr;
+	bool deferred_start;
 };
 
+#define IONIC_Q_TO_QCQ(q)	container_of(q, struct ionic_qcq, q)
+#define IONIC_Q_TO_TX_STATS(q)	(&IONIC_Q_TO_QCQ(q)->stats.tx)
+#define IONIC_Q_TO_RX_STATS(q)	(&IONIC_Q_TO_QCQ(q)->stats.rx)
+
 #define IONIC_LIF_F_INITED		BIT(0)
 #define IONIC_LIF_F_LINK_CHECK_NEEDED	BIT(1)
 
@@ -64,6 +94,8 @@ struct ionic_lif {
 	rte_spinlock_t adminq_service_lock;
 	struct ionic_qcq *adminqcq;
 	struct ionic_qcq *notifyqcq;
+	struct ionic_qcq **txqcqs;
+	struct ionic_qcq **rxqcqs;
 	struct ionic_rx_filters rx_filters;
 	struct ionic_doorbell __iomem *kern_dbpage;
 	uint64_t last_eid;
@@ -122,11 +154,21 @@ int ionic_dev_promiscuous_disable(struct rte_eth_dev *dev);
 int ionic_dev_allmulticast_enable(struct rte_eth_dev *dev);
 int ionic_dev_allmulticast_disable(struct rte_eth_dev *dev);
 
+int ionic_rx_qcq_alloc(struct ionic_lif *lif, uint32_t index,
+		uint16_t nrxq_descs, struct ionic_qcq **qcq);
+int ionic_tx_qcq_alloc(struct ionic_lif *lif, uint32_t index,
+		uint16_t ntxq_descs, struct ionic_qcq **qcq);
 void ionic_qcq_free(struct ionic_qcq *qcq);
 
 int ionic_qcq_enable(struct ionic_qcq *qcq);
 int ionic_qcq_disable(struct ionic_qcq *qcq);
 
+int ionic_lif_rxq_init(struct ionic_qcq *qcq);
+void ionic_lif_rxq_deinit(struct ionic_qcq *qcq);
+
+int ionic_lif_txq_init(struct ionic_qcq *qcq);
+void ionic_lif_txq_deinit(struct ionic_qcq *qcq);
+
 int ionic_lif_rss_config(struct ionic_lif *lif, const uint16_t types,
 		const uint8_t *key, const uint32_t *indir);
 
diff --git a/drivers/net/ionic/ionic_rxtx.c b/drivers/net/ionic/ionic_rxtx.c
new file mode 100644
index 000000000..1a7313cc3
--- /dev/null
+++ b/drivers/net/ionic/ionic_rxtx.c
@@ -0,0 +1,993 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_launch.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_mempool.h>
+#include <rte_malloc.h>
+#include <rte_mbuf.h>
+#include <rte_ether.h>
+#include <rte_ethdev_driver.h>
+#include <rte_prefetch.h>
+#include <rte_udp.h>
+#include <rte_tcp.h>
+#include <rte_sctp.h>
+#include <rte_string_fns.h>
+#include <rte_errno.h>
+#include <rte_ip.h>
+#include <rte_net.h>
+
+#include "ionic_logs.h"
+#include "ionic_mac_api.h"
+#include "ionic_ethdev.h"
+#include "ionic_lif.h"
+#include "ionic_rxtx.h"
+
+#define IONIC_RX_RING_DOORBELL_STRIDE		(32 - 1)
+
+/*********************************************************************
+ *
+ *  TX functions
+ *
+ **********************************************************************/
+
+void
+ionic_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
+		struct rte_eth_txq_info *qinfo)
+{
+	struct ionic_qcq *txq = dev->data->tx_queues[queue_id];
+	struct ionic_queue *q = &txq->q;
+
+	qinfo->nb_desc = q->num_descs;
+	qinfo->conf.offloads = txq->offloads;
+	qinfo->conf.tx_deferred_start = txq->deferred_start;
+}
+
+static inline void __attribute__((cold))
+ionic_tx_flush(struct ionic_cq *cq)
+{
+	struct ionic_queue *q = cq->bound_q;
+	struct ionic_desc_info *q_desc_info;
+	struct rte_mbuf *txm, *next;
+	struct ionic_txq_comp *cq_desc_base = cq->base;
+	struct ionic_txq_comp *cq_desc;
+	u_int32_t comp_index = (u_int32_t)-1;
+
+	cq_desc = &cq_desc_base[cq->tail_idx];
+	while (color_match(cq_desc->color, cq->done_color)) {
+		cq->tail_idx = (cq->tail_idx + 1) & (cq->num_descs - 1);
+
+		/* Prefetch the next 4 descriptors (not really useful here) */
+		if ((cq->tail_idx & 0x3) == 0)
+			rte_prefetch0(&cq_desc_base[cq->tail_idx]); /* cq desc */
+
+		if (cq->tail_idx == 0)
+			cq->done_color = !cq->done_color;
+
+		comp_index = cq_desc->comp_index;
+
+		cq_desc = &cq_desc_base[cq->tail_idx];
+	}
+
+	if (comp_index != (u_int32_t)-1) {
+		while (q->tail_idx != comp_index) {
+			q_desc_info = &q->info[q->tail_idx];
+
+			q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
+
+			/* Prefetch the next 4 descriptors */
+			if ((q->tail_idx & 0x3) == 0)
+				/* q desc info */
+				rte_prefetch0(&q->info[q->tail_idx]);
+
+			/*
+			 * Note: you can just use rte_pktmbuf_free,
+			 * but this loop is faster
+			 */
+			txm = q_desc_info->cb_arg;
+			while (txm != NULL) {
+				next = txm->next;
+				rte_pktmbuf_free_seg(txm);
+				txm = next;
+			}
+		}
+	}
+}
+
+void __attribute__((cold))
+ionic_dev_tx_queue_release(void *tx_queue)
+{
+	struct ionic_qcq *txq = (struct ionic_qcq *)tx_queue;
+
+	ionic_init_print_call();
+
+	ionic_qcq_free(txq);
+}
+
+int __attribute__((cold))
+ionic_dev_tx_queue_stop(struct rte_eth_dev *eth_dev, uint16_t tx_queue_id)
+{
+	struct ionic_qcq *txq;
+
+	ionic_init_print_call();
+
+	txq = eth_dev->data->tx_queues[tx_queue_id];
+
+	/*
+	 * Note: we should better post NOP Tx desc and wait for its completion
+	 * before disabling Tx queue
+	 */
+
+	ionic_qcq_disable(txq);
+
+	ionic_tx_flush(&txq->cq);
+
+	ionic_lif_txq_deinit(txq);
+
+	eth_dev->data->tx_queue_state[tx_queue_id] =
+			RTE_ETH_QUEUE_STATE_STOPPED;
+
+	return 0;
+}
+
+int __attribute__((cold))
+ionic_dev_tx_queue_setup(struct rte_eth_dev *eth_dev, uint16_t tx_queue_id,
+		uint16_t nb_desc, uint32_t socket_id,
+		const struct rte_eth_txconf *tx_conf)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_qcq *txq;
+	uint64_t offloads;
+	int err;
+
+	ionic_init_print_call();
+
+	ionic_init_print(DEBUG, "Configuring TX queue %u with %u buffers",
+		tx_queue_id, nb_desc);
+
+	if (tx_queue_id >= lif->ntxqcqs) {
+		ionic_init_print(DEBUG, "Queue index %u not available "
+				"(max %u queues)",
+				tx_queue_id, lif->ntxqcqs);
+		return -EINVAL;
+	}
+
+	offloads = tx_conf->offloads | eth_dev->data->dev_conf.txmode.offloads;
+
+	/* Validate number of receive descriptors */
+	if (!rte_is_power_of_2(nb_desc) || nb_desc < IONIC_MIN_RING_DESC)
+		return -EINVAL; /* or use IONIC_DEFAULT_RING_DESC */
+
+	/* Free memory prior to re-allocation if needed... */
+	if (eth_dev->data->tx_queues[tx_queue_id] != NULL) {
+		ionic_dev_tx_queue_release(eth_dev->data->tx_queues[tx_queue_id]);
+		eth_dev->data->tx_queues[tx_queue_id] = NULL;
+	}
+
+	err = ionic_tx_qcq_alloc(lif, tx_queue_id, nb_desc, &txq);
+
+	if (err) {
+		ionic_init_print(DEBUG, "Queue allocation failure");
+		return -EINVAL;
+	}
+
+	/* Do not start queue with rte_eth_dev_start() */
+	txq->deferred_start = tx_conf->tx_deferred_start;
+
+	txq->offloads = offloads;
+
+	eth_dev->data->tx_queues[tx_queue_id] = txq;
+
+	return 0;
+}
+
+/*
+ * Start Transmit Units for specified queue.
+ */
+int __attribute__((cold))
+ionic_dev_tx_queue_start(struct rte_eth_dev *eth_dev, uint16_t tx_queue_id)
+{
+	struct ionic_qcq *txq;
+	int err;
+
+	ionic_init_print_call();
+
+	txq = eth_dev->data->tx_queues[tx_queue_id];
+
+	err = ionic_lif_txq_init(txq);
+
+	if (err)
+		return err;
+
+	ionic_qcq_enable(txq);
+
+	eth_dev->data->tx_queue_state[tx_queue_id] =
+			RTE_ETH_QUEUE_STATE_STARTED;
+
+	return 0;
+}
+
+static void
+ionic_tx_tso_post(struct ionic_queue *q, struct ionic_txq_desc *desc,
+		struct rte_mbuf *txm,
+		rte_iova_t addr, uint8_t nsge, uint16_t len,
+		uint32_t hdrlen, uint32_t mss,
+		uint16_t vlan_tci, bool has_vlan,
+		bool start, bool done)
+{
+	uint8_t flags = 0;
+	flags |= has_vlan ? IONIC_TXQ_DESC_FLAG_VLAN : 0;
+	flags |= start ? IONIC_TXQ_DESC_FLAG_TSO_SOT : 0;
+	flags |= done ? IONIC_TXQ_DESC_FLAG_TSO_EOT : 0;
+
+	desc->cmd = encode_txq_desc_cmd(IONIC_TXQ_DESC_OPCODE_TSO,
+					flags, nsge, addr);
+	desc->len = len;
+	desc->vlan_tci = vlan_tci;
+	desc->hdr_len = hdrlen;
+	desc->mss = mss;
+
+	ionic_q_post(q, done, NULL, done ? txm : NULL);
+}
+
+static struct ionic_txq_desc *
+ionic_tx_tso_next(struct ionic_queue *q, struct ionic_txq_sg_elem **elem)
+{
+	struct ionic_txq_desc *desc_base = q->base;
+	struct ionic_txq_sg_desc *sg_desc_base = q->sg_base;
+	struct ionic_txq_desc *desc = &desc_base[q->head_idx];
+	struct ionic_txq_sg_desc *sg_desc = &sg_desc_base[q->head_idx];
+
+	*elem = sg_desc->elems;
+	return desc;
+}
+
+static int
+ionic_tx_tso(struct ionic_queue *q, struct rte_mbuf *txm, uint64_t offloads,
+		bool not_xmit_more)
+{
+	struct ionic_tx_stats *stats = IONIC_Q_TO_TX_STATS(q);
+	struct ionic_txq_desc *desc;
+	struct ionic_txq_sg_elem *elem;
+	struct rte_mbuf *txm_seg;
+	uint64_t desc_addr;
+	uint16_t desc_len;
+	uint8_t desc_nsge;
+	uint32_t hdrlen;
+	uint32_t mss = txm->tso_segsz;
+	uint32_t frag_left = 0;
+	uint32_t left;
+	uint32_t seglen;
+	uint32_t len;
+	uint32_t offset = 0;
+	bool start, done;
+	bool has_vlan = !!(txm->ol_flags & PKT_TX_VLAN_PKT);
+	uint16_t vlan_tci = txm->vlan_tci;
+
+	hdrlen = txm->l2_len + txm->l3_len;
+
+	seglen = hdrlen + mss;
+	left = txm->data_len;
+
+	desc = ionic_tx_tso_next(q, &elem);
+	start = true;
+
+	/* Chop data up into desc segments */
+
+	while (left > 0) {
+		len = RTE_MIN(seglen, left);
+		frag_left = seglen - len;
+		desc_addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(txm));
+		desc_len = len;
+		desc_nsge = 0;
+		left -= len;
+		offset += len;
+		if (txm->nb_segs > 1 && frag_left > 0)
+			continue;
+		done = (txm->nb_segs == 1 && left == 0);
+		ionic_tx_tso_post(q, desc, txm,
+				desc_addr, desc_nsge, desc_len,
+				hdrlen, mss,
+				vlan_tci, has_vlan,
+				start, done && not_xmit_more);
+		desc = ionic_tx_tso_next(q, &elem);
+		start = false;
+		seglen = mss;
+	}
+
+	/* Chop frags into desc segments */
+
+	txm_seg = txm->next;
+	while (txm_seg != NULL) {
+		offset = 0;
+		left = txm_seg->data_len;
+		stats->frags++;
+
+		while (left > 0) {
+			elem->addr = rte_cpu_to_le_64(rte_mbuf_data_iova(txm_seg)) + offset;
+			if (frag_left > 0) {
+				len = RTE_MIN(frag_left, left);
+				frag_left -= len;
+				elem->len = len;
+				elem++;
+				desc_nsge++;
+			} else {
+				len = RTE_MIN(mss, left);
+				frag_left = mss - len;
+				desc_addr = rte_cpu_to_le_64(rte_mbuf_data_iova(txm_seg));
+				desc_len = len;
+				desc_nsge = 0;
+			}
+			left -= len;
+			offset += len;
+			if (txm_seg->next != NULL && frag_left > 0)
+				continue;
+			done = (txm_seg->next == NULL && left == 0);
+			ionic_tx_tso_post(q, desc, txm_seg,
+					desc_addr, desc_nsge, desc_len,
+					hdrlen, mss,
+					vlan_tci, has_vlan,
+					start, done && not_xmit_more);
+			desc = ionic_tx_tso_next(q, &elem);
+			start = false;
+		}
+
+		txm_seg = txm_seg->next;
+	}
+
+	stats->tso++;
+
+	return 0;
+}
+
+static int
+ionic_tx(struct ionic_queue *q, struct rte_mbuf *txm, uint64_t offloads,
+		bool not_xmit_more)
+{
+	struct ionic_txq_desc *desc_base = q->base;
+	struct ionic_txq_sg_desc *sg_desc_base = q->sg_base;
+	struct ionic_txq_desc *desc = &desc_base[q->head_idx];
+	struct ionic_txq_sg_desc *sg_desc = &sg_desc_base[q->head_idx];
+	struct ionic_txq_sg_elem *elem = sg_desc->elems;
+	struct ionic_tx_stats *stats = IONIC_Q_TO_TX_STATS(q);
+	struct rte_mbuf *txm_seg;
+	bool has_vlan;
+	uint64_t ol_flags = txm->ol_flags;
+	uint64_t addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(txm));
+	uint8_t opcode = IONIC_TXQ_DESC_OPCODE_CSUM_NONE;
+	uint8_t flags = 0;
+
+	has_vlan = (ol_flags & PKT_TX_VLAN_PKT);
+
+	flags |= has_vlan ? IONIC_TXQ_DESC_FLAG_VLAN : 0;
+
+	desc->cmd = encode_txq_desc_cmd(opcode, flags, txm->nb_segs - 1, addr);
+	desc->len = txm->data_len;
+	desc->vlan_tci = txm->vlan_tci;
+
+	txm_seg = txm->next;
+	while (txm_seg != NULL) {
+		elem->len = txm_seg->data_len;
+		elem->addr = rte_cpu_to_le_64(rte_mbuf_data_iova(txm_seg));
+		stats->frags++;
+		elem++;
+		txm_seg = txm_seg->next;
+	}
+
+	ionic_q_post(q, not_xmit_more, NULL, txm);
+
+	return 0;
+}
+
+uint16_t
+ionic_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
+		uint16_t nb_pkts)
+{
+	struct ionic_qcq *txq = (struct ionic_qcq *)tx_queue;
+	struct ionic_queue *q = &txq->q;
+	struct ionic_cq *cq = &txq->cq;
+	struct ionic_tx_stats *stats = IONIC_Q_TO_TX_STATS(q);
+	uint32_t next_q_head_idx;
+	uint32_t bytes_tx = 0;
+	uint16_t nb_tx = 0;
+	int err;
+	bool last;
+
+	/* Cleaning old buffers */
+	ionic_tx_flush(cq);
+
+	if (unlikely(ionic_q_space_avail(q) < nb_pkts)) {
+		stats->stop += nb_pkts;
+		return 0;
+	}
+
+	while (nb_tx < nb_pkts) {
+		last = (nb_tx == (nb_pkts - 1));
+
+		next_q_head_idx = (q->head_idx + 1) & (q->num_descs - 1);
+		if ((next_q_head_idx & 0x3) == 0) {
+			struct ionic_txq_desc *desc_base = q->base;
+			rte_prefetch0(&desc_base[next_q_head_idx]); /* q desc */
+			rte_prefetch0(&q->info[next_q_head_idx]);   /* q desc info */
+		}
+
+		if (tx_pkts[nb_tx]->ol_flags & PKT_TX_TCP_SEG)
+			err = ionic_tx_tso(q, tx_pkts[nb_tx], txq->offloads,
+					last);
+		else
+			err = ionic_tx(q, tx_pkts[nb_tx], txq->offloads, last);
+
+		if (err) {
+			stats->drop += nb_pkts - nb_tx;
+			if (nb_tx > 0)
+				ionic_q_flush(q);
+			break;
+		}
+
+		bytes_tx += tx_pkts[nb_tx]->pkt_len;
+		nb_tx++;
+	}
+
+	stats->packets += nb_tx;
+	stats->bytes += bytes_tx;
+
+	return nb_tx;
+}
+
+/*********************************************************************
+ *
+ *  TX prep functions
+ *
+ **********************************************************************/
+
+#define IONIC_TX_OFFLOAD_MASK (	\
+	PKT_TX_IPV4 |		\
+	PKT_TX_IPV6 |		\
+	PKT_TX_VLAN |		\
+	PKT_TX_TCP_SEG |	\
+	PKT_TX_L4_MASK)
+
+#define IONIC_TX_OFFLOAD_NOTSUP_MASK \
+	(PKT_TX_OFFLOAD_MASK ^ IONIC_TX_OFFLOAD_MASK)
+
+uint16_t
+ionic_prep_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	struct rte_mbuf *txm;
+	uint64_t offloads;
+	int i = 0;
+
+	for (i = 0; i < nb_pkts; i++) {
+		txm = tx_pkts[i];
+
+		if (txm->nb_segs > IONIC_TX_MAX_SG_ELEMS) {
+			rte_errno = -EINVAL;
+			break;
+		}
+
+		offloads = txm->ol_flags;
+
+		if (offloads & IONIC_TX_OFFLOAD_NOTSUP_MASK) {
+			rte_errno = -ENOTSUP;
+			break;
+		}
+	}
+
+	return i;
+}
+
+/*********************************************************************
+ *
+ *  RX functions
+ *
+ **********************************************************************/
+
+static void ionic_rx_recycle(struct ionic_queue *q, uint32_t q_desc_index,
+		struct rte_mbuf *mbuf);
+
+void
+ionic_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
+		struct rte_eth_rxq_info *qinfo)
+{
+	struct ionic_qcq *rxq = dev->data->rx_queues[queue_id];
+	struct ionic_queue *q = &rxq->q;
+
+	qinfo->mp = rxq->mb_pool;
+	qinfo->scattered_rx = dev->data->scattered_rx;
+	qinfo->nb_desc = q->num_descs;
+	qinfo->conf.rx_deferred_start = rxq->deferred_start;
+	qinfo->conf.offloads = rxq->offloads;
+}
+
+static void __attribute__((cold))
+ionic_rx_empty(struct ionic_queue *q)
+{
+	struct ionic_qcq *rxq = IONIC_Q_TO_QCQ(q);
+	struct ionic_desc_info *cur;
+	struct rte_mbuf *mbuf;
+
+	while (q->tail_idx != q->head_idx) {
+		cur = &q->info[q->tail_idx];
+		mbuf = cur->cb_arg;
+		rte_mempool_put(rxq->mb_pool, mbuf);
+
+		q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
+	}
+}
+
+void __attribute__((cold))
+ionic_dev_rx_queue_release(void *rx_queue)
+{
+	struct ionic_qcq *rxq = (struct ionic_qcq *)rx_queue;
+
+	ionic_init_print_call();
+
+	ionic_rx_empty(&rxq->q);
+
+	ionic_qcq_free(rxq);
+}
+
+int __attribute__((cold))
+ionic_dev_rx_queue_setup(struct rte_eth_dev *eth_dev,
+			 uint16_t rx_queue_id,
+			 uint16_t nb_desc,
+			 uint32_t socket_id,
+			 const struct rte_eth_rxconf *rx_conf,
+			 struct rte_mempool *mp)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_qcq *rxq;
+	uint64_t offloads;
+	int err;
+
+	ionic_init_print_call();
+
+	ionic_init_print(DEBUG, "Configuring RX queue %u with %u buffers",
+			rx_queue_id, nb_desc);
+
+	if (rx_queue_id >= lif->nrxqcqs) {
+		ionic_init_print(ERR,
+				"Queue index %u not available (max %u queues)",
+				rx_queue_id, lif->nrxqcqs);
+		return -EINVAL;
+	}
+
+	offloads = rx_conf->offloads | eth_dev->data->dev_conf.rxmode.offloads;
+
+	/* Validate number of receive descriptors */
+	if (!rte_is_power_of_2(nb_desc) ||
+			nb_desc < IONIC_MIN_RING_DESC ||
+			nb_desc > IONIC_MAX_RING_DESC) {
+		ionic_init_print(ERR,
+				"Bad number of descriptors (%u) for queue %u (min: %u)",
+				nb_desc, rx_queue_id, IONIC_MIN_RING_DESC);
+		return -EINVAL; /* or use IONIC_DEFAULT_RING_DESC */
+	}
+
+	if (rx_conf->offloads & DEV_RX_OFFLOAD_SCATTER)
+		eth_dev->data->scattered_rx = 1;
+
+	/* Free memory prior to re-allocation if needed... */
+	if (eth_dev->data->rx_queues[rx_queue_id] != NULL) {
+		ionic_dev_rx_queue_release(eth_dev->data->rx_queues[rx_queue_id]);
+		eth_dev->data->rx_queues[rx_queue_id] = NULL;
+	}
+
+	err = ionic_rx_qcq_alloc(lif, rx_queue_id, nb_desc, &rxq);
+
+	if (err) {
+		ionic_init_print(ERR, "Queue allocation failure");
+		return -EINVAL;
+	}
+
+	rxq->mb_pool = mp;
+
+	/*
+	 * Note: the interface does not currently support DEV_RX_OFFLOAD_KEEP_CRC,
+	 * please also consider ETHER_CRC_LEN when the adapter will be able to
+	 * keep the CRC and subtract it to the length for all received packets:
+	 * if (eth_dev->data->dev_conf.rxmode.offloads &
+	 *     DEV_RX_OFFLOAD_KEEP_CRC)
+	 *   rxq->crc_len = ETHER_CRC_LEN;
+	 */
+
+	/* Do not start queue with rte_eth_dev_start() */
+	rxq->deferred_start = rx_conf->rx_deferred_start;
+
+	rxq->offloads = offloads;
+
+	eth_dev->data->rx_queues[rx_queue_id] = rxq;
+
+	return 0;
+}
+
+static void
+ionic_rx_clean(struct ionic_queue *q,
+		uint32_t q_desc_index, uint32_t cq_desc_index,
+		void *cb_arg, void *service_cb_arg)
+{
+	struct ionic_rxq_comp *cq_desc_base = q->bound_cq->base;
+	struct ionic_rxq_comp *cq_desc = &cq_desc_base[cq_desc_index];
+	struct rte_mbuf *rxm = cb_arg;
+	struct rte_mbuf *rxm_seg;
+	struct ionic_qcq *rxq = IONIC_Q_TO_QCQ(q);
+	uint32_t max_frame_size =
+			rxq->lif->eth_dev->data->dev_conf.rxmode.max_rx_pkt_len;
+	uint64_t pkt_flags;
+	uint32_t pkt_type;
+	struct ionic_rx_stats *stats = IONIC_Q_TO_RX_STATS(q);
+	struct ionic_rx_service *recv_args = (struct ionic_rx_service *)
+			service_cb_arg;
+	uint32_t buf_size = (uint16_t)
+			(rte_pktmbuf_data_room_size(rxq->mb_pool) -
+			RTE_PKTMBUF_HEADROOM);
+	uint32_t left;
+
+	if (!recv_args) {
+		stats->no_cb_arg++;
+		/* Flush */
+		rte_pktmbuf_free(rxm);
+		/*
+		 * Note: rte_mempool_put is faster with no segs
+		 * rte_mempool_put(rxq->mb_pool, rxm);
+		 */
+		return;
+	}
+
+	if (cq_desc->status) {
+		stats->bad_cq_status++;
+		ionic_rx_recycle(q, q_desc_index, rxm);
+		return;
+	}
+
+	if (recv_args->nb_rx >= recv_args->nb_pkts) {
+		stats->no_room++;
+		ionic_rx_recycle(q, q_desc_index, rxm);
+		return;
+	}
+
+	if (cq_desc->len > max_frame_size ||
+			cq_desc->len == 0) {
+		stats->bad_len++;
+		ionic_rx_recycle(q, q_desc_index, rxm);
+		return;
+	}
+
+	rxm->data_off = RTE_PKTMBUF_HEADROOM;
+	rte_prefetch1((char *)rxm->buf_addr + rxm->data_off);
+	rxm->nb_segs = 1; /* cq_desc->num_sg_elems */
+	rxm->pkt_len = cq_desc->len;
+	rxm->port = rxq->lif->port_id;
+
+	left = cq_desc->len;
+
+	rxm->data_len = RTE_MIN(buf_size, left);
+	left -= rxm->data_len;
+
+	rxm_seg = rxm->next;
+	while (rxm_seg && left) {
+		rxm_seg->data_len = RTE_MIN(buf_size, left);
+		left -= rxm_seg->data_len;
+
+		rxm_seg = rxm_seg->next;
+		rxm->nb_segs++;
+	}
+
+	/* RSS */
+	pkt_flags = PKT_RX_RSS_HASH;
+	rxm->hash.rss = cq_desc->rss_hash;
+
+	/* Vlan Strip */
+	if (cq_desc->csum_flags & IONIC_RXQ_COMP_CSUM_F_VLAN) {
+		pkt_flags |= PKT_RX_VLAN_STRIPPED;
+		rxm->vlan_tci = cq_desc->vlan_tci;
+	}
+
+	/* Checksum */
+	if (cq_desc->csum_flags & IONIC_RXQ_COMP_CSUM_F_CALC) {
+		if (cq_desc->csum_flags & IONIC_RXQ_COMP_CSUM_F_IP_OK)
+			pkt_flags |= PKT_RX_IP_CKSUM_GOOD;
+		else if (cq_desc->csum_flags & IONIC_RXQ_COMP_CSUM_F_IP_BAD)
+			pkt_flags |= PKT_RX_IP_CKSUM_BAD;
+
+		if ((cq_desc->csum_flags & IONIC_RXQ_COMP_CSUM_F_TCP_OK) ||
+			(cq_desc->csum_flags & IONIC_RXQ_COMP_CSUM_F_UDP_OK))
+			pkt_flags |= PKT_RX_L4_CKSUM_GOOD;
+		else if ((cq_desc->csum_flags &
+				IONIC_RXQ_COMP_CSUM_F_TCP_BAD) ||
+				(cq_desc->csum_flags &
+				IONIC_RXQ_COMP_CSUM_F_UDP_BAD))
+			pkt_flags |= PKT_RX_L4_CKSUM_BAD;
+	}
+
+	rxm->ol_flags = pkt_flags;
+
+	/* Packet Type */
+	switch (cq_desc->pkt_type_color & IONIC_RXQ_COMP_PKT_TYPE_MASK) {
+	case IONIC_PKT_TYPE_IPV4:
+		pkt_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4;
+		break;
+	case IONIC_PKT_TYPE_IPV6:
+		pkt_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6;
+		break;
+	case IONIC_PKT_TYPE_IPV4_TCP:
+		pkt_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4 |
+				RTE_PTYPE_L4_TCP;
+		break;
+	case IONIC_PKT_TYPE_IPV6_TCP:
+		pkt_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6 |
+				RTE_PTYPE_L4_TCP;
+		break;
+	case IONIC_PKT_TYPE_IPV4_UDP:
+		pkt_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4 |
+				RTE_PTYPE_L4_UDP;
+		break;
+	case IONIC_PKT_TYPE_IPV6_UDP:
+		pkt_type = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6 |
+				RTE_PTYPE_L4_UDP;
+		break;
+	default:
+		{
+			struct rte_ether_hdr *eth_h = rte_pktmbuf_mtod(rxm,
+					struct rte_ether_hdr *);
+			uint16_t ether_type = eth_h->ether_type;
+			if (ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP))
+				pkt_type = RTE_PTYPE_L2_ETHER_ARP;
+			else
+				pkt_type = RTE_PTYPE_UNKNOWN;
+			break;
+		}
+	}
+
+	rxm->packet_type = pkt_type;
+
+	recv_args->rx_pkts[recv_args->nb_rx] = rxm;
+	recv_args->nb_rx++;
+
+	stats->packets++;
+	stats->bytes += rxm->pkt_len;
+}
+
+static void
+ionic_rx_recycle(struct ionic_queue *q, uint32_t q_desc_index,
+		 struct rte_mbuf *mbuf)
+{
+	struct ionic_rxq_desc *desc_base = q->base;
+	struct ionic_rxq_desc *old = &desc_base[q_desc_index];
+	struct ionic_rxq_desc *new = &desc_base[q->head_idx];
+
+	new->addr = old->addr;
+	new->len = old->len;
+
+	ionic_q_post(q, true, ionic_rx_clean, mbuf);
+}
+
+static int __attribute__((cold))
+ionic_rx_fill(struct ionic_qcq *rxq, uint32_t len)
+{
+	struct ionic_queue *q = &rxq->q;
+	struct ionic_rxq_desc *desc_base = q->base;
+	struct ionic_rxq_sg_desc *sg_desc_base = q->sg_base;
+	struct ionic_rxq_desc *desc;
+	struct ionic_rxq_sg_desc *sg_desc;
+	struct ionic_rxq_sg_elem *elem;
+	rte_iova_t dma_addr;
+	uint32_t i, j, nsegs, buf_size, size;
+	bool ring_doorbell;
+
+	buf_size = (uint16_t)(rte_pktmbuf_data_room_size(rxq->mb_pool) -
+			RTE_PKTMBUF_HEADROOM);
+
+	/* Initialize software ring entries */
+	for (i = ionic_q_space_avail(q); i; i--) {
+		struct rte_mbuf *rxm = rte_mbuf_raw_alloc(rxq->mb_pool);
+		struct rte_mbuf *prev_rxm_seg;
+
+		if (rxm == NULL) {
+			ionic_init_print(ERR, "RX mbuf alloc failed");
+			return -ENOMEM;
+		}
+
+		nsegs = (len + buf_size - 1) / buf_size;
+
+		desc = &desc_base[q->head_idx];
+		dma_addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(rxm));
+		desc->addr = dma_addr;
+		desc->len = buf_size;
+		size = buf_size;
+		desc->opcode = (nsegs > 1) ? IONIC_RXQ_DESC_OPCODE_SG :
+				IONIC_RXQ_DESC_OPCODE_SIMPLE;
+		rxm->next = NULL;
+
+		prev_rxm_seg = rxm;
+		sg_desc = &sg_desc_base[q->head_idx];
+		elem = sg_desc->elems;
+		for (j = 0; j < nsegs - 1 && j < IONIC_RX_MAX_SG_ELEMS; j++) {
+			struct rte_mbuf *rxm_seg = rte_mbuf_raw_alloc(rxq->mb_pool);
+
+			if (rxm_seg == NULL) {
+				ionic_init_print(ERR, "RX mbuf alloc failed");
+				return -ENOMEM;
+			}
+
+			dma_addr = rte_cpu_to_le_64(rte_mbuf_data_iova(rxm_seg));
+			elem->addr = dma_addr;
+			elem->len = buf_size;
+			size += buf_size;
+			elem++;
+			rxm_seg->next = NULL;
+			prev_rxm_seg->next = rxm_seg;
+			prev_rxm_seg = rxm_seg;
+		}
+
+		if (size < len)
+			ionic_init_print(ERR, "Rx SG size is not sufficient (%d < %d)",
+					size, len);
+
+		ring_doorbell = ((q->head_idx + 1) &
+				IONIC_RX_RING_DOORBELL_STRIDE) == 0;
+
+		ionic_q_post(q, ring_doorbell, ionic_rx_clean, rxm);
+	}
+
+	return 0;
+}
+
+/*
+ * Start Receive Units for specified queue.
+ */
+int __attribute__((cold))
+ionic_dev_rx_queue_start(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id)
+{
+	uint32_t frame_size = eth_dev->data->dev_conf.rxmode.max_rx_pkt_len;
+	struct ionic_qcq *rxq;
+	int err;
+
+	ionic_init_print_call();
+
+	ionic_init_print(DEBUG, "Allocating RX queue buffers (size: %u)",
+			frame_size);
+
+	rxq = eth_dev->data->rx_queues[rx_queue_id];
+
+	err = ionic_lif_rxq_init(rxq);
+
+	if (err)
+		return err;
+
+	/* Allocate buffers for descriptor rings */
+	if (ionic_rx_fill(rxq, frame_size) != 0) {
+		ionic_init_print(ERR, "Could not alloc mbuf for queue:%d",
+				rx_queue_id);
+		return -1;
+	}
+
+	ionic_qcq_enable(rxq);
+
+	eth_dev->data->rx_queue_state[rx_queue_id] =
+			RTE_ETH_QUEUE_STATE_STARTED;
+
+	return 0;
+}
+
+static inline void __attribute__((cold))
+ionic_rxq_service(struct ionic_cq *cq, uint32_t work_to_do,
+		void *service_cb_arg)
+{
+	struct ionic_queue *q = cq->bound_q;
+	struct ionic_desc_info *q_desc_info;
+	struct ionic_rxq_comp *cq_desc_base = cq->base;
+	struct ionic_rxq_comp *cq_desc;
+	bool more;
+	uint32_t curr_q_tail_idx, curr_cq_tail_idx;
+	uint32_t work_done = 0;
+
+	if (work_to_do == 0)
+		return;
+
+	cq_desc = &cq_desc_base[cq->tail_idx];
+	while (color_match(cq_desc->pkt_type_color, cq->done_color)) {
+		curr_cq_tail_idx = cq->tail_idx;
+		cq->tail_idx = (cq->tail_idx + 1) & (cq->num_descs - 1);
+
+		if (cq->tail_idx == 0)
+			cq->done_color = !cq->done_color;
+
+		/* Prefetch the next 4 descriptors */
+		if ((cq->tail_idx & 0x3) == 0)
+			rte_prefetch0(&cq_desc_base[cq->tail_idx]); /* cq desc */
+
+		do {
+			more = (q->tail_idx != cq_desc->comp_index);
+
+			q_desc_info = &q->info[q->tail_idx];
+
+			curr_q_tail_idx = q->tail_idx;
+			q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
+
+			/* Prefetch the next 4 descriptors */
+			if ((q->tail_idx & 0x3) == 0)
+				/* q desc info */
+				rte_prefetch0(&q->info[q->tail_idx]);
+
+			ionic_rx_clean(q, curr_q_tail_idx, curr_cq_tail_idx,
+					q_desc_info->cb_arg, service_cb_arg);
+
+		} while (more);
+
+		if (++work_done == work_to_do)
+			break;
+
+		cq_desc = &cq_desc_base[cq->tail_idx];
+	}
+}
+
+/*
+ * Stop Receive Units for specified queue.
+ */
+int __attribute__((cold))
+ionic_dev_rx_queue_stop(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id)
+{
+	struct ionic_qcq *rxq;
+
+	ionic_init_print_call();
+
+	rxq = eth_dev->data->rx_queues[rx_queue_id];
+
+	ionic_qcq_disable(rxq);
+
+	/* Flush */
+	ionic_rxq_service(&rxq->cq, -1, NULL);
+
+	ionic_lif_rxq_deinit(rxq);
+
+	eth_dev->data->rx_queue_state[rx_queue_id] =
+			RTE_ETH_QUEUE_STATE_STOPPED;
+
+	return 0;
+}
+
+uint16_t
+ionic_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
+		uint16_t nb_pkts)
+{
+	struct ionic_qcq *rxq = (struct ionic_qcq *)rx_queue;
+	uint32_t frame_size =
+			rxq->lif->eth_dev->data->dev_conf.rxmode.max_rx_pkt_len;
+	struct ionic_cq *cq = &rxq->cq;
+	struct ionic_rx_service service_cb_arg;
+
+	service_cb_arg.rx_pkts = rx_pkts;
+	service_cb_arg.nb_pkts = nb_pkts;
+	service_cb_arg.nb_rx = 0;
+
+	ionic_rxq_service(cq, nb_pkts, &service_cb_arg);
+
+	ionic_rx_fill(rxq, frame_size);
+
+	return service_cb_arg.nb_rx;
+}
diff --git a/drivers/net/ionic/ionic_rxtx.h b/drivers/net/ionic/ionic_rxtx.h
new file mode 100644
index 000000000..8f1bbad39
--- /dev/null
+++ b/drivers/net/ionic/ionic_rxtx.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved.
+ */
+
+#ifndef _IONIC_RXTX_H_
+#define _IONIC_RXTX_H_
+
+#include <rte_mbuf.h>
+
+struct ionic_rx_service {
+	/* cb in */
+	struct rte_mbuf **rx_pkts;
+	uint16_t nb_pkts;
+	/* cb out */
+	uint16_t nb_rx;
+};
+
+uint16_t ionic_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
+		uint16_t nb_pkts);
+uint16_t ionic_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
+		uint16_t nb_pkts);
+uint16_t ionic_prep_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
+		uint16_t nb_pkts);
+
+int ionic_dev_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+		uint16_t nb_desc, uint32_t socket_id,
+		const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mp);
+void ionic_dev_rx_queue_release(void *rxq);
+int ionic_dev_rx_queue_start(struct rte_eth_dev *dev, uint16_t rx_queue_id);
+int ionic_dev_rx_queue_stop(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id);
+
+int ionic_dev_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+		uint16_t nb_desc,  uint32_t socket_id,
+		const struct rte_eth_txconf *tx_conf);
+void ionic_dev_tx_queue_release(void *tx_queue);
+int ionic_dev_tx_queue_stop(struct rte_eth_dev *eth_dev, uint16_t tx_queue_id);
+int ionic_dev_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id);
+
+void ionic_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
+		struct rte_eth_rxq_info *qinfo);
+void ionic_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
+		struct rte_eth_txq_info *qinfo);
+
+#endif /* _IONIC_RXTX_H_ */
diff --git a/drivers/net/ionic/meson.build b/drivers/net/ionic/meson.build
index ef202af7f..cc54b56be 100644
--- a/drivers/net/ionic/meson.build
+++ b/drivers/net/ionic/meson.build
@@ -6,6 +6,7 @@ version = 1
 sources = files(
 	'ionic_mac_api.c',
 	'ionic_rx_filter.c',
+	'ionic_rxtx.c',
 	'ionic_dev.c',
 	'ionic_ethdev.c',
 	'ionic_lif.c',


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 15/17] net/ionic: add stats
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
                   ` (13 preceding siblings ...)
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 14/17] net/ionic: add RX and TX handling Alfredo Cardigliano
@ 2019-10-12  0:27 ` Alfredo Cardigliano
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 16/17] net/ionic: add TX checksum support Alfredo Cardigliano
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:27 UTC (permalink / raw)
  To: dev

Add basic, per queue and extended statistics for
RX and TX, both from the adapter and the driver.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 doc/guides/nics/features/ionic.ini |    3 
 drivers/net/ionic/ionic_ethdev.c   |  253 ++++++++++++++++++++++++++++++++++++
 drivers/net/ionic/ionic_lif.c      |  149 +++++++++++++++++++++
 drivers/net/ionic/ionic_lif.h      |    9 +
 4 files changed, 414 insertions(+)

diff --git a/doc/guides/nics/features/ionic.ini b/doc/guides/nics/features/ionic.ini
index 59f0753db..b937092ac 100644
--- a/doc/guides/nics/features/ionic.ini
+++ b/doc/guides/nics/features/ionic.ini
@@ -26,6 +26,9 @@ VLAN offload         = Y
 L3 checksum offload  = Y
 L4 checksum offload  = Y
 Packet type parsing  = Y
+Basic stats          = Y
+Extended stats       = Y
+Stats per queue      = Y
 Linux UIO            = Y
 Linux VFIO           = Y
 x86-64               = Y
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index d91513bc8..1300774a9 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -43,6 +43,19 @@ static int  ionic_dev_rss_hash_conf_get(struct rte_eth_dev *eth_dev,
 static int  ionic_dev_rss_hash_update(struct rte_eth_dev *eth_dev,
 		struct rte_eth_rss_conf *rss_conf);
 static int  ionic_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask);
+static int  ionic_dev_stats_get(struct rte_eth_dev *eth_dev,
+		struct rte_eth_stats *stats);
+static int  ionic_dev_stats_reset(struct rte_eth_dev *eth_dev);
+static int  ionic_dev_xstats_get(struct rte_eth_dev *dev,
+		struct rte_eth_xstat *xstats, unsigned int n);
+static int  ionic_dev_xstats_get_by_id(struct rte_eth_dev *dev,
+		const uint64_t *ids, uint64_t *values, unsigned int n);
+static int  ionic_dev_xstats_reset(struct rte_eth_dev *dev);
+static int  ionic_dev_xstats_get_names(struct rte_eth_dev *dev,
+		struct rte_eth_xstat_name *xstats_names, unsigned int size);
+static int  ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
+		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		unsigned int limit);
 
 int ionic_logtype_init;
 int ionic_logtype_driver;
@@ -103,6 +116,13 @@ static const struct eth_dev_ops ionic_eth_dev_ops = {
 	.tx_queue_start	        = ionic_dev_tx_queue_start,
 	.tx_queue_stop          = ionic_dev_tx_queue_stop,
 	.vlan_offload_set       = ionic_vlan_offload_set,
+	.stats_get              = ionic_dev_stats_get,
+	.stats_reset            = ionic_dev_stats_reset,
+	.xstats_get             = ionic_dev_xstats_get,
+	.xstats_get_by_id       = ionic_dev_xstats_get_by_id,
+	.xstats_reset           = ionic_dev_xstats_reset,
+	.xstats_get_names       = ionic_dev_xstats_get_names,
+	.xstats_get_names_by_id = ionic_dev_xstats_get_names_by_id,
 };
 
 /*
@@ -113,6 +133,93 @@ static LIST_HEAD(ionic_pci_adapters_list, ionic_adapter) ionic_pci_adapters =
 		LIST_HEAD_INITIALIZER(ionic_pci_adapters);
 static rte_spinlock_t ionic_pci_adapters_lock = RTE_SPINLOCK_INITIALIZER;
 
+struct rte_ionic_xstats_name_off {
+	char name[RTE_ETH_XSTATS_NAME_SIZE];
+	unsigned int offset;
+};
+
+static const struct rte_ionic_xstats_name_off rte_ionic_xstats_strings[] = {
+	/* RX */
+	{"rx_ucast_bytes", offsetof(struct ionic_lif_stats,
+			rx_ucast_bytes)},
+	{"rx_ucast_packets", offsetof(struct ionic_lif_stats,
+			rx_ucast_packets)},
+	{"rx_mcast_bytes", offsetof(struct ionic_lif_stats,
+			rx_mcast_bytes)},
+	{"rx_mcast_packets", offsetof(struct ionic_lif_stats,
+			rx_mcast_packets)},
+	{"rx_bcast_bytes", offsetof(struct ionic_lif_stats,
+			rx_bcast_bytes)},
+	{"rx_bcast_packets", offsetof(struct ionic_lif_stats,
+			rx_bcast_packets)},
+	/* RX drops */
+	{"rx_ucast_drop_bytes", offsetof(struct ionic_lif_stats,
+			rx_ucast_drop_bytes)},
+	{"rx_ucast_drop_packets", offsetof(struct ionic_lif_stats,
+			rx_ucast_drop_packets)},
+	{"rx_mcast_drop_bytes", offsetof(struct ionic_lif_stats,
+			rx_mcast_drop_bytes)},
+	{"rx_mcast_drop_packets", offsetof(struct ionic_lif_stats,
+			rx_mcast_drop_packets)},
+	{"rx_bcast_drop_bytes", offsetof(struct ionic_lif_stats,
+			rx_bcast_drop_bytes)},
+	{"rx_bcast_drop_packets", offsetof(struct ionic_lif_stats,
+			rx_bcast_drop_packets)},
+	{"rx_dma_error", offsetof(struct ionic_lif_stats,
+			rx_dma_error)},
+	/* TX */
+	{"tx_ucast_bytes", offsetof(struct ionic_lif_stats,
+			tx_ucast_bytes)},
+	{"tx_ucast_packets", offsetof(struct ionic_lif_stats,
+			tx_ucast_packets)},
+	{"tx_mcast_bytes", offsetof(struct ionic_lif_stats,
+			tx_mcast_bytes)},
+	{"tx_mcast_packets", offsetof(struct ionic_lif_stats,
+			tx_mcast_packets)},
+	{"tx_bcast_bytes", offsetof(struct ionic_lif_stats,
+			tx_bcast_bytes)},
+	{"tx_bcast_packets", offsetof(struct ionic_lif_stats,
+			tx_bcast_packets)},
+	/* TX drops */
+	{"tx_ucast_drop_bytes", offsetof(struct ionic_lif_stats,
+			tx_ucast_drop_bytes)},
+	{"tx_ucast_drop_packets", offsetof(struct ionic_lif_stats,
+			tx_ucast_drop_packets)},
+	{"tx_mcast_drop_bytes", offsetof(struct ionic_lif_stats,
+			tx_mcast_drop_bytes)},
+	{"tx_mcast_drop_packets", offsetof(struct ionic_lif_stats,
+			tx_mcast_drop_packets)},
+	{"tx_bcast_drop_bytes", offsetof(struct ionic_lif_stats,
+			tx_bcast_drop_bytes)},
+	{"tx_bcast_drop_packets", offsetof(struct ionic_lif_stats,
+			tx_bcast_drop_packets)},
+	{"tx_dma_error", offsetof(struct ionic_lif_stats,
+			tx_dma_error)},
+	/* Rx Queue/Ring drops */
+	{"rx_queue_disabled", offsetof(struct ionic_lif_stats,
+			rx_queue_disabled)},
+	{"rx_queue_empty", offsetof(struct ionic_lif_stats,
+			rx_queue_empty)},
+	{"rx_queue_error", offsetof(struct ionic_lif_stats,
+			rx_queue_error)},
+	{"rx_desc_fetch_error", offsetof(struct ionic_lif_stats,
+			rx_desc_fetch_error)},
+	{"rx_desc_data_error", offsetof(struct ionic_lif_stats,
+			rx_desc_data_error)},
+	/* Tx Queue/Ring drops */
+	{"tx_queue_disabled", offsetof(struct ionic_lif_stats,
+			tx_queue_disabled)},
+	{"tx_queue_error", offsetof(struct ionic_lif_stats,
+			tx_queue_error)},
+	{"tx_desc_fetch_error", offsetof(struct ionic_lif_stats,
+			tx_desc_fetch_error)},
+	{"tx_desc_data_error", offsetof(struct ionic_lif_stats,
+			tx_desc_data_error)},
+};
+
+#define IONIC_NB_HW_STATS (sizeof(rte_ionic_xstats_strings) / \
+		sizeof(rte_ionic_xstats_strings[0]))
+
 /*
  * Set device link up, enable tx.
  */
@@ -587,6 +694,152 @@ ionic_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
 	return 0;
 }
 
+static int
+ionic_dev_stats_get(struct rte_eth_dev *eth_dev,
+		struct rte_eth_stats *stats)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+
+	ionic_lif_get_stats(lif, stats);
+
+	return 0;
+}
+
+static int
+ionic_dev_stats_reset(struct rte_eth_dev *eth_dev)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+
+	ionic_init_print_call();
+
+	ionic_lif_reset_stats(lif);
+
+	return 0;
+}
+
+static int
+ionic_dev_xstats_get_names(__rte_unused struct rte_eth_dev *eth_dev,
+		struct rte_eth_xstat_name *xstats_names,
+		__rte_unused unsigned int size)
+{
+	unsigned int i;
+
+	if (xstats_names != NULL) {
+		for (i = 0; i < IONIC_NB_HW_STATS; i++) {
+			snprintf(xstats_names[i].name,
+					sizeof(xstats_names[i].name),
+					"%s", rte_ionic_xstats_strings[i].name);
+		}
+	}
+
+	return IONIC_NB_HW_STATS;
+}
+
+static int
+ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *eth_dev,
+		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+		unsigned int limit)
+{
+	struct rte_eth_xstat_name xstats_names_copy[IONIC_NB_HW_STATS];
+	uint16_t i;
+
+	if (!ids) {
+		if (xstats_names != NULL) {
+			for (i = 0; i < IONIC_NB_HW_STATS; i++) {
+				snprintf(xstats_names[i].name,
+					sizeof(xstats_names[i].name),
+					"%s", rte_ionic_xstats_strings[i].name);
+			}
+		}
+
+		return IONIC_NB_HW_STATS;
+	}
+
+	ionic_dev_xstats_get_names_by_id(eth_dev, xstats_names_copy, NULL,
+		IONIC_NB_HW_STATS);
+
+	for (i = 0; i < limit; i++) {
+		if (ids[i] >= IONIC_NB_HW_STATS) {
+			ionic_drv_print(ERR, "id value isn't valid");
+			return -1;
+		}
+
+		strcpy(xstats_names[i].name, xstats_names_copy[ids[i]].name);
+	}
+
+	return limit;
+}
+
+static int
+ionic_dev_xstats_get(struct rte_eth_dev *eth_dev, struct rte_eth_xstat *xstats,
+		unsigned int n)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_lif_stats hw_stats;
+	uint16_t i;
+
+	if (n < IONIC_NB_HW_STATS)
+		return IONIC_NB_HW_STATS;
+
+	ionic_lif_get_hw_stats(lif, &hw_stats);
+
+	for (i = 0; i < IONIC_NB_HW_STATS; i++) {
+		xstats[i].value = *(uint64_t *)(((char *)&hw_stats) +
+				rte_ionic_xstats_strings[i].offset);
+		xstats[i].id = i;
+	}
+
+	return IONIC_NB_HW_STATS;
+}
+
+static int
+ionic_dev_xstats_get_by_id(struct rte_eth_dev *eth_dev, const uint64_t *ids,
+		uint64_t *values, unsigned int n)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_lif_stats hw_stats;
+	uint64_t values_copy[IONIC_NB_HW_STATS];
+	uint16_t i;
+
+	if (!ids) {
+		if (!ids && n < IONIC_NB_HW_STATS)
+			return IONIC_NB_HW_STATS;
+
+		ionic_lif_get_hw_stats(lif, &hw_stats);
+
+		for (i = 0; i < IONIC_NB_HW_STATS; i++) {
+			values[i] = *(uint64_t *)(((char *)&hw_stats) +
+					rte_ionic_xstats_strings[i].offset);
+		}
+
+		return IONIC_NB_HW_STATS;
+	}
+
+	ionic_dev_xstats_get_by_id(eth_dev, NULL, values_copy,
+			IONIC_NB_HW_STATS);
+
+	for (i = 0; i < n; i++) {
+		if (ids[i] >= IONIC_NB_HW_STATS) {
+			ionic_drv_print(ERR, "id value isn't valid");
+			return -1;
+		}
+
+		values[i] = values_copy[ids[i]];
+	}
+
+	return n;
+}
+
+static int
+ionic_dev_xstats_reset(struct rte_eth_dev *eth_dev)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+
+	ionic_lif_reset_hw_stats(lif);
+
+	return 0;
+}
+
 static int
 ionic_dev_configure(struct rte_eth_dev *eth_dev)
 {
diff --git a/drivers/net/ionic/ionic_lif.c b/drivers/net/ionic/ionic_lif.c
index a8eed76bd..e2cefbaf6 100644
--- a/drivers/net/ionic/ionic_lif.c
+++ b/drivers/net/ionic/ionic_lif.c
@@ -84,6 +84,155 @@ ionic_lif_reset(struct ionic_lif *lif)
 	ionic_dev_cmd_wait_check(idev, IONIC_DEVCMD_TIMEOUT);
 }
 
+static void
+ionic_lif_get_abs_stats(struct ionic_lif *lif, struct rte_eth_stats *stats)
+{
+	struct ionic_lif_stats *ls = &lif->info->stats;
+	uint32_t i;
+	uint32_t num_rx_q_counters = RTE_MIN(lif->nrxqcqs, (uint32_t)
+			RTE_ETHDEV_QUEUE_STAT_CNTRS);
+	uint32_t num_tx_q_counters = RTE_MIN(lif->ntxqcqs, (uint32_t)
+			RTE_ETHDEV_QUEUE_STAT_CNTRS);
+
+	memset(stats, 0, sizeof(*stats));
+
+	if (ls == NULL) {
+		ionic_drv_print(DEBUG, "Stats on port %u not yet initialized",
+			lif->port_id);
+		return;
+	}
+
+	/* RX */
+
+	stats->ipackets = ls->rx_ucast_packets +
+			  ls->rx_mcast_packets +
+			  ls->rx_bcast_packets;
+
+	stats->ibytes = ls->rx_ucast_bytes +
+			ls->rx_mcast_bytes +
+			ls->rx_bcast_bytes;
+
+	stats->ierrors = 0;
+	stats->imissed = 0;
+
+	for (i = 0; i < lif->nrxqcqs; i++) {
+		struct ionic_rx_stats *rx_stats = &lif->rxqcqs[i]->stats.rx;
+		stats->imissed +=
+			rx_stats->no_cb_arg +
+			rx_stats->bad_cq_status +
+			rx_stats->no_room +
+			rx_stats->bad_len;
+	}
+
+	stats->imissed +=
+		ls->rx_ucast_drop_packets +
+		ls->rx_mcast_drop_packets +
+		ls->rx_bcast_drop_packets;
+
+	stats->imissed +=
+		ls->rx_queue_empty +
+		ls->rx_dma_error +
+		ls->rx_queue_disabled +
+		ls->rx_desc_fetch_error +
+		ls->rx_desc_data_error;
+
+	for (i = 0; i < num_rx_q_counters; i++) {
+		struct ionic_rx_stats *rx_stats = &lif->rxqcqs[i]->stats.rx;
+		stats->q_ipackets[i] = rx_stats->packets;
+		stats->q_ibytes[i] = rx_stats->bytes;
+		stats->q_errors[i] =
+			rx_stats->no_cb_arg +
+			rx_stats->bad_cq_status +
+			rx_stats->no_room +
+			rx_stats->bad_len;
+	}
+
+	/* TX */
+
+	stats->opackets = ls->tx_ucast_packets +
+			  ls->tx_mcast_packets +
+			  ls->tx_bcast_packets;
+
+	stats->obytes = ls->tx_ucast_bytes +
+			ls->tx_mcast_bytes +
+			ls->tx_bcast_bytes;
+
+	for (i = 0; i < lif->ntxqcqs; i++) {
+		struct ionic_tx_stats *tx_stats = &lif->txqcqs[i]->stats.tx;
+		stats->oerrors += tx_stats->drop;
+	}
+
+	stats->oerrors +=
+		ls->tx_ucast_drop_packets +
+		ls->tx_mcast_drop_packets +
+		ls->tx_bcast_drop_packets;
+
+	stats->oerrors +=
+		ls->tx_dma_error +
+		ls->tx_queue_disabled +
+		ls->tx_desc_fetch_error +
+		ls->tx_desc_data_error;
+
+	for (i = 0; i < num_tx_q_counters; i++) {
+		struct ionic_tx_stats *tx_stats = &lif->txqcqs[i]->stats.tx;
+		stats->q_opackets[i] = tx_stats->packets;
+		stats->q_obytes[i] = tx_stats->bytes;
+	}
+}
+
+void
+ionic_lif_get_stats(struct ionic_lif *lif, struct rte_eth_stats *stats)
+{
+	ionic_lif_get_abs_stats(lif, stats);
+
+	stats->ipackets  -= lif->stats_base.ipackets;
+	stats->opackets  -= lif->stats_base.opackets;
+	stats->ibytes    -= lif->stats_base.ibytes;
+	stats->obytes    -= lif->stats_base.obytes;
+	stats->imissed   -= lif->stats_base.imissed;
+	stats->ierrors   -= lif->stats_base.ierrors;
+	stats->oerrors   -= lif->stats_base.oerrors;
+	stats->rx_nombuf -= lif->stats_base.rx_nombuf;
+}
+
+void
+ionic_lif_reset_stats(struct ionic_lif *lif)
+{
+	uint32_t i;
+
+	for (i = 0; i < lif->nrxqcqs; i++) {
+		memset(&lif->rxqcqs[i]->stats.rx, 0,
+				sizeof(struct ionic_rx_stats));
+		memset(&lif->txqcqs[i]->stats.tx, 0,
+				sizeof(struct ionic_tx_stats));
+	}
+
+	ionic_lif_get_abs_stats(lif, &lif->stats_base);
+}
+
+void
+ionic_lif_get_hw_stats(struct ionic_lif *lif, struct ionic_lif_stats *stats)
+{
+	uint16_t i, count = sizeof(struct ionic_lif_stats) / sizeof(uint64_t);
+	uint64_t *stats64 = (uint64_t *)stats;
+	uint64_t *lif_stats64 = (uint64_t *)&lif->info->stats;
+	uint64_t *lif_stats64_base = (uint64_t *)&lif->lif_stats_base;
+
+	for (i = 0; i < count; i++)
+		stats64[i] = lif_stats64[i] - lif_stats64_base[i];
+}
+
+void
+ionic_lif_reset_hw_stats(struct ionic_lif *lif)
+{
+	uint16_t i, count = sizeof(struct ionic_lif_stats) / sizeof(uint64_t);
+	uint64_t *lif_stats64 = (uint64_t *)&lif->info->stats;
+	uint64_t *lif_stats64_base = (uint64_t *)&lif->lif_stats_base;
+
+	for (i = 0; i < count; i++)
+		lif_stats64_base[i] = lif_stats64[i];
+}
+
 static int
 ionic_lif_addr_add(struct ionic_lif *lif, const uint8_t *addr)
 {
diff --git a/drivers/net/ionic/ionic_lif.h b/drivers/net/ionic/ionic_lif.h
index a72196de8..aa2f849c0 100644
--- a/drivers/net/ionic/ionic_lif.h
+++ b/drivers/net/ionic/ionic_lif.h
@@ -113,6 +113,8 @@ struct ionic_lif {
 	struct ionic_lif_info *info;
 	rte_iova_t info_pa;
 	const struct rte_memzone *info_z;
+	struct rte_eth_stats stats_base;
+	struct ionic_lif_stats lif_stats_base;
 };
 
 int ionic_lif_identify(struct ionic_adapter *adapter);
@@ -174,6 +176,13 @@ int ionic_lif_rss_config(struct ionic_lif *lif, const uint16_t types,
 
 int ionic_lif_set_features(struct ionic_lif *lif);
 
+void ionic_lif_get_stats(struct ionic_lif *lif, struct rte_eth_stats *stats);
+void ionic_lif_reset_stats(struct ionic_lif *lif);
+
+void ionic_lif_get_hw_stats(struct ionic_lif *lif,
+		struct ionic_lif_stats *stats);
+void ionic_lif_reset_hw_stats(struct ionic_lif *lif);
+
 int ionic_notifyq_handler(struct ionic_lif *lif, int budget);
 
 #endif /* _IONIC_LIF_H_ */


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 16/17] net/ionic: add TX checksum support
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
                   ` (14 preceding siblings ...)
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 15/17] net/ionic: add stats Alfredo Cardigliano
@ 2019-10-12  0:27 ` Alfredo Cardigliano
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 17/17] net/ionic: read fw version Alfredo Cardigliano
  2019-10-12 15:28 ` [dpdk-dev] [PATCH 00/17] Series short description Stephen Hemminger
  17 siblings, 0 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:27 UTC (permalink / raw)
  To: dev

Add support for TX checksumming.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 drivers/net/ionic/ionic_ethdev.c |    5 ++
 drivers/net/ionic/ionic_lif.c    |    1 
 drivers/net/ionic/ionic_lif.h    |    1 
 drivers/net/ionic/ionic_rxtx.c   |   86 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 92 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index 1300774a9..720598dbd 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -413,7 +413,12 @@ ionic_dev_info_get(struct rte_eth_dev *eth_dev,
 		0;
 
 	dev_info->tx_queue_offload_capa =
+		DEV_TX_OFFLOAD_IPV4_CKSUM |
+		DEV_TX_OFFLOAD_UDP_CKSUM |
+		DEV_TX_OFFLOAD_TCP_CKSUM |
 		DEV_TX_OFFLOAD_VLAN_INSERT |
+		DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM |
+		DEV_TX_OFFLOAD_OUTER_UDP_CKSUM |
 		0;
 
 	/*
diff --git a/drivers/net/ionic/ionic_lif.c b/drivers/net/ionic/ionic_lif.c
index e2cefbaf6..6f1cbf8fb 100644
--- a/drivers/net/ionic/ionic_lif.c
+++ b/drivers/net/ionic/ionic_lif.c
@@ -1506,6 +1506,7 @@ ionic_lif_init(struct ionic_lif *lif)
 		| IONIC_ETH_HW_RX_HASH
 		| IONIC_ETH_HW_TX_SG
 		| IONIC_ETH_HW_RX_SG
+		| IONIC_ETH_HW_TX_CSUM
 		| IONIC_ETH_HW_RX_CSUM
 		| IONIC_ETH_HW_TSO
 		| IONIC_ETH_HW_TSO_IPV6
diff --git a/drivers/net/ionic/ionic_lif.h b/drivers/net/ionic/ionic_lif.h
index aa2f849c0..8feaad7e3 100644
--- a/drivers/net/ionic/ionic_lif.h
+++ b/drivers/net/ionic/ionic_lif.h
@@ -32,6 +32,7 @@ struct ionic_tx_stats {
 	uint64_t bytes;
 	uint64_t drop;
 	uint64_t stop;
+	uint64_t no_csum;
 	uint64_t tso;
 	uint64_t frags;
 };
diff --git a/drivers/net/ionic/ionic_rxtx.c b/drivers/net/ionic/ionic_rxtx.c
index 1a7313cc3..09600c953 100644
--- a/drivers/net/ionic/ionic_rxtx.c
+++ b/drivers/net/ionic/ionic_rxtx.c
@@ -231,16 +231,59 @@ ionic_dev_tx_queue_start(struct rte_eth_dev *eth_dev, uint16_t tx_queue_id)
 	return 0;
 }
 
+static void
+ionic_tx_tcp_pseudo_csum(struct rte_mbuf *txm)
+{
+	struct ether_hdr *eth_hdr = rte_pktmbuf_mtod(txm, struct ether_hdr *);
+	char *l3_hdr = ((char *)eth_hdr) + txm->l2_len;
+	struct rte_tcp_hdr *tcp_hdr = (struct rte_tcp_hdr *)
+			(l3_hdr + txm->l3_len);
+
+	if (txm->ol_flags & PKT_TX_IP_CKSUM) {
+		struct rte_ipv4_hdr *ipv4_hdr = (struct rte_ipv4_hdr *)l3_hdr;
+		ipv4_hdr->hdr_checksum = 0;
+		tcp_hdr->cksum = 0;
+		tcp_hdr->cksum = rte_ipv4_udptcp_cksum(ipv4_hdr, tcp_hdr);
+	} else {
+		struct rte_ipv6_hdr *ipv6_hdr = (struct rte_ipv6_hdr *)l3_hdr;
+		tcp_hdr->cksum = 0;
+		tcp_hdr->cksum = rte_ipv6_udptcp_cksum(ipv6_hdr, tcp_hdr);
+	}
+}
+
+static void
+ionic_tx_tcp_inner_pseudo_csum(struct rte_mbuf *txm)
+{
+	struct ether_hdr *eth_hdr = rte_pktmbuf_mtod(txm, struct ether_hdr *);
+	char *l3_hdr = ((char *)eth_hdr) + txm->outer_l2_len +
+			txm->outer_l3_len + txm->l2_len;
+	struct rte_tcp_hdr *tcp_hdr = (struct rte_tcp_hdr *)
+			(l3_hdr + txm->l3_len);
+
+	if (txm->ol_flags & PKT_TX_IPV4) {
+		struct rte_ipv4_hdr *ipv4_hdr = (struct rte_ipv4_hdr *)l3_hdr;
+		ipv4_hdr->hdr_checksum = 0;
+		tcp_hdr->cksum = 0;
+		tcp_hdr->cksum = rte_ipv4_udptcp_cksum(ipv4_hdr, tcp_hdr);
+	} else {
+		struct rte_ipv6_hdr *ipv6_hdr = (struct rte_ipv6_hdr *)l3_hdr;
+		tcp_hdr->cksum = 0;
+		tcp_hdr->cksum = rte_ipv6_udptcp_cksum(ipv6_hdr, tcp_hdr);
+	}
+}
+
 static void
 ionic_tx_tso_post(struct ionic_queue *q, struct ionic_txq_desc *desc,
 		struct rte_mbuf *txm,
 		rte_iova_t addr, uint8_t nsge, uint16_t len,
 		uint32_t hdrlen, uint32_t mss,
+		bool encap,
 		uint16_t vlan_tci, bool has_vlan,
 		bool start, bool done)
 {
 	uint8_t flags = 0;
 	flags |= has_vlan ? IONIC_TXQ_DESC_FLAG_VLAN : 0;
+	flags |= encap ? IONIC_TXQ_DESC_FLAG_ENCAP : 0;
 	flags |= start ? IONIC_TXQ_DESC_FLAG_TSO_SOT : 0;
 	flags |= done ? IONIC_TXQ_DESC_FLAG_TSO_EOT : 0;
 
@@ -285,10 +328,29 @@ ionic_tx_tso(struct ionic_queue *q, struct rte_mbuf *txm, uint64_t offloads,
 	uint32_t len;
 	uint32_t offset = 0;
 	bool start, done;
+	bool encap;
 	bool has_vlan = !!(txm->ol_flags & PKT_TX_VLAN_PKT);
 	uint16_t vlan_tci = txm->vlan_tci;
+	uint64_t ol_flags = txm->ol_flags;
+
+	encap = ((ol_flags & PKT_TX_OUTER_IP_CKSUM) ||
+			(ol_flags & PKT_TX_OUTER_UDP_CKSUM)) &&
+			((ol_flags & PKT_TX_OUTER_IPV4) ||
+			(ol_flags & PKT_TX_OUTER_IPV6));
+
+	/* Preload inner-most TCP csum field with IP pseudo hdr
+	 * calculated with IP length set to zero.  HW will later
+	 * add in length to each TCP segment resulting from the TSO.
+	 */
 
-	hdrlen = txm->l2_len + txm->l3_len;
+	if (encap) {
+		ionic_tx_tcp_inner_pseudo_csum(txm);
+		hdrlen = txm->outer_l2_len + txm->outer_l3_len +
+				txm->l2_len + txm->l3_len + txm->l4_len;
+	} else {
+		ionic_tx_tcp_pseudo_csum(txm);
+		hdrlen = txm->l2_len + txm->l3_len + txm->l4_len;
+	}
 
 	seglen = hdrlen + mss;
 	left = txm->data_len;
@@ -312,6 +374,7 @@ ionic_tx_tso(struct ionic_queue *q, struct rte_mbuf *txm, uint64_t offloads,
 		ionic_tx_tso_post(q, desc, txm,
 				desc_addr, desc_nsge, desc_len,
 				hdrlen, mss,
+				encap,
 				vlan_tci, has_vlan,
 				start, done && not_xmit_more);
 		desc = ionic_tx_tso_next(q, &elem);
@@ -350,6 +413,7 @@ ionic_tx_tso(struct ionic_queue *q, struct rte_mbuf *txm, uint64_t offloads,
 			ionic_tx_tso_post(q, desc, txm_seg,
 					desc_addr, desc_nsge, desc_len,
 					hdrlen, mss,
+					encap,
 					vlan_tci, has_vlan,
 					start, done && not_xmit_more);
 			desc = ionic_tx_tso_next(q, &elem);
@@ -375,15 +439,34 @@ ionic_tx(struct ionic_queue *q, struct rte_mbuf *txm, uint64_t offloads,
 	struct ionic_txq_sg_elem *elem = sg_desc->elems;
 	struct ionic_tx_stats *stats = IONIC_Q_TO_TX_STATS(q);
 	struct rte_mbuf *txm_seg;
+	bool encap;
 	bool has_vlan;
 	uint64_t ol_flags = txm->ol_flags;
 	uint64_t addr = rte_cpu_to_le_64(rte_mbuf_data_iova_default(txm));
 	uint8_t opcode = IONIC_TXQ_DESC_OPCODE_CSUM_NONE;
 	uint8_t flags = 0;
 
+	if ((ol_flags & PKT_TX_IP_CKSUM) &&
+			(offloads & DEV_TX_OFFLOAD_IPV4_CKSUM)) {
+		opcode = IONIC_TXQ_DESC_OPCODE_CSUM_HW;
+		flags |= IONIC_TXQ_DESC_FLAG_CSUM_L3;
+		if (((ol_flags & PKT_TX_TCP_CKSUM) &&
+				(offloads & DEV_TX_OFFLOAD_TCP_CKSUM)) ||
+				((ol_flags & PKT_TX_UDP_CKSUM) &&
+				(offloads & DEV_TX_OFFLOAD_UDP_CKSUM)))
+			flags |= IONIC_TXQ_DESC_FLAG_CSUM_L4;
+	} else {
+		stats->no_csum++;
+	}
+
 	has_vlan = (ol_flags & PKT_TX_VLAN_PKT);
+	encap = ((ol_flags & PKT_TX_OUTER_IP_CKSUM) ||
+			(ol_flags & PKT_TX_OUTER_UDP_CKSUM)) &&
+			((ol_flags & PKT_TX_OUTER_IPV4) ||
+			(ol_flags & PKT_TX_OUTER_IPV6));
 
 	flags |= has_vlan ? IONIC_TXQ_DESC_FLAG_VLAN : 0;
+	flags |= encap ? IONIC_TXQ_DESC_FLAG_ENCAP : 0;
 
 	desc->cmd = encode_txq_desc_cmd(opcode, flags, txm->nb_segs - 1, addr);
 	desc->len = txm->data_len;
@@ -468,6 +551,7 @@ ionic_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 	PKT_TX_IPV4 |		\
 	PKT_TX_IPV6 |		\
 	PKT_TX_VLAN |		\
+	PKT_TX_IP_CKSUM |	\
 	PKT_TX_TCP_SEG |	\
 	PKT_TX_L4_MASK)
 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [dpdk-dev] [PATCH 17/17] net/ionic: read fw version
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
                   ` (15 preceding siblings ...)
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 16/17] net/ionic: add TX checksum support Alfredo Cardigliano
@ 2019-10-12  0:27 ` Alfredo Cardigliano
  2019-10-12 15:28 ` [dpdk-dev] [PATCH 00/17] Series short description Stephen Hemminger
  17 siblings, 0 replies; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-12  0:27 UTC (permalink / raw)
  To: dev

Add support for reading the firmware version.

Signed-off-by: Alfredo Cardigliano <cardigliano@ntop.org>
Reviewed-by: Shannon Nelson <snelson@pensando.io>
---
 doc/guides/nics/features/ionic.ini |    1 +
 drivers/net/ionic/ionic.h          |    1 +
 drivers/net/ionic/ionic_dev.c      |    8 ++++++++
 drivers/net/ionic/ionic_ethdev.c   |   20 ++++++++++++++++++++
 4 files changed, 30 insertions(+)

diff --git a/doc/guides/nics/features/ionic.ini b/doc/guides/nics/features/ionic.ini
index b937092ac..54beb0bd1 100644
--- a/doc/guides/nics/features/ionic.ini
+++ b/doc/guides/nics/features/ionic.ini
@@ -29,6 +29,7 @@ Packet type parsing  = Y
 Basic stats          = Y
 Extended stats       = Y
 Stats per queue      = Y
+FW version           = Y
 Linux UIO            = Y
 Linux VFIO           = Y
 x86-64               = Y
diff --git a/drivers/net/ionic/ionic.h b/drivers/net/ionic/ionic.h
index 05f1df061..4f691b429 100644
--- a/drivers/net/ionic/ionic.h
+++ b/drivers/net/ionic/ionic.h
@@ -60,6 +60,7 @@ struct ionic_adapter {
 	bool intrs[IONIC_INTR_CTRL_REGS_MAX];
 	bool is_mgmt_nic;
 	bool link_up;
+	char fw_version[IONIC_DEVINFO_FWVERS_BUFLEN];
 	struct rte_pci_device *pci_dev;
 	LIST_ENTRY(ionic_adapter) pci_adapters;
 };
diff --git a/drivers/net/ionic/ionic_dev.c b/drivers/net/ionic/ionic_dev.c
index fc165d0a8..dfa41f99a 100644
--- a/drivers/net/ionic/ionic_dev.c
+++ b/drivers/net/ionic/ionic_dev.c
@@ -15,6 +15,7 @@ ionic_dev_setup(struct ionic_adapter *adapter)
 	unsigned int num_bars = adapter->num_bars;
 	struct ionic_dev *idev = &adapter->idev;
 	uint32_t sig;
+	unsigned int i;
 
 	/* BAR0: dev_cmd and interrupts */
 	if (num_bars < 1) {
@@ -41,6 +42,13 @@ ionic_dev_setup(struct ionic_adapter *adapter)
 		return -EFAULT;
 	}
 
+	for (i = 0; i < IONIC_DEVINFO_FWVERS_BUFLEN; i++)
+		adapter->fw_version[i] =
+				ioread8(&idev->dev_info->fw_version[i]);
+	adapter->fw_version[IONIC_DEVINFO_FWVERS_BUFLEN - 1] = '\0';
+
+	ionic_init_print(DEBUG, "Firmware version: %s", adapter->fw_version);
+
 	/* BAR1: doorbells */
 	bar++;
 	if (num_bars < 2) {
diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c
index 720598dbd..95d82a5ca 100644
--- a/drivers/net/ionic/ionic_ethdev.c
+++ b/drivers/net/ionic/ionic_ethdev.c
@@ -56,6 +56,8 @@ static int  ionic_dev_xstats_get_names(struct rte_eth_dev *dev,
 static int  ionic_dev_xstats_get_names_by_id(struct rte_eth_dev *dev,
 		struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
 		unsigned int limit);
+static int  ionic_dev_fw_version_get(struct rte_eth_dev *eth_dev,
+		char *fw_version, size_t fw_size);
 
 int ionic_logtype_init;
 int ionic_logtype_driver;
@@ -123,6 +125,7 @@ static const struct eth_dev_ops ionic_eth_dev_ops = {
 	.xstats_reset           = ionic_dev_xstats_reset,
 	.xstats_get_names       = ionic_dev_xstats_get_names,
 	.xstats_get_names_by_id = ionic_dev_xstats_get_names_by_id,
+	.fw_version_get         = ionic_dev_fw_version_get,
 };
 
 /*
@@ -220,6 +223,23 @@ static const struct rte_ionic_xstats_name_off rte_ionic_xstats_strings[] = {
 #define IONIC_NB_HW_STATS (sizeof(rte_ionic_xstats_strings) / \
 		sizeof(rte_ionic_xstats_strings[0]))
 
+static int
+ionic_dev_fw_version_get(struct rte_eth_dev *eth_dev,
+		char *fw_version, size_t fw_size)
+{
+	struct ionic_lif *lif = IONIC_ETH_DEV_TO_LIF(eth_dev);
+	struct ionic_adapter *adapter = lif->adapter;
+
+	if (fw_version == NULL || fw_size <= 0)
+		return -EINVAL;
+
+	snprintf(fw_version, fw_size, "%s",
+		 adapter->fw_version);
+	fw_version[fw_size - 1] = '\0';
+
+	return 0;
+}
+
 /*
  * Set device link up, enable tx.
  */


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [dpdk-dev] [PATCH 03/17] net/ionic: add log
  2019-10-12  0:26 ` [dpdk-dev] [PATCH 03/17] net/ionic: add log Alfredo Cardigliano
@ 2019-10-12 15:23   ` Stephen Hemminger
  0 siblings, 0 replies; 23+ messages in thread
From: Stephen Hemminger @ 2019-10-12 15:23 UTC (permalink / raw)
  To: Alfredo Cardigliano; +Cc: dev

On Sat, 12 Oct 2019 02:26:41 +0200
Alfredo Cardigliano <cardigliano@ntop.org> wrote:

> +#ifdef RTE_LIBRTE_IONIC_DEBUG_RX
> +#define ionic_rx_print(level, fmt, args...) RTE_LOG(level, PMD, \
> +		"%s(): " fmt "\n", __func__, ## args)
> +#else
> +#define ionic_rx_print(level, fmt, args...) do { } while (0)
> +#endif
> +
> +#ifdef RTE_LIBRTE_IONIC_DEBUG_TX
> +#define ionic_tx_print(level, fmt, args...) RTE_LOG(level, PMD, \
> +		"%s(): " fmt "\n", __func__, ## args)

Please do not add new use of LOGTYPE_PMD, add another level to your existing logtype

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [dpdk-dev] [PATCH 06/17] net/ionic: add basic lif support
  2019-10-12  0:26 ` [dpdk-dev] [PATCH 06/17] net/ionic: add basic lif support Alfredo Cardigliano
@ 2019-10-12 15:26   ` Stephen Hemminger
  0 siblings, 0 replies; 23+ messages in thread
From: Stephen Hemminger @ 2019-10-12 15:26 UTC (permalink / raw)
  To: Alfredo Cardigliano; +Cc: dev

On Sat, 12 Oct 2019 02:26:57 +0200
Alfredo Cardigliano <cardigliano@ntop.org> wrote:

> @@ -37,6 +37,7 @@ ifeq ($(shell test $(GCC_VERSION) -ge 44 && echo 1), 1)
>  CFLAGS += -Wno-deprecated -Wno-unused-parameter -Wno-unused-value
>  CFLAGS += -Wno-strict-aliasing -Wno-format-extra-args
>  CFLAGS += -Wno-missing-field-initializers -Wno-pointer-arith
> +CFLAGS += -Wno-deprecated-declarations
>  endif

Please fix your code instead of turning off warnings.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [dpdk-dev] [PATCH 00/17] Series short description
  2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
                   ` (16 preceding siblings ...)
  2019-10-12  0:27 ` [dpdk-dev] [PATCH 17/17] net/ionic: read fw version Alfredo Cardigliano
@ 2019-10-12 15:28 ` Stephen Hemminger
  2019-10-14  7:16   ` Alfredo Cardigliano
  17 siblings, 1 reply; 23+ messages in thread
From: Stephen Hemminger @ 2019-10-12 15:28 UTC (permalink / raw)
  To: Alfredo Cardigliano; +Cc: dev

On Sat, 12 Oct 2019 02:26:26 +0200
Alfredo Cardigliano <cardigliano@ntop.org> wrote:

> The patch series provides an initial version of a
> poll mode driver for Pensando network adapters.
> The driver name is ionic.
> 
> ---
> 
> Alfredo Cardigliano (17):
>       net/ionic: add skeleton
>       net/ionic: add hardware structures definitions
>       net/ionic: add log
>       net/ionic: register and initialize the adapter
>       net/ionic: add port management commands
>       net/ionic: add basic lif support
>       net/ionic: add doorbells
>       net/ionic: add adminq support
>       net/ionic: add notifyq support
>       net/ionic: add basic port operations
>       net/ionic: add RX filters support
>       net/ionic: net-ionic-add-flow-control-support
>       net/ionic: add RSS support
>       net/ionic: add RX and TX handling
>       net/ionic: add stats
>       net/ionic: add TX checksum support
>       net/ionic: read fw version
> 

When adding a new driver, could you send it as
one unit, yes it is a big bit of code to review but
drippling it out in pieces doesn't make review easier.


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [dpdk-dev] [PATCH 00/17] Series short description
  2019-10-12 15:28 ` [dpdk-dev] [PATCH 00/17] Series short description Stephen Hemminger
@ 2019-10-14  7:16   ` Alfredo Cardigliano
  2019-10-14  7:56     ` Andrew Rybchenko
  0 siblings, 1 reply; 23+ messages in thread
From: Alfredo Cardigliano @ 2019-10-14  7:16 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev

Hi Stephen
yes, we were thinking of doing a single post for just that reason, 
but Thomas recommended that we split it up.

Thank you
Alfredo

> On 12 Oct 2019, at 17:28, Stephen Hemminger <stephen@networkplumber.org> wrote:
> 
> On Sat, 12 Oct 2019 02:26:26 +0200
> Alfredo Cardigliano <cardigliano@ntop.org> wrote:
> 
>> The patch series provides an initial version of a
>> poll mode driver for Pensando network adapters.
>> The driver name is ionic.
>> 
>> ---
>> 
>> Alfredo Cardigliano (17):
>>      net/ionic: add skeleton
>>      net/ionic: add hardware structures definitions
>>      net/ionic: add log
>>      net/ionic: register and initialize the adapter
>>      net/ionic: add port management commands
>>      net/ionic: add basic lif support
>>      net/ionic: add doorbells
>>      net/ionic: add adminq support
>>      net/ionic: add notifyq support
>>      net/ionic: add basic port operations
>>      net/ionic: add RX filters support
>>      net/ionic: net-ionic-add-flow-control-support
>>      net/ionic: add RSS support
>>      net/ionic: add RX and TX handling
>>      net/ionic: add stats
>>      net/ionic: add TX checksum support
>>      net/ionic: read fw version
>> 
> 
> When adding a new driver, could you send it as
> one unit, yes it is a big bit of code to review but
> drippling it out in pieces doesn't make review easier.
> 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [dpdk-dev] [PATCH 00/17] Series short description
  2019-10-14  7:16   ` Alfredo Cardigliano
@ 2019-10-14  7:56     ` Andrew Rybchenko
  0 siblings, 0 replies; 23+ messages in thread
From: Andrew Rybchenko @ 2019-10-14  7:56 UTC (permalink / raw)
  To: Alfredo Cardigliano, Stephen Hemminger; +Cc: dev

On 10/14/19 10:16 AM, Alfredo Cardigliano wrote:
> Hi Stephen
> yes, we were thinking of doing a single post for just that reason,
> but Thomas recommended that we split it up.

I agree with Thomas that it is better to split it up.
What I don't understand from the list below is, for example,
why RSS goes before Rx/Tx handling.  Ideally, it should be
no dead code in patches, the driver should be buildable
from patch #1 and subsequent patches should add more
and more functionality which is testable. Of course, it is
not always doable, for example when a base driver should
be added first, but it does not look so in this case.

> Thank you
> Alfredo
>
>> On 12 Oct 2019, at 17:28, Stephen Hemminger <stephen@networkplumber.org> wrote:
>>
>> On Sat, 12 Oct 2019 02:26:26 +0200
>> Alfredo Cardigliano <cardigliano@ntop.org> wrote:
>>
>>> The patch series provides an initial version of a
>>> poll mode driver for Pensando network adapters.
>>> The driver name is ionic.
>>>
>>> ---
>>>
>>> Alfredo Cardigliano (17):
>>>       net/ionic: add skeleton
>>>       net/ionic: add hardware structures definitions
>>>       net/ionic: add log
>>>       net/ionic: register and initialize the adapter
>>>       net/ionic: add port management commands
>>>       net/ionic: add basic lif support
>>>       net/ionic: add doorbells
>>>       net/ionic: add adminq support
>>>       net/ionic: add notifyq support
>>>       net/ionic: add basic port operations
>>>       net/ionic: add RX filters support
>>>       net/ionic: net-ionic-add-flow-control-support
>>>       net/ionic: add RSS support
>>>       net/ionic: add RX and TX handling
>>>       net/ionic: add stats
>>>       net/ionic: add TX checksum support
>>>       net/ionic: read fw version
>>>
>> When adding a new driver, could you send it as
>> one unit, yes it is a big bit of code to review but
>> drippling it out in pieces doesn't make review easier.
>>


^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, back to index

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-12  0:26 [dpdk-dev] [PATCH 00/17] Series short description Alfredo Cardigliano
2019-10-12  0:26 ` [dpdk-dev] [PATCH 01/17] net/ionic: add skeleton Alfredo Cardigliano
2019-10-12  0:26 ` [dpdk-dev] [PATCH 02/17] net/ionic: add hardware structures definitions Alfredo Cardigliano
2019-10-12  0:26 ` [dpdk-dev] [PATCH 03/17] net/ionic: add log Alfredo Cardigliano
2019-10-12 15:23   ` Stephen Hemminger
2019-10-12  0:26 ` [dpdk-dev] [PATCH 04/17] net/ionic: register and initialize the adapter Alfredo Cardigliano
2019-10-12  0:26 ` [dpdk-dev] [PATCH 05/17] net/ionic: add port management commands Alfredo Cardigliano
2019-10-12  0:26 ` [dpdk-dev] [PATCH 06/17] net/ionic: add basic lif support Alfredo Cardigliano
2019-10-12 15:26   ` Stephen Hemminger
2019-10-12  0:27 ` [dpdk-dev] [PATCH 07/17] net/ionic: add doorbells Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 08/17] net/ionic: add adminq support Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 09/17] net/ionic: add notifyq support Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 10/17] net/ionic: add basic port operations Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 11/17] net/ionic: add RX filters support Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 12/17] net/ionic: net-ionic-add-flow-control-support Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 13/17] net/ionic: add RSS support Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 14/17] net/ionic: add RX and TX handling Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 15/17] net/ionic: add stats Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 16/17] net/ionic: add TX checksum support Alfredo Cardigliano
2019-10-12  0:27 ` [dpdk-dev] [PATCH 17/17] net/ionic: read fw version Alfredo Cardigliano
2019-10-12 15:28 ` [dpdk-dev] [PATCH 00/17] Series short description Stephen Hemminger
2019-10-14  7:16   ` Alfredo Cardigliano
2019-10-14  7:56     ` Andrew Rybchenko

DPDK-dev Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/dpdk-dev/0 dpdk-dev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 dpdk-dev dpdk-dev/ https://lore.kernel.org/dpdk-dev \
		dev@dpdk.org
	public-inbox-index dpdk-dev

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.dpdk.dev


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git