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_utils.h" 10 #include "ulp_template_struct.h" 11 #include "ulp_mapper.h" 12 #include "ulp_flow_db.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 flows 31 * No validation is done in this function. 32 * 33 * flow_db [in] Ptr to flow database 34 * flow_type [in] - specify default or regular 35 * idx [in] The index to bit to be set or reset. 36 * flag [in] 1 to set and 0 to reset. 37 * 38 * returns none 39 */ 40 static void 41 ulp_flow_db_active_flows_bit_set(struct bnxt_ulp_flow_db *flow_db, 42 enum bnxt_ulp_fdb_type flow_type, 43 uint32_t idx, 44 uint32_t flag) 45 { 46 struct bnxt_ulp_flow_tbl *f_tbl = &flow_db->flow_tbl; 47 uint32_t a_idx = idx / ULP_INDEX_BITMAP_SIZE; 48 49 if (flag) { 50 if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR) 51 ULP_INDEX_BITMAP_SET(f_tbl->active_reg_flows[a_idx], 52 idx); 53 else 54 ULP_INDEX_BITMAP_SET(f_tbl->active_dflt_flows[a_idx], 55 idx); 56 } else { 57 if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR) 58 ULP_INDEX_BITMAP_RESET(f_tbl->active_reg_flows[a_idx], 59 idx); 60 else 61 ULP_INDEX_BITMAP_RESET(f_tbl->active_dflt_flows[a_idx], 62 idx); 63 } 64 } 65 66 /* 67 * Helper function to check if given fid is active flow. 68 * No validation being done in this function. 69 * 70 * flow_db [in] Ptr to flow database 71 * flow_type [in] - specify default or regular 72 * idx [in] The index to bit to be set or reset. 73 * 74 * returns 1 on set or 0 if not set. 75 */ 76 static int32_t 77 ulp_flow_db_active_flows_bit_is_set(struct bnxt_ulp_flow_db *flow_db, 78 enum bnxt_ulp_fdb_type flow_type, 79 uint32_t idx) 80 { 81 struct bnxt_ulp_flow_tbl *f_tbl = &flow_db->flow_tbl; 82 uint32_t a_idx = idx / ULP_INDEX_BITMAP_SIZE; 83 84 if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR) 85 return ULP_INDEX_BITMAP_GET(f_tbl->active_reg_flows[a_idx], 86 idx); 87 else 88 return ULP_INDEX_BITMAP_GET(f_tbl->active_dflt_flows[a_idx], 89 idx); 90 } 91 92 static inline enum tf_dir 93 ulp_flow_db_resource_dir_get(struct ulp_fdb_resource_info *res_info) 94 { 95 return ((res_info->nxt_resource_idx & ULP_FLOW_DB_RES_DIR_MASK) >> 96 ULP_FLOW_DB_RES_DIR_BIT); 97 } 98 99 static uint8_t 100 ulp_flow_db_resource_func_get(struct ulp_fdb_resource_info *res_info) 101 { 102 uint8_t func; 103 104 func = (((res_info->nxt_resource_idx & ULP_FLOW_DB_RES_FUNC_MASK) >> 105 ULP_FLOW_DB_RES_FUNC_BITS) << ULP_FLOW_DB_RES_FUNC_UPPER); 106 /* The reource func is split into upper and lower */ 107 if (func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) 108 return (func | res_info->resource_func_lower); 109 return func; 110 } 111 112 /* 113 * Helper function to copy the resource params to resource info 114 * No validation being done in this function. 115 * 116 * resource_info [out] Ptr to resource information 117 * params [in] The input params from the caller 118 * returns none 119 */ 120 static void 121 ulp_flow_db_res_params_to_info(struct ulp_fdb_resource_info *resource_info, 122 struct ulp_flow_db_res_params *params) 123 { 124 uint32_t resource_func; 125 126 resource_info->nxt_resource_idx |= ((params->direction << 127 ULP_FLOW_DB_RES_DIR_BIT) & 128 ULP_FLOW_DB_RES_DIR_MASK); 129 resource_func = (params->resource_func >> ULP_FLOW_DB_RES_FUNC_UPPER); 130 resource_info->nxt_resource_idx |= ((resource_func << 131 ULP_FLOW_DB_RES_FUNC_BITS) & 132 ULP_FLOW_DB_RES_FUNC_MASK); 133 134 if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) { 135 /* Break the resource func into two parts */ 136 resource_func = (params->resource_func & 137 ULP_FLOW_DB_RES_FUNC_LOWER_MASK); 138 resource_info->resource_func_lower = resource_func; 139 } 140 141 /* Store the handle as 64bit only for EM table entries */ 142 if (params->resource_func != BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE && 143 params->resource_func != BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) { 144 resource_info->resource_hndl = (uint32_t)params->resource_hndl; 145 resource_info->resource_type = params->resource_type; 146 resource_info->resource_sub_type = params->resource_sub_type; 147 resource_info->reserved = params->reserved; 148 } else { 149 resource_info->resource_em_handle = params->resource_hndl; 150 } 151 } 152 153 /* 154 * Helper function to copy the resource params to resource info 155 * No validation being done in this function. 156 * 157 * resource_info [in] Ptr to resource information 158 * params [out] The output params to the caller 159 * 160 * returns none 161 */ 162 static void 163 ulp_flow_db_res_info_to_params(struct ulp_fdb_resource_info *resource_info, 164 struct ulp_flow_db_res_params *params) 165 { 166 memset(params, 0, sizeof(struct ulp_flow_db_res_params)); 167 168 /* use the helper function to get the resource func */ 169 params->direction = ulp_flow_db_resource_dir_get(resource_info); 170 params->resource_func = ulp_flow_db_resource_func_get(resource_info); 171 172 if (params->resource_func == BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE || 173 params->resource_func == BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) { 174 params->resource_hndl = resource_info->resource_em_handle; 175 } else if (params->resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) { 176 params->resource_hndl = resource_info->resource_hndl; 177 params->resource_type = resource_info->resource_type; 178 params->resource_sub_type = resource_info->resource_sub_type; 179 params->reserved = resource_info->reserved; 180 } 181 } 182 183 /* 184 * Helper function to allocate the flow table and initialize 185 * the stack for allocation operations. 186 * 187 * flow_db [in] Ptr to flow database structure 188 * 189 * Returns 0 on success or negative number on failure. 190 */ 191 static int32_t 192 ulp_flow_db_alloc_resource(struct bnxt_ulp_flow_db *flow_db) 193 { 194 uint32_t idx = 0; 195 struct bnxt_ulp_flow_tbl *flow_tbl; 196 uint32_t size; 197 198 flow_tbl = &flow_db->flow_tbl; 199 200 size = sizeof(struct ulp_fdb_resource_info) * flow_tbl->num_resources; 201 flow_tbl->flow_resources = 202 rte_zmalloc("ulp_fdb_resource_info", size, 0); 203 204 if (!flow_tbl->flow_resources) { 205 BNXT_TF_DBG(ERR, "Failed to alloc memory for flow table\n"); 206 return -ENOMEM; 207 } 208 size = sizeof(uint32_t) * flow_tbl->num_resources; 209 flow_tbl->flow_tbl_stack = rte_zmalloc("flow_tbl_stack", size, 0); 210 if (!flow_tbl->flow_tbl_stack) { 211 BNXT_TF_DBG(ERR, "Failed to alloc memory flow tbl stack\n"); 212 return -ENOMEM; 213 } 214 size = (flow_tbl->num_flows / sizeof(uint64_t)) + 1; 215 size = ULP_BYTE_ROUND_OFF_8(size); 216 flow_tbl->active_reg_flows = rte_zmalloc("active reg flows", size, 217 ULP_BUFFER_ALIGN_64_BYTE); 218 if (!flow_tbl->active_reg_flows) { 219 BNXT_TF_DBG(ERR, "Failed to alloc memory active reg flows\n"); 220 return -ENOMEM; 221 } 222 223 flow_tbl->active_dflt_flows = rte_zmalloc("active dflt flows", size, 224 ULP_BUFFER_ALIGN_64_BYTE); 225 if (!flow_tbl->active_dflt_flows) { 226 BNXT_TF_DBG(ERR, "Failed to alloc memory active dflt flows\n"); 227 return -ENOMEM; 228 } 229 230 /* Initialize the stack table. */ 231 for (idx = 0; idx < flow_tbl->num_resources; idx++) 232 flow_tbl->flow_tbl_stack[idx] = idx; 233 234 /* Ignore the first element in the list. */ 235 flow_tbl->head_index = 1; 236 /* Tail points to the last entry in the list. */ 237 flow_tbl->tail_index = flow_tbl->num_resources - 1; 238 return 0; 239 } 240 241 /* 242 * Helper function to deallocate the flow table. 243 * 244 * flow_db [in] Ptr to flow database structure 245 * 246 * Returns none. 247 */ 248 static void 249 ulp_flow_db_dealloc_resource(struct bnxt_ulp_flow_db *flow_db) 250 { 251 struct bnxt_ulp_flow_tbl *flow_tbl = &flow_db->flow_tbl; 252 253 /* Free all the allocated tables in the flow table. */ 254 if (flow_tbl->active_reg_flows) { 255 rte_free(flow_tbl->active_reg_flows); 256 flow_tbl->active_reg_flows = NULL; 257 } 258 if (flow_tbl->active_dflt_flows) { 259 rte_free(flow_tbl->active_dflt_flows); 260 flow_tbl->active_dflt_flows = NULL; 261 } 262 263 if (flow_tbl->flow_tbl_stack) { 264 rte_free(flow_tbl->flow_tbl_stack); 265 flow_tbl->flow_tbl_stack = NULL; 266 } 267 268 if (flow_tbl->flow_resources) { 269 rte_free(flow_tbl->flow_resources); 270 flow_tbl->flow_resources = NULL; 271 } 272 } 273 274 /* 275 * Helper function to add function id to the flow table 276 * 277 * flow_db [in] Ptr to flow table 278 * flow_id [in] The flow id of the flow 279 * func_id [in] The func_id to be set, for reset pass zero 280 * 281 * returns none 282 */ 283 static void 284 ulp_flow_db_func_id_set(struct bnxt_ulp_flow_db *flow_db, 285 uint32_t flow_id, 286 uint32_t func_id) 287 { 288 /* set the function id in the function table */ 289 if (flow_id < flow_db->func_id_tbl_size) 290 flow_db->func_id_tbl[flow_id] = func_id; 291 else /* This should never happen */ 292 BNXT_TF_DBG(ERR, "Invalid flow id, flowdb corrupt\n"); 293 } 294 295 /* 296 * Initialize the parent-child database. Memory is allocated in this 297 * call and assigned to the database 298 * 299 * flow_db [in] Ptr to flow table 300 * num_entries[in] - number of entries to allocate 301 * 302 * Returns 0 on success or negative number on failure. 303 */ 304 static int32_t 305 ulp_flow_db_parent_tbl_init(struct bnxt_ulp_flow_db *flow_db, 306 uint32_t num_entries) 307 { 308 struct ulp_fdb_parent_child_db *p_db; 309 uint32_t size, idx; 310 311 if (!num_entries) 312 return 0; 313 314 /* update the sizes for the allocation */ 315 p_db = &flow_db->parent_child_db; 316 p_db->child_bitset_size = (flow_db->flow_tbl.num_flows / 317 sizeof(uint64_t)) + 1; /* size in bytes */ 318 p_db->child_bitset_size = ULP_BYTE_ROUND_OFF_8(p_db->child_bitset_size); 319 p_db->entries_count = num_entries; 320 321 /* allocate the memory */ 322 p_db->parent_flow_tbl = rte_zmalloc("fdb parent flow tbl", 323 sizeof(struct ulp_fdb_parent_info) * 324 p_db->entries_count, 0); 325 if (!p_db->parent_flow_tbl) { 326 BNXT_TF_DBG(ERR, 327 "Failed to allocate memory fdb parent flow tbl\n"); 328 return -ENOMEM; 329 } 330 size = p_db->child_bitset_size * p_db->entries_count; 331 332 /* 333 * allocate the big chunk of memory to be statically carved into 334 * child_fid_bitset pointer. 335 */ 336 p_db->parent_flow_tbl_mem = rte_zmalloc("fdb parent flow tbl mem", 337 size, 338 ULP_BUFFER_ALIGN_64_BYTE); 339 if (!p_db->parent_flow_tbl_mem) { 340 BNXT_TF_DBG(ERR, 341 "Failed to allocate memory fdb parent flow mem\n"); 342 return -ENOMEM; 343 } 344 345 /* set the pointers in parent table to their offsets */ 346 for (idx = 0 ; idx < p_db->entries_count; idx++) { 347 p_db->parent_flow_tbl[idx].child_fid_bitset = 348 (uint64_t *)&p_db->parent_flow_tbl_mem[idx * 349 p_db->child_bitset_size]; 350 } 351 /* success */ 352 return 0; 353 } 354 355 /* 356 * Deinitialize the parent-child database. Memory is deallocated in 357 * this call and all flows should have been purged before this 358 * call. 359 * 360 * flow_db [in] Ptr to flow table 361 * 362 * Returns none 363 */ 364 static void 365 ulp_flow_db_parent_tbl_deinit(struct bnxt_ulp_flow_db *flow_db) 366 { 367 /* free the memory related to parent child database */ 368 if (flow_db->parent_child_db.parent_flow_tbl_mem) { 369 rte_free(flow_db->parent_child_db.parent_flow_tbl_mem); 370 flow_db->parent_child_db.parent_flow_tbl_mem = NULL; 371 } 372 if (flow_db->parent_child_db.parent_flow_tbl) { 373 rte_free(flow_db->parent_child_db.parent_flow_tbl); 374 flow_db->parent_child_db.parent_flow_tbl = NULL; 375 } 376 } 377 378 /* 379 * Initialize the flow database. Memory is allocated in this 380 * call and assigned to the flow database. 381 * 382 * ulp_ctxt [in] Ptr to ulp context 383 * 384 * Returns 0 on success or negative number on failure. 385 */ 386 int32_t 387 ulp_flow_db_init(struct bnxt_ulp_context *ulp_ctxt) 388 { 389 struct bnxt_ulp_device_params *dparms; 390 struct bnxt_ulp_flow_tbl *flow_tbl; 391 struct bnxt_ulp_flow_db *flow_db; 392 uint32_t dev_id, num_flows; 393 enum bnxt_ulp_flow_mem_type mtype; 394 395 /* Get the dev specific number of flows that needed to be supported. */ 396 if (bnxt_ulp_cntxt_dev_id_get(ulp_ctxt, &dev_id)) { 397 BNXT_TF_DBG(ERR, "Invalid device id\n"); 398 return -EINVAL; 399 } 400 401 dparms = bnxt_ulp_device_params_get(dev_id); 402 if (!dparms) { 403 BNXT_TF_DBG(ERR, "could not fetch the device params\n"); 404 return -ENODEV; 405 } 406 407 flow_db = rte_zmalloc("bnxt_ulp_flow_db", 408 sizeof(struct bnxt_ulp_flow_db), 0); 409 if (!flow_db) { 410 BNXT_TF_DBG(ERR, 411 "Failed to allocate memory for flow table ptr\n"); 412 return -ENOMEM; 413 } 414 415 /* Attach the flow database to the ulp context. */ 416 bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, flow_db); 417 418 /* Determine the number of flows based on EM type */ 419 bnxt_ulp_cntxt_mem_type_get(ulp_ctxt, &mtype); 420 if (mtype == BNXT_ULP_FLOW_MEM_TYPE_INT) 421 num_flows = dparms->int_flow_db_num_entries; 422 else 423 num_flows = dparms->ext_flow_db_num_entries; 424 425 /* Populate the regular flow table limits. */ 426 flow_tbl = &flow_db->flow_tbl; 427 flow_tbl->num_flows = num_flows + 1; 428 flow_tbl->num_resources = ((num_flows + 1) * 429 dparms->num_resources_per_flow); 430 431 /* Include the default flow table limits. */ 432 flow_tbl->num_flows += (BNXT_FLOW_DB_DEFAULT_NUM_FLOWS + 1); 433 flow_tbl->num_resources += ((BNXT_FLOW_DB_DEFAULT_NUM_FLOWS + 1) * 434 BNXT_FLOW_DB_DEFAULT_NUM_RESOURCES); 435 436 /* Allocate the resource for the flow table. */ 437 if (ulp_flow_db_alloc_resource(flow_db)) 438 goto error_free; 439 440 /* add 1 since we are not using index 0 for flow id */ 441 flow_db->func_id_tbl_size = flow_tbl->num_flows + 1; 442 /* Allocate the function Id table */ 443 flow_db->func_id_tbl = rte_zmalloc("bnxt_ulp_flow_db_func_id_table", 444 flow_db->func_id_tbl_size * 445 sizeof(uint16_t), 0); 446 if (!flow_db->func_id_tbl) { 447 BNXT_TF_DBG(ERR, 448 "Failed to allocate mem for flow table func id\n"); 449 goto error_free; 450 } 451 /* initialize the parent child database */ 452 if (ulp_flow_db_parent_tbl_init(flow_db, 453 dparms->fdb_parent_flow_entries)) { 454 BNXT_TF_DBG(ERR, 455 "Failed to allocate mem for parent child db\n"); 456 goto error_free; 457 } 458 459 /* All good so return. */ 460 BNXT_TF_DBG(INFO, "FlowDB initialized with %d flows.\n", 461 flow_tbl->num_flows); 462 return 0; 463 error_free: 464 ulp_flow_db_deinit(ulp_ctxt); 465 return -ENOMEM; 466 } 467 468 /* 469 * Deinitialize the flow database. Memory is deallocated in 470 * this call and all flows should have been purged before this 471 * call. 472 * 473 * ulp_ctxt [in] Ptr to ulp context 474 * 475 * Returns 0 on success. 476 */ 477 int32_t 478 ulp_flow_db_deinit(struct bnxt_ulp_context *ulp_ctxt) 479 { 480 struct bnxt_ulp_flow_db *flow_db; 481 482 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 483 if (!flow_db) 484 return -EINVAL; 485 486 /* Detach the flow database from the ulp context. */ 487 bnxt_ulp_cntxt_ptr2_flow_db_set(ulp_ctxt, NULL); 488 489 /* Free up all the memory. */ 490 ulp_flow_db_parent_tbl_deinit(flow_db); 491 ulp_flow_db_dealloc_resource(flow_db); 492 rte_free(flow_db->func_id_tbl); 493 rte_free(flow_db); 494 495 return 0; 496 } 497 498 /* 499 * Allocate the flow database entry 500 * 501 * ulp_ctxt [in] Ptr to ulp_context 502 * flow_type [in] - specify default or regular 503 * func_id [in].function id of the ingress port 504 * fid [out] The index to the flow entry 505 * 506 * returns 0 on success and negative on failure. 507 */ 508 int32_t 509 ulp_flow_db_fid_alloc(struct bnxt_ulp_context *ulp_ctxt, 510 enum bnxt_ulp_fdb_type flow_type, 511 uint16_t func_id, 512 uint32_t *fid) 513 { 514 struct bnxt_ulp_flow_db *flow_db; 515 struct bnxt_ulp_flow_tbl *flow_tbl; 516 517 *fid = 0; /* Initialize fid to invalid value */ 518 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 519 if (!flow_db) { 520 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 521 return -EINVAL; 522 } 523 524 if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) { 525 BNXT_TF_DBG(ERR, "Invalid flow type\n"); 526 return -EINVAL; 527 } 528 529 flow_tbl = &flow_db->flow_tbl; 530 /* check for max flows */ 531 if (flow_tbl->num_flows <= flow_tbl->head_index) { 532 BNXT_TF_DBG(ERR, "Flow database has reached max flows\n"); 533 return -ENOMEM; 534 } 535 if (flow_tbl->tail_index <= (flow_tbl->head_index + 1)) { 536 BNXT_TF_DBG(ERR, "Flow database has reached max resources\n"); 537 return -ENOMEM; 538 } 539 *fid = flow_tbl->flow_tbl_stack[flow_tbl->head_index]; 540 flow_tbl->head_index++; 541 542 /* Set the flow type */ 543 ulp_flow_db_active_flows_bit_set(flow_db, flow_type, *fid, 1); 544 545 /* function id update is only valid for regular flow table */ 546 if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR) 547 ulp_flow_db_func_id_set(flow_db, *fid, func_id); 548 549 /* return success */ 550 return 0; 551 } 552 553 /* 554 * Allocate the flow database entry. 555 * The params->critical_resource has to be set to 0 to allocate a new resource. 556 * 557 * ulp_ctxt [in] Ptr to ulp_context 558 * flow_type [in] Specify it is regular or default flow 559 * fid [in] The index to the flow entry 560 * params [in] The contents to be copied into resource 561 * 562 * returns 0 on success and negative on failure. 563 */ 564 int32_t 565 ulp_flow_db_resource_add(struct bnxt_ulp_context *ulp_ctxt, 566 enum bnxt_ulp_fdb_type flow_type, 567 uint32_t fid, 568 struct ulp_flow_db_res_params *params) 569 { 570 struct bnxt_ulp_flow_db *flow_db; 571 struct bnxt_ulp_flow_tbl *flow_tbl; 572 struct ulp_fdb_resource_info *resource, *fid_resource; 573 uint32_t idx; 574 575 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 576 if (!flow_db) { 577 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 578 return -EINVAL; 579 } 580 581 if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) { 582 BNXT_TF_DBG(ERR, "Invalid flow type\n"); 583 return -EINVAL; 584 } 585 586 flow_tbl = &flow_db->flow_tbl; 587 /* check for max flows */ 588 if (fid >= flow_tbl->num_flows || !fid) { 589 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 590 return -EINVAL; 591 } 592 593 /* check if the flow is active or not */ 594 if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) { 595 BNXT_TF_DBG(ERR, "flow does not exist\n"); 596 return -EINVAL; 597 } 598 599 /* check for max resource */ 600 if ((flow_tbl->head_index + 1) >= flow_tbl->tail_index) { 601 BNXT_TF_DBG(ERR, "Flow db has reached max resources\n"); 602 return -ENOMEM; 603 } 604 fid_resource = &flow_tbl->flow_resources[fid]; 605 606 if (!params->critical_resource) { 607 /* Not the critical_resource so allocate a resource */ 608 idx = flow_tbl->flow_tbl_stack[flow_tbl->tail_index]; 609 resource = &flow_tbl->flow_resources[idx]; 610 flow_tbl->tail_index--; 611 612 /* Update the chain list of resource*/ 613 ULP_FLOW_DB_RES_NXT_SET(resource->nxt_resource_idx, 614 fid_resource->nxt_resource_idx); 615 /* update the contents */ 616 ulp_flow_db_res_params_to_info(resource, params); 617 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx); 618 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx, 619 idx); 620 } else { 621 /* critical resource. Just update the fid resource */ 622 ulp_flow_db_res_params_to_info(fid_resource, params); 623 } 624 625 if (params->resource_type == TF_TBL_TYPE_ACT_STATS_64 && 626 params->resource_sub_type == 627 BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) { 628 /* Store the first HW counter ID for this table */ 629 if (!ulp_fc_mgr_start_idx_isset(ulp_ctxt, params->direction)) 630 ulp_fc_mgr_start_idx_set(ulp_ctxt, params->direction, 631 params->resource_hndl); 632 633 ulp_fc_mgr_cntr_set(ulp_ctxt, params->direction, 634 params->resource_hndl); 635 636 if (!ulp_fc_mgr_thread_isstarted(ulp_ctxt)) 637 ulp_fc_mgr_thread_start(ulp_ctxt); 638 } 639 640 /* all good, return success */ 641 return 0; 642 } 643 644 /* 645 * Free the flow database entry. 646 * The params->critical_resource has to be set to 1 to free the first resource. 647 * 648 * ulp_ctxt [in] Ptr to ulp_context 649 * flow_type [in] Specify it is regular or default flow 650 * fid [in] The index to the flow entry 651 * params [in/out] The contents to be copied into params. 652 * Onlythe critical_resource needs to be set by the caller. 653 * 654 * Returns 0 on success and negative on failure. 655 */ 656 int32_t 657 ulp_flow_db_resource_del(struct bnxt_ulp_context *ulp_ctxt, 658 enum bnxt_ulp_fdb_type flow_type, 659 uint32_t fid, 660 struct ulp_flow_db_res_params *params) 661 { 662 struct bnxt_ulp_flow_db *flow_db; 663 struct bnxt_ulp_flow_tbl *flow_tbl; 664 struct ulp_fdb_resource_info *nxt_resource, *fid_resource; 665 uint32_t nxt_idx = 0; 666 667 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 668 if (!flow_db) { 669 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 670 return -EINVAL; 671 } 672 673 if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) { 674 BNXT_TF_DBG(ERR, "Invalid flow type\n"); 675 return -EINVAL; 676 } 677 678 flow_tbl = &flow_db->flow_tbl; 679 /* check for max flows */ 680 if (fid >= flow_tbl->num_flows || !fid) { 681 BNXT_TF_DBG(ERR, "Invalid flow index %x\n", fid); 682 return -EINVAL; 683 } 684 685 /* check if the flow is active or not */ 686 if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) { 687 BNXT_TF_DBG(ERR, "flow does not exist\n"); 688 return -EINVAL; 689 } 690 691 fid_resource = &flow_tbl->flow_resources[fid]; 692 if (!params->critical_resource) { 693 /* Not the critical resource so free the resource */ 694 ULP_FLOW_DB_RES_NXT_SET(nxt_idx, 695 fid_resource->nxt_resource_idx); 696 if (!nxt_idx) { 697 /* reached end of resources */ 698 return -ENOENT; 699 } 700 nxt_resource = &flow_tbl->flow_resources[nxt_idx]; 701 702 /* connect the fid resource to the next resource */ 703 ULP_FLOW_DB_RES_NXT_RESET(fid_resource->nxt_resource_idx); 704 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx, 705 nxt_resource->nxt_resource_idx); 706 707 /* update the contents to be given to caller */ 708 ulp_flow_db_res_info_to_params(nxt_resource, params); 709 710 /* Delete the nxt_resource */ 711 memset(nxt_resource, 0, sizeof(struct ulp_fdb_resource_info)); 712 713 /* add it to the free list */ 714 flow_tbl->tail_index++; 715 if (flow_tbl->tail_index >= flow_tbl->num_resources) { 716 BNXT_TF_DBG(ERR, "FlowDB:Tail reached max\n"); 717 return -ENOENT; 718 } 719 flow_tbl->flow_tbl_stack[flow_tbl->tail_index] = nxt_idx; 720 721 } else { 722 /* Critical resource. copy the contents and exit */ 723 ulp_flow_db_res_info_to_params(fid_resource, params); 724 ULP_FLOW_DB_RES_NXT_SET(nxt_idx, 725 fid_resource->nxt_resource_idx); 726 memset(fid_resource, 0, sizeof(struct ulp_fdb_resource_info)); 727 ULP_FLOW_DB_RES_NXT_SET(fid_resource->nxt_resource_idx, 728 nxt_idx); 729 } 730 731 /* Now that the HW Flow counter resource is deleted, reset it's 732 * corresponding slot in the SW accumulation table in the Flow Counter 733 * manager 734 */ 735 if (params->resource_type == TF_TBL_TYPE_ACT_STATS_64 && 736 params->resource_sub_type == 737 BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) { 738 ulp_fc_mgr_cntr_reset(ulp_ctxt, params->direction, 739 params->resource_hndl); 740 } 741 742 /* all good, return success */ 743 return 0; 744 } 745 746 /* 747 * Free the flow database entry 748 * 749 * ulp_ctxt [in] Ptr to ulp_context 750 * flow_type [in] - specify default or regular 751 * fid [in] The index to the flow entry 752 * 753 * returns 0 on success and negative on failure. 754 */ 755 int32_t 756 ulp_flow_db_fid_free(struct bnxt_ulp_context *ulp_ctxt, 757 enum bnxt_ulp_fdb_type flow_type, 758 uint32_t fid) 759 { 760 struct bnxt_ulp_flow_db *flow_db; 761 struct bnxt_ulp_flow_tbl *flow_tbl; 762 763 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 764 if (!flow_db) { 765 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 766 return -EINVAL; 767 } 768 769 if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) { 770 BNXT_TF_DBG(ERR, "Invalid flow type\n"); 771 return -EINVAL; 772 } 773 774 flow_tbl = &flow_db->flow_tbl; 775 776 /* check for limits of fid */ 777 if (fid >= flow_tbl->num_flows || !fid) { 778 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 779 return -EINVAL; 780 } 781 782 /* check if the flow is active or not */ 783 if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) { 784 BNXT_TF_DBG(ERR, "flow does not exist\n"); 785 return -EINVAL; 786 } 787 flow_tbl->head_index--; 788 if (!flow_tbl->head_index) { 789 BNXT_TF_DBG(ERR, "FlowDB: Head Ptr is zero\n"); 790 return -ENOENT; 791 } 792 flow_tbl->flow_tbl_stack[flow_tbl->head_index] = fid; 793 794 /* Clear the flows bitmap */ 795 ulp_flow_db_active_flows_bit_set(flow_db, flow_type, fid, 0); 796 797 if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR) 798 ulp_flow_db_func_id_set(flow_db, fid, 0); 799 800 /* all good, return success */ 801 return 0; 802 } 803 804 /* 805 * Get the flow database entry details 806 * 807 * ulp_ctxt [in] Ptr to ulp_context 808 * flow_type [in] - specify default or regular 809 * fid [in] The index to the flow entry 810 * nxt_idx [in/out] the index to the next entry 811 * params [out] The contents to be copied into params. 812 * 813 * returns 0 on success and negative on failure. 814 */ 815 int32_t 816 ulp_flow_db_resource_get(struct bnxt_ulp_context *ulp_ctxt, 817 enum bnxt_ulp_fdb_type flow_type, 818 uint32_t fid, 819 uint32_t *nxt_idx, 820 struct ulp_flow_db_res_params *params) 821 { 822 struct bnxt_ulp_flow_db *flow_db; 823 struct bnxt_ulp_flow_tbl *flow_tbl; 824 struct ulp_fdb_resource_info *nxt_resource, *fid_resource; 825 826 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 827 if (!flow_db) { 828 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 829 return -EINVAL; 830 } 831 832 if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) { 833 BNXT_TF_DBG(ERR, "Invalid flow type\n"); 834 return -EINVAL; 835 } 836 837 flow_tbl = &flow_db->flow_tbl; 838 839 /* check for limits of fid */ 840 if (fid >= flow_tbl->num_flows || !fid) { 841 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 842 return -EINVAL; 843 } 844 845 /* check if the flow is active or not */ 846 if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) { 847 BNXT_TF_DBG(ERR, "flow does not exist\n"); 848 return -EINVAL; 849 } 850 851 if (!*nxt_idx) { 852 fid_resource = &flow_tbl->flow_resources[fid]; 853 ulp_flow_db_res_info_to_params(fid_resource, params); 854 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx, 855 fid_resource->nxt_resource_idx); 856 } else { 857 nxt_resource = &flow_tbl->flow_resources[*nxt_idx]; 858 ulp_flow_db_res_info_to_params(nxt_resource, params); 859 *nxt_idx = 0; 860 ULP_FLOW_DB_RES_NXT_SET(*nxt_idx, 861 nxt_resource->nxt_resource_idx); 862 } 863 864 /* all good, return success */ 865 return 0; 866 } 867 868 /* 869 * Get the flow database entry iteratively 870 * 871 * flow_tbl [in] Ptr to flow table 872 * flow_type [in] - specify default or regular 873 * fid [in/out] The index to the flow entry 874 * 875 * returns 0 on success and negative on failure. 876 */ 877 static int32_t 878 ulp_flow_db_next_entry_get(struct bnxt_ulp_flow_db *flow_db, 879 enum bnxt_ulp_fdb_type flow_type, 880 uint32_t *fid) 881 { 882 uint32_t lfid = *fid; 883 uint32_t idx, s_idx, mod_fid; 884 uint64_t bs; 885 uint64_t *active_flows; 886 struct bnxt_ulp_flow_tbl *flowtbl = &flow_db->flow_tbl; 887 888 if (flow_type == BNXT_ULP_FDB_TYPE_REGULAR) 889 active_flows = flowtbl->active_reg_flows; 890 else 891 active_flows = flowtbl->active_dflt_flows; 892 893 do { 894 /* increment the flow id to find the next valid flow id */ 895 lfid++; 896 if (lfid >= flowtbl->num_flows) 897 return -ENOENT; 898 idx = lfid / ULP_INDEX_BITMAP_SIZE; 899 mod_fid = lfid % ULP_INDEX_BITMAP_SIZE; 900 s_idx = idx; 901 while (!(bs = active_flows[idx])) { 902 idx++; 903 if ((idx * ULP_INDEX_BITMAP_SIZE) >= flowtbl->num_flows) 904 return -ENOENT; 905 } 906 /* 907 * remove the previous bits in the bitset bs to find the 908 * next non zero bit in the bitset. This needs to be done 909 * only if the idx is same as he one you started. 910 */ 911 if (s_idx == idx) 912 bs &= (-1UL >> mod_fid); 913 lfid = (idx * ULP_INDEX_BITMAP_SIZE) + __builtin_clzl(bs); 914 if (*fid >= lfid) { 915 BNXT_TF_DBG(ERR, "Flow Database is corrupt\n"); 916 return -ENOENT; 917 } 918 } while (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, 919 lfid)); 920 921 /* all good, return success */ 922 *fid = lfid; 923 return 0; 924 } 925 926 /* 927 * Flush all flows in the flow database. 928 * 929 * ulp_ctxt [in] Ptr to ulp context 930 * flow_type [in] - specify default or regular 931 * 932 * returns 0 on success or negative number on failure 933 */ 934 int32_t 935 ulp_flow_db_flush_flows(struct bnxt_ulp_context *ulp_ctx, 936 enum bnxt_ulp_fdb_type flow_type) 937 { 938 uint32_t fid = 0; 939 struct bnxt_ulp_flow_db *flow_db; 940 941 if (!ulp_ctx) { 942 BNXT_TF_DBG(ERR, "Invalid Argument\n"); 943 return -EINVAL; 944 } 945 946 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx); 947 if (!flow_db) { 948 BNXT_TF_DBG(ERR, "Flow database not found\n"); 949 return -EINVAL; 950 } 951 if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) { 952 BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n"); 953 return -EINVAL; 954 } 955 956 while (!ulp_flow_db_next_entry_get(flow_db, flow_type, &fid)) 957 ulp_mapper_resources_free(ulp_ctx, flow_type, fid); 958 959 bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx); 960 961 return 0; 962 } 963 964 /* 965 * Flush all flows in the flow database that belong to a device function. 966 * 967 * ulp_ctxt [in] Ptr to ulp context 968 * func_id [in] - The port function id 969 * 970 * returns 0 on success or negative number on failure 971 */ 972 int32_t 973 ulp_flow_db_function_flow_flush(struct bnxt_ulp_context *ulp_ctx, 974 uint16_t func_id) 975 { 976 uint32_t flow_id = 0; 977 struct bnxt_ulp_flow_db *flow_db; 978 979 if (!ulp_ctx || !func_id) { 980 BNXT_TF_DBG(ERR, "Invalid Argument\n"); 981 return -EINVAL; 982 } 983 984 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx); 985 if (!flow_db) { 986 BNXT_TF_DBG(ERR, "Flow database not found\n"); 987 return -EINVAL; 988 } 989 if (bnxt_ulp_cntxt_acquire_fdb_lock(ulp_ctx)) { 990 BNXT_TF_DBG(ERR, "Flow db lock acquire failed\n"); 991 return -EINVAL; 992 } 993 994 while (!ulp_flow_db_next_entry_get(flow_db, BNXT_ULP_FDB_TYPE_REGULAR, 995 &flow_id)) { 996 if (flow_db->func_id_tbl[flow_id] == func_id) 997 ulp_mapper_resources_free(ulp_ctx, 998 BNXT_ULP_FDB_TYPE_REGULAR, 999 flow_id); 1000 } 1001 bnxt_ulp_cntxt_release_fdb_lock(ulp_ctx); 1002 return 0; 1003 } 1004 1005 /* 1006 * Flush all flows in the flow database that are associated with the session. 1007 * 1008 * ulp_ctxt [in] Ptr to ulp context 1009 * 1010 * returns 0 on success or negative number on failure 1011 */ 1012 int32_t 1013 ulp_flow_db_session_flow_flush(struct bnxt_ulp_context *ulp_ctx) 1014 { 1015 /* 1016 * TBD: Tf core implementation of FW session flush shall change this 1017 * implementation. 1018 */ 1019 return ulp_flow_db_flush_flows(ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR); 1020 } 1021 1022 /* 1023 * Check that flow id matches the function id or not 1024 * 1025 * ulp_ctxt [in] Ptr to ulp context 1026 * flow_db [in] Ptr to flow table 1027 * func_id [in] The func_id to be set, for reset pass zero. 1028 * 1029 * returns true on success or false on failure 1030 */ 1031 bool 1032 ulp_flow_db_validate_flow_func(struct bnxt_ulp_context *ulp_ctx, 1033 uint32_t flow_id, 1034 uint32_t func_id) 1035 { 1036 struct bnxt_ulp_flow_db *flow_db; 1037 1038 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx); 1039 if (!flow_db) { 1040 BNXT_TF_DBG(ERR, "Flow database not found\n"); 1041 return false; 1042 } 1043 1044 /* set the function id in the function table */ 1045 if (flow_id < flow_db->func_id_tbl_size && func_id && 1046 flow_db->func_id_tbl[flow_id] == func_id) 1047 return true; 1048 1049 return false; 1050 } 1051 1052 /* 1053 * Internal api to traverse the resource list within a flow 1054 * and match a resource based on resource func and resource 1055 * sub type. This api should be used only for resources that 1056 * are unique and do not have multiple instances of resource 1057 * func and sub type combination since it will return only 1058 * the first match. 1059 */ 1060 static int32_t 1061 ulp_flow_db_resource_hndl_get(struct bnxt_ulp_context *ulp_ctx, 1062 enum bnxt_ulp_fdb_type flow_type, 1063 uint32_t flow_id, 1064 uint32_t resource_func, 1065 uint32_t res_subtype, 1066 uint64_t *res_hndl) 1067 { 1068 struct bnxt_ulp_flow_db *flow_db; 1069 struct bnxt_ulp_flow_tbl *flow_tbl; 1070 struct ulp_fdb_resource_info *fid_res; 1071 uint32_t res_id; 1072 1073 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctx); 1074 if (!flow_db) { 1075 BNXT_TF_DBG(ERR, "Flow database not found\n"); 1076 return -EINVAL; 1077 } 1078 1079 if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) { 1080 BNXT_TF_DBG(ERR, "Invalid flow type\n"); 1081 return -EINVAL; 1082 } 1083 1084 flow_tbl = &flow_db->flow_tbl; 1085 1086 /* check for limits of fid */ 1087 if (flow_id >= flow_tbl->num_flows || !flow_id) { 1088 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 1089 return -EINVAL; 1090 } 1091 1092 /* check if the flow is active or not */ 1093 if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, flow_id)) { 1094 BNXT_TF_DBG(ERR, "flow does not exist\n"); 1095 return -EINVAL; 1096 } 1097 /* Iterate the resource to get the resource handle */ 1098 res_id = flow_id; 1099 while (res_id) { 1100 fid_res = &flow_tbl->flow_resources[res_id]; 1101 if (ulp_flow_db_resource_func_get(fid_res) == resource_func) { 1102 if (resource_func & ULP_FLOW_DB_RES_FUNC_NEED_LOWER) { 1103 if (res_subtype == fid_res->resource_sub_type) { 1104 *res_hndl = fid_res->resource_hndl; 1105 return 0; 1106 } 1107 1108 } else if (resource_func == 1109 BNXT_ULP_RESOURCE_FUNC_EXT_EM_TABLE || 1110 resource_func == 1111 BNXT_ULP_RESOURCE_FUNC_INT_EM_TABLE) { 1112 *res_hndl = fid_res->resource_em_handle; 1113 return 0; 1114 } 1115 } 1116 res_id = 0; 1117 ULP_FLOW_DB_RES_NXT_SET(res_id, fid_res->nxt_resource_idx); 1118 } 1119 return -ENOENT; 1120 } 1121 1122 /* 1123 * Api to get the cfa action pointer from a flow. 1124 * 1125 * ulp_ctxt [in] Ptr to ulp context 1126 * flow_id [in] flow id 1127 * cfa_action [out] The resource handle stored in the flow database 1128 * 1129 * returns 0 on success 1130 */ 1131 int32_t 1132 ulp_default_flow_db_cfa_action_get(struct bnxt_ulp_context *ulp_ctx, 1133 uint32_t flow_id, 1134 uint16_t *cfa_action) 1135 { 1136 uint8_t sub_type = BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_VFR_CFA_ACTION; 1137 uint64_t hndl; 1138 int32_t rc; 1139 1140 rc = ulp_flow_db_resource_hndl_get(ulp_ctx, 1141 BNXT_ULP_FDB_TYPE_DEFAULT, 1142 flow_id, 1143 BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE, 1144 sub_type, &hndl); 1145 if (rc) { 1146 BNXT_TF_DBG(ERR, "CFA Action ptr not found for flow id %u\n", 1147 flow_id); 1148 return -ENOENT; 1149 } 1150 *cfa_action = hndl; 1151 return 0; 1152 } 1153 1154 /* 1155 * Allocate the entry in the parent-child database 1156 * 1157 * ulp_ctxt [in] Ptr to ulp_context 1158 * fid [in] The flow id to the flow entry 1159 * 1160 * returns index on success and negative on failure. 1161 */ 1162 int32_t 1163 ulp_flow_db_parent_flow_alloc(struct bnxt_ulp_context *ulp_ctxt, 1164 uint32_t fid) 1165 { 1166 struct bnxt_ulp_flow_db *flow_db; 1167 struct ulp_fdb_parent_child_db *p_pdb; 1168 uint32_t idx, free_idx = 0; 1169 1170 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 1171 if (!flow_db) { 1172 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 1173 return -EINVAL; 1174 } 1175 1176 /* check for max flows */ 1177 if (fid >= flow_db->flow_tbl.num_flows || !fid) { 1178 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 1179 return -EINVAL; 1180 } 1181 1182 /* No support for parent child db then just exit */ 1183 if (!flow_db->parent_child_db.entries_count) { 1184 BNXT_TF_DBG(ERR, "parent child db not supported\n"); 1185 return -EINVAL; 1186 } 1187 1188 p_pdb = &flow_db->parent_child_db; 1189 for (idx = 0; idx <= p_pdb->entries_count; idx++) { 1190 if (p_pdb->parent_flow_tbl[idx].parent_fid == fid) { 1191 BNXT_TF_DBG(ERR, "fid is already allocated\n"); 1192 return -EINVAL; 1193 } 1194 if (!p_pdb->parent_flow_tbl[idx].parent_fid && !free_idx) 1195 free_idx = idx + 1; 1196 } 1197 /* no free slots */ 1198 if (!free_idx) { 1199 BNXT_TF_DBG(ERR, "parent child db is full\n"); 1200 return -ENOMEM; 1201 } 1202 1203 free_idx -= 1; 1204 /* set the Fid in the parent child */ 1205 p_pdb->parent_flow_tbl[free_idx].parent_fid = fid; 1206 return free_idx; 1207 } 1208 1209 /* 1210 * Free the entry in the parent-child database 1211 * 1212 * ulp_ctxt [in] Ptr to ulp_context 1213 * fid [in] The flow id to the flow entry 1214 * 1215 * returns 0 on success and negative on failure. 1216 */ 1217 int32_t 1218 ulp_flow_db_parent_flow_free(struct bnxt_ulp_context *ulp_ctxt, 1219 uint32_t fid) 1220 { 1221 struct bnxt_ulp_flow_db *flow_db; 1222 struct ulp_fdb_parent_child_db *p_pdb; 1223 uint32_t idx; 1224 1225 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 1226 if (!flow_db) { 1227 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 1228 return -EINVAL; 1229 } 1230 1231 /* check for max flows */ 1232 if (fid >= flow_db->flow_tbl.num_flows || !fid) { 1233 BNXT_TF_DBG(ERR, "Invalid flow index\n"); 1234 return -EINVAL; 1235 } 1236 1237 /* No support for parent child db then just exit */ 1238 if (!flow_db->parent_child_db.entries_count) { 1239 BNXT_TF_DBG(ERR, "parent child db not supported\n"); 1240 return -EINVAL; 1241 } 1242 1243 p_pdb = &flow_db->parent_child_db; 1244 for (idx = 0; idx <= p_pdb->entries_count; idx++) { 1245 if (p_pdb->parent_flow_tbl[idx].parent_fid == fid) { 1246 /* free the contents */ 1247 p_pdb->parent_flow_tbl[idx].parent_fid = 0; 1248 memset(p_pdb->parent_flow_tbl[idx].child_fid_bitset, 1249 0, p_pdb->child_bitset_size); 1250 return 0; 1251 } 1252 } 1253 BNXT_TF_DBG(ERR, "parent entry not found = %x\n", fid); 1254 return -EINVAL; 1255 } 1256 1257 /* 1258 * Set or reset the child flow in the parent-child database 1259 * 1260 * ulp_ctxt [in] Ptr to ulp_context 1261 * parent_fid [in] The flow id of the parent flow entry 1262 * child_fid [in] The flow id of the child flow entry 1263 * set_flag [in] Use 1 for setting child, 0 to reset 1264 * 1265 * returns zero on success and negative on failure. 1266 */ 1267 int32_t 1268 ulp_flow_db_parent_child_flow_set(struct bnxt_ulp_context *ulp_ctxt, 1269 uint32_t parent_fid, 1270 uint32_t child_fid, 1271 uint32_t set_flag) 1272 { 1273 struct bnxt_ulp_flow_db *flow_db; 1274 struct ulp_fdb_parent_child_db *p_pdb; 1275 uint32_t idx, a_idx; 1276 uint64_t *t; 1277 1278 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 1279 if (!flow_db) { 1280 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 1281 return -EINVAL; 1282 } 1283 1284 /* check for fid validity */ 1285 if (parent_fid >= flow_db->flow_tbl.num_flows || !parent_fid) { 1286 BNXT_TF_DBG(ERR, "Invalid parent flow index %x\n", parent_fid); 1287 return -EINVAL; 1288 } 1289 1290 /* check for fid validity */ 1291 if (child_fid >= flow_db->flow_tbl.num_flows || !child_fid) { 1292 BNXT_TF_DBG(ERR, "Invalid child flow index %x\n", child_fid); 1293 return -EINVAL; 1294 } 1295 1296 /* No support for parent child db then just exit */ 1297 if (!flow_db->parent_child_db.entries_count) { 1298 BNXT_TF_DBG(ERR, "parent child db not supported\n"); 1299 return -EINVAL; 1300 } 1301 1302 p_pdb = &flow_db->parent_child_db; 1303 a_idx = child_fid / ULP_INDEX_BITMAP_SIZE; 1304 for (idx = 0; idx <= p_pdb->entries_count; idx++) { 1305 if (p_pdb->parent_flow_tbl[idx].parent_fid == parent_fid) { 1306 t = p_pdb->parent_flow_tbl[idx].child_fid_bitset; 1307 if (set_flag) 1308 ULP_INDEX_BITMAP_SET(t[a_idx], child_fid); 1309 else 1310 ULP_INDEX_BITMAP_RESET(t[a_idx], child_fid); 1311 return 0; 1312 } 1313 } 1314 BNXT_TF_DBG(ERR, "Unable to set the parent-child flow %x:%x\n", 1315 parent_fid, child_fid); 1316 return -1; 1317 } 1318 1319 /* 1320 * Get the parent index from the parent-child database 1321 * 1322 * ulp_ctxt [in] Ptr to ulp_context 1323 * parent_fid [in] The flow id of the parent flow entry 1324 * parent_idx [out] The parent index of parent flow entry 1325 * 1326 * returns zero on success and negative on failure. 1327 */ 1328 int32_t 1329 ulp_flow_db_parent_flow_idx_get(struct bnxt_ulp_context *ulp_ctxt, 1330 uint32_t parent_fid, 1331 uint32_t *parent_idx) 1332 { 1333 struct bnxt_ulp_flow_db *flow_db; 1334 struct ulp_fdb_parent_child_db *p_pdb; 1335 uint32_t idx; 1336 1337 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 1338 if (!flow_db) { 1339 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 1340 return -EINVAL; 1341 } 1342 1343 /* check for fid validity */ 1344 if (parent_fid >= flow_db->flow_tbl.num_flows || !parent_fid) { 1345 BNXT_TF_DBG(ERR, "Invalid parent flow index %x\n", parent_fid); 1346 return -EINVAL; 1347 } 1348 1349 /* No support for parent child db then just exit */ 1350 if (!flow_db->parent_child_db.entries_count) { 1351 BNXT_TF_DBG(ERR, "parent child db not supported\n"); 1352 return -EINVAL; 1353 } 1354 1355 p_pdb = &flow_db->parent_child_db; 1356 for (idx = 0; idx <= p_pdb->entries_count; idx++) { 1357 if (p_pdb->parent_flow_tbl[idx].parent_fid == parent_fid) { 1358 *parent_idx = idx; 1359 return 0; 1360 } 1361 } 1362 BNXT_TF_DBG(ERR, "Unable to get the parent flow %x\n", parent_fid); 1363 return -1; 1364 } 1365 1366 /* 1367 * Get the next child flow in the parent-child database 1368 * 1369 * ulp_ctxt [in] Ptr to ulp_context 1370 * parent_fid [in] The flow id of the parent flow entry 1371 * child_fid [in/out] The flow id of the child flow entry 1372 * 1373 * returns zero on success and negative on failure. 1374 * Pass child_fid as zero for first entry. 1375 */ 1376 int32_t 1377 ulp_flow_db_parent_child_flow_next_entry_get(struct bnxt_ulp_flow_db *flow_db, 1378 uint32_t parent_idx, 1379 uint32_t *child_fid) 1380 { 1381 struct ulp_fdb_parent_child_db *p_pdb; 1382 uint32_t idx, s_idx, mod_fid; 1383 uint32_t next_fid = *child_fid; 1384 uint64_t *child_bitset; 1385 uint64_t bs; 1386 1387 /* check for fid validity */ 1388 p_pdb = &flow_db->parent_child_db; 1389 if (parent_idx >= p_pdb->entries_count || 1390 !p_pdb->parent_flow_tbl[parent_idx].parent_fid) { 1391 BNXT_TF_DBG(ERR, "Invalid parent flow index %x\n", parent_idx); 1392 return -EINVAL; 1393 } 1394 1395 child_bitset = p_pdb->parent_flow_tbl[parent_idx].child_fid_bitset; 1396 do { 1397 /* increment the flow id to find the next valid flow id */ 1398 next_fid++; 1399 if (next_fid >= flow_db->flow_tbl.num_flows) 1400 return -ENOENT; 1401 idx = next_fid / ULP_INDEX_BITMAP_SIZE; 1402 mod_fid = next_fid % ULP_INDEX_BITMAP_SIZE; 1403 s_idx = idx; 1404 while (!(bs = child_bitset[idx])) { 1405 idx++; 1406 if ((idx * ULP_INDEX_BITMAP_SIZE) >= 1407 flow_db->flow_tbl.num_flows) 1408 return -ENOENT; 1409 } 1410 /* 1411 * remove the previous bits in the bitset bs to find the 1412 * next non zero bit in the bitset. This needs to be done 1413 * only if the idx is same as he one you started. 1414 */ 1415 if (s_idx == idx) 1416 bs &= (-1UL >> mod_fid); 1417 next_fid = (idx * ULP_INDEX_BITMAP_SIZE) + __builtin_clzl(bs); 1418 if (*child_fid >= next_fid) { 1419 BNXT_TF_DBG(ERR, "Parent Child Database is corrupt\n"); 1420 return -ENOENT; 1421 } 1422 idx = next_fid / ULP_INDEX_BITMAP_SIZE; 1423 } while (!ULP_INDEX_BITMAP_GET(child_bitset[idx], next_fid)); 1424 *child_fid = next_fid; 1425 return 0; 1426 } 1427 1428 /* 1429 * Orphan the child flow entry 1430 * This is called only for child flows that have 1431 * BNXT_ULP_RESOURCE_FUNC_CHILD_FLOW resource 1432 * 1433 * ulp_ctxt [in] Ptr to ulp_context 1434 * flow_type [in] Specify it is regular or default flow 1435 * fid [in] The index to the flow entry 1436 * 1437 * Returns 0 on success and negative on failure. 1438 */ 1439 int32_t 1440 ulp_flow_db_child_flow_reset(struct bnxt_ulp_context *ulp_ctxt, 1441 enum bnxt_ulp_fdb_type flow_type, 1442 uint32_t fid) 1443 { 1444 struct bnxt_ulp_flow_db *flow_db; 1445 struct bnxt_ulp_flow_tbl *flow_tbl; 1446 struct ulp_fdb_resource_info *fid_res; 1447 uint32_t res_id = 0; 1448 1449 flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt); 1450 if (!flow_db) { 1451 BNXT_TF_DBG(ERR, "Invalid Arguments\n"); 1452 return -EINVAL; 1453 } 1454 1455 if (flow_type > BNXT_ULP_FDB_TYPE_DEFAULT) { 1456 BNXT_TF_DBG(ERR, "Invalid flow type\n"); 1457 return -EINVAL; 1458 } 1459 1460 flow_tbl = &flow_db->flow_tbl; 1461 /* check for max flows */ 1462 if (fid >= flow_tbl->num_flows || !fid) { 1463 BNXT_TF_DBG(ERR, "Invalid flow index %x\n", fid); 1464 return -EINVAL; 1465 } 1466 1467 /* check if the flow is active or not */ 1468 if (!ulp_flow_db_active_flows_bit_is_set(flow_db, flow_type, fid)) { 1469 BNXT_TF_DBG(ERR, "flow does not exist\n"); 1470 return -EINVAL; 1471 } 1472 1473 /* Iterate the resource to get the resource handle */ 1474 res_id = fid; 1475 while (res_id) { 1476 fid_res = &flow_tbl->flow_resources[res_id]; 1477 if (ulp_flow_db_resource_func_get(fid_res) == 1478 BNXT_ULP_RESOURCE_FUNC_CHILD_FLOW) { 1479 /* invalidate the resource details */ 1480 fid_res->resource_hndl = 0; 1481 return 0; 1482 } 1483 res_id = 0; 1484 ULP_FLOW_DB_RES_NXT_SET(res_id, fid_res->nxt_resource_idx); 1485 } 1486 /* failed */ 1487 return -1; 1488 } 1489 1490 /* 1491 * Create parent flow in the parent flow tbl 1492 * 1493 * parms [in] Ptr to mapper params 1494 * 1495 * Returns 0 on success and negative on failure. 1496 */ 1497 int32_t 1498 ulp_flow_db_parent_flow_create(struct bnxt_ulp_mapper_parms *parms) 1499 { 1500 struct ulp_flow_db_res_params fid_parms; 1501 int32_t fid_idx; 1502 1503 /* create the child flow entry in parent flow table */ 1504 fid_idx = ulp_flow_db_parent_flow_alloc(parms->ulp_ctx, parms->fid); 1505 if (fid_idx < 0) { 1506 BNXT_TF_DBG(ERR, "Error in creating parent flow fid %x\n", 1507 parms->fid); 1508 return -1; 1509 } 1510 1511 /* Add the parent details in the resource list of the flow */ 1512 memset(&fid_parms, 0, sizeof(fid_parms)); 1513 fid_parms.resource_func = BNXT_ULP_RESOURCE_FUNC_PARENT_FLOW; 1514 fid_parms.resource_hndl = fid_idx; 1515 fid_parms.critical_resource = BNXT_ULP_CRITICAL_RESOURCE_NO; 1516 if (ulp_flow_db_resource_add(parms->ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR, 1517 parms->fid, &fid_parms)) { 1518 BNXT_TF_DBG(ERR, "Error in adding flow res for fid %x\n", 1519 parms->fid); 1520 return -1; 1521 } 1522 return 0; 1523 } 1524 1525 /* 1526 * Create child flow in the parent flow tbl 1527 * 1528 * parms [in] Ptr to mapper params 1529 * 1530 * Returns 0 on success and negative on failure. 1531 */ 1532 int32_t 1533 ulp_flow_db_child_flow_create(struct bnxt_ulp_mapper_parms *parms) 1534 { 1535 struct ulp_flow_db_res_params fid_parms; 1536 int32_t rc; 1537 1538 /* create the parent flow entry in parent flow table */ 1539 rc = ulp_flow_db_parent_child_flow_set(parms->ulp_ctx, 1540 parms->parent_fid, 1541 parms->fid, 1); 1542 if (rc) { 1543 BNXT_TF_DBG(ERR, "Error in setting child fid %x\n", parms->fid); 1544 return -1; 1545 } 1546 1547 /* Add the parent details in the resource list of the flow */ 1548 memset(&fid_parms, 0, sizeof(fid_parms)); 1549 fid_parms.resource_func = BNXT_ULP_RESOURCE_FUNC_CHILD_FLOW; 1550 fid_parms.resource_hndl = parms->parent_fid; 1551 fid_parms.critical_resource = BNXT_ULP_CRITICAL_RESOURCE_NO; 1552 if (ulp_flow_db_resource_add(parms->ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR, 1553 parms->fid, &fid_parms)) { 1554 BNXT_TF_DBG(ERR, "Error in adding flow res for fid %x\n", 1555 parms->fid); 1556 return -1; 1557 } 1558 return 0; 1559 } 1560