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 return -EINVAL; 356 357 /* Detach the flow database from the ulp context. */ 358 bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, NULL); 359 360 /* Free up all the memory. */ 361 ulp_flow_db_dealloc_resource(flow_db, BNXT_ULP_REGULAR_FLOW_TABLE); 362 ulp_flow_db_dealloc_resource(flow_db, BNXT_ULP_DEFAULT_FLOW_TABLE); 363 rte_free(flow_db->func_id_tbl); 364 rte_free(flow_db); 365 366 return 0; 367 } 368 369 /* 370 * Allocate the flow database entry 371 * 372 * ulp_ctxt [in] Ptr to ulp_context 373 * tbl_idx [in] Specify it is regular or default flow 374 * fid [out] The index to the flow entry 375 * 376 * returns 0 on success and negative on failure. 377 */ 378 int32_t ulp_flow_db_fid_alloc(struct bnxt_ulp_context *ulp_ctxt, 379 enum bnxt_ulp_flow_db_tables tbl_idx, 380 uint16_t func_id, 381 uint32_t *fid) 382 { 383 struct bnxt_ulp_flow_db *flow_db; 384 struct bnxt_ulp_flow_tbl *flow_tbl; 385 386 *fid = 0; /* Initialize fid to invalid value */ 387 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 388 if (!flow_db) { 389 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 390 return -EINVAL; 391 } 392 393 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 394 /* check for max flows */ 395 if (flow_tbl->num_flows <= flow_tbl->head_index) { 396 BNXT_TF_DBG(ERR, "Flow database has reached max flows\n"); 397 return -ENOMEM; 398 } 399 if (flow_tbl->tail_index <= (flow_tbl->head_index + 1)) { 400 BNXT_TF_DBG(ERR, "Flow database has reached max resources\n"); 401 return -ENOMEM; 402 } 403 *fid = flow_tbl->flow_tbl_stack[flow_tbl->head_index]; 404 flow_tbl->head_index++; 405 ulp_flow_db_active_flow_set(flow_tbl, *fid, 1); 406 407 /* The function id update is only valid for regular flow table */ 408 if (tbl_idx == BNXT_ULP_REGULAR_FLOW_TABLE) 409 ulp_flow_db_func_id_set(flow_db, *fid, func_id); 410 411 /* all good, return success */ 412 return 0; 413 } 414 415 /* 416 * Allocate the flow database entry. 417 * The params->critical_resource has to be set to 0 to allocate a new resource. 418 * 419 * ulp_ctxt [in] Ptr to ulp_context 420 * tbl_idx [in] Specify it is regular or default flow 421 * fid [in] The index to the flow entry 422 * params [in] The contents to be copied into resource 423 * 424 * returns 0 on success and negative on failure. 425 */ 426 int32_t ulp_flow_db_resource_add(struct bnxt_ulp_context *ulp_ctxt, 427 enum bnxt_ulp_flow_db_tables tbl_idx, 428 uint32_t fid, 429 struct ulp_flow_db_res_params *params) 430 { 431 struct bnxt_ulp_flow_db *flow_db; 432 struct bnxt_ulp_flow_tbl *flow_tbl; 433 struct ulp_fdb_resource_info *resource, *fid_resource; 434 uint32_t idx; 435 436 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 437 if (!flow_db) { 438 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 439 return -EINVAL; 440 } 441 442 if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) { 443 BNXT_TF_DBG(ERR, "Invalid table index\n"); 444 return -EINVAL; 445 } 446 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 447 448 /* check for max flows */ 449 if (fid >= flow_tbl->num_flows || !fid) { 450 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 451 return -EINVAL; 452 } 453 454 /* check if the flow is active or not */ 455 if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) { 456 BNXT_TF_DBG(ERR, "flow does not exist\n"); 457 return -EINVAL; 458 } 459 460 /* check for max resource */ 461 if ((flow_tbl->head_index + 1) >= flow_tbl->tail_index) { 462 BNXT_TF_DBG(ERR, "Flow db has reached max resources\n"); 463 return -ENOMEM; 464 } 465 fid_resource = &flow_tbl->flow_resources[fid]; 466 467 if (!params->critical_resource) { 468 /* Not the critical_resource so allocate a resource */ 469 idx = flow_tbl->flow_tbl_stack[flow_tbl->tail_index]; 470 resource = &flow_tbl->flow_resources[idx]; 471 flow_tbl->tail_index--; 472 473 /* Update the chain list of resource*/ 474 ULP_FLOW_DB_RES_NXT_SET(resource->nxt_resource_idx, 475 fid_resource->nxt_resource_idx); 476 /* update the contents */ 477 ulp_flow_db_res_params_to_info(resource, params); 478 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx); 479 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx, 480 idx); 481 } else { 482 /* critical resource. Just update the fid resource */ 483 ulp_flow_db_res_params_to_info(fid_resource, params); 484 } 485 486 if (params->resource_type == TF_TBL_TYPE_ACT_STATS_64 && 487 params->resource_sub_type == 488 BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) { 489 /* Store the first HW counter ID for this table */ 490 if (!ulp_fc_mgr_start_idx_isset(ulp_ctxt, params->direction)) 491 ulp_fc_mgr_start_idx_set(ulp_ctxt, params->direction, 492 params->resource_hndl); 493 494 ulp_fc_mgr_cntr_set(ulp_ctxt, params->direction, 495 params->resource_hndl); 496 497 if (!ulp_fc_mgr_thread_isstarted(ulp_ctxt)) 498 ulp_fc_mgr_thread_start(ulp_ctxt); 499 } 500 501 /* all good, return success */ 502 return 0; 503 } 504 505 /* 506 * Free the flow database entry. 507 * The params->critical_resource has to be set to 1 to free the first resource. 508 * 509 * ulp_ctxt [in] Ptr to ulp_context 510 * tbl_idx [in] Specify it is regular or default flow 511 * fid [in] The index to the flow entry 512 * params [in/out] The contents to be copied into params. 513 * Onlythe critical_resource needs to be set by the caller. 514 * 515 * Returns 0 on success and negative on failure. 516 */ 517 int32_t ulp_flow_db_resource_del(struct bnxt_ulp_context *ulp_ctxt, 518 enum bnxt_ulp_flow_db_tables tbl_idx, 519 uint32_t fid, 520 struct ulp_flow_db_res_params *params) 521 { 522 struct bnxt_ulp_flow_db *flow_db; 523 struct bnxt_ulp_flow_tbl *flow_tbl; 524 struct ulp_fdb_resource_info *nxt_resource, *fid_resource; 525 uint32_t nxt_idx = 0; 526 527 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 528 if (!flow_db) { 529 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 530 return -EINVAL; 531 } 532 533 if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) { 534 BNXT_TF_DBG(ERR, "Invalid table index\n"); 535 return -EINVAL; 536 } 537 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 538 539 /* check for max flows */ 540 if (fid >= flow_tbl->num_flows || !fid) { 541 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 542 return -EINVAL; 543 } 544 545 /* check if the flow is active or not */ 546 if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) { 547 BNXT_TF_DBG(ERR, "flow does not exist\n"); 548 return -EINVAL; 549 } 550 551 fid_resource = &flow_tbl->flow_resources[fid]; 552 if (!params->critical_resource) { 553 /* Not the critical resource so free the resource */ 554 ULP_FLOW_DB_RES_NXT_SET(nxt_idx, 555 fid_resource->nxt_resource_idx); 556 if (!nxt_idx) { 557 /* reached end of resources */ 558 return -ENOENT; 559 } 560 nxt_resource = &flow_tbl->flow_resources[nxt_idx]; 561 562 /* connect the fid resource to the next resource */ 563 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx); 564 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx, 565 nxt_resource->nxt_resource_idx); 566 567 /* update the contents to be given to caller */ 568 ulp_flow_db_res_info_to_params(nxt_resource, params); 569 570 /* Delete the nxt_resource */ 571 memset(nxt_resource, 0, sizeof(struct ulp_fdb_resource_info)); 572 573 /* add it to the free list */ 574 flow_tbl->tail_index++; 575 if (flow_tbl->tail_index >= flow_tbl->num_resources) { 576 BNXT_TF_DBG(ERR, "FlowDB:Tail reached max\n"); 577 return -ENOENT; 578 } 579 flow_tbl->flow_tbl_stack[flow_tbl->tail_index] = nxt_idx; 580 581 } else { 582 /* Critical resource. copy the contents and exit */ 583 ulp_flow_db_res_info_to_params(fid_resource, params); 584 ULP_FLOW_DB_RES_NXT_SET(nxt_idx, 585 fid_resource->nxt_resource_idx); 586 memset(fid_resource, 0, sizeof(struct ulp_fdb_resource_info)); 587 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx, 588 nxt_idx); 589 } 590 591 /* Now that the HW Flow counter resource is deleted, reset it's 592 * corresponding slot in the SW accumulation table in the Flow Counter 593 * manager 594 */ 595 if (params->resource_type == TF_TBL_TYPE_ACT_STATS_64 && 596 params->resource_sub_type == 597 BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) { 598 ulp_fc_mgr_cntr_reset(ulp_ctxt, params->direction, 599 params->resource_hndl); 600 } 601 602 /* all good, return success */ 603 return 0; 604 } 605 606 /* 607 * Free the flow database entry 608 * 609 * ulp_ctxt [in] Ptr to ulp_context 610 * tbl_idx [in] Specify it is regular or default flow 611 * fid [in] The index to the flow entry 612 * 613 * returns 0 on success and negative on failure. 614 */ 615 int32_t ulp_flow_db_fid_free(struct bnxt_ulp_context *ulp_ctxt, 616 enum bnxt_ulp_flow_db_tables tbl_idx, 617 uint32_t fid) 618 { 619 struct bnxt_ulp_flow_db *flow_db; 620 struct bnxt_ulp_flow_tbl *flow_tbl; 621 622 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 623 if (!flow_db) { 624 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 625 return -EINVAL; 626 } 627 628 if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) { 629 BNXT_TF_DBG(ERR, "Invalid table index\n"); 630 return -EINVAL; 631 } 632 633 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 634 635 /* check for limits of fid */ 636 if (fid >= flow_tbl->num_flows || !fid) { 637 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 638 return -EINVAL; 639 } 640 641 /* check if the flow is active or not */ 642 if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) { 643 BNXT_TF_DBG(ERR, "flow does not exist\n"); 644 return -EINVAL; 645 } 646 flow_tbl->head_index--; 647 if (!flow_tbl->head_index) { 648 BNXT_TF_DBG(ERR, "FlowDB: Head Ptr is zero\n"); 649 return -ENOENT; 650 } 651 flow_tbl->flow_tbl_stack[flow_tbl->head_index] = fid; 652 ulp_flow_db_active_flow_set(flow_tbl, fid, 0); 653 if (tbl_idx == BNXT_ULP_REGULAR_FLOW_TABLE) 654 ulp_flow_db_func_id_set(flow_db, fid, 0); 655 656 /* all good, return success */ 657 return 0; 658 } 659 660 /* 661 * Get the flow database entry details 662 * 663 * ulp_ctxt [in] Ptr to ulp_context 664 * tbl_idx [in] Specify it is regular or default flow 665 * fid [in] The index to the flow entry 666 * nxt_idx [in/out] the index to the next entry 667 * params [out] The contents to be copied into params. 668 * 669 * returns 0 on success and negative on failure. 670 */ 671 int32_t ulp_flow_db_resource_get(struct bnxt_ulp_context *ulp_ctxt, 672 enum bnxt_ulp_flow_db_tables tbl_idx, 673 uint32_t fid, 674 uint32_t *nxt_idx, 675 struct ulp_flow_db_res_params *params) 676 { 677 struct bnxt_ulp_flow_db *flow_db; 678 struct bnxt_ulp_flow_tbl *flow_tbl; 679 struct ulp_fdb_resource_info *nxt_resource, *fid_resource; 680 681 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 682 if (!flow_db) { 683 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 684 return -EINVAL; 685 } 686 687 if (tbl_idx >= BNXT_ULP_FLOW_TABLE_MAX) { 688 BNXT_TF_DBG(ERR, "Invalid table index\n"); 689 return -EINVAL; 690 } 691 692 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 693 694 /* check for limits of fid */ 695 if (fid >= flow_tbl->num_flows || !fid) { 696 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 697 return -EINVAL; 698 } 699 700 /* check if the flow is active or not */ 701 if (!ulp_flow_db_active_flow_is_set(flow_tbl, fid)) { 702 BNXT_TF_DBG(ERR, "flow does not exist\n"); 703 return -EINVAL; 704 } 705 706 if (!*nxt_idx) { 707 fid_resource = &flow_tbl->flow_resources[fid]; 708 ulp_flow_db_res_info_to_params(fid_resource, params); 709 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx, 710 fid_resource->nxt_resource_idx); 711 } else { 712 nxt_resource = &flow_tbl->flow_resources[*nxt_idx]; 713 ulp_flow_db_res_info_to_params(nxt_resource, params); 714 *nxt_idx = 0; 715 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx, 716 nxt_resource->nxt_resource_idx); 717 } 718 719 /* all good, return success */ 720 return 0; 721 } 722 723 /* 724 * Get the flow database entry iteratively 725 * 726 * flow_tbl [in] Ptr to flow table 727 * fid [in/out] The index to the flow entry 728 * 729 * returns 0 on success and negative on failure. 730 */ 731 static int32_t 732 ulp_flow_db_next_entry_get(struct bnxt_ulp_flow_tbl *flowtbl, 733 uint32_t *fid) 734 { 735 uint32_t lfid = *fid; 736 uint32_t idx, s_idx, mod_fid; 737 uint64_t bs; 738 739 do { 740 /* increment the flow id to find the next valid flow id */ 741 lfid++; 742 if (lfid >= flowtbl->num_flows) 743 return -ENOENT; 744 idx = lfid / ULP_INDEX_BITMAP_SIZE; 745 mod_fid = lfid % ULP_INDEX_BITMAP_SIZE; 746 s_idx = idx; 747 while (!(bs = flowtbl->active_flow_tbl[idx])) { 748 idx++; 749 if ((idx * ULP_INDEX_BITMAP_SIZE) >= flowtbl->num_flows) 750 return -ENOENT; 751 } 752 /* 753 * remove the previous bits in the bitset bs to find the 754 * next non zero bit in the bitset. This needs to be done 755 * only if the idx is same as he one you started. 756 */ 757 if (s_idx == idx) 758 bs &= (-1UL >> mod_fid); 759 lfid = (idx * ULP_INDEX_BITMAP_SIZE) + __builtin_clzl(bs); 760 if (*fid >= lfid) { 761 BNXT_TF_DBG(ERR, "Flow Database is corrupt\n"); 762 return -ENOENT; 763 } 764 } while (!ulp_flow_db_active_flow_is_set(flowtbl, lfid)); 765 766 /* all good, return success */ 767 *fid = lfid; 768 return 0; 769 } 770 771 /* 772 * Flush all flows in the flow database. 773 * 774 * ulp_ctxt [in] Ptr to ulp context 775 * tbl_idx [in] The index to table 776 * 777 * returns 0 on success or negative number on failure 778 */ 779 int32_t ulp_flow_db_flush_flows(struct bnxt_ulp_context *ulp_ctx, 780 uint32_t idx) 781 { 782 uint32_t fid = 0; 783 struct bnxt_ulp_flow_db *flow_db; 784 struct bnxt_ulp_flow_tbl *flow_tbl; 785 786 if (!ulp_ctx) { 787 BNXT_TF_DBG(ERR, "Invalid Argument\n"); 788 return -EINVAL; 789 } 790 791 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx); 792 if (!flow_db) { 793 BNXT_TF_DBG(ERR, "Flow database not found\n"); 794 return -EINVAL; 795 } 796 if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) { 797 BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n"); 798 return -EINVAL; 799 } 800 801 flow_tbl = &flow_db->flow_tbl[idx]; 802 while (!ulp_flow_db_next_entry_get(flow_tbl, &fid)) 803 ulp_mapper_resources_free(ulp_ctx, fid, idx); 804 805 bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx); 806 807 return 0; 808 } 809 810 /* 811 * Flush all flows in the flow database that belong to a device function. 812 * 813 * ulp_ctxt [in] Ptr to ulp context 814 * tbl_idx [in] The index to table 815 * 816 * returns 0 on success or negative number on failure 817 */ 818 int32_t 819 ulp_flow_db_function_flow_flush(struct bnxt_ulp_context *ulp_ctx, 820 uint16_t func_id) 821 { 822 uint32_t flow_id = 0; 823 struct bnxt_ulp_flow_db *flow_db; 824 struct bnxt_ulp_flow_tbl *flow_tbl; 825 826 if (!ulp_ctx || !func_id) { 827 BNXT_TF_DBG(ERR, "Invalid Argument\n"); 828 return -EINVAL; 829 } 830 831 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx); 832 if (!flow_db) { 833 BNXT_TF_DBG(ERR, "Flow database not found\n"); 834 return -EINVAL; 835 } 836 if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) { 837 BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n"); 838 return -EINVAL; 839 } 840 flow_tbl = &flow_db->flow_tbl[BNXT_ULP_REGULAR_FLOW_TABLE]; 841 while (!ulp_flow_db_next_entry_get(flow_tbl, &flow_id)) { 842 if (flow_db->func_id_tbl[flow_id] == func_id) 843 ulp_mapper_resources_free(ulp_ctx, flow_id, 844 BNXT_ULP_REGULAR_FLOW_TABLE); 845 } 846 bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx); 847 return 0; 848 } 849 850 /* 851 * Flush all flows in the flow database that are associated with the session. 852 * 853 * ulp_ctxt [in] Ptr to ulp context 854 * 855 * returns 0 on success or negative number on failure 856 */ 857 int32_t 858 ulp_flow_db_session_flow_flush(struct bnxt_ulp_context *ulp_ctx) 859 { 860 /* 861 * TBD: Tf core implementation of FW session flush shall change this 862 * implementation. 863 */ 864 return ulp_flow_db_flush_flows(ulp_ctx, BNXT_ULP_REGULAR_FLOW_TABLE); 865 } 866 867 /* 868 * Check that flow id matches the function id or not 869 * 870 * ulp_ctxt [in] Ptr to ulp context 871 * flow_db [in] Ptr to flow table 872 * func_id [in] The func_id to be set, for reset pass zero. 873 * 874 * returns true on success or false on failure 875 */ 876 bool 877 ulp_flow_db_validate_flow_func(struct bnxt_ulp_context *ulp_ctx, 878 uint32_t flow_id, 879 uint32_t func_id) 880 { 881 struct bnxt_ulp_flow_db *flow_db; 882 883 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx); 884 if (!flow_db) { 885 BNXT_TF_DBG(ERR, "Flow database not found\n"); 886 return false; 887 } 888 889 /* set the function id in the function table */ 890 if (flow_id < flow_db->func_id_tbl_size && func_id && 891 flow_db->func_id_tbl[flow_id] == func_id) 892 return true; 893 894 return false; 895 } 896 897 /* 898 * Internal api to traverse the resource list within a flow 899 * and match a resource based on resource func and resource 900 * sub type. This api should be used only for resources that 901 * are unique and do not have multiple instances of resource 902 * func and sub type combination since it will return only 903 * the first match. 904 */ 905 static int32_t 906 ulp_flow_db_resource_hndl_get(struct bnxt_ulp_context *ulp_ctx, 907 enum bnxt_ulp_flow_db_tables tbl_idx, 908 uint32_t flow_id, 909 uint32_t resource_func, 910 uint32_t res_subtype, 911 uint64_t *res_hndl) 912 { 913 struct bnxt_ulp_flow_db *flow_db; 914 struct bnxt_ulp_flow_tbl *flow_tbl; 915 struct ulp_fdb_resource_info *fid_res; 916 uint32_t res_id; 917 918 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx); 919 if (!flow_db) { 920 BNXT_TF_DBG(ERR, "Flow database not found\n"); 921 return -EINVAL; 922 } 923 924 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 925 926 /* check for limits of fid */ 927 if (flow_id >= flow_tbl->num_flows || !flow_id) { 928 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 929 return -EINVAL; 930 } 931 932 /* check if the flow is active or not */ 933 if (!ulp_flow_db_active_flow_is_set(flow_tbl, flow_id)) { 934 BNXT_TF_DBG(ERR, "flow does not exist\n"); 935 return -EINVAL; 936 } 937 /* Iterate the resource to get the resource handle */ 938 res_id = flow_id; 939 while (res_id) { 940 fid_res = &flow_tbl->flow_resources[res_id]; 941 if (ulp_flow_db_resource_func_get(fid_res) == resource_func) { 942 if (resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) { 943 if (res_subtype == fid_res->resource_sub_type) { 944 *res_hndl = fid_res->resource_hndl; 945 return 0; 946 } 947 948 } else if (resource_func == 949 BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE || 950 resource_func == 951 BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) { 952 *res_hndl = fid_res->resource_em_handle; 953 return 0; 954 } 955 } 956 res_id = 0; 957 ULP_FLOW_DB_RES_NXT_SET(res_id, fid_res->nxt_resource_idx); 958 } 959 return -ENOENT; 960 } 961 962 /* 963 * Api to get the cfa action pointer from a flow. 964 * 965 * ulp_ctxt [in] Ptr to ulp context 966 * flow_id [in] flow id 967 * cfa_action [out] The resource handle stored in the flow database 968 * 969 * returns 0 on success 970 */ 971 int32_t 972 ulp_default_flow_db_cfa_action_get(struct bnxt_ulp_context *ulp_ctx, 973 uint32_t flow_id, 974 uint16_t *cfa_action) 975 { 976 uint8_t sub_type = BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_VFR_CFA_ACTION; 977 uint64_t hndl; 978 int32_t rc; 979 980 rc = ulp_flow_db_resource_hndl_get(ulp_ctx, 981 BNXT_ULP_DEFAULT_FLOW_TABLE, 982 flow_id, 983 BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE, 984 sub_type, &hndl); 985 if (rc) { 986 BNXT_TF_DBG(ERR, "CFA Action ptr not found for flow id %u\n", 987 flow_id); 988 return -ENOENT; 989 } 990 *cfa_action = hndl; 991 return 0; 992 } 993 994 #ifdef RTE_LIBRTE_BNXT_TRUFLOW_DEBUG 995 /* 996 * Dump the entry details 997 * 998 * ulp_ctxt [in] Ptr to ulp_context 999 * 1000 * returns none 1001 */ 1002 static void ulp_flow_db_res_dump(struct ulp_fdb_resource_info *r, 1003 uint32_t *nxt_res) 1004 { 1005 uint8_t res_func = ulp_flow_db_resource_func_get(r); 1006 1007 BNXT_TF_DBG(DEBUG, "Resource func = %x, nxt_resource_idx = %x\n", 1008 res_func, (ULP_FLOW_DB_RES_NXT_MASK & r->nxt_resource_idx)); 1009 if (res_func == BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE || 1010 res_func == BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) 1011 BNXT_TF_DBG(DEBUG, "EM Handle = 0x%016" PRIX64 "\n", 1012 r->resource_em_handle); 1013 else 1014 BNXT_TF_DBG(DEBUG, "Handle = 0x%08x\n", r->resource_hndl); 1015 1016 *nxt_res = 0; 1017 ULP_FLOW_DB_RES_NXT_SET(*nxt_res, 1018 r->nxt_resource_idx); 1019 } 1020 1021 /* 1022 * Dump the flow database entry details 1023 * 1024 * ulp_ctxt [in] Ptr to ulp_context 1025 * 1026 * returns none 1027 */ 1028 int32_t ulp_flow_db_debug_dump(struct bnxt_ulp_context *ulp_ctxt) 1029 { 1030 struct bnxt_ulp_flow_db *flow_db; 1031 struct bnxt_ulp_flow_tbl *flow_tbl; 1032 struct ulp_fdb_resource_info *r; 1033 uint32_t nxt_res = 0; 1034 enum bnxt_ulp_flow_db_tables tbl_idx; 1035 uint32_t fid; 1036 1037 if (!ulp_ctxt || !ulp_ctxt->cfg_data) { 1038 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 1039 return -EINVAL; 1040 } 1041 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 1042 if (!flow_db) { 1043 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 1044 return -EINVAL; 1045 } 1046 1047 for (tbl_idx = 0; tbl_idx < BNXT_ULP_FLOW_TABLE_MAX; tbl_idx++) { 1048 flow_tbl = &flow_db->flow_tbl[tbl_idx]; 1049 BNXT_TF_DBG(DEBUG, "Dump Tbl index = %u, flows = %u:%u\n", 1050 tbl_idx, flow_tbl->num_flows, 1051 flow_tbl->num_resources); 1052 BNXT_TF_DBG(DEBUG, "Head_index = %u, Tail_index = %u\n", 1053 flow_tbl->head_index, flow_tbl->tail_index); 1054 for (fid = 0; fid < flow_tbl->num_flows; fid++) { 1055 if (ulp_flow_db_active_flow_is_set(flow_tbl, fid)) { 1056 BNXT_TF_DBG(DEBUG, "fid = %u\n", fid); 1057 /* iterate the resource */ 1058 nxt_res = fid; 1059 do { 1060 r = &flow_tbl->flow_resources[nxt_res]; 1061 ulp_flow_db_res_dump(r, &nxt_res); 1062 } while (nxt_res); 1063 } 1064 } 1065 BNXT_TF_DBG(DEBUG, "Done.\n"); 1066 } 1067 return 0; 1068 } 1069 #endif 1070