From patchwork Wed Jun 7 13:02:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Malov X-Patchwork-Id: 128298 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 5271542C4D; Wed, 7 Jun 2023 15:04:13 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 66A2942D56; Wed, 7 Jun 2023 15:02:58 +0200 (CEST) Received: from agw.arknetworks.am (agw.arknetworks.am [79.141.165.80]) by mails.dpdk.org (Postfix) with ESMTP id EB61D42D10 for ; Wed, 7 Jun 2023 15:02:51 +0200 (CEST) Received: from localhost.localdomain (unknown [78.109.69.83]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by agw.arknetworks.am (Postfix) with ESMTPSA id 5F145E12C6; Wed, 7 Jun 2023 17:02:51 +0400 (+04) From: Ivan Malov To: dev@dpdk.org Cc: Andrew Rybchenko , Ferruh Yigit , Denis Pryazhennikov , Andy Moreton Subject: [PATCH v4 09/34] net/sfc: add functions to manipulate MCDI table fields Date: Wed, 7 Jun 2023 17:02:20 +0400 Message-Id: <20230607130245.8048-10-ivan.malov@arknetworks.am> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230607130245.8048-1-ivan.malov@arknetworks.am> References: <20230601195538.8265-1-ivan.malov@arknetworks.am> <20230607130245.8048-1-ivan.malov@arknetworks.am> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Denis Pryazhennikov Implemented functions that help to fill user data for manipulation with HW tables in the required format. Signed-off-by: Denis Pryazhennikov Reviewed-by: Ivan Malov Reviewed-by: Andy Moreton --- drivers/net/sfc/meson.build | 1 + drivers/net/sfc/sfc_tbls.c | 147 ++++++++++++++++++++++++++++++++++++ drivers/net/sfc/sfc_tbls.h | 136 +++++++++++++++++++++++++++++++++ 3 files changed, 284 insertions(+) create mode 100644 drivers/net/sfc/sfc_tbls.c diff --git a/drivers/net/sfc/meson.build b/drivers/net/sfc/meson.build index c2d8430810..39c7f24764 100644 --- a/drivers/net/sfc/meson.build +++ b/drivers/net/sfc/meson.build @@ -87,6 +87,7 @@ sources = files( 'sfc_tso.c', 'sfc_filter.c', 'sfc_switch.c', + 'sfc_tbls.c', 'sfc_mae.c', 'sfc_mae_counter.c', 'sfc_flow.c', diff --git a/drivers/net/sfc/sfc_tbls.c b/drivers/net/sfc/sfc_tbls.c new file mode 100644 index 0000000000..536cf689ba --- /dev/null +++ b/drivers/net/sfc/sfc_tbls.c @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023 Advanced Micro Devices, Inc. + */ + +#include "sfc_tbls.h" +#include "sfc_debug.h" + +#include + +/* Number of bits in uint32_t type */ +#define SFC_TBLS_U32_BITS (sizeof(uint32_t) * CHAR_BIT) + +static uint32_t +sfc_tbls_field_update(uint32_t in, uint16_t lbn, uint16_t width, uint32_t value) +{ + uint32_t mask; + + SFC_ASSERT(width <= SFC_TBLS_U32_BITS); + + if (width == SFC_TBLS_U32_BITS) + return value; + + mask = RTE_LEN2MASK(width, uint32_t); + value &= mask; + + if (lbn != 0) { + mask <<= lbn; + value <<= lbn; + } + + return (in & (~mask)) | value; +} + +void +sfc_tbls_field_set_u32(uint32_t data[], __rte_unused unsigned int data_size, + uint16_t lbn, uint16_t width, uint32_t value) +{ + uint32_t data_offset = 0; + + if (lbn >= SFC_TBLS_U32_BITS) { + data_offset = lbn / SFC_TBLS_U32_BITS; + + SFC_ASSERT(data_offset < data_size); + + data += data_offset; + lbn %= SFC_TBLS_U32_BITS; + } + + if (lbn + width <= SFC_TBLS_U32_BITS) { + *data = sfc_tbls_field_update(*data, lbn, width, value); + } else { + *data = sfc_tbls_field_update(*data, lbn, + SFC_TBLS_U32_BITS - lbn, value); + value >>= SFC_TBLS_U32_BITS - lbn; + + data_offset++; + SFC_ASSERT(data_offset < data_size); + + data++; + *data = sfc_tbls_field_update(*data, 0, + width + lbn - SFC_TBLS_U32_BITS, + value); + } +} + +void +sfc_tbls_field_set_u16(uint32_t data[], unsigned int data_size, uint16_t lbn, + uint16_t width, uint16_t value) +{ + sfc_tbls_field_set_u32(data, data_size, lbn, width, value); +} + +void +sfc_tbls_field_set_u8(uint32_t data[], unsigned int data_size, uint16_t lbn, + uint16_t width, uint8_t value) +{ + sfc_tbls_field_set_u32(data, data_size, lbn, width, value); +} + +void +sfc_tbls_field_set_ip(uint32_t data[], unsigned int data_size, uint16_t lbn, + __rte_unused uint16_t width, const uint32_t *ip) +{ + unsigned int i; + size_t ipv6_addr_len = RTE_SIZEOF_FIELD(struct rte_ipv6_hdr, src_addr); + + /* + * The same 128-bit container is used to store either + * an IPv4 or an IPv6 address, with an IPv4 address + * assumed to have 12 trailing zeroes. + */ + SFC_ASSERT(width == ipv6_addr_len * CHAR_BIT); + + for (i = 0; i < ipv6_addr_len / sizeof(*ip); i++) { + sfc_tbls_field_set_u32(data, data_size, lbn, + SFC_TBLS_U32_BITS, ip[i]); + lbn += SFC_TBLS_U32_BITS; + } +} + +void +sfc_tbls_field_set_u64(uint32_t data[], __rte_unused unsigned int data_size, + uint16_t lbn, uint16_t width, uint64_t value) +{ + uint32_t data_offset = 0; + + if (lbn >= SFC_TBLS_U32_BITS) { + data_offset = lbn / SFC_TBLS_U32_BITS; + + SFC_ASSERT(data_offset < data_size); + + data += data_offset; + lbn %= SFC_TBLS_U32_BITS; + } + + *data = sfc_tbls_field_update(*data, lbn, SFC_TBLS_U32_BITS - lbn, value); + value >>= SFC_TBLS_U32_BITS - lbn; + width -= SFC_TBLS_U32_BITS - lbn; + + data_offset++; + SFC_ASSERT(data_offset < data_size); + + data++; + + if (width > SFC_TBLS_U32_BITS) { + *data = sfc_tbls_field_update(*data, 0, SFC_TBLS_U32_BITS, value); + value >>= SFC_TBLS_U32_BITS; + width -= SFC_TBLS_U32_BITS; + + data_offset++; + SFC_ASSERT(data_offset < data_size); + + data++; + } + + *data = sfc_tbls_field_update(*data, 0, width, value); +} + +void +sfc_tbls_field_set_bit(uint32_t data[], unsigned int data_size, uint16_t lbn, + uint16_t width, bool value) +{ + SFC_ASSERT(width == 1); + + sfc_tbls_field_set_u32(data, data_size, lbn, width, value ? 1 : 0); +} diff --git a/drivers/net/sfc/sfc_tbls.h b/drivers/net/sfc/sfc_tbls.h index 302f67224c..74bdfab476 100644 --- a/drivers/net/sfc/sfc_tbls.h +++ b/drivers/net/sfc/sfc_tbls.h @@ -63,6 +63,142 @@ sfc_tbls_bcam_entry_delete(efx_nic_t *enp, efx_table_id_t table_id, uint16_t key data, data_size); } +/** + * All manipulations with HW tables entries require forming + * a key and response. + * The key and response fields follow, consecutively, each + * packed as follows: + * - the key/response is logically treated as a single wide N-bit value; + * - fields have been placed in these logical values per the "lbn" and "width" + * information from the table field descriptors; + * - the wide N-bit value is padded at the MSB end up to a 32-bit boundary; + * - the values are put into the table op request with bits[31:0] of the wide + * value in the first 32-bit word, bits[63:32] in the second 32-bit word, etc. + * + * Below is an API that helps to form MCDI insertion/deletion request. + * Workflow: + * 1) Allocate an array of EFX_TABLE_ENTRY_LENGTH_MAX bytes. + * 2) Read a descriptor of the table that you want to use. + * 3) Fill the array using sfc_tbls_field_set_* functions to form a key. + * Each field of the key has LBN and width. This information can be + * found in a field's descriptor. + * 4) Use sfc_tbls_next_req_fields() to get a pointer where the response + * must start. It's required as the key and response need to be + * zero-padded at the MSB end to multiples of 32 bits. + * 5) Fill the response the same way. + * 6) Use sfc_tbls_next_req_fields() to get the end of the data request. + * It will help you to get the real size of the data request. + */ + +/** + * Get a pointer to the beginning of the next 32-bit wide fields + * that go after a given width. + * It should be used to get a pointer to the response's start and the end + * of the data for an MCDI request. + * + * @param data Pointer to the data to make an offset from + * @param width Width of fields to offset + * + * @note @p width is expected to be a key's or response's size. + * + * @return Pointer to the beginning of the next field. + */ +static inline uint32_t * +sfc_tbls_next_req_fields(uint32_t *data, uint16_t width) +{ + return data + EFX_DIV_ROUND_UP(width, sizeof(*data) * CHAR_BIT); +} + +/** + * Insert value into a field in the @p data buffer starting at + * bit offset @p lbn and containing @p width bits. + * + * @param data Data buffer + * @param data_size Size of the data buffer + * @param lbn Offset + * @param width Width of @p value in bits + * @param value uint32_t value to insert + * + * @note @p width and @p lbn must to be obtained from the field's descriptor. + */ +void sfc_tbls_field_set_u32(uint32_t data[], unsigned int data_size, + uint16_t lbn, uint16_t width, uint32_t value); + +/** + * Insert value into a field in the @p data buffer starting at + * bit offset @p lbn and containing @p width bits. + * + * @param data Data buffer + * @param data_size Size of the data buffer + * @param lbn Offset + * @param width Width of @p value in bits + * @param value uint16_t value to insert + * + * @note @p width and @p lbn must to be obtained from the field's descriptor. + */ +void sfc_tbls_field_set_u16(uint32_t data[], unsigned int data_size, + uint16_t lbn, uint16_t width, uint16_t value); + +/** + * Insert value into a field in the @p data buffer starting at + * bit offset @p lbn and containing @p width bits. + * + * @param data Data buffer + * @param data_size Size of the data buffer + * @param lbn Offset + * @param width Width of @p value in bits + * @param value uint8_t value to insert + * + * @note @p width and @p lbn must to be obtained from the field's descriptor. + */ +void sfc_tbls_field_set_u8(uint32_t data[], unsigned int data_size, + uint16_t lbn, uint16_t width, uint8_t value); + +/** + * Insert IP address into a field in the @p data buffer starting at + * bit offset @p lbn and containing @p width bits. + * + * @param data Data buffer + * @param data_size Size of the data buffer + * @param lbn Offset + * @param width Width of @p value in bits + * @param ip IP address to insert + * + * @note @p width and @p lbn must to be obtained from the field's descriptor. + */ +void sfc_tbls_field_set_ip(uint32_t data[], unsigned int data_size, + uint16_t lbn, uint16_t width, const uint32_t *ip); + +/** + * Insert value into a field in the data buffer starting at + * bit offset @p lbn and containing @p width bits. + * + * @param data Data buffer + * @param data_size Size of the data buffer + * @param lbn Offset + * @param width Width of @p value in bits + * @param value uint64_t value to insert + * + * @note @p width and @p lbn must to be obtained from the field's descriptor. + */ +void sfc_tbls_field_set_u64(uint32_t data[], unsigned int data_size, + uint16_t lbn, uint16_t width, uint64_t value); + +/** + * Insert value into a field in the @p data buffer starting at + * bit offset @p lbn and containing @p width bits. + * + * @param data Data buffer + * @param data_size Size of the data buffer + * @param lbn Offset + * @param width Width of @p value in bits + * @param value Bit value to insert + * + * @note @p width and @p lbn must to be obtained from the field's descriptor. + */ +void sfc_tbls_field_set_bit(uint32_t data[], unsigned int data_size, + uint16_t lbn, uint16_t width, bool value); + #ifdef __cplusplus } #endif