f-stack/dpdk/drivers/net/sfc/sfc_tbls.c

208 lines
4.3 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2023 Advanced Micro Devices, Inc.
*/
#include "sfc.h"
#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)
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)
{
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);
}