On 6/5/23 02:24, Ivan Malov wrote:
From: Denis Pryazhennikov <denis.pryazhenni...@arknetworks.am>

Implemented functions that help to fill user data for
manipulation with HW tables in the required format.

Signed-off-by: Denis Pryazhennikov <denis.pryazhenni...@arknetworks.am>
Reviewed-by: Ivan Malov <ivan.ma...@arknetworks.am>
Reviewed-by: Andy Moreton <amore...@xilinx.com>
---
  drivers/net/sfc/meson.build |   1 +
  drivers/net/sfc/sfc_tbls.c  | 140 ++++++++++++++++++++++++++++++++++++
  drivers/net/sfc/sfc_tbls.h  | 135 ++++++++++++++++++++++++++++++++++
  3 files changed, 276 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..db54fc0d40
--- /dev/null
+++ b/drivers/net/sfc/sfc_tbls.c
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2023 Advanced Micro Devices, Inc.
+ */
+
+#include "sfc_tbls.h"
+#include "sfc_debug.h"
+
+#include <rte_ip.h>
+
+/* 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;
+
+       if (width == SFC_TBLS_U32_BITS)
+               return value;
+
+       mask = RTE_LEN2MASK(width, uint32_t);

What should/will happen if width is more than 32?

+       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);

It is unclear why the function is about IPv6 address only. Could you add a comment to explain IPv4 case.

+
+       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 2a5c87b82c..7b6bb5b341 100644
--- a/drivers/net/sfc/sfc_tbls.h
+++ b/drivers/net/sfc/sfc_tbls.h
@@ -63,6 +63,141 @@ 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) {

Wrong position of open curly bracket.

+       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

Reply via email to