1 /* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright (c) 2023 Advanced Micro Devices, Inc.
4 */
5
6 #include "efx.h"
7 #include "efx_impl.h"
8
9 /* List of HW tables that have support in efx */
10 static const efx_table_id_t efx_supported_table_ids[] = {
11 EFX_TABLE_ID_CONNTRACK,
12 };
13
14 __checkReturn efx_rc_t
efx_table_list(__in efx_nic_t * enp,__in uint32_t entry_ofst,__out_opt unsigned int * total_n_tablesp,__out_ecount_opt (n_table_ids)efx_table_id_t * table_ids,__in unsigned int n_table_ids,__out_opt unsigned int * n_table_ids_writtenp)15 efx_table_list(
16 __in efx_nic_t *enp,
17 __in uint32_t entry_ofst,
18 __out_opt unsigned int *total_n_tablesp,
19 __out_ecount_opt(n_table_ids) efx_table_id_t *table_ids,
20 __in unsigned int n_table_ids,
21 __out_opt unsigned int *n_table_ids_writtenp)
22 {
23 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
24 unsigned int n_entries;
25 efx_mcdi_req_t req;
26 unsigned int i;
27 efx_rc_t rc;
28 EFX_MCDI_DECLARE_BUF(payload,
29 MC_CMD_TABLE_LIST_IN_LEN,
30 MC_CMD_TABLE_LIST_OUT_LENMAX_MCDI2);
31
32 /* Ensure EFX and MCDI use same values for table IDs */
33 EFX_STATIC_ASSERT(EFX_TABLE_ID_CONNTRACK == TABLE_ID_CONNTRACK_TABLE);
34
35 if (encp->enc_table_api_supported == B_FALSE) {
36 rc = ENOTSUP;
37 goto fail1;
38 }
39
40 if ((n_table_ids != 0) &&
41 ((table_ids == NULL) || (n_table_ids_writtenp == NULL))) {
42 rc = EINVAL;
43 goto fail2;
44 }
45
46 req.emr_cmd = MC_CMD_TABLE_LIST;
47 req.emr_in_buf = payload;
48 req.emr_in_length = MC_CMD_TABLE_LIST_IN_LEN;
49 req.emr_out_buf = payload;
50 req.emr_out_length = MC_CMD_TABLE_LIST_OUT_LENMAX_MCDI2;
51
52 MCDI_IN_SET_DWORD(req, TABLE_LIST_IN_FIRST_TABLE_ID_INDEX, entry_ofst);
53
54 efx_mcdi_execute(enp, &req);
55
56 if (req.emr_rc != 0) {
57 rc = req.emr_rc;
58 goto fail3;
59 }
60
61 if (req.emr_out_length_used < MC_CMD_TABLE_LIST_OUT_LENMIN) {
62 rc = EMSGSIZE;
63 goto fail4;
64 }
65
66 if (total_n_tablesp != NULL)
67 *total_n_tablesp = MCDI_OUT_DWORD(req, TABLE_LIST_OUT_N_TABLES);
68
69 n_entries = MC_CMD_TABLE_LIST_OUT_TABLE_ID_NUM(req.emr_out_length_used);
70
71 if (table_ids != NULL) {
72 if (n_entries > n_table_ids) {
73 rc = ENOMEM;
74 goto fail5;
75 }
76
77 for (i = 0; i < n_entries; i++) {
78 table_ids[i] = MCDI_OUT_INDEXED_DWORD(req,
79 TABLE_LIST_OUT_TABLE_ID, i);
80 }
81 }
82
83 if (n_table_ids_writtenp != NULL)
84 *n_table_ids_writtenp = n_entries;
85
86 return (0);
87
88 fail5:
89 EFSYS_PROBE(fail5);
90 fail4:
91 EFSYS_PROBE(fail4);
92 fail3:
93 EFSYS_PROBE(fail3);
94 fail2:
95 EFSYS_PROBE(fail2);
96 fail1:
97 EFSYS_PROBE1(fail1, efx_rc_t, rc);
98 return (rc);
99 }
100
101 __checkReturn size_t
efx_table_supported_num_get(__in void)102 efx_table_supported_num_get(
103 __in void)
104 {
105 return (EFX_ARRAY_SIZE(efx_supported_table_ids));
106 }
107
108 __checkReturn boolean_t
efx_table_is_supported(__in efx_table_id_t table_id)109 efx_table_is_supported(
110 __in efx_table_id_t table_id)
111 {
112 size_t i;
113
114 for (i = 0; i < efx_table_supported_num_get(); i++) {
115 if (efx_supported_table_ids[i] == table_id)
116 return (B_TRUE);
117 }
118
119 return (B_FALSE);
120 }
121
122 static __checkReturn efx_rc_t
efx_table_ct_desc_fields_check(__in_ecount (n_fields_descs)efx_table_field_descriptor_t * fields_descsp,__in unsigned int n_fields_descs)123 efx_table_ct_desc_fields_check(
124 __in_ecount(n_fields_descs) efx_table_field_descriptor_t *fields_descsp,
125 __in unsigned int n_fields_descs)
126 {
127 unsigned int i;
128 efx_rc_t rc;
129
130 for (i = 0; i < n_fields_descs; i++) {
131 switch (fields_descsp[i].field_id) {
132 case EFX_TABLE_FIELD_ID_ETHER_TYPE:
133 case EFX_TABLE_FIELD_ID_SRC_IP:
134 case EFX_TABLE_FIELD_ID_DST_IP:
135 case EFX_TABLE_FIELD_ID_IP_PROTO:
136 case EFX_TABLE_FIELD_ID_SRC_PORT:
137 case EFX_TABLE_FIELD_ID_DST_PORT:
138 if (fields_descsp[i].mask_type != EFX_TABLE_FIELD_MASK_EXACT) {
139 rc = EINVAL;
140 goto fail1;
141 }
142 break;
143 /*
144 * TODO:
145 * All fields in the CT table have EXACT mask.
146 * All the response field descriptors must have the EXACT mask.
147 * In the current implementation, only the Ethertype, source and
148 * destination IP address, IP protocol, and source and destination IP
149 * are used for the lookup by the key.
150 * FW could use the NEVER mask for the fields in the key that are not
151 * used for the lookup.
152 * As an alternative, a new mask could be added for these fields,
153 * like EXACT_NOT_USED.
154 */
155 default:
156 if ((fields_descsp[i].mask_type != EFX_TABLE_FIELD_MASK_NEVER) &&
157 (fields_descsp[i].mask_type != EFX_TABLE_FIELD_MASK_EXACT)) {
158 rc = EINVAL;
159 goto fail2;
160 }
161 break;
162 }
163 }
164
165 return (0);
166
167 fail2:
168 EFSYS_PROBE(fail2);
169 fail1:
170 EFSYS_PROBE1(fail1, efx_rc_t, rc);
171 return (rc);
172 }
173
174 static __checkReturn efx_rc_t
efx_table_desc_fields_check(__in efx_table_id_t table_id,__in_ecount (n_fields_descs)efx_table_field_descriptor_t * fields_descsp,__in unsigned int n_fields_descs)175 efx_table_desc_fields_check(
176 __in efx_table_id_t table_id,
177 __in_ecount(n_fields_descs) efx_table_field_descriptor_t *fields_descsp,
178 __in unsigned int n_fields_descs)
179 {
180 efx_rc_t rc;
181
182 switch (table_id) {
183 case EFX_TABLE_ID_CONNTRACK:
184 rc = efx_table_ct_desc_fields_check(fields_descsp, n_fields_descs);
185 if (rc != 0)
186 goto fail1;
187 break;
188 default:
189 break;
190 }
191
192 return (0);
193
194 fail1:
195 EFSYS_PROBE1(fail1, efx_rc_t, rc);
196 return (rc);
197 }
198
199 static void
efx_table_desc_fields_get(__in const efx_mcdi_req_t * req,__out_ecount (n_fields_descs)efx_table_field_descriptor_t * fields_descsp,__in unsigned int n_fields_descs)200 efx_table_desc_fields_get(
201 __in const efx_mcdi_req_t *req,
202 __out_ecount(n_fields_descs) efx_table_field_descriptor_t *fields_descsp,
203 __in unsigned int n_fields_descs)
204 {
205 unsigned int i;
206
207 for (i = 0; i < n_fields_descs; i++) {
208 fields_descsp[i].field_id = (efx_table_field_id_t)
209 MCDI_OUT_INDEXED_QWORD_FIELD(*req,
210 TABLE_DESCRIPTOR_OUT_FIELDS, i, TABLE_FIELD_DESCR_FIELD_ID);
211
212 fields_descsp[i].lbn =
213 MCDI_OUT_INDEXED_QWORD_FIELD(*req,
214 TABLE_DESCRIPTOR_OUT_FIELDS, i, TABLE_FIELD_DESCR_LBN);
215
216 fields_descsp[i].width =
217 MCDI_OUT_INDEXED_QWORD_FIELD(*req,
218 TABLE_DESCRIPTOR_OUT_FIELDS, i, TABLE_FIELD_DESCR_WIDTH);
219
220 fields_descsp[i].mask_type = (efx_table_field_mask_type_t)
221 MCDI_OUT_INDEXED_QWORD_FIELD(*req,
222 TABLE_DESCRIPTOR_OUT_FIELDS, i, TABLE_FIELD_DESCR_MASK_TYPE);
223
224 fields_descsp[i].scheme =
225 MCDI_OUT_INDEXED_QWORD_FIELD(*req,
226 TABLE_DESCRIPTOR_OUT_FIELDS, i, TABLE_FIELD_DESCR_SCHEME);
227 }
228 }
229
230 __checkReturn efx_rc_t
efx_table_describe(__in efx_nic_t * enp,__in efx_table_id_t table_id,__in uint32_t field_offset,__out_opt efx_table_descriptor_t * table_descp,__out_ecount_opt (n_field_descs)efx_table_field_descriptor_t * fields_descs,__in unsigned int n_field_descs,__out_opt unsigned int * n_field_descs_writtenp)231 efx_table_describe(
232 __in efx_nic_t *enp,
233 __in efx_table_id_t table_id,
234 __in uint32_t field_offset,
235 __out_opt efx_table_descriptor_t *table_descp,
236 __out_ecount_opt(n_field_descs) efx_table_field_descriptor_t *fields_descs,
237 __in unsigned int n_field_descs,
238 __out_opt unsigned int *n_field_descs_writtenp)
239 {
240 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
241 unsigned int n_entries;
242 efx_mcdi_req_t req;
243 unsigned int i;
244 efx_rc_t rc;
245 EFX_MCDI_DECLARE_BUF(payload,
246 MC_CMD_TABLE_DESCRIPTOR_IN_LEN,
247 MC_CMD_TABLE_DESCRIPTOR_OUT_LENMAX_MCDI2);
248
249 /* Ensure EFX and MCDI use same values for table types */
250 EFX_STATIC_ASSERT(EFX_TABLE_TYPE_BCAM == MC_CMD_TABLE_DESCRIPTOR_OUT_TYPE_BCAM);
251
252 /* Ensure EFX and MCDI use same values for table fields */
253 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_UNUSED == TABLE_FIELD_ID_UNUSED);
254 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_COUNTER_ID == TABLE_FIELD_ID_COUNTER_ID);
255 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_ETHER_TYPE == TABLE_FIELD_ID_ETHER_TYPE);
256 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_SRC_IP == TABLE_FIELD_ID_SRC_IP);
257 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_DST_IP == TABLE_FIELD_ID_DST_IP);
258 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_IP_PROTO == TABLE_FIELD_ID_IP_PROTO);
259 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_SRC_PORT == TABLE_FIELD_ID_SRC_PORT);
260 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_DST_PORT == TABLE_FIELD_ID_DST_PORT);
261 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_NAT_PORT == TABLE_FIELD_ID_NAT_PORT);
262 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_NAT_IP == TABLE_FIELD_ID_NAT_IP);
263 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_NAT_DIR == TABLE_FIELD_ID_NAT_DIR);
264 EFX_STATIC_ASSERT(EFX_TABLE_FIELD_ID_CT_MARK == TABLE_FIELD_ID_CT_MARK);
265
266 if (encp->enc_table_api_supported == B_FALSE) {
267 rc = ENOTSUP;
268 goto fail1;
269 }
270
271 if (!efx_table_is_supported(table_id)) {
272 rc = ENOTSUP;
273 goto fail2;
274 }
275
276 if ((n_field_descs != 0) &&
277 ((fields_descs == NULL) || (n_field_descs_writtenp == NULL))) {
278 rc = EINVAL;
279 goto fail3;
280 }
281
282 req.emr_cmd = MC_CMD_TABLE_DESCRIPTOR;
283 req.emr_in_buf = payload;
284 req.emr_in_length = MC_CMD_TABLE_DESCRIPTOR_IN_LEN;
285 req.emr_out_buf = payload;
286 req.emr_out_length = MC_CMD_TABLE_DESCRIPTOR_OUT_LENMAX_MCDI2;
287
288 MCDI_IN_SET_DWORD(req, TABLE_DESCRIPTOR_IN_TABLE_ID, (uint32_t)table_id);
289 MCDI_IN_SET_DWORD(req, TABLE_DESCRIPTOR_IN_FIRST_FIELDS_INDEX, field_offset);
290
291 efx_mcdi_execute(enp, &req);
292
293 if (req.emr_rc != 0) {
294 rc = req.emr_rc;
295 goto fail4;
296 }
297
298 if (req.emr_out_length_used < MC_CMD_TABLE_DESCRIPTOR_OUT_LENMIN) {
299 rc = EMSGSIZE;
300 goto fail5;
301 }
302
303 if (table_descp != NULL) {
304 table_descp->type = (efx_table_type_t)MCDI_OUT_WORD(
305 req, TABLE_DESCRIPTOR_OUT_TYPE);
306 table_descp->key_width = MCDI_OUT_WORD(
307 req, TABLE_DESCRIPTOR_OUT_KEY_WIDTH);
308 table_descp->resp_width = MCDI_OUT_WORD(
309 req, TABLE_DESCRIPTOR_OUT_RESP_WIDTH);
310 table_descp->n_key_fields = MCDI_OUT_WORD(
311 req, TABLE_DESCRIPTOR_OUT_N_KEY_FIELDS);
312 table_descp->n_resp_fields = MCDI_OUT_WORD(
313 req, TABLE_DESCRIPTOR_OUT_N_RESP_FIELDS);
314 }
315
316 n_entries = MC_CMD_TABLE_DESCRIPTOR_OUT_FIELDS_NUM(req.emr_out_length_used);
317
318 if (fields_descs != NULL) {
319 if (n_entries > n_field_descs) {
320 rc = ENOMEM;
321 goto fail6;
322 }
323
324 efx_table_desc_fields_get(&req, fields_descs, n_entries);
325 rc = efx_table_desc_fields_check(table_id, fields_descs, n_entries);
326 if (rc != 0)
327 goto fail7;
328 }
329
330 if (n_field_descs_writtenp != NULL)
331 *n_field_descs_writtenp = n_entries;
332
333 return (0);
334
335 fail7:
336 EFSYS_PROBE(fail7);
337 fail6:
338 EFSYS_PROBE(fail6);
339 fail5:
340 EFSYS_PROBE(fail5);
341 fail4:
342 EFSYS_PROBE(fail4);
343 fail3:
344 EFSYS_PROBE(fail3);
345 fail2:
346 EFSYS_PROBE(fail2);
347 fail1:
348 EFSYS_PROBE1(fail1, efx_rc_t, rc);
349 return (rc);
350 }
351
352 __checkReturn efx_rc_t
efx_table_entry_insert(__in efx_nic_t * enp,__in efx_table_id_t table_id,__in uint16_t priority,__in uint16_t mask_id,__in uint16_t key_width,__in uint16_t mask_width,__in uint16_t resp_width,__in_bcount (data_size)uint8_t * entry_datap,__in unsigned int data_size)353 efx_table_entry_insert(
354 __in efx_nic_t *enp,
355 __in efx_table_id_t table_id,
356 __in uint16_t priority,
357 __in uint16_t mask_id,
358 __in uint16_t key_width,
359 __in uint16_t mask_width,
360 __in uint16_t resp_width,
361 __in_bcount(data_size) uint8_t *entry_datap,
362 __in unsigned int data_size)
363 {
364 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
365 unsigned int n_dwords;
366 efx_mcdi_req_t req;
367 efx_rc_t rc;
368 EFX_MCDI_DECLARE_BUF(payload,
369 MC_CMD_TABLE_INSERT_IN_LENMAX_MCDI2,
370 MC_CMD_TABLE_INSERT_OUT_LEN);
371
372 /*
373 * Ensure MCDI number of 32bit units matches EFX maximum possible
374 * data in bytes.
375 */
376 EFX_STATIC_ASSERT((MC_CMD_TABLE_INSERT_IN_LENMAX * sizeof(uint32_t)) ==
377 EFX_TABLE_ENTRY_LENGTH_MAX);
378
379 if (encp->enc_table_api_supported == B_FALSE) {
380 rc = ENOTSUP;
381 goto fail1;
382 }
383
384 if ((data_size % sizeof(uint32_t)) != 0) {
385 rc = EINVAL;
386 goto fail2;
387 }
388
389 if ((data_size == 0) || (data_size > EFX_TABLE_ENTRY_LENGTH_MAX)) {
390 rc = EINVAL;
391 goto fail3;
392 }
393
394 n_dwords = data_size / sizeof(uint32_t);
395
396 req.emr_cmd = MC_CMD_TABLE_INSERT;
397 req.emr_in_buf = payload;
398 req.emr_in_length = MC_CMD_TABLE_INSERT_IN_LEN(n_dwords);
399 req.emr_out_buf = payload;
400 req.emr_out_length = MC_CMD_TABLE_INSERT_OUT_LEN;
401
402 MCDI_IN_SET_DWORD(req, TABLE_INSERT_IN_TABLE_ID, (uint32_t)table_id);
403 MCDI_IN_SET_WORD(req, TABLE_INSERT_IN_PRIORITY, priority);
404 MCDI_IN_SET_WORD(req, TABLE_INSERT_IN_MASK_ID, mask_id);
405 MCDI_IN_SET_WORD(req, TABLE_INSERT_IN_KEY_WIDTH, key_width);
406 MCDI_IN_SET_WORD(req, TABLE_INSERT_IN_MASK_WIDTH, mask_width);
407 MCDI_IN_SET_WORD(req, TABLE_INSERT_IN_RESP_WIDTH, resp_width);
408
409 memcpy(MCDI_IN2(req, uint8_t, TABLE_INSERT_IN_DATA), entry_datap, data_size);
410
411 efx_mcdi_execute(enp, &req);
412
413 if (req.emr_rc != 0) {
414 rc = req.emr_rc;
415 goto fail4;
416 }
417
418 return (0);
419
420 fail4:
421 EFSYS_PROBE(fail4);
422 fail3:
423 EFSYS_PROBE(fail3);
424 fail2:
425 EFSYS_PROBE(fail2);
426 fail1:
427 EFSYS_PROBE1(fail1, efx_rc_t, rc);
428 return (rc);
429 }
430
431 __checkReturn efx_rc_t
efx_table_entry_delete(__in efx_nic_t * enp,__in efx_table_id_t table_id,__in uint16_t mask_id,__in uint16_t key_width,__in uint16_t mask_width,__in_bcount (data_size)uint8_t * entry_datap,__in unsigned int data_size)432 efx_table_entry_delete(
433 __in efx_nic_t *enp,
434 __in efx_table_id_t table_id,
435 __in uint16_t mask_id,
436 __in uint16_t key_width,
437 __in uint16_t mask_width,
438 __in_bcount(data_size) uint8_t *entry_datap,
439 __in unsigned int data_size)
440 {
441 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
442 unsigned int n_dwords;
443 efx_mcdi_req_t req;
444 efx_rc_t rc;
445 EFX_MCDI_DECLARE_BUF(payload,
446 MC_CMD_TABLE_DELETE_IN_LENMAX_MCDI2,
447 MC_CMD_TABLE_DELETE_OUT_LEN);
448
449 /*
450 * Ensure MCDI number of 32bit units matches EFX maximum possible
451 * data in bytes.
452 */
453 EFX_STATIC_ASSERT((MC_CMD_TABLE_DELETE_IN_LENMAX * sizeof(uint32_t)) ==
454 EFX_TABLE_ENTRY_LENGTH_MAX);
455
456 if (encp->enc_table_api_supported == B_FALSE) {
457 rc = ENOTSUP;
458 goto fail1;
459 }
460
461 if ((data_size % sizeof(uint32_t)) != 0) {
462 rc = EINVAL;
463 goto fail2;
464 }
465
466 if ((data_size == 0) || (data_size > EFX_TABLE_ENTRY_LENGTH_MAX)) {
467 rc = EINVAL;
468 goto fail3;
469 }
470
471 n_dwords = data_size / sizeof(uint32_t);
472
473 req.emr_cmd = MC_CMD_TABLE_DELETE;
474 req.emr_in_buf = payload;
475 req.emr_in_length = MC_CMD_TABLE_DELETE_IN_LEN(n_dwords);
476 req.emr_out_buf = payload;
477 req.emr_out_length = MC_CMD_TABLE_DELETE_OUT_LEN;
478
479 MCDI_IN_SET_DWORD(req, TABLE_DELETE_IN_TABLE_ID, (uint32_t)table_id);
480 MCDI_IN_SET_WORD(req, TABLE_DELETE_IN_MASK_ID, mask_id);
481 MCDI_IN_SET_WORD(req, TABLE_DELETE_IN_KEY_WIDTH, key_width);
482 MCDI_IN_SET_WORD(req, TABLE_DELETE_IN_MASK_WIDTH, mask_width);
483
484
485 memcpy(MCDI_IN2(req, uint8_t, TABLE_DELETE_IN_DATA), entry_datap, data_size);
486
487 efx_mcdi_execute(enp, &req);
488
489 if (req.emr_rc != 0) {
490 rc = req.emr_rc;
491 goto fail4;
492 }
493
494 return (0);
495
496 fail4:
497 EFSYS_PROBE(fail4);
498
499 fail3:
500 EFSYS_PROBE(fail3);
501 fail2:
502 EFSYS_PROBE(fail2);
503 fail1:
504 EFSYS_PROBE1(fail1, efx_rc_t, rc);
505 return (rc);
506 }
507