@@ -71,7 +71,7 @@ if not cc.links(atomic_check_code)
ext_deps += libatomic_dep
endif
-deps += ['common_sfc_efx', 'bus_pci']
+deps += ['common_sfc_efx', 'bus_pci', 'hash']
sources = files(
'sfc_ethdev.c',
'sfc_kvargs.c',
@@ -88,6 +88,8 @@ sources = files(
'sfc_filter.c',
'sfc_switch.c',
'sfc_tbls.c',
+ 'sfc_tbl_meta.c',
+ 'sfc_tbl_meta_cache.c',
'sfc_mae.c',
'sfc_mae_counter.c',
'sfc_flow.c',
@@ -491,6 +491,10 @@ sfc_try_start(struct sfc_adapter *sa)
if (rc != 0)
goto fail_ev_start;
+ rc = sfc_tbls_start(sa);
+ if (rc != 0)
+ goto fail_tbls_start;
+
rc = sfc_port_start(sa);
if (rc != 0)
goto fail_port_start;
@@ -526,9 +530,12 @@ sfc_try_start(struct sfc_adapter *sa)
fail_rx_start:
sfc_port_stop(sa);
-fail_port_start:
+fail_tbls_start:
sfc_ev_stop(sa);
+fail_port_start:
+ sfc_tbls_stop(sa);
+
fail_ev_start:
sfc_intr_stop(sa);
@@ -626,6 +633,7 @@ sfc_stop(struct sfc_adapter *sa)
sfc_tx_stop(sa);
sfc_rx_stop(sa);
sfc_port_stop(sa);
+ sfc_tbls_stop(sa);
sfc_ev_stop(sa);
sfc_intr_stop(sa);
efx_nic_fini(sa->nic);
@@ -983,6 +991,10 @@ sfc_attach(struct sfc_adapter *sa)
if (rc != 0)
goto fail_mae_attach;
+ rc = sfc_tbls_attach(sa);
+ if (rc != 0)
+ goto fail_tables_attach;
+
rc = sfc_mae_switchdev_init(sa);
if (rc != 0)
goto fail_mae_switchdev_init;
@@ -1025,6 +1037,9 @@ sfc_attach(struct sfc_adapter *sa)
sfc_mae_switchdev_fini(sa);
fail_mae_switchdev_init:
+ sfc_tbls_detach(sa);
+
+fail_tables_attach:
sfc_mae_detach(sa);
fail_mae_attach:
@@ -1088,6 +1103,7 @@ sfc_detach(struct sfc_adapter *sa)
sfc_repr_proxy_detach(sa);
sfc_mae_switchdev_fini(sa);
+ sfc_tbls_detach(sa);
sfc_mae_detach(sa);
sfc_mae_counter_rxq_detach(sa);
sfc_filter_detach(sa);
@@ -31,6 +31,7 @@
#include "sfc_flow_tunnel.h"
#include "sfc_sriov.h"
#include "sfc_mae.h"
+#include "sfc_tbls.h"
#include "sfc_dp.h"
#include "sfc_sw_stats.h"
#include "sfc_repr_proxy.h"
@@ -244,6 +245,7 @@ struct sfc_adapter {
struct sfc_ft_ctx ft_ctx_pool[SFC_FT_MAX_NTUNNELS];
struct sfc_filter filter;
struct sfc_mae mae;
+ struct sfc_tbls hw_tables;
struct sfc_repr_proxy repr_proxy;
struct sfc_flow_list flow_list;
new file mode 100644
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2023 Advanced Micro Devices, Inc.
+ */
+
+#include "sfc.h"
+#include "sfc_tbl_meta.h"
+#include "sfc_tbl_meta_cache.h"
+
+const struct sfc_tbl_meta *
+sfc_tbl_meta_lookup(struct sfc_adapter *sa, efx_table_id_t table_id)
+{
+ struct sfc_tbl_meta *meta;
+ struct sfc_tbls *tables = &sa->hw_tables;
+ int rc;
+
+ SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+ if (tables->status != SFC_TBLS_STATUS_SUPPORTED)
+ return NULL;
+
+ rc = rte_hash_lookup_data(tables->meta.cache, (const void *)&table_id,
+ (void **)&meta);
+ if (rc < 0)
+ return NULL;
+
+ SFC_ASSERT(meta != NULL);
+ SFC_ASSERT(meta->table_id == table_id);
+
+ return meta;
+}
+
+int
+sfc_tbl_meta_init(struct sfc_adapter *sa)
+{
+ struct sfc_tbls *tables = &sa->hw_tables;
+ struct sfc_tbl_meta_cache *meta = &tables->meta;
+ int rc;
+
+ SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+ if (tables->status != SFC_TBLS_STATUS_SUPPORTED)
+ return 0;
+
+ rc = sfc_tbl_meta_cache_ctor(&meta->cache);
+ if (rc != 0)
+ return rc;
+
+ rc = sfc_tbl_meta_cache_update(meta->cache, sa->nic);
+ if (rc != 0) {
+ sfc_tbl_meta_cache_dtor(&meta->cache);
+ return rc;
+ }
+
+ return 0;
+}
+
+void
+sfc_tbl_meta_fini(struct sfc_adapter *sa)
+{
+ struct sfc_tbls *tables = &sa->hw_tables;
+ struct sfc_tbl_meta_cache *meta = &tables->meta;
+
+ if (meta->cache == NULL)
+ return;
+
+ SFC_ASSERT(sfc_adapter_is_locked(sa));
+ SFC_ASSERT(tables->status == SFC_TBLS_STATUS_SUPPORTED);
+
+ sfc_tbl_meta_cache_dtor(&meta->cache);
+}
new file mode 100644
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2023 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _SFC_TBL_META_H
+#define _SFC_TBL_META_H
+
+#include <rte_hash.h>
+
+#include "efx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Metadata about table layout */
+struct sfc_tbl_meta {
+ efx_table_id_t table_id;
+ efx_table_descriptor_t descriptor;
+ efx_table_field_descriptor_t *keys;
+ efx_table_field_descriptor_t *responses;
+};
+
+struct sfc_tbl_meta_cache {
+ struct rte_hash *cache;
+};
+
+struct sfc_adapter;
+
+const struct sfc_tbl_meta *sfc_tbl_meta_lookup(struct sfc_adapter *sa,
+ efx_table_id_t table_id);
+
+int sfc_tbl_meta_init(struct sfc_adapter *sa);
+void sfc_tbl_meta_fini(struct sfc_adapter *sa);
+
+#endif /* _SFC_TBL_META_H */
new file mode 100644
@@ -0,0 +1,253 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2023 Advanced Micro Devices, Inc.
+ */
+
+#include <rte_malloc.h>
+#include <rte_jhash.h>
+
+#include "sfc_tbl_meta_cache.h"
+#include "sfc_debug.h"
+
+/* The minimal size of the table meta cache */
+#define SFC_TBL_META_CACHE_SIZE_MIN 8
+
+int
+sfc_tbl_meta_cache_ctor(struct rte_hash **ref_cache)
+{
+ size_t cache_size = RTE_MAX((unsigned int)SFC_TBL_META_CACHE_SIZE_MIN,
+ efx_table_supported_num_get());
+ struct rte_hash *cache = NULL;
+ const struct rte_hash_parameters hash_params = {
+ .name = "meta_hash_table",
+ .hash_func = rte_jhash,
+ .entries = cache_size,
+ .socket_id = rte_socket_id(),
+ .key_len = sizeof(efx_table_id_t),
+ };
+
+ cache = rte_hash_create(&hash_params);
+ if (cache == NULL)
+ return -ENOMEM;
+
+ *ref_cache = cache;
+
+ return 0;
+}
+
+static void
+sfc_tbl_meta_cache_free(struct sfc_tbl_meta *meta)
+{
+ SFC_ASSERT(meta != NULL);
+
+ rte_free(meta->keys);
+ rte_free(meta->responses);
+ rte_free(meta);
+}
+
+void
+sfc_tbl_meta_cache_dtor(struct rte_hash **ref_cache)
+{
+ struct rte_hash *cache = *ref_cache;
+ const void *next_key;
+ uint32_t iter = 0;
+ void *next_meta;
+
+ if (cache == NULL)
+ return;
+
+ while (rte_hash_iterate(cache, &next_key, &next_meta, &iter) >= 0)
+ sfc_tbl_meta_cache_free((struct sfc_tbl_meta *)next_meta);
+
+ rte_hash_free(cache);
+
+ *ref_cache = NULL;
+}
+
+/**
+ * Table descriptor contains information about the table's
+ * fields that can be associated with both the key and the response.
+ * Save these fields by separating the key from the response in
+ * appropriate places based on their lengths.
+ */
+static int
+sfc_tbl_meta_desc_fields_copy(struct sfc_tbl_meta *meta, efx_nic_t *enp,
+ efx_table_field_descriptor_t *fields,
+ unsigned int total_n_fields)
+{
+ uint16_t n_key_fields = meta->descriptor.n_key_fields;
+ size_t field_size = sizeof(*fields);
+ unsigned int n_field_descs_written;
+ uint32_t field_offset;
+ int rc;
+
+ for (n_field_descs_written = 0, field_offset = 0;
+ field_offset < total_n_fields;
+ field_offset += n_field_descs_written) {
+ rc = efx_table_describe(enp, meta->table_id, field_offset, NULL,
+ fields, total_n_fields, &n_field_descs_written);
+ if (rc != 0)
+ return rc;
+
+ if (field_offset + n_field_descs_written > total_n_fields)
+ return -EINVAL;
+
+ if (field_offset < n_key_fields &&
+ field_offset + n_field_descs_written > n_key_fields) {
+ /*
+ * Some of the descriptors belong to key,
+ * the other to response.
+ */
+ rte_memcpy(RTE_PTR_ADD(meta->keys, field_offset * field_size),
+ fields, (n_key_fields - field_offset) * field_size);
+ rte_memcpy(meta->responses,
+ RTE_PTR_ADD(fields,
+ (n_key_fields - field_offset) * field_size),
+ (field_offset + n_field_descs_written - n_key_fields) *
+ field_size);
+ } else if (field_offset < n_key_fields) {
+ /* All fields belong to the key */
+ rte_memcpy(RTE_PTR_ADD(meta->keys, field_offset * field_size),
+ fields, n_field_descs_written * field_size);
+ } else {
+ /* All fields belong to the response */
+ rte_memcpy(RTE_PTR_ADD(meta->responses,
+ (field_offset - n_key_fields) * field_size),
+ fields, n_field_descs_written * field_size);
+ }
+ }
+
+ return 0;
+}
+
+static int
+sfc_tbl_meta_desc_read(struct sfc_tbl_meta *meta, efx_nic_t *enp,
+ efx_table_id_t table_id)
+{
+ efx_table_field_descriptor_t *fields;
+ unsigned int total_n_fields;
+ int rc;
+
+ rc = efx_table_describe(enp, table_id, 0, &meta->descriptor, NULL, 0, NULL);
+ if (rc != 0)
+ return rc;
+
+ total_n_fields = meta->descriptor.n_key_fields + meta->descriptor.n_resp_fields;
+
+ fields = rte_calloc(NULL, total_n_fields, sizeof(*fields), 0);
+ if (fields == NULL)
+ return -ENOMEM;
+
+ meta->table_id = table_id;
+
+ meta->keys = rte_calloc("efx_table_key_field_descs",
+ meta->descriptor.n_key_fields,
+ sizeof(*meta->keys), 0);
+ if (meta->keys == NULL) {
+ rc = -ENOMEM;
+ goto fail_alloc_keys;
+ }
+
+ meta->responses = rte_calloc("efx_table_response_field_descs",
+ meta->descriptor.n_resp_fields,
+ sizeof(*meta->responses), 0);
+ if (meta->responses == NULL) {
+ rc = -ENOMEM;
+ goto fail_alloc_responses;
+ }
+
+ rc = sfc_tbl_meta_desc_fields_copy(meta, enp, fields, total_n_fields);
+ if (rc != 0)
+ goto fail_copy_fields;
+
+ return 0;
+
+fail_copy_fields:
+ rte_free(meta->responses);
+fail_alloc_responses:
+ rte_free(meta->keys);
+fail_alloc_keys:
+ rte_free(fields);
+
+ return rc;
+}
+
+static int
+sfc_tbl_meta_cache_add(struct rte_hash *cache, efx_nic_t *enp,
+ efx_table_id_t table_id)
+{
+ struct sfc_tbl_meta *meta = NULL;
+ int rc;
+
+ meta = rte_zmalloc("sfc_tbl_meta", sizeof(*meta), 0);
+ if (meta == NULL)
+ return -ENOMEM;
+
+ rc = sfc_tbl_meta_desc_read(meta, enp, table_id);
+ if (rc != 0)
+ goto fail_read_meta;
+
+ rc = rte_hash_add_key_data(cache, &table_id, meta);
+ if (rc != 0)
+ goto fail_add_key;
+
+ return 0;
+
+fail_add_key:
+ rte_free(meta->keys);
+ rte_free(meta->responses);
+fail_read_meta:
+ rte_free(meta);
+
+ return rc;
+}
+
+int
+sfc_tbl_meta_cache_update(struct rte_hash *cache, efx_nic_t *enp)
+{
+ efx_table_id_t *table_ids = NULL;
+ unsigned int n_table_ids_written;
+ unsigned int total_n_tables;
+ unsigned int n_table_ids;
+ uint32_t table_index;
+ unsigned int i;
+ int rc = 0;
+
+ rc = efx_table_list(enp, 0, &total_n_tables, NULL, 0, NULL);
+ if (rc != 0)
+ return rc;
+
+ table_ids = rte_calloc(NULL, total_n_tables, sizeof(*table_ids), 0);
+ if (table_ids == NULL)
+ return -ENOMEM;
+
+ n_table_ids = total_n_tables;
+
+ for (table_index = 0, n_table_ids_written = 0;
+ table_index < total_n_tables;
+ table_index += n_table_ids_written) {
+ rc = efx_table_list(enp, table_index, NULL,
+ table_ids, n_table_ids, &n_table_ids_written);
+ if (rc != 0)
+ goto out;
+
+ if (table_index + n_table_ids_written > total_n_tables) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < n_table_ids_written; i++, table_index++) {
+ if (!efx_table_is_supported(table_ids[i]))
+ continue;
+
+ rc = sfc_tbl_meta_cache_add(cache, enp, table_ids[i]);
+ if (rc != 0)
+ goto out;
+ }
+ }
+
+out:
+ rte_free(table_ids);
+
+ return rc;
+}
new file mode 100644
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2023 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _SFC_TBL_META_CACHE_H
+#define _SFC_TBL_META_CACHE_H
+
+#include <rte_hash.h>
+
+#include "efx.h"
+
+#include "sfc_tbl_meta.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int sfc_tbl_meta_cache_ctor(struct rte_hash **ref_cache);
+
+void sfc_tbl_meta_cache_dtor(struct rte_hash **ref_cache);
+
+int sfc_tbl_meta_cache_update(struct rte_hash *cache, efx_nic_t *enp);
+
+#endif /* _SFC_TBLS_DESC_CACHE_H */
@@ -3,6 +3,7 @@
* Copyright (c) 2023 Advanced Micro Devices, Inc.
*/
+#include "sfc.h"
#include "sfc_tbls.h"
#include "sfc_debug.h"
@@ -11,6 +12,65 @@
/* Number of bits in uint32_t type */
#define SFC_TBLS_U32_BITS (sizeof(uint32_t) * CHAR_BIT)
+int
+sfc_tbls_attach(struct sfc_adapter *sa)
+{
+ struct sfc_tbls *tables = &sa->hw_tables;
+ const struct sfc_mae *mae = &sa->mae;
+ const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
+ int rc;
+
+ sfc_log_init(sa, "entry");
+
+ if (mae->status != SFC_MAE_STATUS_ADMIN ||
+ !encp->enc_table_api_supported) {
+ tables->status = SFC_TBLS_STATUS_UNSUPPORTED;
+ return 0;
+ }
+
+ tables->status = SFC_TBLS_STATUS_SUPPORTED;
+
+ rc = sfc_tbl_meta_init(sa);
+ if (rc != 0)
+ return rc;
+
+ sfc_log_init(sa, "done");
+
+ return 0;
+}
+
+void
+sfc_tbls_detach(struct sfc_adapter *sa)
+{
+ struct sfc_tbls *tables = &sa->hw_tables;
+
+ sfc_log_init(sa, "entry");
+
+ if (tables->status != SFC_TBLS_STATUS_SUPPORTED)
+ goto done;
+
+ sfc_tbl_meta_fini(sa);
+
+done:
+ sfc_log_init(sa, "done");
+
+ tables->status = SFC_TBLS_STATUS_UNKNOWN;
+}
+
+int
+sfc_tbls_start(struct sfc_adapter *sa)
+{
+ struct sfc_tbls *tables = &sa->hw_tables;
+ int rc;
+
+ if (tables->status == SFC_TBLS_STATUS_UNKNOWN) {
+ rc = sfc_tbls_attach(sa);
+ return rc;
+ }
+
+ return 0;
+}
+
static uint32_t
sfc_tbls_field_update(uint32_t in, uint16_t lbn, uint16_t width, uint32_t value)
{
@@ -8,6 +8,8 @@
#include "efx.h"
+#include "sfc_tbl_meta.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -44,6 +46,85 @@ extern "C" {
/* Mask is used only for STCAM */
#define SFC_TBLS_BCAM_MASK_WIDTH 0
+/** Options for HW tables support status */
+enum sfc_tbls_status {
+ SFC_TBLS_STATUS_UNKNOWN = 0,
+ SFC_TBLS_STATUS_UNSUPPORTED,
+ SFC_TBLS_STATUS_SUPPORTED,
+};
+
+/**
+ * Entry point to access HW tables
+ *
+ * SFC driver can access hardware (HW) tables.
+ * Interaction with HW tables is done through the MCDI table access API
+ * that is implemented in EFX.
+ *
+ * In order to manipulate data on HW tables it's necessary to
+ * - discover the list of supported tables;
+ * - read a table descriptor to get details of the structure
+ * of the table;
+ * - get named fields of the table;
+ * - insert/delete/update table entries based on given fields
+ * and information about the table
+ *
+ * All table layout data should be saved in a cache.
+ * The cache allows to avoid getting the table descriptor each time when you want
+ * to manipulate table entries. It just contains the table
+ * descriptors and all associated data. The cache is based on the RTE hash map and
+ * it uses a table ID as a key.
+ * The sfc_tbl_meta library serves as a wrapper over the cache and allows to user
+ * to get all information about the tables without worrying about the cache.
+ *
+ * +------------------------+
+ * | Cache is uninitialized |<----------------------------------+
+ * +------------------------+ |
+ * | |
+ * | sfc_attach() |
+ * | sfc_tbls_attach() -- (fail) -- sfc_tbls_detach()------+
+ * V ^
+ * +------------------------+ |
+ * | Cache is initialized | +-------+
+ * +------------------------+ |
+ * | sfc_start() |
+ * | sfc_tbls_start() -- (fail) -- sfc_tbls_stop()-+
+ * V |
+ * +------------------------+ |
+ * | Cache is initialized | |
+ * | and valid | |
+ * +------------------------+ |
+ * | |
+ * | sfc_restart() |
+ * V |
+ * +------------------------+ |
+ * | Cache is initialized | |
+ * | but can be invalid | |
+ * +------------------------+---------------------------+
+ */
+struct sfc_tbls {
+ struct sfc_tbl_meta_cache meta;
+ enum sfc_tbls_status status;
+};
+
+struct sfc_adapter;
+
+static inline bool
+sfc_tbls_id_is_supported(struct sfc_adapter *sa,
+ efx_table_id_t table_id)
+{
+ return (sfc_tbl_meta_lookup(sa, table_id) == NULL ? false : true);
+}
+
+int sfc_tbls_attach(struct sfc_adapter *sa);
+void sfc_tbls_detach(struct sfc_adapter *sa);
+int sfc_tbls_start(struct sfc_adapter *sa);
+
+static inline void
+sfc_tbls_stop(struct sfc_adapter *sa)
+{
+ sfc_tbls_detach(sa);
+}
+
static inline int
sfc_tbls_bcam_entry_insert(efx_nic_t *enp, efx_table_id_t table_id, uint16_t key_width,
uint16_t resp_width, uint8_t *data, unsigned int data_size)