1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2019-2020 Broadcom 3 * All rights reserved. 4 */ 5 6 #include <string.h> 7 #include <rte_common.h> 8 9 #include "tf_tcam.h" 10 #include "tf_common.h" 11 #include "tf_util.h" 12 #include "tf_rm.h" 13 #include "tf_device.h" 14 #include "tfp.h" 15 #include "tf_session.h" 16 #include "tf_msg.h" 17 #include "tf_shadow_tcam.h" 18 19 struct tf; 20 21 /** 22 * TCAM DBs. 23 */ 24 static void *tcam_db[TF_DIR_MAX]; 25 26 /** 27 * TCAM Shadow DBs 28 */ 29 static void *shadow_tcam_db[TF_DIR_MAX]; 30 31 /** 32 * Init flag, set on bind and cleared on unbind 33 */ 34 static uint8_t init; 35 36 /** 37 * Shadow init flag, set on bind and cleared on unbind 38 */ 39 static uint8_t shadow_init; 40 41 int 42 tf_tcam_bind(struct tf *tfp, 43 struct tf_tcam_cfg_parms *parms) 44 { 45 int rc; 46 int i, d; 47 struct tf_rm_alloc_info info; 48 struct tf_rm_free_db_parms fparms; 49 struct tf_rm_create_db_parms db_cfg; 50 struct tf_tcam_resources *tcam_cnt; 51 struct tf_shadow_tcam_free_db_parms fshadow; 52 struct tf_rm_get_alloc_info_parms ainfo; 53 struct tf_shadow_tcam_cfg_parms shadow_cfg; 54 struct tf_shadow_tcam_create_db_parms shadow_cdb; 55 56 TF_CHECK_PARMS2(tfp, parms); 57 58 if (init) { 59 TFP_DRV_LOG(ERR, 60 "TCAM DB already initialized\n"); 61 return -EINVAL; 62 } 63 64 tcam_cnt = parms->resources->tcam_cnt; 65 if ((tcam_cnt[TF_DIR_RX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] % 2) || 66 (tcam_cnt[TF_DIR_TX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] % 2)) { 67 TFP_DRV_LOG(ERR, 68 "Number of WC TCAM entries cannot be odd num\n"); 69 return -EINVAL; 70 } 71 72 memset(&db_cfg, 0, sizeof(db_cfg)); 73 74 db_cfg.type = TF_DEVICE_MODULE_TYPE_TCAM; 75 db_cfg.num_elements = parms->num_elements; 76 db_cfg.cfg = parms->cfg; 77 78 for (d = 0; d < TF_DIR_MAX; d++) { 79 db_cfg.dir = d; 80 db_cfg.alloc_cnt = parms->resources->tcam_cnt[d].cnt; 81 db_cfg.rm_db = &tcam_db[d]; 82 rc = tf_rm_create_db(tfp, &db_cfg); 83 if (rc) { 84 TFP_DRV_LOG(ERR, 85 "%s: TCAM DB creation failed\n", 86 tf_dir_2_str(d)); 87 return rc; 88 } 89 } 90 91 /* Initialize the TCAM manager. */ 92 if (parms->shadow_copy) { 93 for (d = 0; d < TF_DIR_MAX; d++) { 94 memset(&shadow_cfg, 0, sizeof(shadow_cfg)); 95 memset(&shadow_cdb, 0, sizeof(shadow_cdb)); 96 /* Get the base addresses of the tcams for tcam mgr */ 97 for (i = 0; i < TF_TCAM_TBL_TYPE_MAX; i++) { 98 memset(&info, 0, sizeof(info)); 99 100 if (!parms->resources->tcam_cnt[d].cnt[i]) 101 continue; 102 ainfo.rm_db = tcam_db[d]; 103 ainfo.db_index = i; 104 ainfo.info = &info; 105 rc = tf_rm_get_info(&ainfo); 106 if (rc) 107 goto error; 108 109 shadow_cfg.base_addr[i] = info.entry.start; 110 } 111 112 /* Create the shadow db */ 113 shadow_cfg.alloc_cnt = 114 parms->resources->tcam_cnt[d].cnt; 115 shadow_cfg.num_entries = parms->num_elements; 116 117 shadow_cdb.shadow_db = &shadow_tcam_db[d]; 118 shadow_cdb.cfg = &shadow_cfg; 119 rc = tf_shadow_tcam_create_db(&shadow_cdb); 120 if (rc) { 121 TFP_DRV_LOG(ERR, 122 "TCAM MGR DB creation failed " 123 "rc=%d\n", rc); 124 goto error; 125 } 126 } 127 shadow_init = 1; 128 } 129 130 init = 1; 131 132 TFP_DRV_LOG(INFO, 133 "TCAM - initialized\n"); 134 135 return 0; 136 error: 137 for (i = 0; i < TF_DIR_MAX; i++) { 138 memset(&fparms, 0, sizeof(fparms)); 139 fparms.dir = i; 140 fparms.rm_db = tcam_db[i]; 141 /* Ignoring return here since we are in the error case */ 142 (void)tf_rm_free_db(tfp, &fparms); 143 144 if (parms->shadow_copy) { 145 fshadow.shadow_db = shadow_tcam_db[i]; 146 tf_shadow_tcam_free_db(&fshadow); 147 shadow_tcam_db[i] = NULL; 148 } 149 150 tcam_db[i] = NULL; 151 } 152 153 shadow_init = 0; 154 init = 0; 155 156 return rc; 157 } 158 159 int 160 tf_tcam_unbind(struct tf *tfp) 161 { 162 int rc; 163 int i; 164 struct tf_rm_free_db_parms fparms; 165 struct tf_shadow_tcam_free_db_parms fshadow; 166 167 TF_CHECK_PARMS1(tfp); 168 169 /* Bail if nothing has been initialized */ 170 if (!init) { 171 TFP_DRV_LOG(INFO, 172 "No TCAM DBs created\n"); 173 return 0; 174 } 175 176 for (i = 0; i < TF_DIR_MAX; i++) { 177 memset(&fparms, 0, sizeof(fparms)); 178 fparms.dir = i; 179 fparms.rm_db = tcam_db[i]; 180 rc = tf_rm_free_db(tfp, &fparms); 181 if (rc) 182 return rc; 183 184 tcam_db[i] = NULL; 185 186 if (shadow_init) { 187 memset(&fshadow, 0, sizeof(fshadow)); 188 189 fshadow.shadow_db = shadow_tcam_db[i]; 190 tf_shadow_tcam_free_db(&fshadow); 191 shadow_tcam_db[i] = NULL; 192 } 193 } 194 195 shadow_init = 0; 196 init = 0; 197 198 return 0; 199 } 200 201 int 202 tf_tcam_alloc(struct tf *tfp, 203 struct tf_tcam_alloc_parms *parms) 204 { 205 int rc; 206 struct tf_session *tfs; 207 struct tf_dev_info *dev; 208 struct tf_rm_allocate_parms aparms; 209 uint16_t num_slice_per_row = 1; 210 211 TF_CHECK_PARMS2(tfp, parms); 212 213 if (!init) { 214 TFP_DRV_LOG(ERR, 215 "%s: No TCAM DBs created\n", 216 tf_dir_2_str(parms->dir)); 217 return -EINVAL; 218 } 219 220 /* Retrieve the session information */ 221 rc = tf_session_get_session_internal(tfp, &tfs); 222 if (rc) 223 return rc; 224 225 /* Retrieve the device information */ 226 rc = tf_session_get_device(tfs, &dev); 227 if (rc) 228 return rc; 229 230 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 231 rc = -EOPNOTSUPP; 232 TFP_DRV_LOG(ERR, 233 "%s: Operation not supported, rc:%s\n", 234 tf_dir_2_str(parms->dir), 235 strerror(-rc)); 236 return rc; 237 } 238 239 /* Need to retrieve row size etc */ 240 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, 241 parms->type, 242 parms->key_size, 243 &num_slice_per_row); 244 if (rc) 245 return rc; 246 247 /* Allocate requested element */ 248 memset(&aparms, 0, sizeof(aparms)); 249 250 aparms.rm_db = tcam_db[parms->dir]; 251 aparms.db_index = parms->type; 252 aparms.priority = parms->priority; 253 aparms.index = (uint32_t *)&parms->idx; 254 rc = tf_rm_allocate(&aparms); 255 if (rc) { 256 TFP_DRV_LOG(ERR, 257 "%s: Failed tcam, type:%d\n", 258 tf_dir_2_str(parms->dir), 259 parms->type); 260 return rc; 261 } 262 263 if (parms->type == TF_TCAM_TBL_TYPE_WC_TCAM && 264 (parms->idx % 2) != 0) { 265 rc = tf_rm_allocate(&aparms); 266 if (rc) { 267 TFP_DRV_LOG(ERR, 268 "%s: Failed tcam, type:%d\n", 269 tf_dir_2_str(parms->dir), 270 parms->type); 271 return rc; 272 } 273 } 274 275 parms->idx *= num_slice_per_row; 276 277 return 0; 278 } 279 280 int 281 tf_tcam_free(struct tf *tfp, 282 struct tf_tcam_free_parms *parms) 283 { 284 int rc; 285 struct tf_session *tfs; 286 struct tf_dev_info *dev; 287 struct tf_rm_is_allocated_parms aparms; 288 struct tf_rm_free_parms fparms; 289 struct tf_rm_get_hcapi_parms hparms; 290 uint16_t num_slice_per_row = 1; 291 int allocated = 0; 292 struct tf_shadow_tcam_remove_parms shparms; 293 294 TF_CHECK_PARMS2(tfp, parms); 295 296 if (!init) { 297 TFP_DRV_LOG(ERR, 298 "%s: No TCAM DBs created\n", 299 tf_dir_2_str(parms->dir)); 300 return -EINVAL; 301 } 302 303 /* Retrieve the session information */ 304 rc = tf_session_get_session_internal(tfp, &tfs); 305 if (rc) 306 return rc; 307 308 /* Retrieve the device information */ 309 rc = tf_session_get_device(tfs, &dev); 310 if (rc) 311 return rc; 312 313 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 314 rc = -EOPNOTSUPP; 315 TFP_DRV_LOG(ERR, 316 "%s: Operation not supported, rc:%s\n", 317 tf_dir_2_str(parms->dir), 318 strerror(-rc)); 319 return rc; 320 } 321 322 /* Need to retrieve row size etc */ 323 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, 324 parms->type, 325 0, 326 &num_slice_per_row); 327 if (rc) 328 return rc; 329 330 /* Check if element is in use */ 331 memset(&aparms, 0, sizeof(aparms)); 332 333 aparms.rm_db = tcam_db[parms->dir]; 334 aparms.db_index = parms->type; 335 aparms.index = parms->idx / num_slice_per_row; 336 aparms.allocated = &allocated; 337 rc = tf_rm_is_allocated(&aparms); 338 if (rc) 339 return rc; 340 341 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) { 342 TFP_DRV_LOG(ERR, 343 "%s: Entry already free, type:%d, index:%d\n", 344 tf_dir_2_str(parms->dir), 345 parms->type, 346 parms->idx); 347 return -EINVAL; 348 } 349 350 /* 351 * The Shadow mgmt, if enabled, determines if the entry needs 352 * to be deleted. 353 */ 354 if (shadow_init) { 355 shparms.shadow_db = shadow_tcam_db[parms->dir]; 356 shparms.fparms = parms; 357 rc = tf_shadow_tcam_remove(&shparms); 358 if (rc) { 359 /* 360 * Should not get here, log it and let the entry be 361 * deleted. 362 */ 363 TFP_DRV_LOG(ERR, "%s: Shadow free fail, " 364 "type:%d index:%d deleting the entry.\n", 365 tf_dir_2_str(parms->dir), 366 parms->type, 367 parms->idx); 368 } else { 369 /* 370 * If the entry still has references, just return the 371 * ref count to the caller. No need to remove entry 372 * from rm or hw 373 */ 374 if (parms->ref_cnt >= 1) 375 return rc; 376 } 377 } 378 379 /* Free requested element */ 380 memset(&fparms, 0, sizeof(fparms)); 381 fparms.rm_db = tcam_db[parms->dir]; 382 fparms.db_index = parms->type; 383 fparms.index = parms->idx / num_slice_per_row; 384 rc = tf_rm_free(&fparms); 385 if (rc) { 386 TFP_DRV_LOG(ERR, 387 "%s: Free failed, type:%d, index:%d\n", 388 tf_dir_2_str(parms->dir), 389 parms->type, 390 parms->idx); 391 return rc; 392 } 393 394 if (parms->type == TF_TCAM_TBL_TYPE_WC_TCAM) { 395 int i; 396 397 for (i = -1; i < 3; i += 3) { 398 aparms.index += i; 399 rc = tf_rm_is_allocated(&aparms); 400 if (rc) 401 return rc; 402 403 if (allocated == TF_RM_ALLOCATED_ENTRY_IN_USE) { 404 /* Free requested element */ 405 fparms.index = aparms.index; 406 rc = tf_rm_free(&fparms); 407 if (rc) { 408 TFP_DRV_LOG(ERR, 409 "%s: Free failed, type:%d, " 410 "index:%d\n", 411 tf_dir_2_str(parms->dir), 412 parms->type, 413 fparms.index); 414 return rc; 415 } 416 } 417 } 418 } 419 420 /* Convert TF type to HCAPI RM type */ 421 memset(&hparms, 0, sizeof(hparms)); 422 423 hparms.rm_db = tcam_db[parms->dir]; 424 hparms.db_index = parms->type; 425 hparms.hcapi_type = &parms->hcapi_type; 426 427 rc = tf_rm_get_hcapi_type(&hparms); 428 if (rc) 429 return rc; 430 431 rc = tf_msg_tcam_entry_free(tfp, parms); 432 if (rc) { 433 /* Log error */ 434 TFP_DRV_LOG(ERR, 435 "%s: %s: Entry %d free failed, rc:%s\n", 436 tf_dir_2_str(parms->dir), 437 tf_tcam_tbl_2_str(parms->type), 438 parms->idx, 439 strerror(-rc)); 440 return rc; 441 } 442 443 return 0; 444 } 445 446 int 447 tf_tcam_alloc_search(struct tf *tfp, 448 struct tf_tcam_alloc_search_parms *parms) 449 { 450 struct tf_shadow_tcam_search_parms sparms; 451 struct tf_shadow_tcam_bind_index_parms bparms; 452 struct tf_tcam_alloc_parms aparms; 453 struct tf_tcam_free_parms fparms; 454 uint16_t num_slice_per_row = 1; 455 struct tf_session *tfs; 456 struct tf_dev_info *dev; 457 int rc; 458 459 TF_CHECK_PARMS2(tfp, parms); 460 461 if (!init) { 462 TFP_DRV_LOG(ERR, 463 "%s: No TCAM DBs created\n", 464 tf_dir_2_str(parms->dir)); 465 return -EINVAL; 466 } 467 468 if (!shadow_init || !shadow_tcam_db[parms->dir]) { 469 TFP_DRV_LOG(ERR, "%s: TCAM Shadow not initialized for %s\n", 470 tf_dir_2_str(parms->dir), 471 tf_tcam_tbl_2_str(parms->type)); 472 return -EINVAL; 473 } 474 475 /* Retrieve the session information */ 476 rc = tf_session_get_session_internal(tfp, &tfs); 477 if (rc) 478 return rc; 479 480 /* Retrieve the device information */ 481 rc = tf_session_get_device(tfs, &dev); 482 if (rc) 483 return rc; 484 485 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 486 rc = -EOPNOTSUPP; 487 TFP_DRV_LOG(ERR, 488 "%s: Operation not supported, rc:%s\n", 489 tf_dir_2_str(parms->dir), 490 strerror(-rc)); 491 return rc; 492 } 493 494 /* Need to retrieve row size etc */ 495 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, 496 parms->type, 497 parms->key_size, 498 &num_slice_per_row); 499 if (rc) 500 return rc; 501 502 /* 503 * Prep the shadow search, reusing the parms from original search 504 * instead of copying them. Shadow will update output in there. 505 */ 506 memset(&sparms, 0, sizeof(sparms)); 507 sparms.sparms = parms; 508 sparms.shadow_db = shadow_tcam_db[parms->dir]; 509 510 rc = tf_shadow_tcam_search(&sparms); 511 if (rc) 512 return rc; 513 514 /* 515 * The app didn't request us to alloc the entry, so return now. 516 * The hit should have been updated in the original search parm. 517 */ 518 if (!parms->alloc || parms->search_status != MISS) 519 return rc; 520 521 /* Caller desires an allocate on miss */ 522 if (dev->ops->tf_dev_alloc_tcam == NULL) { 523 rc = -EOPNOTSUPP; 524 TFP_DRV_LOG(ERR, 525 "%s: Operation not supported, rc:%s\n", 526 tf_dir_2_str(parms->dir), 527 strerror(-rc)); 528 return rc; 529 } 530 memset(&aparms, 0, sizeof(aparms)); 531 aparms.dir = parms->dir; 532 aparms.type = parms->type; 533 aparms.key_size = parms->key_size; 534 aparms.priority = parms->priority; 535 rc = dev->ops->tf_dev_alloc_tcam(tfp, &aparms); 536 if (rc) 537 return rc; 538 539 /* Successful allocation, attempt to add it to the shadow */ 540 memset(&bparms, 0, sizeof(bparms)); 541 bparms.dir = parms->dir; 542 bparms.shadow_db = shadow_tcam_db[parms->dir]; 543 bparms.type = parms->type; 544 bparms.key = parms->key; 545 bparms.mask = parms->mask; 546 bparms.key_size = parms->key_size; 547 bparms.idx = aparms.idx; 548 bparms.hb_handle = sparms.hb_handle; 549 rc = tf_shadow_tcam_bind_index(&bparms); 550 if (rc) { 551 /* Error binding entry, need to free the allocated idx */ 552 if (dev->ops->tf_dev_free_tcam == NULL) { 553 rc = -EOPNOTSUPP; 554 TFP_DRV_LOG(ERR, 555 "%s: Operation not supported, rc:%s\n", 556 tf_dir_2_str(parms->dir), 557 strerror(-rc)); 558 return rc; 559 } 560 561 fparms.dir = parms->dir; 562 fparms.type = parms->type; 563 fparms.idx = aparms.idx; 564 rc = dev->ops->tf_dev_free_tcam(tfp, &fparms); 565 if (rc) 566 return rc; 567 } 568 569 /* Add the allocated index to output and done */ 570 parms->idx = aparms.idx; 571 572 return 0; 573 } 574 575 int 576 tf_tcam_set(struct tf *tfp __rte_unused, 577 struct tf_tcam_set_parms *parms __rte_unused) 578 { 579 int rc; 580 struct tf_session *tfs; 581 struct tf_dev_info *dev; 582 struct tf_rm_is_allocated_parms aparms; 583 struct tf_rm_get_hcapi_parms hparms; 584 struct tf_shadow_tcam_insert_parms iparms; 585 uint16_t num_slice_per_row = 1; 586 int allocated = 0; 587 588 TF_CHECK_PARMS2(tfp, parms); 589 590 if (!init) { 591 TFP_DRV_LOG(ERR, 592 "%s: No TCAM DBs created\n", 593 tf_dir_2_str(parms->dir)); 594 return -EINVAL; 595 } 596 597 /* Retrieve the session information */ 598 rc = tf_session_get_session_internal(tfp, &tfs); 599 if (rc) 600 return rc; 601 602 /* Retrieve the device information */ 603 rc = tf_session_get_device(tfs, &dev); 604 if (rc) 605 return rc; 606 607 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 608 rc = -EOPNOTSUPP; 609 TFP_DRV_LOG(ERR, 610 "%s: Operation not supported, rc:%s\n", 611 tf_dir_2_str(parms->dir), 612 strerror(-rc)); 613 return rc; 614 } 615 616 /* Need to retrieve row size etc */ 617 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, 618 parms->type, 619 parms->key_size, 620 &num_slice_per_row); 621 if (rc) 622 return rc; 623 624 /* Check if element is in use */ 625 memset(&aparms, 0, sizeof(aparms)); 626 627 aparms.rm_db = tcam_db[parms->dir]; 628 aparms.db_index = parms->type; 629 aparms.index = parms->idx / num_slice_per_row; 630 aparms.allocated = &allocated; 631 rc = tf_rm_is_allocated(&aparms); 632 if (rc) 633 return rc; 634 635 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) { 636 TFP_DRV_LOG(ERR, 637 "%s: Entry is not allocated, type:%d, index:%d\n", 638 tf_dir_2_str(parms->dir), 639 parms->type, 640 parms->idx); 641 return -EINVAL; 642 } 643 644 /* Convert TF type to HCAPI RM type */ 645 memset(&hparms, 0, sizeof(hparms)); 646 647 hparms.rm_db = tcam_db[parms->dir]; 648 hparms.db_index = parms->type; 649 hparms.hcapi_type = &parms->hcapi_type; 650 651 rc = tf_rm_get_hcapi_type(&hparms); 652 if (rc) 653 return rc; 654 655 rc = tf_msg_tcam_entry_set(tfp, parms); 656 if (rc) { 657 /* Log error */ 658 TFP_DRV_LOG(ERR, 659 "%s: %s: Entry %d set failed, rc:%s", 660 tf_dir_2_str(parms->dir), 661 tf_tcam_tbl_2_str(parms->type), 662 parms->idx, 663 strerror(-rc)); 664 return rc; 665 } 666 667 /* Successfully added to hw, now for shadow if enabled. */ 668 if (!shadow_init || !shadow_tcam_db[parms->dir]) 669 return 0; 670 671 iparms.shadow_db = shadow_tcam_db[parms->dir]; 672 iparms.sparms = parms; 673 rc = tf_shadow_tcam_insert(&iparms); 674 if (rc) { 675 TFP_DRV_LOG(ERR, 676 "%s: %s: Entry %d set failed, rc:%s", 677 tf_dir_2_str(parms->dir), 678 tf_tcam_tbl_2_str(parms->type), 679 parms->idx, 680 strerror(-rc)); 681 return rc; 682 } 683 684 return 0; 685 } 686 687 int 688 tf_tcam_get(struct tf *tfp __rte_unused, 689 struct tf_tcam_get_parms *parms __rte_unused) 690 { 691 return 0; 692 } 693