1 /* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright (c) 2023 Advanced Micro Devices, Inc.
4 */
5
6 #include "sfc.h"
7 #include "sfc_tbls.h"
8 #include "sfc_debug.h"
9
10 #include <rte_ip.h>
11
12 /* Number of bits in uint32_t type */
13 #define SFC_TBLS_U32_BITS (sizeof(uint32_t) * CHAR_BIT)
14
15 int
sfc_tbls_attach(struct sfc_adapter * sa)16 sfc_tbls_attach(struct sfc_adapter *sa)
17 {
18 struct sfc_tbls *tables = &sa->hw_tables;
19 const struct sfc_mae *mae = &sa->mae;
20 const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
21 int rc;
22
23 sfc_log_init(sa, "entry");
24
25 if (mae->status != SFC_MAE_STATUS_ADMIN ||
26 !encp->enc_table_api_supported) {
27 tables->status = SFC_TBLS_STATUS_UNSUPPORTED;
28 return 0;
29 }
30
31 tables->status = SFC_TBLS_STATUS_SUPPORTED;
32
33 rc = sfc_tbl_meta_init(sa);
34 if (rc != 0)
35 return rc;
36
37 sfc_log_init(sa, "done");
38
39 return 0;
40 }
41
42 void
sfc_tbls_detach(struct sfc_adapter * sa)43 sfc_tbls_detach(struct sfc_adapter *sa)
44 {
45 struct sfc_tbls *tables = &sa->hw_tables;
46
47 sfc_log_init(sa, "entry");
48
49 if (tables->status != SFC_TBLS_STATUS_SUPPORTED)
50 goto done;
51
52 sfc_tbl_meta_fini(sa);
53
54 done:
55 sfc_log_init(sa, "done");
56
57 tables->status = SFC_TBLS_STATUS_UNKNOWN;
58 }
59
60 int
sfc_tbls_start(struct sfc_adapter * sa)61 sfc_tbls_start(struct sfc_adapter *sa)
62 {
63 struct sfc_tbls *tables = &sa->hw_tables;
64 int rc;
65
66 if (tables->status == SFC_TBLS_STATUS_UNKNOWN) {
67 rc = sfc_tbls_attach(sa);
68 return rc;
69 }
70
71 return 0;
72 }
73
74 static uint32_t
sfc_tbls_field_update(uint32_t in,uint16_t lbn,uint16_t width,uint32_t value)75 sfc_tbls_field_update(uint32_t in, uint16_t lbn, uint16_t width, uint32_t value)
76 {
77 uint32_t mask;
78
79 SFC_ASSERT(width <= SFC_TBLS_U32_BITS);
80
81 if (width == SFC_TBLS_U32_BITS)
82 return value;
83
84 mask = RTE_LEN2MASK(width, uint32_t);
85 value &= mask;
86
87 if (lbn != 0) {
88 mask <<= lbn;
89 value <<= lbn;
90 }
91
92 return (in & (~mask)) | value;
93 }
94
95 void
sfc_tbls_field_set_u32(uint32_t data[],__rte_unused unsigned int data_size,uint16_t lbn,uint16_t width,uint32_t value)96 sfc_tbls_field_set_u32(uint32_t data[], __rte_unused unsigned int data_size,
97 uint16_t lbn, uint16_t width, uint32_t value)
98 {
99 uint32_t data_offset = 0;
100
101 if (lbn >= SFC_TBLS_U32_BITS) {
102 data_offset = lbn / SFC_TBLS_U32_BITS;
103
104 SFC_ASSERT(data_offset < data_size);
105
106 data += data_offset;
107 lbn %= SFC_TBLS_U32_BITS;
108 }
109
110 if (lbn + width <= SFC_TBLS_U32_BITS) {
111 *data = sfc_tbls_field_update(*data, lbn, width, value);
112 } else {
113 *data = sfc_tbls_field_update(*data, lbn,
114 SFC_TBLS_U32_BITS - lbn, value);
115 value >>= SFC_TBLS_U32_BITS - lbn;
116
117 data_offset++;
118 SFC_ASSERT(data_offset < data_size);
119
120 data++;
121 *data = sfc_tbls_field_update(*data, 0,
122 width + lbn - SFC_TBLS_U32_BITS,
123 value);
124 }
125 }
126
127 void
sfc_tbls_field_set_u16(uint32_t data[],unsigned int data_size,uint16_t lbn,uint16_t width,uint16_t value)128 sfc_tbls_field_set_u16(uint32_t data[], unsigned int data_size, uint16_t lbn,
129 uint16_t width, uint16_t value)
130 {
131 sfc_tbls_field_set_u32(data, data_size, lbn, width, value);
132 }
133
134 void
sfc_tbls_field_set_u8(uint32_t data[],unsigned int data_size,uint16_t lbn,uint16_t width,uint8_t value)135 sfc_tbls_field_set_u8(uint32_t data[], unsigned int data_size, uint16_t lbn,
136 uint16_t width, uint8_t value)
137 {
138 sfc_tbls_field_set_u32(data, data_size, lbn, width, value);
139 }
140
141 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)142 sfc_tbls_field_set_ip(uint32_t data[], unsigned int data_size, uint16_t lbn,
143 __rte_unused uint16_t width, const uint32_t *ip)
144 {
145 unsigned int i;
146 size_t ipv6_addr_len = RTE_SIZEOF_FIELD(struct rte_ipv6_hdr, src_addr);
147
148 /*
149 * The same 128-bit container is used to store either
150 * an IPv4 or an IPv6 address, with an IPv4 address
151 * assumed to have 12 trailing zeroes.
152 */
153 SFC_ASSERT(width == ipv6_addr_len * CHAR_BIT);
154
155 for (i = 0; i < ipv6_addr_len / sizeof(*ip); i++) {
156 sfc_tbls_field_set_u32(data, data_size, lbn,
157 SFC_TBLS_U32_BITS, ip[i]);
158 lbn += SFC_TBLS_U32_BITS;
159 }
160 }
161
162 void
sfc_tbls_field_set_u64(uint32_t data[],__rte_unused unsigned int data_size,uint16_t lbn,uint16_t width,uint64_t value)163 sfc_tbls_field_set_u64(uint32_t data[], __rte_unused unsigned int data_size,
164 uint16_t lbn, uint16_t width, uint64_t value)
165 {
166 uint32_t data_offset = 0;
167
168 if (lbn >= SFC_TBLS_U32_BITS) {
169 data_offset = lbn / SFC_TBLS_U32_BITS;
170
171 SFC_ASSERT(data_offset < data_size);
172
173 data += data_offset;
174 lbn %= SFC_TBLS_U32_BITS;
175 }
176
177 *data = sfc_tbls_field_update(*data, lbn, SFC_TBLS_U32_BITS - lbn, value);
178 value >>= SFC_TBLS_U32_BITS - lbn;
179 width -= SFC_TBLS_U32_BITS - lbn;
180
181 data_offset++;
182 SFC_ASSERT(data_offset < data_size);
183
184 data++;
185
186 if (width > SFC_TBLS_U32_BITS) {
187 *data = sfc_tbls_field_update(*data, 0, SFC_TBLS_U32_BITS, value);
188 value >>= SFC_TBLS_U32_BITS;
189 width -= SFC_TBLS_U32_BITS;
190
191 data_offset++;
192 SFC_ASSERT(data_offset < data_size);
193
194 data++;
195 }
196
197 *data = sfc_tbls_field_update(*data, 0, width, value);
198 }
199
200 void
sfc_tbls_field_set_bit(uint32_t data[],unsigned int data_size,uint16_t lbn,uint16_t width,bool value)201 sfc_tbls_field_set_bit(uint32_t data[], unsigned int data_size, uint16_t lbn,
202 uint16_t width, bool value)
203 {
204 SFC_ASSERT(width == 1);
205
206 sfc_tbls_field_set_u32(data, data_size, lbn, width, value ? 1 : 0);
207 }
208