19200192fSDenis Pryazhennikov /* SPDX-License-Identifier: BSD-3-Clause
29200192fSDenis Pryazhennikov *
39200192fSDenis Pryazhennikov * Copyright (c) 2023 Advanced Micro Devices, Inc.
49200192fSDenis Pryazhennikov */
59200192fSDenis Pryazhennikov
6*bc712f1cSDenis Pryazhennikov #include "sfc.h"
79200192fSDenis Pryazhennikov #include "sfc_tbls.h"
89200192fSDenis Pryazhennikov #include "sfc_debug.h"
99200192fSDenis Pryazhennikov
109200192fSDenis Pryazhennikov #include <rte_ip.h>
119200192fSDenis Pryazhennikov
129200192fSDenis Pryazhennikov /* Number of bits in uint32_t type */
139200192fSDenis Pryazhennikov #define SFC_TBLS_U32_BITS (sizeof(uint32_t) * CHAR_BIT)
149200192fSDenis Pryazhennikov
15*bc712f1cSDenis Pryazhennikov int
sfc_tbls_attach(struct sfc_adapter * sa)16*bc712f1cSDenis Pryazhennikov sfc_tbls_attach(struct sfc_adapter *sa)
17*bc712f1cSDenis Pryazhennikov {
18*bc712f1cSDenis Pryazhennikov struct sfc_tbls *tables = &sa->hw_tables;
19*bc712f1cSDenis Pryazhennikov const struct sfc_mae *mae = &sa->mae;
20*bc712f1cSDenis Pryazhennikov const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
21*bc712f1cSDenis Pryazhennikov int rc;
22*bc712f1cSDenis Pryazhennikov
23*bc712f1cSDenis Pryazhennikov sfc_log_init(sa, "entry");
24*bc712f1cSDenis Pryazhennikov
25*bc712f1cSDenis Pryazhennikov if (mae->status != SFC_MAE_STATUS_ADMIN ||
26*bc712f1cSDenis Pryazhennikov !encp->enc_table_api_supported) {
27*bc712f1cSDenis Pryazhennikov tables->status = SFC_TBLS_STATUS_UNSUPPORTED;
28*bc712f1cSDenis Pryazhennikov return 0;
29*bc712f1cSDenis Pryazhennikov }
30*bc712f1cSDenis Pryazhennikov
31*bc712f1cSDenis Pryazhennikov tables->status = SFC_TBLS_STATUS_SUPPORTED;
32*bc712f1cSDenis Pryazhennikov
33*bc712f1cSDenis Pryazhennikov rc = sfc_tbl_meta_init(sa);
34*bc712f1cSDenis Pryazhennikov if (rc != 0)
35*bc712f1cSDenis Pryazhennikov return rc;
36*bc712f1cSDenis Pryazhennikov
37*bc712f1cSDenis Pryazhennikov sfc_log_init(sa, "done");
38*bc712f1cSDenis Pryazhennikov
39*bc712f1cSDenis Pryazhennikov return 0;
40*bc712f1cSDenis Pryazhennikov }
41*bc712f1cSDenis Pryazhennikov
42*bc712f1cSDenis Pryazhennikov void
sfc_tbls_detach(struct sfc_adapter * sa)43*bc712f1cSDenis Pryazhennikov sfc_tbls_detach(struct sfc_adapter *sa)
44*bc712f1cSDenis Pryazhennikov {
45*bc712f1cSDenis Pryazhennikov struct sfc_tbls *tables = &sa->hw_tables;
46*bc712f1cSDenis Pryazhennikov
47*bc712f1cSDenis Pryazhennikov sfc_log_init(sa, "entry");
48*bc712f1cSDenis Pryazhennikov
49*bc712f1cSDenis Pryazhennikov if (tables->status != SFC_TBLS_STATUS_SUPPORTED)
50*bc712f1cSDenis Pryazhennikov goto done;
51*bc712f1cSDenis Pryazhennikov
52*bc712f1cSDenis Pryazhennikov sfc_tbl_meta_fini(sa);
53*bc712f1cSDenis Pryazhennikov
54*bc712f1cSDenis Pryazhennikov done:
55*bc712f1cSDenis Pryazhennikov sfc_log_init(sa, "done");
56*bc712f1cSDenis Pryazhennikov
57*bc712f1cSDenis Pryazhennikov tables->status = SFC_TBLS_STATUS_UNKNOWN;
58*bc712f1cSDenis Pryazhennikov }
59*bc712f1cSDenis Pryazhennikov
60*bc712f1cSDenis Pryazhennikov int
sfc_tbls_start(struct sfc_adapter * sa)61*bc712f1cSDenis Pryazhennikov sfc_tbls_start(struct sfc_adapter *sa)
62*bc712f1cSDenis Pryazhennikov {
63*bc712f1cSDenis Pryazhennikov struct sfc_tbls *tables = &sa->hw_tables;
64*bc712f1cSDenis Pryazhennikov int rc;
65*bc712f1cSDenis Pryazhennikov
66*bc712f1cSDenis Pryazhennikov if (tables->status == SFC_TBLS_STATUS_UNKNOWN) {
67*bc712f1cSDenis Pryazhennikov rc = sfc_tbls_attach(sa);
68*bc712f1cSDenis Pryazhennikov return rc;
69*bc712f1cSDenis Pryazhennikov }
70*bc712f1cSDenis Pryazhennikov
71*bc712f1cSDenis Pryazhennikov return 0;
72*bc712f1cSDenis Pryazhennikov }
73*bc712f1cSDenis Pryazhennikov
749200192fSDenis Pryazhennikov static uint32_t
sfc_tbls_field_update(uint32_t in,uint16_t lbn,uint16_t width,uint32_t value)759200192fSDenis Pryazhennikov sfc_tbls_field_update(uint32_t in, uint16_t lbn, uint16_t width, uint32_t value)
769200192fSDenis Pryazhennikov {
779200192fSDenis Pryazhennikov uint32_t mask;
789200192fSDenis Pryazhennikov
799200192fSDenis Pryazhennikov SFC_ASSERT(width <= SFC_TBLS_U32_BITS);
809200192fSDenis Pryazhennikov
819200192fSDenis Pryazhennikov if (width == SFC_TBLS_U32_BITS)
829200192fSDenis Pryazhennikov return value;
839200192fSDenis Pryazhennikov
849200192fSDenis Pryazhennikov mask = RTE_LEN2MASK(width, uint32_t);
859200192fSDenis Pryazhennikov value &= mask;
869200192fSDenis Pryazhennikov
879200192fSDenis Pryazhennikov if (lbn != 0) {
889200192fSDenis Pryazhennikov mask <<= lbn;
899200192fSDenis Pryazhennikov value <<= lbn;
909200192fSDenis Pryazhennikov }
919200192fSDenis Pryazhennikov
929200192fSDenis Pryazhennikov return (in & (~mask)) | value;
939200192fSDenis Pryazhennikov }
949200192fSDenis Pryazhennikov
959200192fSDenis Pryazhennikov void
sfc_tbls_field_set_u32(uint32_t data[],__rte_unused unsigned int data_size,uint16_t lbn,uint16_t width,uint32_t value)969200192fSDenis Pryazhennikov sfc_tbls_field_set_u32(uint32_t data[], __rte_unused unsigned int data_size,
979200192fSDenis Pryazhennikov uint16_t lbn, uint16_t width, uint32_t value)
989200192fSDenis Pryazhennikov {
999200192fSDenis Pryazhennikov uint32_t data_offset = 0;
1009200192fSDenis Pryazhennikov
1019200192fSDenis Pryazhennikov if (lbn >= SFC_TBLS_U32_BITS) {
1029200192fSDenis Pryazhennikov data_offset = lbn / SFC_TBLS_U32_BITS;
1039200192fSDenis Pryazhennikov
1049200192fSDenis Pryazhennikov SFC_ASSERT(data_offset < data_size);
1059200192fSDenis Pryazhennikov
1069200192fSDenis Pryazhennikov data += data_offset;
1079200192fSDenis Pryazhennikov lbn %= SFC_TBLS_U32_BITS;
1089200192fSDenis Pryazhennikov }
1099200192fSDenis Pryazhennikov
1109200192fSDenis Pryazhennikov if (lbn + width <= SFC_TBLS_U32_BITS) {
1119200192fSDenis Pryazhennikov *data = sfc_tbls_field_update(*data, lbn, width, value);
1129200192fSDenis Pryazhennikov } else {
1139200192fSDenis Pryazhennikov *data = sfc_tbls_field_update(*data, lbn,
1149200192fSDenis Pryazhennikov SFC_TBLS_U32_BITS - lbn, value);
1159200192fSDenis Pryazhennikov value >>= SFC_TBLS_U32_BITS - lbn;
1169200192fSDenis Pryazhennikov
1179200192fSDenis Pryazhennikov data_offset++;
1189200192fSDenis Pryazhennikov SFC_ASSERT(data_offset < data_size);
1199200192fSDenis Pryazhennikov
1209200192fSDenis Pryazhennikov data++;
1219200192fSDenis Pryazhennikov *data = sfc_tbls_field_update(*data, 0,
1229200192fSDenis Pryazhennikov width + lbn - SFC_TBLS_U32_BITS,
1239200192fSDenis Pryazhennikov value);
1249200192fSDenis Pryazhennikov }
1259200192fSDenis Pryazhennikov }
1269200192fSDenis Pryazhennikov
1279200192fSDenis Pryazhennikov void
sfc_tbls_field_set_u16(uint32_t data[],unsigned int data_size,uint16_t lbn,uint16_t width,uint16_t value)1289200192fSDenis Pryazhennikov sfc_tbls_field_set_u16(uint32_t data[], unsigned int data_size, uint16_t lbn,
1299200192fSDenis Pryazhennikov uint16_t width, uint16_t value)
1309200192fSDenis Pryazhennikov {
1319200192fSDenis Pryazhennikov sfc_tbls_field_set_u32(data, data_size, lbn, width, value);
1329200192fSDenis Pryazhennikov }
1339200192fSDenis Pryazhennikov
1349200192fSDenis Pryazhennikov void
sfc_tbls_field_set_u8(uint32_t data[],unsigned int data_size,uint16_t lbn,uint16_t width,uint8_t value)1359200192fSDenis Pryazhennikov sfc_tbls_field_set_u8(uint32_t data[], unsigned int data_size, uint16_t lbn,
1369200192fSDenis Pryazhennikov uint16_t width, uint8_t value)
1379200192fSDenis Pryazhennikov {
1389200192fSDenis Pryazhennikov sfc_tbls_field_set_u32(data, data_size, lbn, width, value);
1399200192fSDenis Pryazhennikov }
1409200192fSDenis Pryazhennikov
1419200192fSDenis Pryazhennikov 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)1429200192fSDenis Pryazhennikov sfc_tbls_field_set_ip(uint32_t data[], unsigned int data_size, uint16_t lbn,
1439200192fSDenis Pryazhennikov __rte_unused uint16_t width, const uint32_t *ip)
1449200192fSDenis Pryazhennikov {
1459200192fSDenis Pryazhennikov unsigned int i;
1469200192fSDenis Pryazhennikov size_t ipv6_addr_len = RTE_SIZEOF_FIELD(struct rte_ipv6_hdr, src_addr);
1479200192fSDenis Pryazhennikov
1489200192fSDenis Pryazhennikov /*
1499200192fSDenis Pryazhennikov * The same 128-bit container is used to store either
1509200192fSDenis Pryazhennikov * an IPv4 or an IPv6 address, with an IPv4 address
1519200192fSDenis Pryazhennikov * assumed to have 12 trailing zeroes.
1529200192fSDenis Pryazhennikov */
1539200192fSDenis Pryazhennikov SFC_ASSERT(width == ipv6_addr_len * CHAR_BIT);
1549200192fSDenis Pryazhennikov
1559200192fSDenis Pryazhennikov for (i = 0; i < ipv6_addr_len / sizeof(*ip); i++) {
1569200192fSDenis Pryazhennikov sfc_tbls_field_set_u32(data, data_size, lbn,
1579200192fSDenis Pryazhennikov SFC_TBLS_U32_BITS, ip[i]);
1589200192fSDenis Pryazhennikov lbn += SFC_TBLS_U32_BITS;
1599200192fSDenis Pryazhennikov }
1609200192fSDenis Pryazhennikov }
1619200192fSDenis Pryazhennikov
1629200192fSDenis Pryazhennikov void
sfc_tbls_field_set_u64(uint32_t data[],__rte_unused unsigned int data_size,uint16_t lbn,uint16_t width,uint64_t value)1639200192fSDenis Pryazhennikov sfc_tbls_field_set_u64(uint32_t data[], __rte_unused unsigned int data_size,
1649200192fSDenis Pryazhennikov uint16_t lbn, uint16_t width, uint64_t value)
1659200192fSDenis Pryazhennikov {
1669200192fSDenis Pryazhennikov uint32_t data_offset = 0;
1679200192fSDenis Pryazhennikov
1689200192fSDenis Pryazhennikov if (lbn >= SFC_TBLS_U32_BITS) {
1699200192fSDenis Pryazhennikov data_offset = lbn / SFC_TBLS_U32_BITS;
1709200192fSDenis Pryazhennikov
1719200192fSDenis Pryazhennikov SFC_ASSERT(data_offset < data_size);
1729200192fSDenis Pryazhennikov
1739200192fSDenis Pryazhennikov data += data_offset;
1749200192fSDenis Pryazhennikov lbn %= SFC_TBLS_U32_BITS;
1759200192fSDenis Pryazhennikov }
1769200192fSDenis Pryazhennikov
1779200192fSDenis Pryazhennikov *data = sfc_tbls_field_update(*data, lbn, SFC_TBLS_U32_BITS - lbn, value);
1789200192fSDenis Pryazhennikov value >>= SFC_TBLS_U32_BITS - lbn;
1799200192fSDenis Pryazhennikov width -= SFC_TBLS_U32_BITS - lbn;
1809200192fSDenis Pryazhennikov
1819200192fSDenis Pryazhennikov data_offset++;
1829200192fSDenis Pryazhennikov SFC_ASSERT(data_offset < data_size);
1839200192fSDenis Pryazhennikov
1849200192fSDenis Pryazhennikov data++;
1859200192fSDenis Pryazhennikov
1869200192fSDenis Pryazhennikov if (width > SFC_TBLS_U32_BITS) {
1879200192fSDenis Pryazhennikov *data = sfc_tbls_field_update(*data, 0, SFC_TBLS_U32_BITS, value);
1889200192fSDenis Pryazhennikov value >>= SFC_TBLS_U32_BITS;
1899200192fSDenis Pryazhennikov width -= SFC_TBLS_U32_BITS;
1909200192fSDenis Pryazhennikov
1919200192fSDenis Pryazhennikov data_offset++;
1929200192fSDenis Pryazhennikov SFC_ASSERT(data_offset < data_size);
1939200192fSDenis Pryazhennikov
1949200192fSDenis Pryazhennikov data++;
1959200192fSDenis Pryazhennikov }
1969200192fSDenis Pryazhennikov
1979200192fSDenis Pryazhennikov *data = sfc_tbls_field_update(*data, 0, width, value);
1989200192fSDenis Pryazhennikov }
1999200192fSDenis Pryazhennikov
2009200192fSDenis Pryazhennikov void
sfc_tbls_field_set_bit(uint32_t data[],unsigned int data_size,uint16_t lbn,uint16_t width,bool value)2019200192fSDenis Pryazhennikov sfc_tbls_field_set_bit(uint32_t data[], unsigned int data_size, uint16_t lbn,
2029200192fSDenis Pryazhennikov uint16_t width, bool value)
2039200192fSDenis Pryazhennikov {
2049200192fSDenis Pryazhennikov SFC_ASSERT(width == 1);
2059200192fSDenis Pryazhennikov
2069200192fSDenis Pryazhennikov sfc_tbls_field_set_u32(data, data_size, lbn, width, value ? 1 : 0);
2079200192fSDenis Pryazhennikov }
208