xref: /dpdk/drivers/common/sfc_efx/base/efx_table.c (revision a5a8beb55fbb9e5780a6ceb9da63e37d3d914cfc)
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