From patchwork Sun Jun 4 23:24:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Malov X-Patchwork-Id: 128038 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 183A442C2C; Mon, 5 Jun 2023 01:26:39 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id A5F6542D70; Mon, 5 Jun 2023 01:25:38 +0200 (CEST) Received: from agw.arknetworks.am (agw.arknetworks.am [79.141.165.80]) by mails.dpdk.org (Postfix) with ESMTP id 2DF2F42D35 for ; Mon, 5 Jun 2023 01:25:30 +0200 (CEST) Received: from localhost.localdomain (unknown [78.109.68.201]) (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 A0FB8E12CA; Mon, 5 Jun 2023 03:25:29 +0400 (+04) From: Ivan Malov To: dev@dpdk.org Cc: Andrew Rybchenko , Ferruh Yigit , Denis Pryazhennikov , Andy Moreton Subject: [PATCH v3 10/34] net/sfc: attach to HW table API Date: Mon, 5 Jun 2023 03:24:59 +0400 Message-Id: <20230604232523.6746-11-ivan.malov@arknetworks.am> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230604232523.6746-1-ivan.malov@arknetworks.am> References: <20230601195538.8265-1-ivan.malov@arknetworks.am> <20230604232523.6746-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 The patch adds APIs to initialise, manipulate and finalise HW tables API-specific context in NIC control structure. The context itself will be used to store HW tables-related info, like table descriptors and field descriptors. Signed-off-by: Denis Pryazhennikov Reviewed-by: Ivan Malov Reviewed-by: Andy Moreton --- drivers/net/sfc/meson.build | 4 +- drivers/net/sfc/sfc.c | 18 +- drivers/net/sfc/sfc.h | 2 + drivers/net/sfc/sfc_tbl_meta.c | 71 ++++++++ drivers/net/sfc/sfc_tbl_meta.h | 37 ++++ drivers/net/sfc/sfc_tbl_meta_cache.c | 253 +++++++++++++++++++++++++++ drivers/net/sfc/sfc_tbl_meta_cache.h | 25 +++ drivers/net/sfc/sfc_tbls.c | 60 +++++++ drivers/net/sfc/sfc_tbls.h | 81 +++++++++ 9 files changed, 549 insertions(+), 2 deletions(-) create mode 100644 drivers/net/sfc/sfc_tbl_meta.c create mode 100644 drivers/net/sfc/sfc_tbl_meta.h create mode 100644 drivers/net/sfc/sfc_tbl_meta_cache.c create mode 100644 drivers/net/sfc/sfc_tbl_meta_cache.h diff --git a/drivers/net/sfc/meson.build b/drivers/net/sfc/meson.build index 39c7f24764..c9d4264674 100644 --- a/drivers/net/sfc/meson.build +++ b/drivers/net/sfc/meson.build @@ -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', diff --git a/drivers/net/sfc/sfc.c b/drivers/net/sfc/sfc.c index 22753e3417..a56521696a 100644 --- a/drivers/net/sfc/sfc.c +++ b/drivers/net/sfc/sfc.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); diff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h index 730d054aea..6b301aad60 100644 --- a/drivers/net/sfc/sfc.h +++ b/drivers/net/sfc/sfc.h @@ -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; diff --git a/drivers/net/sfc/sfc_tbl_meta.c b/drivers/net/sfc/sfc_tbl_meta.c new file mode 100644 index 0000000000..997082fd74 --- /dev/null +++ b/drivers/net/sfc/sfc_tbl_meta.c @@ -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); +} diff --git a/drivers/net/sfc/sfc_tbl_meta.h b/drivers/net/sfc/sfc_tbl_meta.h new file mode 100644 index 0000000000..7d39957514 --- /dev/null +++ b/drivers/net/sfc/sfc_tbl_meta.h @@ -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 + +#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 */ diff --git a/drivers/net/sfc/sfc_tbl_meta_cache.c b/drivers/net/sfc/sfc_tbl_meta_cache.c new file mode 100644 index 0000000000..65ba0b001e --- /dev/null +++ b/drivers/net/sfc/sfc_tbl_meta_cache.c @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2023 Advanced Micro Devices, Inc. + */ + +#include +#include + +#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) + 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; +} diff --git a/drivers/net/sfc/sfc_tbl_meta_cache.h b/drivers/net/sfc/sfc_tbl_meta_cache.h new file mode 100644 index 0000000000..2deff620a4 --- /dev/null +++ b/drivers/net/sfc/sfc_tbl_meta_cache.h @@ -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 + +#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 */ diff --git a/drivers/net/sfc/sfc_tbls.c b/drivers/net/sfc/sfc_tbls.c index db54fc0d40..d41b961454 100644 --- a/drivers/net/sfc/sfc_tbls.c +++ b/drivers/net/sfc/sfc_tbls.c @@ -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) { diff --git a/drivers/net/sfc/sfc_tbls.h b/drivers/net/sfc/sfc_tbls.h index 7b6bb5b341..be0abbf161 100644 --- a/drivers/net/sfc/sfc_tbls.h +++ b/drivers/net/sfc/sfc_tbls.h @@ -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)