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