1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2014-2020 Broadcom 3 * All rights reserved. 4 */ 5 6 #include <rte_malloc.h> 7 #include "bnxt.h" 8 #include "bnxt_tf_common.h" 9 #include "ulp_flow_db.h" 10 #include "ulp_utils.h" 11 #include "ulp_template_struct.h" 12 #include "ulp_mapper.h" 13 #include "ulp_fc_mgr.h" 14 15 #define ULP_FLOW_DB_RES_DIR_BIT 31 16 #define ULP_FLOW_DB_RES_DIR_MASK 0x80000000 17 #define ULP_FLOW_DB_RES_FUNC_BITS 28 18 #define ULP_FLOW_DB_RES_FUNC_MASK 0x70000000 19 #define ULP_FLOW_DB_RES_NXT_MASK 0x0FFFFFFF 20 #define ULP_FLOW_DB_RES_FUNC_UPPER 5 21 #define ULP_FLOW_DB_RES_FUNC_NEED_LOWER 0x80 22 #define ULP_FLOW_DB_RES_FUNC_LOWER_MASK 0x1F 23 24 /* Macro to copy the nxt_resource_idx */ 25 #define ULP_FLOW_DB_RES_NXT_SET(dst, src) {(dst) |= ((src) &\ 26 ULP_FLOW_DB_RES_NXT_MASK); } 27 #define ULP_FLOW_DB_RES_NXT_RESET(dst) ((dst) &= ~(ULP_FLOW_DB_RES_NXT_MASK)) 28 29 /* 30 * Helper function to set the bit in the active flow table 31 * No validation is done in this function. 32 * 33 * flow_tbl [in] Ptr to flow table 34 * idx [in] The index to bit to be set or reset. 35 * flag [in] 1 to set and 0 to reset. 36 * 37 * returns none 38 */ 39 static void 40 ulp_flow_db_active_flow_set(struct bnxt_ulp_flow_tbl *flow_tbl, 41 uint32_t idx, 42 uint32_t flag) 43 { 44 uint32_t active_index; 45 46 active_index = idx / ULP_INDEX_BITMAP_SIZE; 47 if (flag) 48 ULP_INDEX_BITMAP_SET(flow_tbl->active_flow_tbl[active_index], 49 idx); 50 else 51 ULP_INDEX_BITMAP_RESET(flow_tbl->active_flow_tbl[active_index], 52 idx); 53 } 54 55 /* 56 * Helper function to allocate the flow table and initialize 57 * is set.No validation being done in this function. 58 * 59 * flow_tbl [in] Ptr to flow table 60 * idx [in] The index to bit to be set or reset. 61 * 62 * returns 1 on set or 0 if not set. 63 */ 64 static int32_t 65 ulp_flow_db_active_flow_is_set(struct bnxt_ulp_flow_tbl *flow_tbl, 66 uint32_t idx) 67 { 68 uint32_t active_index; 69 70 active_index = idx / ULP_INDEX_BITMAP_SIZE; 71 return ULP_INDEX_BITMAP_GET(flow_tbl->active_flow_tbl[active_index], 72 idx); 73 } 74 75 static uint8_t 76 ulp_flow_db_resource_func_get(struct ulp_fdb_resource_info *res_info) 77 { 78 uint8_t func; 79 80 func = (((res_info->nxt_resource_idx & ULP_FLOW_DB_RES_FUNC_MASK) >> 81 ULP_FLOW_DB_RES_FUNC_BITS) << ULP_FLOW_DB_RES_FUNC_UPPER); 82 /* The reource func is split into upper and lower */ 83 if (func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) 84 return (func | res_info->resource_func_lower); 85 return func; 86 } 87 88 /* 89 * Helper function to copy the resource params to resource info 90 * No validation being done in this function. 91 * 92 * resource_info [out] Ptr to resource information 93 * params [in] The input params from the caller 94 * returns none 95 */ 96 static void 97 ulp_flow_db_res_params_to_info(struct ulp_fdb_resource_info *resource_info, 98 struct ulp_flow_db_res_params *params) 99 { 100 uint32_t resource_func; 101 102 resource_info->nxt_resource_idx |= ((params->direction << 103 ULP_FLOW_DB_RES_DIR_BIT) & 104 ULP_FLOW_DB_RES_DIR_MASK); 105 resource_func = (params->resource_func >> ULP_FLOW_DB_RES_FUNC_UPPER); 106 resource_info->nxt_resource_idx |= ((resource_func << 107 ULP_FLOW_DB_RES_FUNC_BITS) & 108 ULP_FLOW_DB_RES_FUNC_MASK); 109 110 if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) { 111 /* Break the resource func into two parts */ 112 resource_func = (params->resource_func & 113 ULP_FLOW_DB_RES_FUNC_LOWER_MASK); 114 resource_info->resource_func_lower = resource_func; 115 } 116 117 /* Store the handle as 64bit only for EM table entries */ 118 if (params->resource_func != BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE && 119 params->resource_func != BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) { 120 resource_info->resource_hndl = (uint32_t)params->resource_hndl; 121 resource_info->resource_type = params->resource_type; 122 resource_info->resource_sub_type = params->resource_sub_type; 123 resource_info->reserved = params->reserved; 124 } else { 125 resource_info->resource_em_handle = params->resource_hndl; 126 } 127 } 128 129 /* 130 * Helper function to copy the resource params to resource info 131 * No validation being done in this function. 132 * 133 * resource_info [in] Ptr to resource information 134 * params [out] The output params to the caller 135 * 136 * returns none 137 */ 138 static void 139 ulp_flow_db_res_info_to_params(struct ulp_fdb_resource_info *resource_info, 140 struct ulp_flow_db_res_params *params) 141 { 142 memset(params, 0, sizeof(struct ulp_flow_db_res_params)); 143 params->direction = ((resource_info->nxt_resource_idx & 144 ULP_FLOW_DB_RES_DIR_MASK) >> 145 ULP_FLOW_DB_RES_DIR_BIT); 146 147 /* use the helper function to get the resource func */ 148 params->resource_func = ulp_flow_db_resource_func_get(resource_info); 149 150 if (params->resource_func == BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE || 151 params->resource_func == BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) { 152 params->resource_hndl = resource_info->resource_em_handle; 153 } else if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) { 154 params->resource_hndl = resource_info->resource_hndl; 155 params->resource_type = resource_info->resource_type; 156 params->resource_sub_type = resource_info->resource_sub_type; 157 params->reserved = resource_info->reserved; 158 } 159 } 160 161 /* 162 * Helper function to allocate the flow table and initialize 163 * the stack for allocation operations. 164 * 165 * flow_db [in] Ptr to flow database structure 166 * tbl_idx [in] The index to table creation. 167 * 168 * Returns 0 on success or negative number on failure. 169 */ 170 static int32_t 171 ulp_flow_db_alloc_resource(struct bnxt_ulp_flow_db *flow_db, 172 enum bnxt_ulp_flow_db_tables tbl_idx) 173 { 174 uint32_t idx = 0; 175 struct bnxt_ulp_flow_tbl *flow_tbl; 176 uint32_t size; 177 178 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 179 180 size = sizeof(struct ulp_fdb_resource_info) * flow_tbl->num_resources; 181 flow_tbl->flow_resources = 182 rte_zmalloc("ulp_fdb_resource_info", size, 0); 183 184 if (!flow_tbl->flow_resources) { 185 BNXT_TF_DBG(ERR, "Failed to alloc memory for flow table\n"); 186 return -ENOMEM; 187 } 188 size = sizeof(uint32_t) * flow_tbl->num_resources; 189 flow_tbl->flow_tbl_stack = rte_zmalloc("flow_tbl_stack", size, 0); 190 if (!flow_tbl->flow_tbl_stack) { 191 BNXT_TF_DBG(ERR, "Failed to alloc memory flow tbl stack\n"); 192 return -ENOMEM; 193 } 194 size = (flow_tbl->num_flows / sizeof(uint64_t)) + 1; 195 flow_tbl->active_flow_tbl = rte_zmalloc("active flow tbl", size, 0); 196 if (!flow_tbl->active_flow_tbl) { 197 BNXT_TF_DBG(ERR, "Failed to alloc memory active tbl\n"); 198 return -ENOMEM; 199 } 200 201 /* Initialize the stack table. */ 202 for (idx = 0; idx < flow_tbl->num_resources; idx++) 203 flow_tbl->flow_tbl_stack[idx] = idx; 204 205 /* Ignore the first element in the list. */ 206 flow_tbl->head_index = 1; 207 /* Tail points to the last entry in the list. */ 208 flow_tbl->tail_index = flow_tbl->num_resources - 1; 209 return 0; 210 } 211 212 /* 213 * Helper function to deallocate the flow table. 214 * 215 * flow_db [in] Ptr to flow database structure 216 * tbl_idx [in] The index to table creation. 217 * 218 * Returns none. 219 */ 220 static void 221 ulp_flow_db_dealloc_resource(struct bnxt_ulp_flow_db *flow_db, 222 enum bnxt_ulp_flow_db_tables tbl_idx) 223 { 224 struct bnxt_ulp_flow_tbl *flow_tbl; 225 226 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 227 228 /* Free all the allocated tables in the flow table. */ 229 if (flow_tbl->active_flow_tbl) { 230 rte_free(flow_tbl->active_flow_tbl); 231 flow_tbl->active_flow_tbl = NULL; 232 } 233 234 if (flow_tbl->flow_tbl_stack) { 235 rte_free(flow_tbl->flow_tbl_stack); 236 flow_tbl->flow_tbl_stack = NULL; 237 } 238 239 if (flow_tbl->flow_resources) { 240 rte_free(flow_tbl->flow_resources); 241 flow_tbl->flow_resources = NULL; 242 } 243 } 244 245 /* 246 * Helper function to add function id to the flow table 247 * 248 * flow_db [in] Ptr to flow table 249 * flow_id [in] The flow id of the flow 250 * func_id [in] The func_id to be set, for reset pass zero 251 * 252 * returns none 253 */ 254 static void 255 ulp_flow_db_func_id_set(struct bnxt_ulp_flow_db *flow_db, 256 uint32_t flow_id, 257 uint32_t func_id) 258 { 259 /* set the function id in the function table */ 260 if (flow_id < flow_db->func_id_tbl_size) 261 flow_db->func_id_tbl[flow_id] = func_id; 262 else /* This should never happen */ 263 BNXT_TF_DBG(ERR, "Invalid flow id, flowdb corrupt\n"); 264 } 265 266 /* 267 * Initialize the flow database. Memory is allocated in this 268 * call and assigned to the flow database. 269 * 270 * ulp_ctxt [in] Ptr to ulp context 271 * 272 * Returns 0 on success or negative number on failure. 273 */ 274 int32_t ulp_flow_db_init(struct bnxt_ulp_context *ulp_ctxt) 275 { 276 struct bnxt_ulp_device_params *dparms; 277 struct bnxt_ulp_flow_tbl *flow_tbl; 278 struct bnxt_ulp_flow_db *flow_db; 279 uint32_t dev_id; 280 281 /* Get the dev specific number of flows that needed to be supported. */ 282 if (bnxt_ulp_cntxt_dev_id_get(ulp_ctxt, &dev_id)) { 283 BNXT_TF_DBG(ERR, "Invalid device id\n"); 284 return -EINVAL; 285 } 286 287 dparms = bnxt_ulp_device_params_get(dev_id); 288 if (!dparms) { 289 BNXT_TF_DBG(ERR, "could not fetch the device params\n"); 290 return -ENODEV; 291 } 292 293 flow_db = rte_zmalloc("bnxt_ulp_flow_db", 294 sizeof(struct bnxt_ulp_flow_db), 0); 295 if (!flow_db) { 296 BNXT_TF_DBG(ERR, 297 "Failed to allocate memory for flow table ptr\n"); 298 return -ENOMEM; 299 } 300 301 /* Attach the flow database to the ulp context. */ 302 bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, flow_db); 303 304 /* Populate the regular flow table limits. */ 305 flow_tbl = &flow_db->flow_tbl[BNXT_ULP_REGULAR_FLOW_TABLE]; 306 flow_tbl->num_flows = dparms->flow_db_num_entries + 1; 307 flow_tbl->num_resources = (flow_tbl->num_flows * 308 dparms->num_resources_per_flow); 309 310 /* Populate the default flow table limits. */ 311 flow_tbl = &flow_db->flow_tbl[BNXT_ULP_DEFAULT_FLOW_TABLE]; 312 flow_tbl->num_flows = BNXT_FLOW_DB_DEFAULT_NUM_FLOWS + 1; 313 flow_tbl->num_resources = (flow_tbl->num_flows * 314 BNXT_FLOW_DB_DEFAULT_NUM_RESOURCES); 315 316 /* Allocate the resource for the regular flow table. */ 317 if (ulp_flow_db_alloc_resource(flow_db, BNXT_ULP_REGULAR_FLOW_TABLE)) 318 goto error_free; 319 if (ulp_flow_db_alloc_resource(flow_db, BNXT_ULP_DEFAULT_FLOW_TABLE)) 320 goto error_free; 321 322 /* add 1 since we are not using index 0 for flow id */ 323 flow_db->func_id_tbl_size = dparms->flow_db_num_entries + 1; 324 /* Allocate the function Id table */ 325 flow_db->func_id_tbl = rte_zmalloc("bnxt_ulp_flow_db_func_id_table", 326 flow_db->func_id_tbl_size * 327 sizeof(uint16_t), 0); 328 if (!flow_db->func_id_tbl) { 329 BNXT_TF_DBG(ERR, 330 "Failed to allocate mem for flow table func id\n"); 331 goto error_free; 332 } 333 /* All good so return. */ 334 return 0; 335 error_free: 336 ulp_flow_db_deinit(ulp_ctxt); 337 return -ENOMEM; 338 } 339 340 /* 341 * Deinitialize the flow database. Memory is deallocated in 342 * this call and all flows should have been purged before this 343 * call. 344 * 345 * ulp_ctxt [in] Ptr to ulp context 346 * 347 * Returns 0 on success. 348 */ 349 int32_t ulp_flow_db_deinit(struct bnxt_ulp_context *ulp_ctxt) 350 { 351 struct bnxt_ulp_flow_db *flow_db; 352 353 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 354 if (!flow_db) { 355 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 356 return -EINVAL; 357 } 358 359 /* Detach the flow database from the ulp context. */ 360 bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, NULL); 361 362 /* Free up all the memory. */ 363 ulp_flow_db_dealloc_resource(flow_db, BNXT_ULP_REGULAR_FLOW_TABLE); 364 ulp_flow_db_dealloc_resource(flow_db, BNXT_ULP_DEFAULT_FLOW_TABLE); 365 rte_free(flow_db->func_id_tbl); 366 rte_free(flow_db); 367 368 return 0; 369 } 370 371 /* 372 * Allocate the flow database entry 373 * 374 * ulp_ctxt [in] Ptr to ulp_context 375 * tbl_idx [in] Specify it is regular or default flow 376 * fid [out] The index to the flow entry 377 * 378 * returns 0 on success and negative on failure. 379 */ 380 int32_t ulp_flow_db_fid_alloc(struct bnxt_ulp_context *ulp_ctxt, 381 enum bnxt_ulp_flow_db_tables tbl_idx, 382 uint16_t func_id, 383 uint32_t *fid) 384 { 385 struct bnxt_ulp_flow_db *flow_db; 386 struct bnxt_ulp_flow_tbl *flow_tbl; 387 388 *fid = 0; /* Initialize fid to invalid value */ 389 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 390 if (!flow_db) { 391 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 392 return -EINVAL; 393 } 394 395 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 396 /* check for max flows */ 397 if (flow_tbl->num_flows <= flow_tbl->head_index) { 398 BNXT_TF_DBG(ERR, "Flow database has reached max flows\n"); 399 return -ENOMEM; 400 } 401 if (flow_tbl->tail_index <= (flow_tbl->head_index + 1)) { 402 BNXT_TF_DBG(ERR, "Flow database has reached max resources\n"); 403 return -ENOMEM; 404 } 405 *fid = flow_tbl->flow_tbl_stack[flow_tbl->head_index]; 406 flow_tbl->head_index++; 407 ulp_flow_db_active_flow_set(flow_tbl, *fid, 1); 408 409 /* The function id update is only valid for regular flow table */ 410 if (tbl_idx == BNXT_ULP_REGULAR_FLOW_TABLE) 411 ulp_flow_db_func_id_set(flow_db, *fid, func_id); 412 413 /* all good, return success */ 414 return 0; 415 } 416 417 /* 418 * Allocate the flow database entry. 419 * The params->critical_resource has to be set to 0 to allocate a new resource. 420 * 421 * ulp_ctxt [in] Ptr to ulp_context 422 * tbl_idx [in] Specify it is regular or default flow 423 * fid [in] The index to the flow entry 424 * params [in] The contents to be copied into resource 425 * 426 * returns 0 on success and negative on failure. 427 */ 428 int32_t ulp_flow_db_resource_add(struct bnxt_ulp_context *ulp_ctxt, 429 enum bnxt_ulp_flow_db_tables tbl_idx, 430 uint32_t fid, 431 struct ulp_flow_db_res_params *params) 432 { 433 struct bnxt_ulp_flow_db *flow_db; 434 struct bnxt_ulp_flow_tbl *flow_tbl; 435 struct ulp_fdb_resource_info *resource, *fid_resource; 436 uint32_t idx; 437 438 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 439 if (!flow_db) { 440 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 441 return -EINVAL; 442 } 443 444 if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) { 445 BNXT_TF_DBG(ERR, "Invalid table index\n"); 446 return -EINVAL; 447 } 448 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 449 450 /* check for max flows */ 451 if (fid >= flow_tbl->num_flows || !fid) { 452 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 453 return -EINVAL; 454 } 455 456 /* check if the flow is active or not */ 457 if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) { 458 BNXT_TF_DBG(ERR, "flow does not exist\n"); 459 return -EINVAL; 460 } 461 462 /* check for max resource */ 463 if ((flow_tbl->head_index + 1) >= flow_tbl->tail_index) { 464 BNXT_TF_DBG(ERR, "Flow db has reached max resources\n"); 465 return -ENOMEM; 466 } 467 fid_resource = &flow_tbl->flow_resources[fid]; 468 469 if (!params->critical_resource) { 470 /* Not the critical_resource so allocate a resource */ 471 idx = flow_tbl->flow_tbl_stack[flow_tbl->tail_index]; 472 resource = &flow_tbl->flow_resources[idx]; 473 flow_tbl->tail_index--; 474 475 /* Update the chain list of resource*/ 476 ULP_FLOW_DB_RES_NXT_SET(resource->nxt_resource_idx, 477 fid_resource->nxt_resource_idx); 478 /* update the contents */ 479 ulp_flow_db_res_params_to_info(resource, params); 480 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx); 481 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx, 482 idx); 483 } else { 484 /* critical resource. Just update the fid resource */ 485 ulp_flow_db_res_params_to_info(fid_resource, params); 486 } 487 488 if (params->resource_type == TF_TBL_TYPE_ACT_STATS_64 && 489 params->resource_sub_type == 490 BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) { 491 /* Store the first HW counter ID for this table */ 492 if (!ulp_fc_mgr_start_idx_isset(ulp_ctxt, params->direction)) 493 ulp_fc_mgr_start_idx_set(ulp_ctxt, params->direction, 494 params->resource_hndl); 495 496 ulp_fc_mgr_cntr_set(ulp_ctxt, params->direction, 497 params->resource_hndl); 498 499 if (!ulp_fc_mgr_thread_isstarted(ulp_ctxt)) 500 ulp_fc_mgr_thread_start(ulp_ctxt); 501 } 502 503 /* all good, return success */ 504 return 0; 505 } 506 507 /* 508 * Free the flow database entry. 509 * The params->critical_resource has to be set to 1 to free the first resource. 510 * 511 * ulp_ctxt [in] Ptr to ulp_context 512 * tbl_idx [in] Specify it is regular or default flow 513 * fid [in] The index to the flow entry 514 * params [in/out] The contents to be copied into params. 515 * Onlythe critical_resource needs to be set by the caller. 516 * 517 * Returns 0 on success and negative on failure. 518 */ 519 int32_t ulp_flow_db_resource_del(struct bnxt_ulp_context *ulp_ctxt, 520 enum bnxt_ulp_flow_db_tables tbl_idx, 521 uint32_t fid, 522 struct ulp_flow_db_res_params *params) 523 { 524 struct bnxt_ulp_flow_db *flow_db; 525 struct bnxt_ulp_flow_tbl *flow_tbl; 526 struct ulp_fdb_resource_info *nxt_resource, *fid_resource; 527 uint32_t nxt_idx = 0; 528 529 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 530 if (!flow_db) { 531 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 532 return -EINVAL; 533 } 534 535 if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) { 536 BNXT_TF_DBG(ERR, "Invalid table index\n"); 537 return -EINVAL; 538 } 539 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 540 541 /* check for max flows */ 542 if (fid >= flow_tbl->num_flows || !fid) { 543 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 544 return -EINVAL; 545 } 546 547 /* check if the flow is active or not */ 548 if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) { 549 BNXT_TF_DBG(ERR, "flow does not exist\n"); 550 return -EINVAL; 551 } 552 553 fid_resource = &flow_tbl->flow_resources[fid]; 554 if (!params->critical_resource) { 555 /* Not the critical resource so free the resource */ 556 ULP_FLOW_DB_RES_NXT_SET(nxt_idx, 557 fid_resource->nxt_resource_idx); 558 if (!nxt_idx) { 559 /* reached end of resources */ 560 return -ENOENT; 561 } 562 nxt_resource = &flow_tbl->flow_resources[nxt_idx]; 563 564 /* connect the fid resource to the next resource */ 565 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx); 566 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx, 567 nxt_resource->nxt_resource_idx); 568 569 /* update the contents to be given to caller */ 570 ulp_flow_db_res_info_to_params(nxt_resource, params); 571 572 /* Delete the nxt_resource */ 573 memset(nxt_resource, 0, sizeof(struct ulp_fdb_resource_info)); 574 575 /* add it to the free list */ 576 flow_tbl->tail_index++; 577 if (flow_tbl->tail_index >= flow_tbl->num_resources) { 578 BNXT_TF_DBG(ERR, "FlowDB:Tail reached max\n"); 579 return -ENOENT; 580 } 581 flow_tbl->flow_tbl_stack[flow_tbl->tail_index] = nxt_idx; 582 583 } else { 584 /* Critical resource. copy the contents and exit */ 585 ulp_flow_db_res_info_to_params(fid_resource, params); 586 ULP_FLOW_DB_RES_NXT_SET(nxt_idx, 587 fid_resource->nxt_resource_idx); 588 memset(fid_resource, 0, sizeof(struct ulp_fdb_resource_info)); 589 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx, 590 nxt_idx); 591 } 592 593 /* Now that the HW Flow counter resource is deleted, reset it's 594 * corresponding slot in the SW accumulation table in the Flow Counter 595 * manager 596 */ 597 if (params->resource_type == TF_TBL_TYPE_ACT_STATS_64 && 598 params->resource_sub_type == 599 BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) { 600 ulp_fc_mgr_cntr_reset(ulp_ctxt, params->direction, 601 params->resource_hndl); 602 } 603 604 /* all good, return success */ 605 return 0; 606 } 607 608 /* 609 * Free the flow database entry 610 * 611 * ulp_ctxt [in] Ptr to ulp_context 612 * tbl_idx [in] Specify it is regular or default flow 613 * fid [in] The index to the flow entry 614 * 615 * returns 0 on success and negative on failure. 616 */ 617 int32_t ulp_flow_db_fid_free(struct bnxt_ulp_context *ulp_ctxt, 618 enum bnxt_ulp_flow_db_tables tbl_idx, 619 uint32_t fid) 620 { 621 struct bnxt_ulp_flow_db *flow_db; 622 struct bnxt_ulp_flow_tbl *flow_tbl; 623 624 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 625 if (!flow_db) { 626 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 627 return -EINVAL; 628 } 629 630 if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) { 631 BNXT_TF_DBG(ERR, "Invalid table index\n"); 632 return -EINVAL; 633 } 634 635 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 636 637 /* check for limits of fid */ 638 if (fid >= flow_tbl->num_flows || !fid) { 639 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 640 return -EINVAL; 641 } 642 643 /* check if the flow is active or not */ 644 if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) { 645 BNXT_TF_DBG(ERR, "flow does not exist\n"); 646 return -EINVAL; 647 } 648 flow_tbl->head_index--; 649 if (!flow_tbl->head_index) { 650 BNXT_TF_DBG(ERR, "FlowDB: Head Ptr is zero\n"); 651 return -ENOENT; 652 } 653 flow_tbl->flow_tbl_stack[flow_tbl->head_index] = fid; 654 ulp_flow_db_active_flow_set(flow_tbl, fid, 0); 655 if (tbl_idx == BNXT_ULP_REGULAR_FLOW_TABLE) 656 ulp_flow_db_func_id_set(flow_db, fid, 0); 657 658 /* all good, return success */ 659 return 0; 660 } 661 662 /* 663 * Get the flow database entry details 664 * 665 * ulp_ctxt [in] Ptr to ulp_context 666 * tbl_idx [in] Specify it is regular or default flow 667 * fid [in] The index to the flow entry 668 * nxt_idx [in/out] the index to the next entry 669 * params [out] The contents to be copied into params. 670 * 671 * returns 0 on success and negative on failure. 672 */ 673 int32_t ulp_flow_db_resource_get(struct bnxt_ulp_context *ulp_ctxt, 674 enum bnxt_ulp_flow_db_tables tbl_idx, 675 uint32_t fid, 676 uint32_t *nxt_idx, 677 struct ulp_flow_db_res_params *params) 678 { 679 struct bnxt_ulp_flow_db *flow_db; 680 struct bnxt_ulp_flow_tbl *flow_tbl; 681 struct ulp_fdb_resource_info *nxt_resource, *fid_resource; 682 683 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 684 if (!flow_db) { 685 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 686 return -EINVAL; 687 } 688 689 if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) { 690 BNXT_TF_DBG(ERR, "Invalid table index\n"); 691 return -EINVAL; 692 } 693 694 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 695 696 /* check for limits of fid */ 697 if (fid >= flow_tbl->num_flows || !fid) { 698 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 699 return -EINVAL; 700 } 701 702 /* check if the flow is active or not */ 703 if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) { 704 BNXT_TF_DBG(ERR, "flow does not exist\n"); 705 return -EINVAL; 706 } 707 708 if (!*nxt_idx) { 709 fid_resource = &flow_tbl->flow_resources[fid]; 710 ulp_flow_db_res_info_to_params(fid_resource, params); 711 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx, 712 fid_resource->nxt_resource_idx); 713 } else { 714 nxt_resource = &flow_tbl->flow_resources[*nxt_idx]; 715 ulp_flow_db_res_info_to_params(nxt_resource, params); 716 *nxt_idx = 0; 717 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx, 718 nxt_resource->nxt_resource_idx); 719 } 720 721 /* all good, return success */ 722 return 0; 723 } 724 725 /* 726 * Get the flow database entry iteratively 727 * 728 * flow_tbl [in] Ptr to flow table 729 * fid [in/out] The index to the flow entry 730 * 731 * returns 0 on success and negative on failure. 732 */ 733 static int32_t 734 ulp_flow_db_next_entry_get(struct bnxt_ulp_flow_tbl *flowtbl, 735 uint32_t *fid) 736 { 737 uint32_t lfid = *fid; 738 uint32_t idx, s_idx, mod_fid; 739 uint64_t bs; 740 741 do { 742 /* increment the flow id to find the next valid flow id */ 743 lfid++; 744 if (lfid >= flowtbl->num_flows) 745 return -ENOENT; 746 idx = lfid / ULP_INDEX_BITMAP_SIZE; 747 mod_fid = lfid % ULP_INDEX_BITMAP_SIZE; 748 s_idx = idx; 749 while (!(bs = flowtbl->active_flow_tbl[idx])) { 750 idx++; 751 if ((idx * ULP_INDEX_BITMAP_SIZE) >= flowtbl->num_flows) 752 return -ENOENT; 753 } 754 /* 755 * remove the previous bits in the bitset bs to find the 756 * next non zero bit in the bitset. This needs to be done 757 * only if the idx is same as he one you started. 758 */ 759 if (s_idx == idx) 760 bs &= (-1UL >> mod_fid); 761 lfid = (idx * ULP_INDEX_BITMAP_SIZE) + __builtin_clzl(bs); 762 if (*fid >= lfid) { 763 BNXT_TF_DBG(ERR, "Flow Database is corrupt\n"); 764 return -ENOENT; 765 } 766 } while (!ulp_flow_db_active_flow_is_set(flowtbl, lfid)); 767 768 /* all good, return success */ 769 *fid = lfid; 770 return 0; 771 } 772 773 /* 774 * Flush all flows in the flow database. 775 * 776 * ulp_ctxt [in] Ptr to ulp context 777 * tbl_idx [in] The index to table 778 * 779 * returns 0 on success or negative number on failure 780 */ 781 int32_t ulp_flow_db_flush_flows(struct bnxt_ulp_context *ulp_ctx, 782 uint32_t idx) 783 { 784 uint32_t fid = 0; 785 struct bnxt_ulp_flow_db *flow_db; 786 struct bnxt_ulp_flow_tbl *flow_tbl; 787 788 if (!ulp_ctx) { 789 BNXT_TF_DBG(ERR, "Invalid Argument\n"); 790 return -EINVAL; 791 } 792 793 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx); 794 if (!flow_db) { 795 BNXT_TF_DBG(ERR, "Flow database not found\n"); 796 return -EINVAL; 797 } 798 flow_tbl = &flow_db->flow_tbl[idx]; 799 while (!ulp_flow_db_next_entry_get(flow_tbl, &fid)) 800 ulp_mapper_resources_free(ulp_ctx, fid, idx); 801 802 return 0; 803 } 804 805 /* 806 * Flush all flows in the flow database that belong to a device function. 807 * 808 * ulp_ctxt [in] Ptr to ulp context 809 * tbl_idx [in] The index to table 810 * 811 * returns 0 on success or negative number on failure 812 */ 813 int32_t 814 ulp_flow_db_function_flow_flush(struct bnxt_ulp_context *ulp_ctx, 815 uint16_t func_id) 816 { 817 uint32_t flow_id = 0; 818 struct bnxt_ulp_flow_db *flow_db; 819 struct bnxt_ulp_flow_tbl *flow_tbl; 820 821 if (!ulp_ctx || !func_id) { 822 BNXT_TF_DBG(ERR, "Invalid Argument\n"); 823 return -EINVAL; 824 } 825 826 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx); 827 if (!flow_db) { 828 BNXT_TF_DBG(ERR, "Flow database not found\n"); 829 return -EINVAL; 830 } 831 flow_tbl = &flow_db->flow_tbl[BNXT_ULP_REGULAR_FLOW_TABLE]; 832 while (!ulp_flow_db_next_entry_get(flow_tbl, &flow_id)) { 833 if (flow_db->func_id_tbl[flow_id] == func_id) 834 ulp_mapper_resources_free(ulp_ctx, flow_id, 835 BNXT_ULP_REGULAR_FLOW_TABLE); 836 } 837 838 return 0; 839 } 840 841 /* 842 * Flush all flows in the flow database that are associated with the session. 843 * 844 * ulp_ctxt [in] Ptr to ulp context 845 * 846 * returns 0 on success or negative number on failure 847 */ 848 int32_t 849 ulp_flow_db_session_flow_flush(struct bnxt_ulp_context *ulp_ctx) 850 { 851 /* 852 * TBD: Tf core implementation of FW session flush shall change this 853 * implementation. 854 */ 855 return ulp_flow_db_flush_flows(ulp_ctx, BNXT_ULP_REGULAR_FLOW_TABLE); 856 } 857 858 /* 859 * Check that flow id matches the function id or not 860 * 861 * ulp_ctxt [in] Ptr to ulp context 862 * flow_db [in] Ptr to flow table 863 * func_id [in] The func_id to be set, for reset pass zero. 864 * 865 * returns true on success or false on failure 866 */ 867 bool 868 ulp_flow_db_validate_flow_func(struct bnxt_ulp_context *ulp_ctx, 869 uint32_t flow_id, 870 uint32_t func_id) 871 { 872 struct bnxt_ulp_flow_db *flow_db; 873 874 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx); 875 if (!flow_db) { 876 BNXT_TF_DBG(ERR, "Flow database not found\n"); 877 return false; 878 } 879 880 /* set the function id in the function table */ 881 if (flow_id < flow_db->func_id_tbl_size && func_id && 882 flow_db->func_id_tbl[flow_id] == func_id) 883 return true; 884 885 return false; 886 } 887 888 /* 889 * Internal api to traverse the resource list within a flow 890 * and match a resource based on resource func and resource 891 * sub type. This api should be used only for resources that 892 * are unique and do not have multiple instances of resource 893 * func and sub type combination since it will return only 894 * the first match. 895 */ 896 static int32_t 897 ulp_flow_db_resource_hndl_get(struct bnxt_ulp_context *ulp_ctx, 898 enum bnxt_ulp_flow_db_tables tbl_idx, 899 uint32_t flow_id, 900 uint32_t resource_func, 901 uint32_t res_subtype, 902 uint64_t *res_hndl) 903 { 904 struct bnxt_ulp_flow_db *flow_db; 905 struct bnxt_ulp_flow_tbl *flow_tbl; 906 struct ulp_fdb_resource_info *fid_res; 907 uint32_t res_id; 908 909 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx); 910 if (!flow_db) { 911 BNXT_TF_DBG(ERR, "Flow database not found\n"); 912 return -EINVAL; 913 } 914 915 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 916 917 /* check for limits of fid */ 918 if (flow_id >= flow_tbl->num_flows || !flow_id) { 919 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 920 return -EINVAL; 921 } 922 923 /* check if the flow is active or not */ 924 if (!ulp_flow_db_active_flow_is_set(flow_tbl, flow_id)) { 925 BNXT_TF_DBG(ERR, "flow does not exist\n"); 926 return -EINVAL; 927 } 928 /* Iterate the resource to get the resource handle */ 929 res_id = flow_id; 930 while (res_id) { 931 fid_res = &flow_tbl->flow_resources[res_id]; 932 if (ulp_flow_db_resource_func_get(fid_res) == resource_func) { 933 if (resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) { 934 if (res_subtype == fid_res->resource_sub_type) { 935 *res_hndl = fid_res->resource_hndl; 936 return 0; 937 } 938 939 } else if (resource_func == 940 BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE || 941 resource_func == 942 BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) { 943 *res_hndl = fid_res->resource_em_handle; 944 return 0; 945 } 946 } 947 res_id = 0; 948 ULP_FLOW_DB_RES_NXT_SET(res_id, fid_res->nxt_resource_idx); 949 } 950 return -ENOENT; 951 } 952 953 /* 954 * Api to get the cfa action pointer from a flow. 955 * 956 * ulp_ctxt [in] Ptr to ulp context 957 * flow_id [in] flow id 958 * cfa_action [out] The resource handle stored in the flow database 959 * 960 * returns 0 on success 961 */ 962 int32_t 963 ulp_default_flow_db_cfa_action_get(struct bnxt_ulp_context *ulp_ctx, 964 uint32_t flow_id, 965 uint16_t *cfa_action) 966 { 967 uint8_t sub_type = BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_VFR_CFA_ACTION; 968 uint64_t hndl; 969 int32_t rc; 970 971 rc = ulp_flow_db_resource_hndl_get(ulp_ctx, 972 BNXT_ULP_DEFAULT_FLOW_TABLE, 973 flow_id, 974 BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE, 975 sub_type, &hndl); 976 if (rc) { 977 BNXT_TF_DBG(ERR, "CFA Action ptr not found for flow id %u\n", 978 flow_id); 979 return -ENOENT; 980 } 981 *cfa_action = hndl; 982 return 0; 983 } 984 985 #ifdef RTE_LIBRTE_BNXT_TRUFLOW_DEBUG 986 /* 987 * Dump the entry details 988 * 989 * ulp_ctxt [in] Ptr to ulp_context 990 * 991 * returns none 992 */ 993 static void ulp_flow_db_res_dump(struct ulp_fdb_resource_info *r, 994 uint32_t *nxt_res) 995 { 996 uint8_t res_func = ulp_flow_db_resource_func_get(r); 997 998 BNXT_TF_DBG(DEBUG, "Resource func = %x, nxt_resource_idx = %x\n", 999 res_func, (ULP_FLOW_DB_RES_NXT_MASK & r->nxt_resource_idx)); 1000 if (res_func == BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE || 1001 res_func == BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) 1002 BNXT_TF_DBG(DEBUG, "EM Handle = 0x%016" PRIX64 "\n", 1003 r->resource_em_handle); 1004 else 1005 BNXT_TF_DBG(DEBUG, "Handle = 0x%08x\n", r->resource_hndl); 1006 1007 *nxt_res = 0; 1008 ULP_FLOW_DB_RES_NXT_SET(*nxt_res, 1009 r->nxt_resource_idx); 1010 } 1011 1012 /* 1013 * Dump the flow database entry details 1014 * 1015 * ulp_ctxt [in] Ptr to ulp_context 1016 * 1017 * returns none 1018 */ 1019 int32_t ulp_flow_db_debug_dump(struct bnxt_ulp_context *ulp_ctxt) 1020 { 1021 struct bnxt_ulp_flow_db *flow_db; 1022 struct bnxt_ulp_flow_tbl *flow_tbl; 1023 struct ulp_fdb_resource_info *r; 1024 uint32_t nxt_res = 0; 1025 enum bnxt_ulp_flow_db_tables tbl_idx; 1026 uint32_t fid; 1027 1028 if (!ulp_ctxt || !ulp_ctxt->cfg_data) { 1029 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 1030 return -EINVAL; 1031 } 1032 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 1033 if (!flow_db) { 1034 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 1035 return -EINVAL; 1036 } 1037 1038 for (tbl_idx = 0; tbl_idx < BNXT_ULP_FLOW_TABLE_MAX; tbl_idx++) { 1039 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 1040 BNXT_TF_DBG(DEBUG, "Dump Tbl index = %u, flows = %u:%u\n", 1041 tbl_idx, flow_tbl->num_flows, 1042 flow_tbl->num_resources); 1043 BNXT_TF_DBG(DEBUG, "Head_index = %u, Tail_index = %u\n", 1044 flow_tbl->head_index, flow_tbl->tail_index); 1045 for (fid = 0; fid < flow_tbl->num_flows; fid++) { 1046 if (ulp_flow_db_active_flow_is_set(flow_tbl, fid)) { 1047 BNXT_TF_DBG(DEBUG, "fid = %u\n", fid); 1048 /* iterate the resource */ 1049 nxt_res = fid; 1050 do { 1051 r = &flow_tbl->flow_resources[nxt_res]; 1052 ulp_flow_db_res_dump(r, &nxt_res); 1053 } while (nxt_res); 1054 } 1055 } 1056 BNXT_TF_DBG(DEBUG, "Done.\n"); 1057 } 1058 return 0; 1059 } 1060 #endif 1061