From patchwork Thu Dec 19 22:18:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64014 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 572B4A04F3; Thu, 19 Dec 2019 23:19:05 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id C5A591BF73; Thu, 19 Dec 2019 23:18:58 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id 831821B9BF for ; Thu, 19 Dec 2019 23:18:53 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id 17E8C401BF; Thu, 19 Dec 2019 23:18:53 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793933; bh=pPRd95btk/meX+Aii1QqMg9uTB4nIJ7ayi0JOB2AcwI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GDGg5GyD9CNPWa29SalwRwWFJ0wi1SgTNWHTALF5EzuTUqZzg1bZM9FkON+m2kXaM w1Z7zfmgtf6o6AtByAaIK9YIOXpP12dCPLsea5uiDyPgmYJ1k0jXbPGSReN08wOFd6 NruALpw1Hc8eF9IeH6jwn2QPhIbI1drpep5PdnlE= From: Alfredo Cardigliano To: Thomas Monjalon , Alfredo Cardigliano , John McNamara , Marko Kovacevic Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:31 +0100 Message-Id: <20191219221847.29989-2-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 01/17] net/ionic: add skeleton X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "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 Reviewed-by: Shannon Nelson --- MAINTAINERS | 6 +++ config/common_armv8a_linux | 2 + config/common_base | 5 +++ config/defconfig_arm-armv7a-linuxapp-gcc | 1 + config/defconfig_ppc_64-power8-linuxapp-gcc | 1 + doc/guides/nics/features/ionic.ini | 8 ++++ doc/guides/nics/index.rst | 1 + doc/guides/nics/ionic.rst | 43 +++++++++++++++++++++ doc/guides/rel_notes/release_20_02.rst | 4 ++ drivers/net/Makefile | 1 + drivers/net/ionic/Makefile | 25 ++++++++++++ drivers/net/ionic/meson.build | 6 +++ drivers/net/ionic/rte_pmd_ionic_version.map | 5 +++ mk/rte.app.mk | 1 + 14 files changed, 109 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 4395d8df1..bb4422344 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -810,6 +810,12 @@ F: doc/guides/nics/pfe.rst F: drivers/net/pfe/ F: doc/guides/nics/features/pfe.ini +Pensando ionic +M: Alfredo Cardigliano +F: drivers/net/ionic/ +F: doc/guides/nics/ionic.rst +F: doc/guides/nics/features/ionic.ini + QLogic bnx2x M: Rasesh Mody M: Shahed Shaikh diff --git a/config/common_armv8a_linux b/config/common_armv8a_linux index 782877bb2..2057d9138 100644 --- a/config/common_armv8a_linux +++ b/config/common_armv8a_linux @@ -42,3 +42,5 @@ CONFIG_RTE_LIBRTE_PMD_IOAT_RAWDEV=n CONFIG_RTE_LIBRTE_PFE_PMD=y CONFIG_RTE_SCHED_VECTOR=n + +CONFIG_RTE_LIBRTE_IONIC_PMD=n diff --git a/config/common_base b/config/common_base index 7dec7ed45..626c83d05 100644 --- a/config/common_base +++ b/config/common_base @@ -277,6 +277,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/config/defconfig_arm-armv7a-linuxapp-gcc b/config/defconfig_arm-armv7a-linuxapp-gcc index c91423f0e..6ac7f47e4 100644 --- a/config/defconfig_arm-armv7a-linuxapp-gcc +++ b/config/defconfig_arm-armv7a-linuxapp-gcc @@ -57,3 +57,4 @@ CONFIG_RTE_LIBRTE_NFP_PMD=n CONFIG_RTE_LIBRTE_HINIC_PMD=n CONFIG_RTE_LIBRTE_HNS3_PMD=n CONFIG_RTE_LIBRTE_PMD_IOAT_RAWDEV=n +CONFIG_RTE_LIBRTE_IONIC_PMD=n diff --git a/config/defconfig_ppc_64-power8-linuxapp-gcc b/config/defconfig_ppc_64-power8-linuxapp-gcc index b7b9d6f48..c917c4774 100644 --- a/config/defconfig_ppc_64-power8-linuxapp-gcc +++ b/config/defconfig_ppc_64-power8-linuxapp-gcc @@ -32,3 +32,4 @@ CONFIG_RTE_LIBRTE_AVP_PMD=n CONFIG_RTE_LIBRTE_HINIC_PMD=n CONFIG_RTE_LIBRTE_HNS3_PMD=n CONFIG_RTE_LIBRTE_PMD_IOAT_RAWDEV=n +CONFIG_RTE_LIBRTE_IONIC_PMD=n 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 d61c27fdf..7b5fea029 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..e81771cb2 --- /dev/null +++ b/doc/guides/nics/ionic.rst @@ -0,0 +1,43 @@ +.. SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) + Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved. + +IONIC Driver +============ + +The ionic driver provides support for Pensando server adapters. +It currently supports the below models: + +- `Naples DSC-25 +`_ +- `Naples DSC-100 +`_ + +Please visit https://pensando.io for more information. + +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. + +- ``CONFIG_RTE_LIBRTE_IONIC_PMD`` (default ``y``) + + Toggle compilation of ionic PMD. + +Building DPDK +------------- + +The ionic PMD driver supports UIO and VFIO, please refer to the +:ref:`DPDK documentation that comes with the DPDK suite ` +for instructions on how to build DPDK. diff --git a/doc/guides/rel_notes/release_20_02.rst b/doc/guides/rel_notes/release_20_02.rst index 0eaa45a76..133c34e50 100644 --- a/doc/guides/rel_notes/release_20_02.rst +++ b/doc/guides/rel_notes/release_20_02.rst @@ -56,6 +56,10 @@ New Features Also, make sure to start the actual text at the margin. ========================================================= +* **Added IONIC net PMD.** + + Added the new ``ionic`` net driver for Pensando Ethernet Network Adapters. + See the :doc:`../nics/ionic` NIC guide for more details on this new driver. Removed Items ------------- diff --git a/drivers/net/Makefile b/drivers/net/Makefile index cee30367a..63a52ee79 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..9c2f9cf2e --- /dev/null +++ b/drivers/net/ionic/Makefile @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) +# 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 + +LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring +LDLIBS += -lrte_ethdev -lrte_net +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..5386e23ca --- /dev/null +++ b/drivers/net/ionic/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) +# Copyright(c) 2019 Pensando + +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..3fb4ff7eb --- /dev/null +++ b/drivers/net/ionic/rte_pmd_ionic_version.map @@ -0,0 +1,5 @@ +DPDK_20.0 { + + local: *; +}; + diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 05ea034b9..57f5f77de 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -183,6 +183,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 From patchwork Thu Dec 19 22:18:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64015 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 730FEA04F3; Thu, 19 Dec 2019 23:19:14 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 62F931BF7B; Thu, 19 Dec 2019 23:19:01 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id E02421B9BF for ; Thu, 19 Dec 2019 23:18:53 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id 823F63FAB6; Thu, 19 Dec 2019 23:18:53 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793933; bh=oLc+8Ze44uURbt/dueVSTzlaN6lO3jDpfBtxW94wISI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gOKoVSKVJdOjBtK30QQgiZQAYZstzB6EnHGZ+CGdDM3Ns/VbfwW3TLgahcWOPPLlP qcWjgwK6PqTBLtREAIePsvtF7dxEGUVXWotyM3H6UTdgFgn5ZiwJj3E4fxyW0XD3MR 1Ten61qtCdvU+2S77Zsek07VIsKZcIrHl5raYXYk= From: Alfredo Cardigliano To: Alfredo Cardigliano Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:32 +0100 Message-Id: <20191219221847.29989-3-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 02/17] net/ionic: add hardware structures definitions X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add hardware structures and message commands definitions for Pensando network adapters. Signed-off-by: Alfredo Cardigliano Reviewed-by: Shannon Nelson --- 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..b3d1c85dc --- /dev/null +++ b/drivers/net/ionic/ionic_if.h @@ -0,0 +1,2491 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB OR BSD-3-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_ */ From patchwork Thu Dec 19 22:18:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64016 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id C6829A04F3; Thu, 19 Dec 2019 23:19:24 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 5D8081BF81; Thu, 19 Dec 2019 23:19:04 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id 41B551B9BF for ; Thu, 19 Dec 2019 23:18:54 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id F2AF13FAB6; Thu, 19 Dec 2019 23:18:53 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793934; bh=U+lUxmutKNWsIXT/fH1X1r0ksseoC+Sh0f214lbZoqs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mptjgtJJC+EJJio/aoI9HOPeN4KwRkeSdoOSDniY7uXkVi4f9RC8B4KjyXFGbgqYv aFDOI2APZlYB3CL4eFYCaCGxmgmRQPhhoaaVyiuHoP865JgXp/yIPy8mfyVrr4Yy+C 4ta5XmYAokDSAjPhIwyEtR3qZ0bCl9S5dO4iUHcs= From: Alfredo Cardigliano To: Alfredo Cardigliano Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:33 +0100 Message-Id: <20191219221847.29989-4-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 03/17] net/ionic: add log X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "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 Reviewed-by: Shannon Nelson --- drivers/net/ionic/Makefile | 2 +- drivers/net/ionic/ionic_ethdev.c | 15 +++++++++++++++ drivers/net/ionic/ionic_logs.h | 26 ++++++++++++++++++++++++++ drivers/net/ionic/meson.build | 1 + 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ionic/ionic_ethdev.c create mode 100644 drivers/net/ionic/ionic_logs.h diff --git a/drivers/net/ionic/Makefile b/drivers/net/ionic/Makefile index 9c2f9cf2e..baa34b055 100644 --- a/drivers/net/ionic/Makefile +++ b/drivers/net/ionic/Makefile @@ -20,6 +20,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..f19de85a9 --- /dev/null +++ b/drivers/net/ionic/ionic_ethdev.c @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) + * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved. + */ + +#include "ionic_logs.h" + +int ionic_logtype; + +RTE_INIT(ionic_init_log) +{ + ionic_logtype = rte_log_register("pmd.net.ionic"); + + if (ionic_logtype >= 0) + rte_log_set_level(ionic_logtype, 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..bc10ad174 --- /dev/null +++ b/drivers/net/ionic/ionic_logs.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) + * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved. + */ + +#ifndef _IONIC_LOGS_H_ +#define _IONIC_LOGS_H_ + +#include + +extern int ionic_logtype; + +#define IONIC_PRINT(level, fmt, args...) rte_log(RTE_LOG_ ## level, \ + ionic_logtype, "%s(): " fmt "\n", __func__, ##args) + +#define IONIC_PRINT_CALL() IONIC_PRINT(DEBUG, " >>") + +#ifndef IONIC_WARN_ON +#define IONIC_WARN_ON(x) do { \ + int ret = !!(x); \ + if (unlikely(ret)) \ + IONIC_PRINT(WARNING, "WARN_ON: \"" #x "\" at %s:%d\n", \ + __func__, __LINE__); \ +} while (0) +#endif + +#endif /* _IONIC_LOGS_H_ */ diff --git a/drivers/net/ionic/meson.build b/drivers/net/ionic/meson.build index 5386e23ca..f5e3c36c9 100644 --- a/drivers/net/ionic/meson.build +++ b/drivers/net/ionic/meson.build @@ -2,5 +2,6 @@ # Copyright(c) 2019 Pensando sources = files( + 'ionic_ethdev.c' ) From patchwork Thu Dec 19 22:18:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64017 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id C52BBA04F3; Thu, 19 Dec 2019 23:19:38 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id E638C1BF8F; Thu, 19 Dec 2019 23:19:07 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id B8B4B1B9BF for ; Thu, 19 Dec 2019 23:18:54 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id 5783A3FAB6; Thu, 19 Dec 2019 23:18:54 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793934; bh=XUat0FY75MxHSZnO4a9S6x3FNrpp2qnNUYnPqMQkd5U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pTrySQKcR/opnz6dhTMMYJC5naRaqP4PS9Bu96F3Q2TI5I8Ns//4kthDGbB5U2qlj YUhChvM4QyxSRnGDbXidIRbwdRhsV6BsTYa1ra68FhTlRDF9t60mZ5m9xo4VQ/B4EJ JTqP8qBjEtVx0OpJBe+4OcG6f9LSuYr0YRr2uV0c= From: Alfredo Cardigliano To: Alfredo Cardigliano , John McNamara , Marko Kovacevic , Anatoly Burakov Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:34 +0100 Message-Id: <20191219221847.29989-5-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 04/17] net/ionic: register and initialize the adapter X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Register the Pensando ionic PMD (net_ionic) and define initial probe and remove callbacks with adapter initialization. Signed-off-by: Alfredo Cardigliano Reviewed-by: Shannon Nelson --- doc/guides/nics/features/ionic.ini | 2 + drivers/net/ionic/Makefile | 3 + drivers/net/ionic/ionic.h | 63 +++++++++++++ drivers/net/ionic/ionic_dev.c | 134 +++++++++++++++++++++++++++ drivers/net/ionic/ionic_dev.h | 127 ++++++++++++++++++++++++++ drivers/net/ionic/ionic_ethdev.c | 118 ++++++++++++++++++++++++ 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, 879 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 baa34b055..31abe5b95 100644 --- a/drivers/net/ionic/Makefile +++ b/drivers/net/ionic/Makefile @@ -20,6 +20,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..5c869e698 --- /dev/null +++ b/drivers/net/ionic/ionic.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) + * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved. + */ + +#ifndef _IONIC_H_ +#define _IONIC_H_ + +#include + +#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..a8ad5358f --- /dev/null +++ b/drivers/net/ionic/ionic_dev.c @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) + * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved. + */ + +#include + +#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; + u_char *bar0_base; + + /* BAR0: dev_cmd and interrupts */ + if (num_bars < 1) { + IONIC_PRINT(ERR, "No bars found, aborting"); + return -EFAULT; + } + + if (bar->len < IONIC_BAR0_SIZE) { + IONIC_PRINT(ERR, + "Resource bar size %lu too small, aborting", + bar->len); + return -EFAULT; + } + + bar0_base = bar->vaddr; + idev->dev_info = (union ionic_dev_info_regs *) + &bar0_base[IONIC_BAR0_DEV_INFO_REGS_OFFSET]; + idev->dev_cmd = (union ionic_dev_cmd_regs *) + &bar0_base[IONIC_BAR0_DEV_CMD_REGS_OFFSET]; + idev->intr_status = (struct ionic_intr_status *) + &bar0_base[IONIC_BAR0_INTR_STATUS_OFFSET]; + idev->intr_ctrl = (struct ionic_intr *) + &bar0_base[IONIC_BAR0_INTR_CTRL_OFFSET]; + + sig = ioread32(&idev->dev_info->signature); + if (sig != IONIC_DEV_INFO_SIGNATURE) { + IONIC_PRINT(ERR, "Incompatible firmware signature %" PRIx32 "", + sig); + return -EFAULT; + } + + /* BAR1: doorbells */ + bar++; + if (num_bars < 2) { + IONIC_PRINT(ERR, "Doorbell bar missing, aborting"); + 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..82a3cdb70 --- /dev/null +++ b/drivers/net/ionic/ionic_dev.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR 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" + +#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 f19de85a9..a6154ddc1 100644 --- a/drivers/net/ionic/ionic_ethdev.c +++ b/drivers/net/ionic/ionic_ethdev.c @@ -2,10 +2,128 @@ * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved. */ +#include +#include +#include +#include +#include + #include "ionic_logs.h" +#include "ionic.h" +#include "ionic_dev.h" +#include "ionic_mac_api.h" int ionic_logtype; +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 */ }, +}; + +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; + + /* Check structs (trigger error at compilation time) */ + ionic_struct_size_checks(); + + /* Multi-process not supported */ + if (rte_eal_process_type() != RTE_PROC_PRIMARY) { + err = -EPERM; + goto err; + } + + IONIC_PRINT(DEBUG, "Initializing device %s", + pci_dev->device.name); + + adapter = rte_zmalloc("ionic", sizeof(*adapter), 0); + + if (!adapter) { + IONIC_PRINT(ERR, "OOM"); + err = -ENOMEM; + goto err; + } + + 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_PRINT(ERR, "Mac init failed: %d", err); + err = -EIO; + goto err_free_adapter; + } + + 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_PRINT(ERR, "Cannot setup device: %d, aborting", err); + goto err_free_adapter; + } + + err = ionic_identify(adapter); + if (err) { + IONIC_PRINT(ERR, "Cannot identify device: %d, aborting", + err); + goto err_free_adapter; + } + + err = ionic_init(adapter); + if (err) { + IONIC_PRINT(ERR, "Cannot init device: %d, aborting", err); + goto err_free_adapter; + } + + return 0; + +err_free_adapter: + rte_free(adapter); +err: + return err; +} + +static int +eth_ionic_pci_remove(struct rte_pci_device *pci_dev) +{ + 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 = rte_log_register("pmd.net.ionic"); diff --git a/drivers/net/ionic/ionic_mac_api.c b/drivers/net/ionic/ionic_mac_api.c new file mode 100644 index 000000000..189b8b81a --- /dev/null +++ b/drivers/net/ionic/ionic_mac_api.c @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR 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_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_PRINT_CALL(); + + if (hw->vendor_id != IONIC_PENSANDO_VENDOR_ID) { + IONIC_PRINT(ERR, "Unsupported vendor id: %" PRIx32 "", + 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_PRINT(ERR, "Unsupported device id: %" PRIx32 "", + hw->device_id); + break; + } + + IONIC_PRINT(INFO, "Mac: %d (%d)", + 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..ed9e059a6 --- /dev/null +++ b/drivers/net/ionic/ionic_mac_api.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR 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..572316c84 --- /dev/null +++ b/drivers/net/ionic/ionic_main.c @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR 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_PRINT(DEBUG, "DEVCMD %d done took %ld msecs", + 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_PRINT(DEBUG, "DEVCMD %d timeout after %ld msecs", + 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..09a0e85b5 --- /dev/null +++ b/drivers/net/ionic/ionic_osdep.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) + * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved. + */ + +#ifndef _IONIC_OSDEP_ +#define _IONIC_OSDEP_ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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..3adc2bc7c --- /dev/null +++ b/drivers/net/ionic/ionic_regs.h @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR 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 f5e3c36c9..8de34ca5a 100644 --- a/drivers/net/ionic/meson.build +++ b/drivers/net/ionic/meson.build @@ -2,6 +2,10 @@ # Copyright(c) 2019 Pensando sources = files( + 'ionic_mac_api.c', + 'ionic_dev.c', + 'ionic_ethdev.c', + 'ionic_main.c', 'ionic_ethdev.c' ) From patchwork Thu Dec 19 22:18:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64018 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 453F9A04F3; Thu, 19 Dec 2019 23:19:47 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 18CB31BF83; Thu, 19 Dec 2019 23:19:10 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id 183581B9BF for ; Thu, 19 Dec 2019 23:18:55 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id C9D234090E; Thu, 19 Dec 2019 23:18:54 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793934; bh=nQI5u20Deemn+TrG9fYduJOdpCFIYbojacIbaD1d/nk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AbccYkIMgPxJWCBYI2TrQsolQfzLj8YHm7lVkD0Bs8aRgwzWCYSbkJDkU+eTfmg35 fkaKrH8fD7OMy+SKh9BQUxwbqPmHJY5YKDNHOvPjFn8S8hX6uEaBKipys3ivm6ueVn uhA06Fg2IDzNfEj0Jix89YhOc+J3dVDumkkU0ZLY= From: Alfredo Cardigliano To: Alfredo Cardigliano Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:35 +0100 Message-Id: <20191219221847.29989-6-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 05/17] net/ionic: add port management commands X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "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 Reviewed-by: Shannon Nelson --- 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 5c869e698..a29f0bb89 100644 --- a/drivers/net/ionic/ionic.h +++ b/drivers/net/ionic/ionic.h @@ -7,6 +7,8 @@ #include +#include + #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 a8ad5358f..d74834122 100644 --- a/drivers/net/ionic/ionic_dev.c +++ b/drivers/net/ionic/ionic_dev.c @@ -132,3 +132,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 82a3cdb70..75c50d4cb 100644 --- a/drivers/net/ionic/ionic_dev.h +++ b/drivers/net/ionic/ionic_dev.h @@ -10,6 +10,7 @@ #include "ionic_regs.h" #define IONIC_DEVCMD_TIMEOUT 30 /* devcmd_timeout */ +#define IONIC_ALIGN 4096 struct ionic_adapter; @@ -111,6 +112,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); @@ -124,4 +130,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 a6154ddc1..cbb70125b 100644 --- a/drivers/net/ionic/ionic_ethdev.c +++ b/drivers/net/ionic/ionic_ethdev.c @@ -99,6 +99,22 @@ eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, goto err_free_adapter; } + /* Configure the ports */ + err = ionic_port_identify(adapter); + + if (err) { + IONIC_PRINT(ERR, "Cannot identify port: %d, aborting", + err); + goto err_free_adapter; + } + + err = ionic_port_init(adapter); + + if (err) { + IONIC_PRINT(ERR, "Cannot init port: %d, aborting", err); + goto err_free_adapter; + } + return 0; err_free_adapter: diff --git a/drivers/net/ionic/ionic_main.c b/drivers/net/ionic/ionic_main.c index 572316c84..da558cdce 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 + #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_PRINT(INFO, "speed %d ", ident->port.config.speed); + IONIC_PRINT(INFO, "mtu %d ", ident->port.config.mtu); + IONIC_PRINT(INFO, "state %d ", ident->port.config.state); + IONIC_PRINT(INFO, "an_enable %d ", ident->port.config.an_enable); + IONIC_PRINT(INFO, "fec_type %d ", ident->port.config.fec_type); + IONIC_PRINT(INFO, "pause_type %d ", ident->port.config.pause_type); + IONIC_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_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_PRINT(ERR, "Failed to init port"); + 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_PRINT(WARNING, "Failed to bring port UP"); + 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_PRINT(ERR, "Failed to reset port"); + return err; + } + + idev->port_info = NULL; + idev->port_info_pa = 0; + + return 0; +} From patchwork Thu Dec 19 22:18:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64019 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 91B26A04F3; Thu, 19 Dec 2019 23:19:54 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B63411BF9A; Thu, 19 Dec 2019 23:19:11 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id AB9451BE9D for ; Thu, 19 Dec 2019 23:18:55 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id 2C1094090E; Thu, 19 Dec 2019 23:18:55 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793935; bh=vvAklMfFVDN8XnAFBWSgrabxjeQsu37sbHUZpne7j2s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Y88F0VRxzjl5weidS+pLeS6ZLcUTVBRUkhHTqTTdBVuU5N14fdoaW4LSu0STUVysJ 86zKTEZmN/A5HkHLKHP6MHsjXIMDQhj/z6lftAz7A+dyu1DfnWlW6MlmznU0yyPVXg xH5+/tzTCCdm4XGbYPM9ayq2bnp/WC+ZfaCOl3vo= From: Alfredo Cardigliano To: Alfredo Cardigliano , Anatoly Burakov Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:36 +0100 Message-Id: <20191219221847.29989-7-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 06/17] net/ionic: add basic lif support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "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 Reviewed-by: Shannon Nelson --- drivers/net/ionic/Makefile | 4 + 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 | 140 +++++++++++++++++++++++++++++ drivers/net/ionic/ionic_ethdev.h | 14 +++ drivers/net/ionic/ionic_lif.c | 145 +++++++++++++++++++++++++++++++ drivers/net/ionic/ionic_lif.h | 48 ++++++++++ drivers/net/ionic/meson.build | 4 +- 9 files changed, 404 insertions(+), 2 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 31abe5b95..2dc88cdd5 100644 --- a/drivers/net/ionic/Makefile +++ b/drivers/net/ionic/Makefile @@ -8,6 +8,9 @@ include $(RTE_SDK)/mk/rte.vars.mk # LIB = librte_pmd_ionic.a +# Required to use rte_eth_dev_create and rte_eth_dev_destroy +CFLAGS += -DALLOW_EXPERIMENTAL_API + CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) @@ -23,6 +26,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 a29f0bb89..b6ef63161 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 d74834122..c63709ee8 100644 --- a/drivers/net/ionic/ionic_dev.c +++ b/drivers/net/ionic/ionic_dev.c @@ -259,3 +259,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 75c50d4cb..afcfcbf56 100644 --- a/drivers/net/ionic/ionic_dev.h +++ b/drivers/net/ionic/ionic_dev.h @@ -9,6 +9,8 @@ #include "ionic_if.h" #include "ionic_regs.h" +#define IONIC_LIFS_MAX 1024 + #define IONIC_DEVCMD_TIMEOUT 30 /* devcmd_timeout */ #define IONIC_ALIGN 4096 @@ -142,4 +144,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 cbb70125b..7f3645665 100644 --- a/drivers/net/ionic/ionic_ethdev.c +++ b/drivers/net/ionic/ionic_ethdev.c @@ -7,11 +7,17 @@ #include #include #include +#include #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; @@ -22,10 +28,83 @@ static const struct rte_pci_id pci_id_ionic_map[] = { { .vendor_id = 0, /* sentinel */ }, }; +static const struct eth_dev_ops ionic_eth_dev_ops = { +}; + +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_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_PRINT(ERR, "Cannot allocate LIFs: %d, aborting", + err); + goto err; + } + + err = ionic_lif_init(lif); + + if (err) { + IONIC_PRINT(ERR, "Cannot init LIFs: %d, aborting", err); + goto err_free_lif; + } + + IONIC_PRINT(DEBUG, "Port %u initialized", eth_dev->data->port_id); + + return 0; + +err_free_lif: + ionic_lif_free(lif); +err: + return err; +} + +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_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; @@ -115,6 +194,41 @@ eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, goto err_free_adapter; } + /* Configure LIFs */ + err = ionic_lif_identify(adapter); + + if (err) { + IONIC_PRINT(ERR, "Cannot identify lif: %d, aborting", err); + goto err_free_adapter; + } + + /* Allocate and init LIFs */ + err = ionic_lifs_size(adapter); + + if (err) { + IONIC_PRINT(ERR, "Cannot size LIFs: %d, aborting", err); + goto err_free_adapter; + } + + 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_PRINT(ERR, "Cannot create eth device for " + "ionic lif %s", name); + break; + } + + adapter->nlifs++; + } + return 0; err_free_adapter: @@ -126,6 +240,32 @@ eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, static int eth_ionic_pci_remove(struct rte_pci_device *pci_dev) { + char name[RTE_ETH_NAME_MAX_LEN]; + struct ionic_adapter *adapter = NULL; + struct rte_eth_dev *eth_dev; + struct ionic_lif *lif; + uint32_t i; + + /* Adapter lookup is using (the first) eth_dev name */ + snprintf(name, sizeof(name), "net_%s_lif_0", + pci_dev->device.name); + + eth_dev = rte_eth_dev_allocated(name); + + if (eth_dev) { + lif = IONIC_ETH_DEV_TO_LIF(eth_dev); + adapter = lif->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..7228d8969 --- /dev/null +++ b/drivers/net/ionic/ionic_ethdev.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR 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..0728738e7 --- /dev/null +++ b/drivers/net/ionic/ionic_lif.c @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) + * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved. + */ + +#include +#include + +#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_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_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); + lif->info = NULL; + } +} + +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_PRINT(INFO, "capabilities 0x%" PRIx64 " ", + ident->lif.capabilities); + + IONIC_PRINT(INFO, "eth.max_ucast_filters 0x%" PRIx32 " ", + ident->lif.eth.max_ucast_filters); + IONIC_PRINT(INFO, "eth.max_mcast_filters 0x%" PRIx32 " ", + ident->lif.eth.max_mcast_filters); + + IONIC_PRINT(INFO, "eth.features 0x%" PRIx64 " ", + ident->lif.eth.config.features); + IONIC_PRINT(INFO, "eth.queue_count[IONIC_QTYPE_ADMINQ] 0x%" PRIx32 " ", + ident->lif.eth.config.queue_count[IONIC_QTYPE_ADMINQ]); + IONIC_PRINT(INFO, "eth.queue_count[IONIC_QTYPE_NOTIFYQ] 0x%" PRIx32 " ", + ident->lif.eth.config.queue_count[IONIC_QTYPE_NOTIFYQ]); + IONIC_PRINT(INFO, "eth.queue_count[IONIC_QTYPE_RXQ] 0x%" PRIx32 " ", + ident->lif.eth.config.queue_count[IONIC_QTYPE_RXQ]); + IONIC_PRINT(INFO, "eth.queue_count[IONIC_QTYPE_TXQ] 0x%" PRIx32 " ", + 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_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..49bceaccf --- /dev/null +++ b/drivers/net/ionic/ionic_lif.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) + * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved. + */ + +#ifndef _IONIC_LIF_H_ +#define _IONIC_LIF_H_ + +#include + +#include +#include + +#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_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 8de34ca5a..f28016105 100644 --- a/drivers/net/ionic/meson.build +++ b/drivers/net/ionic/meson.build @@ -5,7 +5,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' ) From patchwork Thu Dec 19 22:18:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64020 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id A6E0DA04F3; Thu, 19 Dec 2019 23:20:05 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 3F5B31BFA0; Thu, 19 Dec 2019 23:19:13 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id CE06D1BF70 for ; Thu, 19 Dec 2019 23:18:55 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id 874D441B6E; Thu, 19 Dec 2019 23:18:55 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793935; bh=N5oa1QDC0m9McXdR1dFsZpG3b0NG68QUhmFHom7Czvg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=s7EsampveJsQpv41vQyUElpLM7Sj/32xdHsDmo9i6gJyMCeN63+CpQkoAbdnLQWQI GeqHKYy2Zbo7AqkBLqfsrbMEqlHxdOGpeYEZb+XkKnlaW/+c1rNi2Dd6RpWy0zScJz I8QlRnjs3k7mXPWxBLiqtFj7Vnds08/Mv6c7mSyM= From: Alfredo Cardigliano To: Alfredo Cardigliano Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:37 +0100 Message-Id: <20191219221847.29989-8-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 07/17] net/ionic: add doorbells X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "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 Reviewed-by: Shannon Nelson --- 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 c63709ee8..13e99ace6 100644 --- a/drivers/net/ionic/ionic_dev.c +++ b/drivers/net/ionic/ionic_dev.c @@ -5,6 +5,7 @@ #include #include "ionic_dev.h" +#include "ionic_lif.h" #include "ionic.h" int @@ -297,3 +298,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 afcfcbf56..ca9807a9b 100644 --- a/drivers/net/ionic/ionic_dev.h +++ b/drivers/net/ionic/ionic_dev.h @@ -121,6 +121,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); @@ -150,4 +167,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 0728738e7..75085b0fc 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_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_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 49bceaccf..6e3233d1d 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; From patchwork Thu Dec 19 22:18:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64021 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id CDB59A04F3; Thu, 19 Dec 2019 23:20:14 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id DD3CC1BFA4; Thu, 19 Dec 2019 23:19:14 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id 2BFBD1BE9D for ; Thu, 19 Dec 2019 23:18:56 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id DD1C941B7E; Thu, 19 Dec 2019 23:18:55 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793936; bh=x8by12T3X08QxezroCDmPT/awOhym4H2KwHWFvo5T/k=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QTs+YSOx2GZ736UQ28lS/BO8OB8sdZMuUzbF9tyoUq36wMhAyvKbUrEUZ9ej9vj6q CxcGqCLWFNqVrYj0hOX+a1t7XzXNGGwkQZfeHJXieay5SQD7jqJArndl3p1I8+zRXp vQE1kffBu2Fz/9wriW8JzT3FbFnTQJsNssUB2i6o= From: Alfredo Cardigliano To: Alfredo Cardigliano Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:38 +0100 Message-Id: <20191219221847.29989-9-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 08/17] net/ionic: add adminq support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add support for the admin queue, which is used for most of the NIC configurations. Signed-off-by: Alfredo Cardigliano Reviewed-by: Shannon Nelson --- drivers/net/ionic/ionic.h | 3 + drivers/net/ionic/ionic_dev.c | 255 +++++++++++++++++++++++ drivers/net/ionic/ionic_dev.h | 95 ++++++++- drivers/net/ionic/ionic_lif.c | 356 +++++++++++++++++++++++++++++++++ drivers/net/ionic/ionic_lif.h | 36 ++++ drivers/net/ionic/ionic_main.c | 186 +++++++++++++++++ 6 files changed, 930 insertions(+), 1 deletion(-) diff --git a/drivers/net/ionic/ionic.h b/drivers/net/ionic/ionic.h index b6ef63161..7defb5fe0 100644 --- a/drivers/net/ionic/ionic.h +++ b/drivers/net/ionic/ionic.h @@ -55,11 +55,14 @@ 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_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 13e99ace6..e2cd15792 100644 --- a/drivers/net/ionic/ionic_dev.c +++ b/drivers/net/ionic/ionic_dev.c @@ -299,6 +299,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) { @@ -312,3 +318,252 @@ 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_PRINT(ERR, "Descriptor size is %zu", 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_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, 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 ca9807a9b..a832ff405 100644 --- a/drivers/net/ionic/ionic_dev.h +++ b/drivers/net/ionic/ionic_dev.h @@ -9,6 +9,9 @@ #include "ionic_if.h" #include "ionic_regs.h" +#define IONIC_MAX_RING_DESC 32768 +#define IONIC_MIN_RING_DESC 16 + #define IONIC_LIFS_MAX 1024 #define IONIC_DEVCMD_TIMEOUT 30 /* devcmd_timeout */ @@ -121,6 +124,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) @@ -129,11 +170,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); @@ -166,7 +230,36 @@ 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, 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 75085b0fc..8425881b7 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_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_PRINT(ERR, "Cannot allocate queue info"); + return -ENOMEM; + } + + new->q.type = type; + + err = ionic_q_init(lif, idev, &new->q, index, num_descs, + desc_size, sg_desc_size, pid); + + if (err) { + IONIC_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_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_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_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,11 +280,15 @@ 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_PRINT(DEBUG, "Allocating Lif Info"); + rte_spinlock_init(&lif->adminq_lock); + rte_spinlock_init(&lif->adminq_service_lock); + lif->kern_pid = 0; dbpage_num = ionic_db_page_num(lif, 0); @@ -43,6 +300,17 @@ ionic_lif_alloc(struct ionic_lif *lif) return -ENOMEM; } + IONIC_PRINT(DEBUG, "Allocating Admin Queue"); + + err = ionic_admin_qcq_alloc(lif); + + if (err) { + IONIC_PRINT(ERR, "Cannot allocate admin queue"); + return err; + } + + IONIC_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,12 +331,93 @@ 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); lif->info = NULL; } } +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_PRINT(DEBUG, "adminq->hw_type %d", q->hw_type); + IONIC_PRINT(DEBUG, "adminq->hw_index %d", q->hw_index); + IONIC_PRINT(DEBUG, "adminq->db %p", 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) { @@ -84,6 +433,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; @@ -95,6 +449,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 6e3233d1d..96522c544 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; @@ -47,4 +70,17 @@ int ionic_lif_start(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 da558cdce..0d7e27530 100644 --- a/drivers/net/ionic/ionic_main.c +++ b/drivers/net/ionic/ionic_main.c @@ -5,6 +5,192 @@ #include #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_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_PRINT(ERR, "%s (%d) failed: %s (%d)", + 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_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_PRINT(ERR, "Failure posting to the admin queue %d (%d)", + ctx->cmd.cmd.opcode, err); + + return err; + } + + done = ionic_wait_ctx_for_completion(lif, qcq, ctx, + IONIC_DEVCMD_TIMEOUT); + + err = ionic_adminq_check_err(ctx, !done /* timed out */); + + return err; +} static int ionic_dev_cmd_wait(struct ionic_dev *idev, unsigned long max_wait) From patchwork Thu Dec 19 22:18:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64022 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 4F13BA04F3; Thu, 19 Dec 2019 23:20:24 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 8D8CC1BFAA; Thu, 19 Dec 2019 23:19:16 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id 83CD51BE9D for ; Thu, 19 Dec 2019 23:18:56 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id 3CC5941B6E; Thu, 19 Dec 2019 23:18:56 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793936; bh=ch5DhdUKnPiCHAvd0GlYK1Q+oqoVb1eg3FNDCib0HLc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eU3un7h5q3tdG1Eahak8ni4zHP9exGuiaw4+ExKkfy+SfQIWkeF9WtY2Y0xU01R+I TxHo276XKKRzYDbD3ZzkfIx7rnQSJqGw8xFRdfMkYivEasRBR4KqHYJo7Jq6ovsYaR Iitn0Of5OlQyBE44as6jVfgtgqLlUnr21Vge5r3U= From: Alfredo Cardigliano To: Alfredo Cardigliano Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:39 +0100 Message-Id: <20191219221847.29989-10-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 09/17] net/ionic: add notifyq support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add support for the notify queue, which is used for events published by the NIC. Signed-off-by: Alfredo Cardigliano Reviewed-by: Shannon Nelson --- drivers/net/ionic/ionic.h | 2 + drivers/net/ionic/ionic_ethdev.c | 97 +++++++++++++++ drivers/net/ionic/ionic_lif.c | 196 ++++++++++++++++++++++++++++++- drivers/net/ionic/ionic_lif.h | 7 ++ 4 files changed, 301 insertions(+), 1 deletion(-) diff --git a/drivers/net/ionic/ionic.h b/drivers/net/ionic/ionic.h index 7defb5fe0..e7c8ad34b 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 7f3645665..01027f0d1 100644 --- a/drivers/net/ionic/ionic_ethdev.c +++ b/drivers/net/ionic/ionic_ethdev.c @@ -31,6 +31,30 @@ static const struct rte_pci_id pci_id_ionic_map[] = { static const struct eth_dev_ops ionic_eth_dev_ops = { }; +/** + * 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_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) { @@ -100,6 +124,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_PRINT(DEBUG, "Configuring %u intrs", adapter->nintrs); + + if (rte_intr_efd_enable(intr_handle, adapter->nintrs)) { + IONIC_PRINT(ERR, "Fail to create eventfd"); + return -1; + } + + if (rte_intr_dp_is_en(intr_handle)) + IONIC_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_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_PRINT(ERR, + "Failure registering interrupts handler (%d)", + err); + return err; + } + + /* enable intr mapping */ + err = rte_intr_enable(intr_handle); + + if (err) { + IONIC_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) @@ -229,6 +317,13 @@ eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, adapter->nlifs++; } + err = ionic_configure_intr(adapter); + + if (err) { + IONIC_PRINT(ERR, "Failed to configure interrupts"); + goto err_free_adapter; + } + return 0; err_free_adapter: @@ -258,6 +353,8 @@ eth_ionic_pci_remove(struct rte_pci_device *pci_dev) } 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 8425881b7..ae45e76db 100644 --- a/drivers/net/ionic/ionic_lif.c +++ b/drivers/net/ionic/ionic_lif.c @@ -29,7 +29,7 @@ ionic_qcq_enable(struct ionic_qcq *qcq) if (qcq->flags & IONIC_QCQ_F_INTR) { ionic_intr_mask(idev->intr_ctrl, qcq->intr.index, - IONIC_INTR_MASK_CLEAR); + IONIC_INTR_MASK_CLEAR); } return ionic_adminq_post_wait(lif, &ctx); @@ -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) { @@ -300,6 +322,17 @@ ionic_lif_alloc(struct ionic_lif *lif) return -ENOMEM; } + IONIC_PRINT(DEBUG, "Allocating Notify Queue"); + + err = ionic_notify_qcq_alloc(lif); + + if (err) { + IONIC_PRINT(ERR, "Cannot allocate notify queue"); + return err; + } + + IONIC_PRINT(DEBUG, "Allocating Admin Queue"); + IONIC_PRINT(DEBUG, "Allocating Admin Queue"); err = ionic_admin_qcq_alloc(lif); @@ -331,6 +364,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; @@ -385,6 +423,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_PRINT(DEBUG, "Link up - %d Gbps", + lif->info->status.link_speed); + adapter->link_speed = lif->info->status.link_speed; + } else { + IONIC_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_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_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_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_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) { @@ -418,6 +549,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_PRINT(DEBUG, "notifyq_init.pid %d", ctx.cmd.q_init.pid); + IONIC_PRINT(DEBUG, "notifyq_init.index %d", + ctx.cmd.q_init.index); + IONIC_PRINT(DEBUG, "notifyq_init.ring_base 0x%" PRIx64 "", + ctx.cmd.q_init.ring_base); + IONIC_PRINT(DEBUG, "notifyq_init.ring_size %d", + 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_PRINT(DEBUG, "notifyq->hw_type %d", q->hw_type); + IONIC_PRINT(DEBUG, "notifyq->hw_index %d", q->hw_index); + IONIC_PRINT(DEBUG, "notifyq->db %p", 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) { @@ -438,9 +621,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 @@ -449,6 +642,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 96522c544..78cf92db8 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; @@ -83,4 +88,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_ */ From patchwork Thu Dec 19 22:18:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64024 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 15F95A04F3; Thu, 19 Dec 2019 23:20:40 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id EF71E1BFB9; Thu, 19 Dec 2019 23:19:19 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id F23651BF70 for ; Thu, 19 Dec 2019 23:18:56 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id 94DDF41B6E; Thu, 19 Dec 2019 23:18:56 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793936; bh=vDF8XUbuVnjaTxSoqAka/2eQzItc50uqIS2HBbrCtKg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=X9YTULiGsltQUVk4hApoDUEUfOjbp1SGJ/LqsTU01XswE9qqtQyG7PX/3xfPoF17D jakG6WplqRqjaa9i3vv96JBp4kSSZQSQUqx0HkEb7iGetTBRRrdby7Bk52LFJPR7PI OxdNg6kRo7Tu14hCiNZj1zqx8rus6+cCuMogsMMo= From: Alfredo Cardigliano To: Alfredo Cardigliano , John McNamara , Marko Kovacevic Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:40 +0100 Message-Id: <20191219221847.29989-11-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 10/17] net/ionic: add basic port operations X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add support for port start/stop and handle basic features including mtu and link up/down. Signed-off-by: Alfredo Cardigliano Reviewed-by: Shannon Nelson --- 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 | 327 +++++++++++++++++++++++++++++ drivers/net/ionic/ionic_lif.c | 270 ++++++++++++++++++++++++ drivers/net/ionic/ionic_lif.h | 10 + 6 files changed, 615 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 e7c8ad34b..ae4f6acc7 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 a832ff405..61576621b 100644 --- a/drivers/net/ionic/ionic_dev.h +++ b/drivers/net/ionic/ionic_dev.h @@ -9,6 +9,9 @@ #include "ionic_if.h" #include "ionic_regs.h" +#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 01027f0d1..3f9988acc 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; @@ -29,8 +40,115 @@ 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, }; +/* + * 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_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_PRINT(WARNING, "Failed to bring port UP"); + 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_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_PRINT(WARNING, "Failed to bring port DOWN"); + 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_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. @@ -55,6 +173,194 @@ 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); + uint32_t max_frame_size; + int err; + + IONIC_PRINT_CALL(); + + /* + * Note: mtu check against IONIC_MIN_MTU, IONIC_MAX_MTU + * is done by the the API. + */ + + /* + * Max frame size is MTU + Ethernet header + VLAN + QinQ + * (plus ETHER_CRC_LEN if the adapter is able to keep CRC) + */ + max_frame_size = mtu + RTE_ETHER_HDR_LEN + 4 + 4; + + if (eth_dev->data->dev_conf.rxmode.max_rx_pkt_len < max_frame_size) + return -EINVAL; + + err = ionic_lif_change_mtu(lif, mtu); + + if (err) + return err; + + 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_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->min_mtu = IONIC_MIN_MTU; + dev_info->max_mtu = IONIC_MAX_MTU; + + 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_PRINT_CALL(); + + err = ionic_lif_configure(lif); + + if (err) { + IONIC_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 rte_eth_conf *dev_conf = ð_dev->data->dev_conf; + 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_PRINT_CALL(); + + 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 (dev_conf->link_speeds & ~allowed_speeds) { + IONIC_PRINT(ERR, "Invalid link setting"); + return -EINVAL; + } + + err = ionic_lif_start(lif); + + if (err) { + IONIC_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(dev_conf->link_speeds); + + if (speed) + ionic_dev_cmd_port_speed(idev, speed); + } + + 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_PRINT_CALL(); + + err = ionic_lif_stop(lif); + + if (err) + IONIC_PRINT(ERR, "Cannot stop LIF: %d", err); +} + +/* + * 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_PRINT_CALL(); + + err = ionic_lif_stop(lif); + + if (err) { + IONIC_PRINT(ERR, "Cannot stop LIF: %d", err); + return; + } + + err = eth_ionic_dev_uninit(eth_dev); + + if (err) { + IONIC_PRINT(ERR, "Cannot destroy LIF: %d", err); + return; + } +} + static int eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void *init_params) { @@ -78,6 +384,21 @@ eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void *init_params) lif->adapter = adapter; adapter->lifs[adapter->nlifs] = lif; + IONIC_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_PRINT(ERR, "Failed to allocate %u bytes needed to " + "store MAC addresses", + RTE_ETHER_ADDR_LEN * adapter->max_mac_addrs); + err = -ENOMEM; + goto err; + } + err = ionic_lif_alloc(lif); if (err) { @@ -93,6 +414,10 @@ eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void *init_params) goto err_free_lif; } + /* Copy the MAC address */ + rte_ether_addr_copy((struct rte_ether_addr *)lif->mac_addr, + ð_dev->data->mac_addrs[0]); + IONIC_PRINT(DEBUG, "Port %u initialized", eth_dev->data->port_id); return 0; @@ -298,6 +623,8 @@ eth_ionic_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, goto err_free_adapter; } + 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 ae45e76db..518e177eb 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,107 @@ ionic_qcq_disable(struct ionic_qcq *qcq) return ionic_adminq_post_wait(lif, &ctx); } +int +ionic_lif_stop(struct ionic_lif *lif __rte_unused) +{ + /* Carrier OFF here */ + + return 0; +} + +void +ionic_lif_reset(struct ionic_lif *lif) +{ + struct ionic_dev *idev = &lif->adapter->idev; + + IONIC_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 __rte_unused, + const uint8_t *addr __rte_unused) +{ + IONIC_PRINT(INFO, "%s: stubbed", __func__); + + return 0; +} + +static int +ionic_lif_addr_del(struct ionic_lif *lif __rte_unused, + const uint8_t *addr __rte_unused) +{ + IONIC_PRINT(INFO, "%s: stubbed", __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_PRINT(DEBUG, "rx_mode IONIC_RX_MODE_F_UNICAST"); + if (rx_mode & IONIC_RX_MODE_F_MULTICAST) + IONIC_PRINT(DEBUG, "rx_mode IONIC_RX_MODE_F_MULTICAST"); + if (rx_mode & IONIC_RX_MODE_F_BROADCAST) + IONIC_PRINT(DEBUG, "rx_mode IONIC_RX_MODE_F_BROADCAST"); + if (rx_mode & IONIC_RX_MODE_F_PROMISC) + IONIC_PRINT(DEBUG, "rx_mode IONIC_RX_MODE_F_PROMISC"); + if (rx_mode & IONIC_RX_MODE_F_ALLMULTI) + IONIC_PRINT(DEBUG, "rx_mode IONIC_RX_MODE_F_ALLMULTI"); + + err = ionic_adminq_post_wait(lif, &ctx); + + if (err) + IONIC_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) { @@ -601,6 +705,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_PRINT(DEBUG, "feature IONIC_ETH_HW_VLAN_TX_TAG"); + if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_STRIP) + IONIC_PRINT(DEBUG, "feature IONIC_ETH_HW_VLAN_RX_STRIP"); + if (lif->hw_features & IONIC_ETH_HW_VLAN_RX_FILTER) + IONIC_PRINT(DEBUG, "feature IONIC_ETH_HW_VLAN_RX_FILTER"); + if (lif->hw_features & IONIC_ETH_HW_RX_HASH) + IONIC_PRINT(DEBUG, "feature IONIC_ETH_HW_RX_HASH"); + if (lif->hw_features & IONIC_ETH_HW_TX_SG) + IONIC_PRINT(DEBUG, "feature IONIC_ETH_HW_TX_SG"); + if (lif->hw_features & IONIC_ETH_HW_RX_SG) + IONIC_PRINT(DEBUG, "feature IONIC_ETH_HW_RX_SG"); + if (lif->hw_features & IONIC_ETH_HW_TX_CSUM) + IONIC_PRINT(DEBUG, "feature IONIC_ETH_HW_TX_CSUM"); + if (lif->hw_features & IONIC_ETH_HW_RX_CSUM) + IONIC_PRINT(DEBUG, "feature IONIC_ETH_HW_RX_CSUM"); + if (lif->hw_features & IONIC_ETH_HW_TSO) + IONIC_PRINT(DEBUG, "feature IONIC_ETH_HW_TSO"); + if (lif->hw_features & IONIC_ETH_HW_TSO_IPV6) + IONIC_PRINT(DEBUG, "feature IONIC_ETH_HW_TSO_IPV6"); + if (lif->hw_features & IONIC_ETH_HW_TSO_ECN) + IONIC_PRINT(DEBUG, "feature IONIC_ETH_HW_TSO_ECN"); + if (lif->hw_features & IONIC_ETH_HW_TSO_GRE) + IONIC_PRINT(DEBUG, "feature IONIC_ETH_HW_TSO_GRE"); + if (lif->hw_features & IONIC_ETH_HW_TSO_GRE_CSUM) + IONIC_PRINT(DEBUG, "feature IONIC_ETH_HW_TSO_GRE_CSUM"); + if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP4) + IONIC_PRINT(DEBUG, "feature IONIC_ETH_HW_TSO_IPXIP4"); + if (lif->hw_features & IONIC_ETH_HW_TSO_IPXIP6) + IONIC_PRINT(DEBUG, "feature IONIC_ETH_HW_TSO_IPXIP6"); + if (lif->hw_features & IONIC_ETH_HW_TSO_UDP) + IONIC_PRINT(DEBUG, "feature IONIC_ETH_HW_TSO_UDP"); + if (lif->hw_features & IONIC_ETH_HW_TSO_UDP_CSUM) + IONIC_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_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_PRINT(INFO, "deleting station MAC addr"); + + ionic_lif_addr_del(lif, lif->mac_addr); + } + + memcpy(lif->mac_addr, ctx.comp.lif_getattr.mac, RTE_ETHER_ADDR_LEN); + + if (rte_is_zero_ether_addr((struct rte_ether_addr *)lif->mac_addr)) { + IONIC_PRINT(NOTICE, "empty MAC addr (VF?)"); + return 0; + } + + IONIC_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) { @@ -626,10 +848,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); @@ -648,6 +887,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_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 78cf92db8..9dbc54e27 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[RTE_ETHER_ADDR_LEN]; uint32_t info_sz; struct ionic_lif_info *info; rte_iova_t info_pa; @@ -71,6 +76,7 @@ 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); @@ -83,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_ */ From patchwork Thu Dec 19 22:18:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64023 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 4173AA04F3; Thu, 19 Dec 2019 23:20:32 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 38F9A1BFB2; Thu, 19 Dec 2019 23:19:18 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id 699151BF71 for ; Thu, 19 Dec 2019 23:18:57 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id 146CA41B7E; Thu, 19 Dec 2019 23:18:57 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793937; bh=C8h6PK6MzqIFldnOs8st3nvjCgmGWzo8jOEMADuvPzU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NnFVyPDL+FLulFQ3X8RXsaP6VpGEbJFms8NDddED/mQA2lKjoXciotJmhqh8Ji38E /mYKBbk2kZ1gEy1KGgWzG/mmNDiZBjFWibo2jGAiCvHvtgoWf9LCPUu3tR74AF73uG SDt/Btxb0vzFUW7Epx9wjv5mbE92opxFGLdiG4so= From: Alfredo Cardigliano To: Alfredo Cardigliano , John McNamara , Marko Kovacevic Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:41 +0100 Message-Id: <20191219221847.29989-12-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 11/17] net/ionic: add RX filters support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "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 Reviewed-by: Shannon Nelson --- 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 | 259 +++++++++++++++++++++++++++- drivers/net/ionic/ionic_lif.h | 16 ++ drivers/net/ionic/ionic_rx_filter.c | 139 +++++++++++++++ drivers/net/ionic/ionic_rx_filter.h | 47 +++++ drivers/net/ionic/meson.build | 1 + 8 files changed, 468 insertions(+), 7 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 2dc88cdd5..2b7cbaf9e 100644 --- a/drivers/net/ionic/Makefile +++ b/drivers/net/ionic/Makefile @@ -24,6 +24,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 3f9988acc..dbeb737fd 100644 --- a/drivers/net/ionic/ionic_ethdev.c +++ b/drivers/net/ionic/ionic_ethdev.c @@ -49,6 +49,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 518e177eb..86c05ff4e 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); @@ -83,23 +84,205 @@ ionic_lif_reset(struct ionic_lif *lif) } static int -ionic_lif_addr_add(struct ionic_lif *lif __rte_unused, - const uint8_t *addr __rte_unused) +ionic_lif_addr_add(struct ionic_lif *lif, const uint8_t *addr) { - IONIC_PRINT(INFO, "%s: stubbed", __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; + + memcpy(ctx.cmd.rx_filter_add.mac.addr, addr, RTE_ETHER_ADDR_LEN); + + err = ionic_adminq_post_wait(lif, &ctx); + + if (err) + return err; + + IONIC_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, &ctx); +} + +static int +ionic_lif_addr_del(struct ionic_lif *lif, const uint8_t *addr) +{ + 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_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(f); + + rte_spinlock_unlock(&lif->rx_filters.lock); + + err = ionic_adminq_post_wait(lif, &ctx); + + if (err) + return err; + + IONIC_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_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_PRINT_CALL(); + + if (index >= adapter->max_mac_addrs) { + IONIC_PRINT(WARNING, + "Index %u is above MAC filter limit %u", + index, adapter->max_mac_addrs); + return; + } + + if (!rte_is_valid_assigned_ether_addr(ð_dev->data->mac_addrs[index])) + return; + + ionic_lif_addr_del(lif, (const uint8_t *) + ð_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_PRINT_CALL(); + + if (mac_addr == NULL) { + IONIC_PRINT(NOTICE, "New mac is null"); + return -1; + } + + if (!rte_is_zero_ether_addr((struct rte_ether_addr *)lif->mac_addr)) { + IONIC_PRINT(INFO, "Deleting mac addr %pM", + lif->mac_addr); + ionic_lif_addr_del(lif, lif->mac_addr); + memset(lif->mac_addr, 0, RTE_ETHER_ADDR_LEN); + } + + IONIC_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_lif_addr_del(struct ionic_lif *lif __rte_unused, - const uint8_t *addr __rte_unused) +ionic_vlan_rx_add_vid(struct ionic_lif *lif, uint16_t vid) { - IONIC_PRINT(INFO, "%s: stubbed", __func__); + 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_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, &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_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(f); + rte_spinlock_unlock(&lif->rx_filters.lock); + + err = ionic_adminq_post_wait(lif, &ctx); + + if (err) + return err; + + IONIC_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) { @@ -139,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_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) @@ -855,17 +1091,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); @@ -881,6 +1125,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 9dbc54e27..e0863c5de 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..00b5cee49 --- /dev/null +++ b/drivers/net/ionic/ionic_rx_filter.c @@ -0,0 +1,139 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) + * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved. + */ + +#include + +#include + +#include "ionic_lif.h" +#include "ionic_rx_filter.h" + +void +ionic_rx_filter_free(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(f); + } + } +} + +int +ionic_rx_filter_save(struct ionic_lif *lif, uint32_t flow_id, + uint16_t rxq_index, 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, RTE_ETHER_ADDR_LEN) == 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..6204a7b53 --- /dev/null +++ b/drivers/net/ionic/ionic_rx_filter.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) + * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved. + */ + +#ifndef _IONIC_RX_FILTER_H_ +#define _IONIC_RX_FILTER_H_ + +#include + +#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_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, 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 f28016105..ec7246753 100644 --- a/drivers/net/ionic/meson.build +++ b/drivers/net/ionic/meson.build @@ -3,6 +3,7 @@ sources = files( 'ionic_mac_api.c', + 'ionic_rx_filter.c', 'ionic_dev.c', 'ionic_ethdev.c', 'ionic_lif.c', From patchwork Thu Dec 19 22:18:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64025 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 132B0A04F3; Thu, 19 Dec 2019 23:20:48 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 856DC1BFC0; Thu, 19 Dec 2019 23:19:21 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id CAD911BF72 for ; Thu, 19 Dec 2019 23:18:57 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id 7424941B84; Thu, 19 Dec 2019 23:18:57 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793937; bh=8ZYx3Kt6SSmuMp6viADW/7ezFukxIdEsqDpkZKc7fR0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dgZEW9v9qK1Xy51UTNYTREemACUy1D8MoD4IadyuXzJ3g/IQrGgZQFLKNtmXOB6zX Kfd5L+Ahh94k67fkHAtpjhbXtDMRCuNhJhGNa2CGbhwiNyebAb+aDOKM5adpnkRxuF 0RICOHDeLZ9ESDS4dClBkWpECiSJzVrKtt6/6sbY= From: Alfredo Cardigliano To: Alfredo Cardigliano , John McNamara , Marko Kovacevic Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:42 +0100 Message-Id: <20191219221847.29989-13-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 12/17] net/ionic: add Flow Control support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add support for managing Flow Control. Signed-off-by: Alfredo Cardigliano Reviewed-by: Shannon Nelson --- 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 dbeb737fd..ba1d1de16 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; @@ -57,6 +61,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, }; /* @@ -243,6 +249,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) { From patchwork Thu Dec 19 22:18:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64026 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 1C846A04F3; Thu, 19 Dec 2019 23:20:54 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 4035F1BFC7; Thu, 19 Dec 2019 23:19:23 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id 411401BF70 for ; Thu, 19 Dec 2019 23:18:58 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id DC7D441B85; Thu, 19 Dec 2019 23:18:57 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793938; bh=EPEiCbs/P2ZHWfqGtMuzBV+bD+BRF2HFLtwpUaFDMdQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TrJ7plyj5BJ+KdVFYbVvNXyq3qW0e2JRAF8qa13CadkfxSBiYAbIYQoryofzqErH7 T1itKCmDcldjdMHIxs0N1HQUNC5arglZ7BOgJhDa+iFIffZlB9a3PyrV6FILzggaw2 9RcM7DW4VvuFc5BGjnT5FSJiUblY1xvAP3eJHGmo= From: Alfredo Cardigliano To: Alfredo Cardigliano , John McNamara , Marko Kovacevic Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:43 +0100 Message-Id: <20191219221847.29989-14-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 13/17] net/ionic: add RX and TX handling X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add RX and TX queues setup and handling. Signed-off-by: Alfredo Cardigliano Reviewed-by: Shannon Nelson --- 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 | 115 ++++ drivers/net/ionic/ionic_lif.c | 222 ++++++- drivers/net/ionic/ionic_lif.h | 44 ++ drivers/net/ionic/ionic_rxtx.c | 999 +++++++++++++++++++++++++++++ drivers/net/ionic/ionic_rxtx.h | 44 ++ drivers/net/ionic/meson.build | 1 + 9 files changed, 1436 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 05bdb2d98..8fde998c1 100644 --- a/doc/guides/nics/features/ionic.ini +++ b/doc/guides/nics/features/ionic.ini @@ -7,12 +7,22 @@ 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 VLAN filter = Y +VLAN offload = Y Flow control = Y +CRC 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 2b7cbaf9e..f74ac2d34 100644 --- a/drivers/net/ionic/Makefile +++ b/drivers/net/ionic/Makefile @@ -25,6 +25,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 61576621b..8c1ec13a6 100644 --- a/drivers/net/ionic/ionic_dev.h +++ b/drivers/net/ionic/ionic_dev.h @@ -14,6 +14,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 ba1d1de16..e49531d21 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); @@ -33,6 +34,7 @@ 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_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask); int ionic_logtype; @@ -43,6 +45,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, @@ -63,6 +79,17 @@ 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, + .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, }; /* @@ -246,6 +273,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; } @@ -299,6 +370,44 @@ ionic_flow_ctrl_set(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 = ð_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) { @@ -436,6 +545,9 @@ eth_ionic_dev_init(struct rte_eth_dev *eth_dev, void *init_params) IONIC_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) @@ -509,6 +621,9 @@ 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; + eth_dev->tx_pkt_prepare = NULL; return 0; } diff --git a/drivers/net/ionic/ionic_lif.c b/drivers/net/ionic/ionic_lif.c index 86c05ff4e..f4f340dc1 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) { @@ -662,6 +709,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_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_PRINT(ERR, "Cannot allocate rx queues array"); + return -ENOMEM; + } + IONIC_PRINT(DEBUG, "Allocating Notify Queue"); err = ionic_notify_qcq_alloc(lif); @@ -714,6 +777,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); lif->info = NULL; @@ -735,6 +808,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) @@ -1000,6 +1085,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_PRINT(DEBUG, "txq_init.pid %d", ctx.cmd.q_init.pid); + IONIC_PRINT(DEBUG, "txq_init.index %d", ctx.cmd.q_init.index); + IONIC_PRINT(DEBUG, "txq_init.ring_base 0x%" PRIx64 "", + ctx.cmd.q_init.ring_base); + IONIC_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_PRINT(DEBUG, "txq->hw_type %d", q->hw_type); + IONIC_PRINT(DEBUG, "txq->hw_index %d", q->hw_index); + IONIC_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_PRINT(DEBUG, "rxq_init.pid %d", ctx.cmd.q_init.pid); + IONIC_PRINT(DEBUG, "rxq_init.index %d", ctx.cmd.q_init.index); + IONIC_PRINT(DEBUG, "rxq_init.ring_base 0x%" PRIx64 "", + ctx.cmd.q_init.ring_base); + IONIC_PRINT(DEBUG, "rxq_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); + + qcq->flags |= IONIC_QCQ_F_INITED; + + IONIC_PRINT(DEBUG, "rxq->hw_type %d", q->hw_type); + IONIC_PRINT(DEBUG, "rxq->hw_index %d", q->hw_index); + IONIC_PRINT(DEBUG, "rxq->db %p", q->db); + + return 0; +} + static int ionic_station_set(struct ionic_lif *lif) { @@ -1084,7 +1265,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); @@ -1137,6 +1328,9 @@ ionic_lif_configure(struct ionic_lif *lif) { lif->port_id = lif->eth_dev->data->port_id; + lif->nrxqcqs = 1; + lif->ntxqcqs = 1; + return 0; } @@ -1144,6 +1338,8 @@ int ionic_lif_start(struct ionic_lif *lif) { uint32_t rx_mode = 0; + uint32_t i; + int err; IONIC_PRINT(DEBUG, "Setting RX mode on port %u", lif->port_id); @@ -1156,6 +1352,30 @@ ionic_lif_start(struct ionic_lif *lif) ionic_set_rx_mode(lif, rx_mode); + IONIC_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 e0863c5de..5e7d9ae0c 100644 --- a/drivers/net/ionic/ionic_lif.h +++ b/drivers/net/ionic/ionic_lif.h @@ -17,6 +17,26 @@ #define IONIC_ADMINQ_LENGTH 16 /* must be a power of two */ #define IONIC_NOTIFYQ_LENGTH 64 /* must be a power of two */ +#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) @@ -24,18 +44,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) @@ -49,11 +79,15 @@ 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; 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; @@ -107,11 +141,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_set_features(struct ionic_lif *lif); int ionic_notifyq_handler(struct ionic_lif *lif, int budget); diff --git a/drivers/net/ionic/ionic_rxtx.c b/drivers/net/ionic/ionic_rxtx.c new file mode 100644 index 000000000..91d28fa98 --- /dev/null +++ b/drivers/net/ionic/ionic_rxtx.c @@ -0,0 +1,999 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) + * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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]); + + 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_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_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 __rte_unused, + 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_PRINT_CALL(); + + IONIC_PRINT(DEBUG, "Configuring TX queue %u with %u buffers", + tx_queue_id, nb_desc); + + if (tx_queue_id >= lif->ntxqcqs) { + IONIC_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) { + void *tx_queue = eth_dev->data->tx_queues[tx_queue_id]; + ionic_dev_tx_queue_release(tx_queue); + eth_dev->data->tx_queues[tx_queue_id] = NULL; + } + + err = ionic_tx_qcq_alloc(lif, tx_queue_id, nb_desc, &txq); + + if (err) { + IONIC_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_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 __rte_unused, 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 = 0; + uint16_t desc_len = 0; + 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) { + rte_iova_t data_iova; + data_iova = rte_mbuf_data_iova(txm_seg); + elem->addr = rte_cpu_to_le_64(data_iova) + 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; + data_iova = rte_mbuf_data_iova(txm_seg); + desc_addr = rte_cpu_to_le_64(data_iova); + 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 __rte_unused, 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]); + rte_prefetch0(&q->info[next_q_head_idx]); + } + + 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 __rte_unused, 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_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 __rte_unused, + 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_PRINT_CALL(); + + IONIC_PRINT(DEBUG, "Configuring RX queue %u with %u buffers", + rx_queue_id, nb_desc); + + if (rx_queue_id >= lif->nrxqcqs) { + IONIC_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_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) { + void *rx_queue = eth_dev->data->rx_queues[rx_queue_id]; + ionic_dev_rx_queue_release(rx_queue); + eth_dev->data->rx_queues[rx_queue_id] = NULL; + } + + err = ionic_rx_qcq_alloc(lif, rx_queue_id, nb_desc, &rxq); + + if (err) { + IONIC_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 = 0; + 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++; + } + + /* Vlan Strip */ + if (cq_desc->csum_flags & IONIC_RXQ_COMP_CSUM_F_VLAN) { + pkt_flags |= PKT_RX_VLAN | 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_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_iova_t data_iova; + + rxm_seg = rte_mbuf_raw_alloc(rxq->mb_pool); + if (rxm_seg == NULL) { + IONIC_PRINT(ERR, "RX mbuf alloc failed"); + return -ENOMEM; + } + + data_iova = rte_mbuf_data_iova(rxm_seg); + dma_addr = rte_cpu_to_le_64(data_iova); + 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_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_PRINT_CALL(); + + IONIC_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_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]); + + 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_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..5c85b9c49 --- /dev/null +++ b/drivers/net/ionic/ionic_rxtx.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) + * Copyright(c) 2018-2019 Pensando Systems, Inc. All rights reserved. + */ + +#ifndef _IONIC_RXTX_H_ +#define _IONIC_RXTX_H_ + +#include + +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 ec7246753..dee8a3608 100644 --- a/drivers/net/ionic/meson.build +++ b/drivers/net/ionic/meson.build @@ -4,6 +4,7 @@ sources = files( 'ionic_mac_api.c', 'ionic_rx_filter.c', + 'ionic_rxtx.c', 'ionic_dev.c', 'ionic_ethdev.c', 'ionic_lif.c', From patchwork Thu Dec 19 22:18:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64027 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 74785A04F3; Thu, 19 Dec 2019 23:21:02 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 3EE5B1BFCC; Thu, 19 Dec 2019 23:19:25 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id AE2011BF71 for ; Thu, 19 Dec 2019 23:18:58 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id 53CAB41B8A; Thu, 19 Dec 2019 23:18:58 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793938; bh=XA+3f7wFb74igF9refatH+PEmSfqaxZNVF6btGkOoMU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OZeu1qgn15F4hnzvALvDUkXHnAPdMRmcATkCCsItK3Ow2g9L871iqBIXvknvpqHMF 8XgNRGSCuWwdK/6jwe+l7y+IhWQqVLcGuZRxICBpWPHQ8ekfijrUEzlrXwTlzT5Xff +GbnmPNIz864qfUDXv1lifcaNK98SyoknLAF/MjU= From: Alfredo Cardigliano To: Alfredo Cardigliano , John McNamara , Marko Kovacevic Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:44 +0100 Message-Id: <20191219221847.29989-15-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 14/17] net/ionic: add RSS support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add code to manipulate the RSS configuration used by the adapter. Signed-off-by: Alfredo Cardigliano Reviewed-by: Shannon Nelson --- 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 | 16 +++ drivers/net/ionic/ionic_rxtx.c | 4 + 6 files changed, 324 insertions(+), 2 deletions(-) diff --git a/doc/guides/nics/features/ionic.ini b/doc/guides/nics/features/ionic.ini index 8fde998c1..9a155251c 100644 --- a/doc/guides/nics/features/ionic.ini +++ b/doc/guides/nics/features/ionic.ini @@ -16,6 +16,9 @@ TSO = 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 VLAN offload = Y Flow control = Y diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c index e49531d21..121404a1f 100644 --- a/drivers/net/ionic/ionic_ethdev.c +++ b/drivers/net/ionic/ionic_ethdev.c @@ -35,6 +35,14 @@ static int ionic_flow_ctrl_get(struct rte_eth_dev *eth_dev, static int ionic_flow_ctrl_set(struct rte_eth_dev *eth_dev, struct rte_eth_fc_conf *fc_conf); static int ionic_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask); +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; @@ -90,6 +98,10 @@ 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, + .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, }; /* @@ -266,6 +278,10 @@ ionic_dev_info_get(struct rte_eth_dev *eth_dev, dev_info->min_mtu = IONIC_MIN_MTU; dev_info->max_mtu = IONIC_MAX_MTU; + 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 | @@ -408,6 +424,165 @@ ionic_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask) 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_PRINT_CALL(); + + if (!lif->rss_ind_tbl) { + IONIC_PRINT(ERR, "RSS RETA not initialized, " + "can't update the table"); + return -EINVAL; + } + + if (reta_size != ident->lif.eth.rss_ind_tbl_sz) { + IONIC_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_PRINT_CALL(); + + if (reta_size != ident->lif.eth.rss_ind_tbl_sz) { + IONIC_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_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_PRINT_CALL(); + + if (!lif->rss_ind_tbl) { + IONIC_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_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 7228d8969..578e2301f 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 f4f340dc1..e4ee828b5 100644 --- a/drivers/net/ionic/ionic_lif.c +++ b/drivers/net/ionic/ionic_lif.c @@ -793,6 +793,97 @@ ionic_lif_free(struct ionic_lif *lif) } } +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_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_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_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) { @@ -1317,6 +1408,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); @@ -1326,10 +1418,27 @@ 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; - lif->nrxqcqs = 1; - lif->ntxqcqs = 1; + IONIC_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; } @@ -1341,6 +1450,13 @@ ionic_lif_start(struct ionic_lif *lif) uint32_t i; int err; + IONIC_PRINT(DEBUG, "Setting RSS configuration on port %u", + lif->port_id); + + err = ionic_lif_rss_setup(lif); + if (err) + return err; + IONIC_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 5e7d9ae0c..a6f579d1c 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_GET_SG_CNTR_IDX(num_sg_elems) (num_sg_elems) struct ionic_tx_stats { @@ -96,6 +104,11 @@ struct ionic_lif { uint32_t rx_mode; char name[IONIC_LIF_NAME_MAX_SZ]; uint8_t mac_addr[RTE_ETHER_ADDR_LEN]; + 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; @@ -156,6 +169,9 @@ 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); + int ionic_lif_set_features(struct ionic_lif *lif); int ionic_notifyq_handler(struct ionic_lif *lif, int budget); diff --git a/drivers/net/ionic/ionic_rxtx.c b/drivers/net/ionic/ionic_rxtx.c index 91d28fa98..614215ffa 100644 --- a/drivers/net/ionic/ionic_rxtx.c +++ b/drivers/net/ionic/ionic_rxtx.c @@ -704,6 +704,10 @@ ionic_rx_clean(struct ionic_queue *q, 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 | PKT_RX_VLAN_STRIPPED; From patchwork Thu Dec 19 22:18:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64028 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id A57F9A04F3; Thu, 19 Dec 2019 23:21:13 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B150A1BFD5; Thu, 19 Dec 2019 23:19:28 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id 1C0B11BF76 for ; Thu, 19 Dec 2019 23:18:59 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id B9C0B41BA8; Thu, 19 Dec 2019 23:18:58 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793938; bh=H21FVMzm4cMYs0cXHVMqMjz+lqiuubdPyOcqxesCyHg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fNHaSzZ110uvilwUbnmZCmq9JWV+BBmZiSas2VZpaPB9hTsaKh50771NY6cZ3i5HB 1fDrKzVjRKdaAu/G3NV2Ha9UljWQgG8vYXnFHx4FIBqhSOiMT3EDPMtDjc5uiJNDgM mSjXDFpne+8cj4uCBygFRVp2Di/EdVrvrCZMEGc8= From: Alfredo Cardigliano To: Alfredo Cardigliano , John McNamara , Marko Kovacevic Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:45 +0100 Message-Id: <20191219221847.29989-16-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 15/17] net/ionic: add stats X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add basic, per queue and extended statistics for RX and TX, both from the adapter and the driver. Signed-off-by: Alfredo Cardigliano Reviewed-by: Shannon Nelson --- doc/guides/nics/features/ionic.ini | 3 + drivers/net/ionic/ionic_ethdev.c | 253 +++++++++++++++++++++++++++++ drivers/net/ionic/ionic_lif.c | 148 +++++++++++++++++ drivers/net/ionic/ionic_lif.h | 9 + 4 files changed, 413 insertions(+) diff --git a/doc/guides/nics/features/ionic.ini b/doc/guides/nics/features/ionic.ini index 9a155251c..8cd5936d6 100644 --- a/doc/guides/nics/features/ionic.ini +++ b/doc/guides/nics/features/ionic.ini @@ -26,6 +26,9 @@ CRC 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 121404a1f..fdd56134e 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, 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_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; @@ -102,8 +115,102 @@ 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, + .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, }; +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. */ @@ -583,6 +690,152 @@ ionic_dev_rss_hash_update(struct rte_eth_dev *eth_dev, 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_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_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_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 e4ee828b5..29fca11a1 100644 --- a/drivers/net/ionic/ionic_lif.c +++ b/drivers/net/ionic/ionic_lif.c @@ -84,6 +84,152 @@ 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_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; + + 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) { @@ -1338,6 +1484,8 @@ ionic_lif_init(struct ionic_lif *lif) struct ionic_q_init_comp comp; int err; + memset(&lif->stats_base, 0, sizeof(lif->stats_base)); + 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); diff --git a/drivers/net/ionic/ionic_lif.h b/drivers/net/ionic/ionic_lif.h index a6f579d1c..dd7bd11e3 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_ */ From patchwork Thu Dec 19 22:18:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64029 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 43BB2A04F3; Thu, 19 Dec 2019 23:21:23 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 584721BFDE; Thu, 19 Dec 2019 23:19:31 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id 6B6101BF71 for ; Thu, 19 Dec 2019 23:18:59 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id 2A62A41C32; Thu, 19 Dec 2019 23:18:59 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793939; bh=5otiM1TKe6MkK/KWp1IAX3WJe/CZFZtakfKC8tBrxlM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JDrNOBfYWf0LZ+sSLrI46P4Be/ySSbHg8GoOc11zULQR5UUqrPtpdiHzz9PjGoCuN sEUCxG3++Wwo1mQ8ZtKd9D+U72/nYq0wshWhtdeTpWad0hBN4n84tEGaz8/yknzAKA EeUO9yNljXfsZAIppNT3cK6PDDGA2PSm311zb1WE= From: Alfredo Cardigliano To: Alfredo Cardigliano Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:46 +0100 Message-Id: <20191219221847.29989-17-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 16/17] net/ionic: add TX checksum support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add support for TX checksumming. Signed-off-by: Alfredo Cardigliano Reviewed-by: Shannon Nelson --- 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 | 88 +++++++++++++++++++++++++++++++- 4 files changed, 93 insertions(+), 2 deletions(-) diff --git a/drivers/net/ionic/ionic_ethdev.c b/drivers/net/ionic/ionic_ethdev.c index fdd56134e..6267fde35 100644 --- a/drivers/net/ionic/ionic_ethdev.c +++ b/drivers/net/ionic/ionic_ethdev.c @@ -409,7 +409,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 29fca11a1..0d066c6e4 100644 --- a/drivers/net/ionic/ionic_lif.c +++ b/drivers/net/ionic/ionic_lif.c @@ -1511,6 +1511,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 dd7bd11e3..d1e1541ca 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 614215ffa..f36112ced 100644 --- a/drivers/net/ionic/ionic_rxtx.c +++ b/drivers/net/ionic/ionic_rxtx.c @@ -232,16 +232,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; @@ -286,10 +329,29 @@ ionic_tx_tso(struct ionic_queue *q, struct rte_mbuf *txm, 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; - hdrlen = txm->l2_len + txm->l3_len; + 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. + */ + + 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; @@ -313,6 +375,7 @@ ionic_tx_tso(struct ionic_queue *q, struct rte_mbuf *txm, 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); @@ -354,6 +417,7 @@ ionic_tx_tso(struct ionic_queue *q, struct rte_mbuf *txm, 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); @@ -370,7 +434,7 @@ ionic_tx_tso(struct ionic_queue *q, struct rte_mbuf *txm, static int ionic_tx(struct ionic_queue *q, struct rte_mbuf *txm, - uint64_t offloads __rte_unused, bool not_xmit_more) + 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; @@ -379,15 +443,34 @@ ionic_tx(struct ionic_queue *q, struct rte_mbuf *txm, 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; @@ -472,6 +555,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) From patchwork Thu Dec 19 22:18:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alfredo Cardigliano X-Patchwork-Id: 64030 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 5D883A04F3; Thu, 19 Dec 2019 23:21:30 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 2AF741BFE0; Thu, 19 Dec 2019 23:19:33 +0100 (CET) Received: from mail.ntop.org (mail-digitalocean.ntop.org [167.99.215.164]) by dpdk.org (Postfix) with ESMTP id 252491BF76 for ; Thu, 19 Dec 2019 23:19:00 +0100 (CET) Received: from devele.ntop.org (net-93-145-196-230.cust.vodafonedsl.it [93.145.196.230]) by mail.ntop.org (Postfix) with ESMTPSA id 7D44941C32; Thu, 19 Dec 2019 23:18:59 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ntop.org; s=mail; t=1576793939; bh=VJ0KO1HJQhOZ4s4syHJn85F1HKhc8JgJY8I/4erJKoQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=moT+a+LznuzKXBJ2uo5DxCzodWU8Cy6phOCzhey0oqHyimHT/pYjS0Rv7Fnwssz7l z3w3XssiEya6CF0BZeQrcPV00JW63DvXfV/zhHg0AcVs2y3JveDDNAZFOQ02WyaqIF GI8OBtiV+eVu+jYILWqX03xd6ukDE05Tg8ACZhkY= From: Alfredo Cardigliano To: Alfredo Cardigliano , John McNamara , Marko Kovacevic Cc: dev@dpdk.org Date: Thu, 19 Dec 2019 23:18:47 +0100 Message-Id: <20191219221847.29989-18-cardigliano@ntop.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191219221847.29989-1-cardigliano@ntop.org> References: <20191219221847.29989-1-cardigliano@ntop.org> Subject: [dpdk-dev] [PATCH v4 17/17] net/ionic: read fw version X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add support for reading the firmware version. Signed-off-by: Alfredo Cardigliano Reviewed-by: Shannon Nelson --- 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 8cd5936d6..083c7bd99 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 ae4f6acc7..45a7879c9 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 e2cd15792..c3f83559f 100644 --- a/drivers/net/ionic/ionic_dev.c +++ b/drivers/net/ionic/ionic_dev.c @@ -16,6 +16,7 @@ ionic_dev_setup(struct ionic_adapter *adapter) struct ionic_dev *idev = &adapter->idev; uint32_t sig; u_char *bar0_base; + unsigned int i; /* BAR0: dev_cmd and interrupts */ if (num_bars < 1) { @@ -47,6 +48,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_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 6267fde35..4097bb697 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; @@ -122,6 +124,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, }; struct rte_ionic_xstats_name_off { @@ -211,6 +214,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. */