xref: /dpdk/drivers/net/bnxt/tf_core/tf_resources.c (revision 4545fdf6a25f1d2d7c269eb46c200a5526028a5e)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2024 Broadcom
3  * All rights reserved.
4  */
5 
6 /* Truflow Table APIs and supporting code */
7 
8 #include <rte_common.h>
9 
10 #include "tf_tbl.h"
11 #include "tf_common.h"
12 #include "tf_rm.h"
13 #include "tf_util.h"
14 #include "tf_msg.h"
15 #include "tfp.h"
16 #include "tf_session.h"
17 #include "tf_device.h"
18 #include "cfa_tcam_mgr_device.h"
19 
20 #ifdef TF_FLOW_SCALE_QUERY
21 
22 /* Logging defines */
23 #define TF_FLOW_SCALE_QUERY_DEBUG 0
24 
25 /* global data stored in firmware memory and TruFlow driver*/
26 struct cfa_tf_resc_usage tf_resc_usage[TF_DIR_MAX];
27 
28 struct tf_resc_usage_buffer_control {
29 	enum tf_device_type device_type;
30 	bool fw_sync_paused;
31 	uint32_t buffer_dirty[TF_DIR_MAX];
32 };
33 
34 static struct tf_resc_usage_buffer_control resc_usage_control;
35 
36 /* Check if supporting resource usage */
37 static bool tf_resc_usage_support(struct tf *tfp)
38 {
39 	struct tf_session *tfs;
40 	bool support = true;
41 	int rc;
42 
43 	/* Not valid session id */
44 	rc = tf_session_get_session_internal(tfp, &tfs);
45 	if (rc)
46 		return false;
47 
48 	/* Support Thor */
49 	if (resc_usage_control.device_type != tfs->dev.type)
50 		support = false;
51 
52 #if (TF_FLOW_SCALE_QUERY_DEBUG == 1)
53 	TFP_DRV_LOG(INFO, "Resc usage update on device type: %d, allow: %s\n",
54 		    resc_usage_control.device_type,
55 		    support ? "True" : "False");
56 #endif /* TF_FLOW_SCALE_QUERY_DEBUG == 1 */
57 	return support;
58 }
59 
60 /* Reset the resource usage buffer */
61 void tf_resc_usage_reset(struct tf *tfp __rte_unused, enum tf_device_type type)
62 {
63 	/* Support Thor only*/
64 	if (type != TF_DEVICE_TYPE_P5)
65 		return;
66 
67 	resc_usage_control.fw_sync_paused = false;
68 	resc_usage_control.device_type = type;
69 	resc_usage_control.buffer_dirty[TF_DIR_RX] = 1;
70 	resc_usage_control.buffer_dirty[TF_DIR_TX] = 1;
71 	memset(tf_resc_usage, 0, sizeof(tf_resc_usage));
72 }
73 
74 /* Check the bumber of the used slices in a row */
75 static int
76 tf_tcam_mgr_row_entry_used(struct cfa_tcam_mgr_table_rows_0 *row,
77 			    int max_slices)
78 {
79 	int used = 0, j;
80 
81 	for (j = 0; j < (max_slices / row->entry_size); j++) {
82 		if (ROW_ENTRY_INUSE(row, j))
83 			used++;
84 	}
85 	return used;
86 }
87 
88 /* Initialize the resource usage buffer for WC-TCAM tables */
89 void tf_tcam_usage_init(struct tf *tfp)
90 {
91 	enum cfa_tcam_mgr_tbl_type type = CFA_TCAM_MGR_TBL_TYPE_WC_TCAM;
92 	struct cfa_tcam_mgr_table_data *table_data = NULL;
93 	struct tf_resc_wc_tcam_usage *usage_data = NULL;
94 	struct cfa_tcam_mgr_data *tcam_mgr_data;
95 	struct tf_session *tfs;
96 	enum tf_dir dir;
97 	int rc;
98 
99 	/* Check if supported on this device */
100 	rc = tf_session_get_session_internal(tfp, &tfs);
101 	if (rc)
102 		return;
103 
104 	tcam_mgr_data = tfs->tcam_mgr_handle;
105 	if (!tcam_mgr_data) {
106 		TFP_DRV_LOG(ERR,
107 			    "%s: No TCAM data created for session\n",
108 			    __func__);
109 		return;
110 	}
111 
112 	/* Iterate over all directions */
113 	for (dir = 0; dir < TF_DIR_MAX; dir++) {
114 		table_data = &tcam_mgr_data->cfa_tcam_mgr_tables[dir][type];
115 		usage_data = &tf_resc_usage[dir].wc_tcam_usage;
116 
117 		/* cfa_tcam_mgr_table_dump(tfs->session_id.id, dir, type); */
118 		memset(usage_data, 0, sizeof(*usage_data));
119 		if (table_data->start_row != table_data->end_row)
120 			usage_data->max_row_number = table_data->end_row -
121 						     table_data->start_row + 1;
122 		usage_data->unused_row_number = usage_data->max_row_number;
123 
124 #if (TF_FLOW_SCALE_QUERY_DEBUG == 1)
125 		/* dump usage data */
126 		TFP_DRV_LOG(INFO, "WC-TCAM:  1-p  1-f  2-p  2-f  4-f  free-rows\n");
127 		TFP_DRV_LOG(INFO, "%s	 %-4d %-4d %-4d %-4d %-4d %-4d\n",
128 			    (dir == TF_DIR_RX) ? "RX" : "TX",
129 			    usage_data->slice_row_1_p_used,
130 			    usage_data->slice_row_1_f_used,
131 			    usage_data->slice_row_2_p_used,
132 			    usage_data->slice_row_2_f_used,
133 			    usage_data->slice_row_4_used,
134 			    usage_data->unused_row_number);
135 #endif
136 	}
137 }
138 
139 /* Update wc-tcam table resoure usage */
140 int tf_tcam_usage_update(struct tf *tfp,
141 			 enum tf_dir dir,
142 			 int tcam_tbl_type,
143 			 void *data,
144 			 enum tf_resc_opt resc_opt)
145 {
146 	struct cfa_tcam_mgr_table_rows_0 *key_row = (struct cfa_tcam_mgr_table_rows_0 *)data;
147 	struct tf_resc_wc_tcam_usage *usage_data;
148 	struct cfa_tcam_mgr_data *tcam_mgr_data;
149 	int key_slices = key_row->entry_size;
150 	struct tf_session *tfs;
151 	int used_entries;
152 	int rc;
153 
154 	/* Check if supported on this device */
155 	rc = tf_session_get_session_internal(tfp, &tfs);
156 	if (rc)
157 		return rc;
158 
159 	tcam_mgr_data = tfs->tcam_mgr_handle;
160 	if (!tcam_mgr_data) {
161 		TFP_DRV_LOG(ERR,
162 			    "%s: No TCAM data created for session\n",
163 			    __func__);
164 		return -CFA_TCAM_MGR_ERR_CODE(PERM);
165 	}
166 
167 	/* Check if supported on this device */
168 	if (!tf_resc_usage_support(tfp))
169 		return -1;
170 
171 	/* Support WC-TCAM APPs only */
172 	if (tcam_tbl_type != CFA_TCAM_MGR_TBL_TYPE_WC_TCAM)
173 		return 0;
174 
175 	resc_usage_control.buffer_dirty[dir] = 1;
176 	usage_data = &tf_resc_usage[dir].wc_tcam_usage;
177 	if (resc_opt == TF_RESC_ALLOC) {
178 		switch (key_slices) {
179 		case 4:
180 			usage_data->unused_row_number -= 1;
181 			usage_data->slice_row_4_used += 1;
182 			break;
183 		case 2:
184 			used_entries = tf_tcam_mgr_row_entry_used(key_row, 4);
185 			if (used_entries == 2) {
186 				usage_data->slice_row_2_p_used -= 1;
187 				usage_data->slice_row_2_f_used += 1;
188 			} else {
189 				usage_data->unused_row_number -= 1;
190 				usage_data->slice_row_2_p_used += 1;
191 			}
192 			break;
193 		case 1:
194 			used_entries = tf_tcam_mgr_row_entry_used(key_row, 4);
195 			if (used_entries == 4) {
196 				usage_data->slice_row_1_p_used -= 1;
197 				usage_data->slice_row_1_f_used += 1;
198 			} else if (used_entries == 1) {
199 				usage_data->slice_row_1_p_used += 1;
200 				usage_data->unused_row_number -= 1;
201 			}
202 			break;
203 		default:
204 			TFP_DRV_LOG(ERR, "CFA invalid size of key slices: %d\n",
205 				    key_slices);
206 			break;
207 		}
208 	} else { /* free one entry */
209 		switch (key_slices) {
210 		case 4:
211 			usage_data->unused_row_number += 1;
212 			usage_data->slice_row_4_used -= 1;
213 			break;
214 		case 2:
215 			if (!ROW_INUSE(key_row)) {  /* empty */
216 				usage_data->unused_row_number += 1;
217 				usage_data->slice_row_2_p_used -= 1;
218 			} else {
219 				usage_data->slice_row_2_p_used += 1;
220 				usage_data->slice_row_2_f_used -= 1;
221 			}
222 			break;
223 		case 1:
224 			used_entries = tf_tcam_mgr_row_entry_used(key_row, 4);
225 			if (!ROW_INUSE(key_row)) {  /* empty */
226 				usage_data->unused_row_number += 1;
227 				usage_data->slice_row_1_p_used -= 1;
228 			} else if (used_entries == 3) {
229 				usage_data->slice_row_1_f_used -= 1;
230 				usage_data->slice_row_1_p_used += 1;
231 			}
232 			break;
233 		default:
234 			TFP_DRV_LOG(ERR, "CFA invalid size of key slices: %d\n",
235 				    key_slices);
236 			break;
237 		}
238 	}
239 
240 #if (TF_FLOW_SCALE_QUERY_DEBUG == 1)
241 	/* dump usage data*/
242 	TFP_DRV_LOG(INFO, "WC-TCAM:  1-p  1-f  2-p  2-f  4-f  free-rows\n");
243 	TFP_DRV_LOG(INFO, "	  %-4d %-4d %-4d %-4d %-4d %-4d\n",
244 		    usage_data->slice_row_1_p_used,
245 		    usage_data->slice_row_1_f_used,
246 		    usage_data->slice_row_2_p_used,
247 		    usage_data->slice_row_2_f_used,
248 		    usage_data->slice_row_4_used,
249 		    usage_data->unused_row_number);
250 #endif
251 	return 0;
252 }
253 
254 /* Initialize the EM usage table */
255 void tf_em_usage_init(struct tf *tfp, enum tf_dir dir, uint16_t max_entries)
256 {
257 	struct tf_resc_em_usage *em;
258 
259 	/* Check if supported on this device */
260 	if (!tf_resc_usage_support(tfp))
261 		return;
262 
263 	em = &tf_resc_usage[dir].em_int_usage;
264 	em->max_entries = max_entries;
265 	em->used_entries = 0;
266 }
267 
268 /* Update the EM usage table */
269 int tf_em_usage_update(struct tf *tfp,
270 		       enum tf_dir dir,
271 		       uint16_t size,
272 		       enum tf_resc_opt resc_opt)
273 {
274 	struct tf_resc_em_usage *em;
275 
276 #if (TF_FLOW_SCALE_QUERY_DEBUG == 1)
277 	TFP_DRV_LOG(INFO, "%s: %s: EM record size: %d, %s\n",
278 		    __func__,
279 		    dir ? "TX" : "RX",
280 		    size,
281 		    resc_opt == TF_RESC_ALLOC ? "Alloc" : "Free");
282 #endif /* TF_FLOW_SCALE_QUERY_DEBUG == 1 */
283 
284 	/* Check if supported on this device */
285 	if (!tf_resc_usage_support(tfp))
286 		return -1;
287 
288 	/* not valid size */
289 	if (!size)
290 		return 0;
291 
292 	resc_usage_control.buffer_dirty[dir] = 1;
293 	em = &tf_resc_usage[dir].em_int_usage;
294 	if (resc_opt == TF_RESC_ALLOC) {
295 		em->used_entries += size;
296 		assert(em->used_entries <= em->max_entries);
297 	} else {
298 		assert(em->used_entries >= size);
299 		em->used_entries -= size;
300 	}
301 	return 0;
302 }
303 
304 /* Initialize the usage buffer for all kinds of sram tables */
305 void tf_tbl_usage_init(struct tf *tfp,
306 		       enum tf_dir dir,
307 		       uint32_t tbl_type,
308 		       uint16_t max_entries)
309 {
310 	struct tf_rm_element_cfg *tbl_cfg = tf_tbl_p58[dir];
311 
312 #if (TF_FLOW_SCALE_QUERY_DEBUG == 1)
313 	TFP_DRV_LOG(INFO, "%s: %s: tbl_type: %d[%s], max entries: [%d]:[0x%x]\n",
314 		    __func__,
315 		    dir ? "TX" : "RX",
316 		    tbl_type,
317 		    tf_tbl_type_2_str(tbl_type),
318 		    max_entries,
319 		    max_entries);
320 #endif /* TF_FLOW_SCALE_QUERY_DEBUG == 1 */
321 
322 	/* Check if supported on this device */
323 	if (!tf_resc_usage_support(tfp))
324 		return;
325 
326 	/* Convert to entries */
327 	if (tbl_cfg[tbl_type].slices)
328 		max_entries *= (16 / tbl_cfg[tbl_type].slices);
329 
330 	switch (tbl_type) {
331 	/* Counter Action */
332 	case TF_TBL_TYPE_ACT_STATS_64:
333 	{
334 		struct tf_resc_cnt_usage *cnt;
335 		cnt = &tf_resc_usage[dir].cnt_usage;
336 		cnt->max_entries = max_entries;
337 		cnt->used_entries = 0;
338 		break;
339 	}
340 	/* Action Recrod */
341 	case TF_TBL_TYPE_COMPACT_ACT_RECORD:
342 	case TF_TBL_TYPE_FULL_ACT_RECORD:
343 	{
344 		struct tf_resc_act_usage *act;
345 		act = &tf_resc_usage[dir].act_usage;
346 		act->max_entries += max_entries;
347 		act->free_entries += max_entries;
348 		act->num_compact_act_records = 0;
349 		act->num_full_act_records = 0;
350 		break;
351 	}
352 	/* ACT_ENCAP adn ACT_MODIFY Records */
353 	case TF_TBL_TYPE_ACT_ENCAP_8B:
354 	case TF_TBL_TYPE_ACT_ENCAP_16B:
355 	case TF_TBL_TYPE_ACT_ENCAP_32B:
356 	case TF_TBL_TYPE_ACT_ENCAP_64B:
357 	case TF_TBL_TYPE_ACT_ENCAP_128B:
358 	case TF_TBL_TYPE_ACT_MODIFY_8B:
359 	case TF_TBL_TYPE_ACT_MODIFY_16B:
360 	case TF_TBL_TYPE_ACT_MODIFY_32B:
361 	case TF_TBL_TYPE_ACT_MODIFY_64B:
362 	{
363 		struct tf_resc_act_mod_enc_usage *mod_encap;
364 		mod_encap = &tf_resc_usage[dir].mod_encap_usage;
365 		mod_encap->max_entries += max_entries;
366 		mod_encap->free_entries += max_entries;
367 		break;
368 	}
369 	/* SP_SMAC Record */
370 	case TF_TBL_TYPE_ACT_SP_SMAC:
371 	case TF_TBL_TYPE_ACT_SP_SMAC_IPV4:
372 	case TF_TBL_TYPE_ACT_SP_SMAC_IPV6:
373 	{
374 		struct tf_resc_act_sp_smac_usage *sp_smac;
375 		sp_smac = &tf_resc_usage[dir].sp_smac_usage;
376 		sp_smac->max_entries += max_entries;
377 		sp_smac->free_entries += max_entries;
378 		break;
379 	}
380 	/** Meter Profiles */
381 	case TF_TBL_TYPE_METER_PROF:
382 		tf_resc_usage[dir].meter_usage.max_meter_profile = max_entries;
383 		break;
384 	/** Meter Instance */
385 	case TF_TBL_TYPE_METER_INST:
386 		tf_resc_usage[dir].meter_usage.max_meter_instance = max_entries;
387 		break;
388 	default:
389 		break;
390 	}
391 }
392 
393 /* Update the usage buffer for sram tables: add or free one entry */
394 int tf_tbl_usage_update(struct tf *tfp,
395 			 enum tf_dir dir,
396 			 uint32_t tbl_type,
397 			 enum tf_resc_opt resc_opt)
398 {
399 	struct tf_rm_element_cfg *tbl_cfg = tf_tbl_p58[dir];
400 	struct tf_resc_cnt_usage *cnt;
401 	int inc = (resc_opt == TF_RESC_ALLOC) ? 1 : -1;
402 	int slices = tbl_cfg[tbl_type].slices;
403 	int entries = 0;
404 
405 	/* Check if supported on this device */
406 	if (!tf_resc_usage_support(tfp))
407 		return -1;
408 
409 	/* Convert to entries */
410 	if (slices)
411 		entries = inc * (16 / slices);
412 
413 #if (TF_FLOW_SCALE_QUERY_DEBUG == 1)
414 	TFP_DRV_LOG(INFO, "%s: %s: tbl_type: %d[%s] %s, Entries: %d\n", __func__,
415 		    dir ? "TX" : "RX",
416 		    tbl_type,
417 		    tf_tbl_type_2_str(tbl_type),
418 		    resc_opt ? "Alloc" : "Free",
419 		    entries);
420 #endif /* TF_FLOW_SCALE_QUERY_DEBUG == 1 */
421 
422 	resc_usage_control.buffer_dirty[dir] = 1;
423 	switch (tbl_type) {
424 	/* Counter Action */
425 	case TF_TBL_TYPE_ACT_STATS_64:
426 		cnt = &tf_resc_usage[dir].cnt_usage;
427 		cnt->used_entries += inc;
428 		break;
429 	/* ACTION Record */
430 	case TF_TBL_TYPE_FULL_ACT_RECORD:
431 	case TF_TBL_TYPE_COMPACT_ACT_RECORD:
432 	{
433 		struct tf_resc_act_usage *act;
434 		act = &tf_resc_usage[dir].act_usage;
435 		if (tbl_type == TF_TBL_TYPE_COMPACT_ACT_RECORD)
436 			act->num_compact_act_records += inc;
437 		else
438 			act->num_full_act_records += inc;
439 		act->free_entries -= entries;
440 		break;
441 	}
442 	/* ACT_ENCAP and ACT_MODIFY Records */
443 	case TF_TBL_TYPE_ACT_ENCAP_8B:
444 	case TF_TBL_TYPE_ACT_ENCAP_16B:
445 	case TF_TBL_TYPE_ACT_ENCAP_32B:
446 	case TF_TBL_TYPE_ACT_ENCAP_64B:
447 	case TF_TBL_TYPE_ACT_ENCAP_128B:
448 	case TF_TBL_TYPE_ACT_MODIFY_8B:
449 	case TF_TBL_TYPE_ACT_MODIFY_16B:
450 	case TF_TBL_TYPE_ACT_MODIFY_32B:
451 	case TF_TBL_TYPE_ACT_MODIFY_64B:
452 	{
453 		struct tf_resc_act_mod_enc_usage *mod_encap;
454 		mod_encap = &tf_resc_usage[dir].mod_encap_usage;
455 		switch (slices) {
456 		case 1:
457 			mod_encap->data.num_128b_records += inc;
458 			break;
459 		case 2:
460 			mod_encap->data.num_64b_records += inc;
461 			break;
462 		case 4:
463 			mod_encap->data.num_32b_records += inc;
464 			break;
465 		case 8:
466 			mod_encap->data.num_16b_records += inc;
467 			break;
468 		case 16:
469 			mod_encap->data.num_8b_records += inc;
470 			break;
471 		default:
472 			break;
473 		}
474 		mod_encap->free_entries -= entries;
475 		break;
476 	}
477 	/* SP SMAC table */
478 	case TF_TBL_TYPE_ACT_SP_SMAC:
479 	case TF_TBL_TYPE_ACT_SP_SMAC_IPV4:
480 	case TF_TBL_TYPE_ACT_SP_SMAC_IPV6:
481 	{
482 		struct tf_resc_act_sp_smac_usage *sp_smac;
483 		sp_smac = &tf_resc_usage[dir].sp_smac_usage;
484 		if (tbl_type == TF_TBL_TYPE_ACT_SP_SMAC)
485 			sp_smac->num_sp_smac_records += inc;
486 		else if (tbl_type == TF_TBL_TYPE_ACT_SP_SMAC_IPV4)
487 			sp_smac->num_sp_smac_ipv4_records += inc;
488 		else if (tbl_type == TF_TBL_TYPE_ACT_SP_SMAC_IPV6)
489 			sp_smac->num_sp_smac_ipv6_records += inc;
490 		sp_smac->free_entries -= entries;
491 		break;
492 	}
493 	/* Meter Profiles */
494 	case TF_TBL_TYPE_METER_PROF:
495 		tf_resc_usage[dir].meter_usage.used_meter_profile += inc;
496 		break;
497 	/* Meter Instance */
498 	case TF_TBL_TYPE_METER_INST:
499 		tf_resc_usage[dir].meter_usage.used_meter_instance += inc;
500 		break;
501 	default:
502 	/* not support types */
503 		break;
504 	}
505 	return 0;
506 }
507 
508 /* pause usage state update with firmware */
509 void tf_resc_pause_usage_update(void)
510 {
511 	resc_usage_control.fw_sync_paused = true;
512 }
513 
514 /* resume usage state update with firmware */
515 void tf_resc_resume_usage_update(void)
516 {
517 	resc_usage_control.fw_sync_paused = false;
518 }
519 
520 /* check if paused the resource usage update with firmware */
521 static bool tf_resc_usage_update_paused(void)
522 {
523 	return resc_usage_control.fw_sync_paused;
524 }
525 
526 /* resync all resource usage state with firmware for both direction */
527 void tf_resc_usage_update_all(struct bnxt *bp)
528 {
529 	struct tf *tfp;
530 	enum tf_dir dir;
531 
532 	/* When paused state update with firmware, do nothing */
533 	if (tf_resc_usage_update_paused())
534 		return;
535 
536 	tfp = bnxt_ulp_bp_tfp_get(bp, BNXT_ULP_SESSION_TYPE_DEFAULT);
537 	if (!tfp || !tfp->session) {
538 		BNXT_DRV_DBG(ERR, "Failed to get truflow or session pointer\n");
539 		return;
540 	}
541 
542 	/* Check if supported on this device */
543 	if (!tf_resc_usage_support(tfp))
544 		return;
545 
546 	/* update usage state with firmware for each direction */
547 	for (dir = 0; dir < TF_DIR_MAX; dir++) {
548 		if (resc_usage_control.buffer_dirty[dir]) {
549 			tf_update_resc_usage(tfp, dir, TF_FLOW_RESC_TYPE_ALL);
550 			resc_usage_control.buffer_dirty[dir] = 0;
551 		}
552 	}
553 }
554 
555 void dump_tf_resc_usage(__rte_unused enum tf_dir dir,
556 			__rte_unused void *data,
557 			__rte_unused uint32_t size)
558 {
559 	/* empty routine */
560 }
561 #endif /* TF_FLOW_SCALE_QUERY */
562