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