1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2019-2023 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_tcam_mgr_msg.h" 18 19 struct tf; 20 21 int 22 tf_tcam_bind(struct tf *tfp, 23 struct tf_tcam_cfg_parms *parms) 24 { 25 int rc; 26 int db_rc[TF_DIR_MAX] = { 0 }; 27 int d, t; 28 struct tf_rm_alloc_info info; 29 struct tf_rm_free_db_parms fparms; 30 struct tf_rm_create_db_parms db_cfg; 31 struct tf_tcam_resources local_tcam_cnt[TF_DIR_MAX]; 32 struct tf_tcam_resources *tcam_cnt; 33 struct tf_rm_get_alloc_info_parms ainfo; 34 uint16_t num_slices = 1; 35 struct tf_session *tfs; 36 struct tf_dev_info *dev; 37 struct tcam_rm_db *tcam_db; 38 struct tfp_calloc_parms cparms; 39 struct tf_resource_info resv_res[TF_DIR_MAX][TF_TCAM_TBL_TYPE_MAX]; 40 uint32_t rx_supported; 41 uint32_t tx_supported; 42 bool no_req = true; 43 44 TF_CHECK_PARMS2(tfp, parms); 45 46 /* Retrieve the session information */ 47 rc = tf_session_get_session_internal(tfp, &tfs); 48 if (rc) 49 return rc; 50 51 /* Retrieve the device information */ 52 rc = tf_session_get_device(tfs, &dev); 53 if (rc) 54 return rc; 55 56 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 57 rc = -EOPNOTSUPP; 58 TFP_DRV_LOG(ERR, 59 "Operation not supported, rc:%s\n", 60 strerror(-rc)); 61 return rc; 62 } 63 64 tcam_cnt = parms->resources->tcam_cnt; 65 66 for (d = 0; d < TF_DIR_MAX; d++) { 67 for (t = 0; t < TF_TCAM_TBL_TYPE_MAX; t++) { 68 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, t, 0, 69 &num_slices); 70 if (rc) 71 return rc; 72 73 if (num_slices == 1) 74 continue; 75 76 if (tcam_cnt[d].cnt[t] % num_slices) { 77 TFP_DRV_LOG(ERR, 78 "%s: Requested num of %s entries " 79 "has to be multiple of %d\n", 80 tf_dir_2_str(d), 81 tf_tcam_tbl_2_str(t), 82 num_slices); 83 return -EINVAL; 84 } 85 } 86 } 87 88 memset(&db_cfg, 0, sizeof(db_cfg)); 89 cparms.nitems = 1; 90 cparms.size = sizeof(struct tcam_rm_db); 91 cparms.alignment = 0; 92 if (tfp_calloc(&cparms) != 0) { 93 TFP_DRV_LOG(ERR, "tcam_rm_db alloc error %s\n", 94 strerror(ENOMEM)); 95 return -ENOMEM; 96 } 97 98 tcam_db = cparms.mem_va; 99 for (d = 0; d < TF_DIR_MAX; d++) 100 tcam_db->tcam_db[d] = NULL; 101 tf_session_set_db(tfp, TF_MODULE_TYPE_TCAM, tcam_db); 102 103 db_cfg.module = TF_MODULE_TYPE_TCAM; 104 db_cfg.num_elements = parms->num_elements; 105 db_cfg.cfg = parms->cfg; 106 107 for (d = 0; d < TF_DIR_MAX; d++) { 108 db_cfg.dir = d; 109 db_cfg.alloc_cnt = tcam_cnt[d].cnt; 110 db_cfg.rm_db = (void *)&tcam_db->tcam_db[d]; 111 if (tf_session_is_shared_session(tfs) && 112 (!tf_session_is_shared_session_creator(tfs))) 113 db_rc[d] = tf_rm_create_db_no_reservation(tfp, &db_cfg); 114 else 115 db_rc[d] = tf_rm_create_db(tfp, &db_cfg); 116 } 117 /* No db created */ 118 if (db_rc[TF_DIR_RX] && db_rc[TF_DIR_TX]) { 119 TFP_DRV_LOG(ERR, "No TCAM DB created\n"); 120 return db_rc[TF_DIR_RX]; 121 } 122 123 /* Collect info on which entries were reserved. */ 124 for (d = 0; d < TF_DIR_MAX; d++) { 125 for (t = 0; t < TF_TCAM_TBL_TYPE_MAX; t++) { 126 memset(&info, 0, sizeof(info)); 127 if (tcam_cnt[d].cnt[t] == 0) { 128 resv_res[d][t].start = 0; 129 resv_res[d][t].stride = 0; 130 continue; 131 } 132 ainfo.rm_db = tcam_db->tcam_db[d]; 133 ainfo.subtype = t; 134 ainfo.info = &info; 135 rc = tf_rm_get_info(&ainfo); 136 if (rc) 137 goto error; 138 139 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, t, 0, 140 &num_slices); 141 if (rc) 142 return rc; 143 144 if (num_slices > 1) { 145 /* check if reserved resource for is multiple of 146 * num_slices 147 */ 148 if (info.entry.start % num_slices != 0 || 149 info.entry.stride % num_slices != 0) { 150 TFP_DRV_LOG(ERR, 151 "%s: %s reserved resource" 152 " is not multiple of %d\n", 153 tf_dir_2_str(d), 154 tf_tcam_tbl_2_str(t), 155 num_slices); 156 rc = -EINVAL; 157 goto error; 158 } 159 } 160 161 resv_res[d][t].start = info.entry.start; 162 resv_res[d][t].stride = info.entry.stride; 163 } 164 } 165 166 rc = tf_tcam_mgr_bind_msg(tfp, dev, parms, resv_res); 167 if (rc) 168 return rc; 169 170 rc = tf_tcam_mgr_qcaps_msg(tfp, dev, 171 &rx_supported, &tx_supported); 172 if (rc) 173 return rc; 174 175 for (t = 0; t < TF_TCAM_TBL_TYPE_MAX; t++) { 176 if (rx_supported & 1 << t) 177 tfs->tcam_mgr_control[TF_DIR_RX][t] = 1; 178 if (tx_supported & 1 << t) 179 tfs->tcam_mgr_control[TF_DIR_TX][t] = 1; 180 } 181 182 /* 183 * Make a local copy of tcam_cnt with only resources not managed by TCAM 184 * Manager requested. 185 */ 186 memcpy(&local_tcam_cnt, tcam_cnt, sizeof(local_tcam_cnt)); 187 tcam_cnt = local_tcam_cnt; 188 for (d = 0; d < TF_DIR_MAX; d++) { 189 for (t = 0; t < TF_TCAM_TBL_TYPE_MAX; t++) { 190 /* If controlled by TCAM Manager */ 191 if (tfs->tcam_mgr_control[d][t]) 192 tcam_cnt[d].cnt[t] = 0; 193 else if (tcam_cnt[d].cnt[t] > 0) 194 no_req = false; 195 } 196 } 197 198 /* If no resources left to request */ 199 if (no_req) 200 goto finished; 201 202 finished: 203 TFP_DRV_LOG(INFO, 204 "TCAM - initialized\n"); 205 206 return 0; 207 error: 208 for (d = 0; d < TF_DIR_MAX; d++) { 209 if (tcam_db->tcam_db[d] != NULL) { 210 memset(&fparms, 0, sizeof(fparms)); 211 fparms.dir = d; 212 fparms.rm_db = tcam_db->tcam_db[d]; 213 /* 214 * Ignoring return here since we are in the error case 215 */ 216 (void)tf_rm_free_db(tfp, &fparms); 217 218 tcam_db->tcam_db[d] = NULL; 219 } 220 tcam_db->tcam_db[d] = NULL; 221 tf_session_set_db(tfp, TF_MODULE_TYPE_TCAM, NULL); 222 } 223 return rc; 224 } 225 226 int 227 tf_tcam_unbind(struct tf *tfp) 228 { 229 int rc; 230 int i; 231 struct tf_rm_free_db_parms fparms; 232 struct tcam_rm_db *tcam_db; 233 void *tcam_db_ptr = NULL; 234 struct tf_session *tfs; 235 struct tf_dev_info *dev; 236 TF_CHECK_PARMS1(tfp); 237 238 /* Retrieve the session information */ 239 rc = tf_session_get_session_internal(tfp, &tfs); 240 if (rc) 241 return rc; 242 243 /* Retrieve the device information */ 244 rc = tf_session_get_device(tfs, &dev); 245 if (rc) 246 return rc; 247 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 248 if (rc) 249 return 0; 250 251 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 252 253 for (i = 0; i < TF_DIR_MAX; i++) { 254 if (tcam_db->tcam_db[i] != NULL) { 255 memset(&fparms, 0, sizeof(fparms)); 256 fparms.dir = i; 257 fparms.rm_db = tcam_db->tcam_db[i]; 258 rc = tf_rm_free_db(tfp, &fparms); 259 if (rc) 260 return rc; 261 262 tcam_db->tcam_db[i] = NULL; 263 } 264 } 265 266 rc = tf_tcam_mgr_unbind_msg(tfp, dev); 267 if (rc) 268 return rc; 269 270 return 0; 271 } 272 273 int 274 tf_tcam_alloc(struct tf *tfp, 275 struct tf_tcam_alloc_parms *parms) 276 { 277 int rc, i; 278 struct tf_session *tfs; 279 struct tf_dev_info *dev; 280 struct tf_rm_allocate_parms aparms; 281 uint16_t num_slices = 1; 282 uint32_t index; 283 struct tcam_rm_db *tcam_db; 284 void *tcam_db_ptr = NULL; 285 286 TF_CHECK_PARMS2(tfp, parms); 287 288 /* Retrieve the session information */ 289 rc = tf_session_get_session_internal(tfp, &tfs); 290 if (rc) 291 return rc; 292 293 /* Retrieve the device information */ 294 rc = tf_session_get_device(tfs, &dev); 295 if (rc) 296 return rc; 297 298 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 299 rc = -EOPNOTSUPP; 300 TFP_DRV_LOG(ERR, 301 "%s: Operation not supported, rc:%s\n", 302 tf_dir_2_str(parms->dir), 303 strerror(-rc)); 304 return rc; 305 } 306 307 /* Need to retrieve number of slices based on the key_size */ 308 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, 309 parms->type, 310 parms->key_size, 311 &num_slices); 312 if (rc) 313 return rc; 314 315 /* If TCAM controlled by TCAM Manager */ 316 if (tfs->tcam_mgr_control[parms->dir][parms->type]) 317 return tf_tcam_mgr_alloc_msg(tfp, dev, parms); 318 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 319 if (rc) { 320 TFP_DRV_LOG(ERR, 321 "Failed to get tcam_db from session, rc:%s\n", 322 strerror(-rc)); 323 return rc; 324 } 325 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 326 327 /* 328 * For WC TCAM, number of slices could be 4, 2, 1 based on 329 * the key_size. For other TCAM, it is always 1 330 */ 331 for (i = 0; i < num_slices; i++) { 332 memset(&aparms, 0, sizeof(aparms)); 333 aparms.rm_db = tcam_db->tcam_db[parms->dir]; 334 aparms.subtype = parms->type; 335 aparms.priority = parms->priority; 336 aparms.index = &index; 337 rc = tf_rm_allocate(&aparms); 338 if (rc) { 339 TFP_DRV_LOG(ERR, 340 "%s: Failed tcam, type:%d\n", 341 tf_dir_2_str(parms->dir), 342 parms->type); 343 return rc; 344 } 345 346 /* return the start index of each row */ 347 if (i == 0) 348 parms->idx = index; 349 } 350 351 return 0; 352 } 353 354 int 355 tf_tcam_free(struct tf *tfp, 356 struct tf_tcam_free_parms *parms) 357 { 358 int rc; 359 struct tf_session *tfs; 360 struct tf_dev_info *dev; 361 struct tf_rm_is_allocated_parms aparms; 362 struct tf_rm_free_parms fparms; 363 struct tf_rm_get_hcapi_parms hparms; 364 uint16_t num_slices = 1; 365 int allocated = 0; 366 int i; 367 struct tcam_rm_db *tcam_db; 368 void *tcam_db_ptr = NULL; 369 370 TF_CHECK_PARMS2(tfp, parms); 371 372 /* Retrieve the session information */ 373 rc = tf_session_get_session_internal(tfp, &tfs); 374 if (rc) 375 return rc; 376 377 /* Retrieve the device information */ 378 rc = tf_session_get_device(tfs, &dev); 379 if (rc) 380 return rc; 381 382 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 383 rc = -EOPNOTSUPP; 384 TFP_DRV_LOG(ERR, 385 "%s: Operation not supported, rc:%s\n", 386 tf_dir_2_str(parms->dir), 387 strerror(-rc)); 388 return rc; 389 } 390 391 /* Need to retrieve row size etc */ 392 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, 393 parms->type, 394 0, 395 &num_slices); 396 if (rc) 397 return rc; 398 399 /* If TCAM controlled by TCAM Manager */ 400 if (tfs->tcam_mgr_control[parms->dir][parms->type]) 401 /* 402 * If a session can have multiple references to an entry, check 403 * the reference count here before actually freeing the entry. 404 */ 405 return tf_tcam_mgr_free_msg(tfp, dev, parms); 406 407 if (parms->idx % num_slices) { 408 TFP_DRV_LOG(ERR, 409 "%s: TCAM reserved resource is not multiple of %d\n", 410 tf_dir_2_str(parms->dir), 411 num_slices); 412 return -EINVAL; 413 } 414 415 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 416 if (rc) { 417 TFP_DRV_LOG(ERR, 418 "Failed to get em_ext_db from session, rc:%s\n", 419 strerror(-rc)); 420 return rc; 421 } 422 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 423 424 /* Check if element is in use */ 425 memset(&aparms, 0, sizeof(aparms)); 426 aparms.rm_db = tcam_db->tcam_db[parms->dir]; 427 aparms.subtype = parms->type; 428 aparms.index = parms->idx; 429 aparms.allocated = &allocated; 430 rc = tf_rm_is_allocated(&aparms); 431 if (rc) 432 return rc; 433 434 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) { 435 TFP_DRV_LOG(ERR, 436 "%s: Entry already free, type:%d, index:%d\n", 437 tf_dir_2_str(parms->dir), 438 parms->type, 439 parms->idx); 440 return -EINVAL; 441 } 442 443 for (i = 0; i < num_slices; i++) { 444 /* Free requested element */ 445 memset(&fparms, 0, sizeof(fparms)); 446 fparms.rm_db = tcam_db->tcam_db[parms->dir]; 447 fparms.subtype = parms->type; 448 fparms.index = parms->idx + i; 449 rc = tf_rm_free(&fparms); 450 if (rc) { 451 TFP_DRV_LOG(ERR, 452 "%s: Free failed, type:%d, index:%d\n", 453 tf_dir_2_str(parms->dir), 454 parms->type, 455 parms->idx); 456 return rc; 457 } 458 } 459 460 /* Convert TF type to HCAPI RM type */ 461 memset(&hparms, 0, sizeof(hparms)); 462 463 hparms.rm_db = tcam_db->tcam_db[parms->dir]; 464 hparms.subtype = parms->type; 465 hparms.hcapi_type = &parms->hcapi_type; 466 467 rc = tf_rm_get_hcapi_type(&hparms); 468 if (rc) 469 return rc; 470 471 rc = tf_msg_tcam_entry_free(tfp, dev, parms); 472 if (rc) { 473 /* Log error */ 474 TFP_DRV_LOG(ERR, 475 "%s: %s: Entry %d free failed, rc:%s\n", 476 tf_dir_2_str(parms->dir), 477 tf_tcam_tbl_2_str(parms->type), 478 parms->idx, 479 strerror(-rc)); 480 return rc; 481 } 482 483 return 0; 484 } 485 486 int 487 tf_tcam_set(struct tf *tfp __rte_unused, 488 struct tf_tcam_set_parms *parms __rte_unused) 489 { 490 int rc; 491 struct tf_session *tfs; 492 struct tf_dev_info *dev; 493 struct tf_rm_is_allocated_parms aparms; 494 struct tf_rm_get_hcapi_parms hparms; 495 uint16_t num_slice_per_row = 1; 496 int allocated = 0; 497 struct tcam_rm_db *tcam_db; 498 void *tcam_db_ptr = NULL; 499 500 TF_CHECK_PARMS2(tfp, parms); 501 502 /* Retrieve the session information */ 503 rc = tf_session_get_session_internal(tfp, &tfs); 504 if (rc) 505 return rc; 506 507 /* Retrieve the device information */ 508 rc = tf_session_get_device(tfs, &dev); 509 if (rc) 510 return rc; 511 512 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 513 rc = -EOPNOTSUPP; 514 TFP_DRV_LOG(ERR, 515 "%s: Operation not supported, rc:%s\n", 516 tf_dir_2_str(parms->dir), 517 strerror(-rc)); 518 return rc; 519 } 520 521 /* Need to retrieve row size etc */ 522 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, 523 parms->type, 524 parms->key_size, 525 &num_slice_per_row); 526 if (rc) 527 return rc; 528 529 /* If TCAM controlled by TCAM Manager */ 530 if (tfs->tcam_mgr_control[parms->dir][parms->type]) 531 return tf_tcam_mgr_set_msg(tfp, dev, parms); 532 533 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 534 if (rc) { 535 TFP_DRV_LOG(ERR, 536 "Failed to get em_ext_db from session, rc:%s\n", 537 strerror(-rc)); 538 return rc; 539 } 540 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 541 542 /* Check if element is in use */ 543 memset(&aparms, 0, sizeof(aparms)); 544 545 aparms.rm_db = tcam_db->tcam_db[parms->dir]; 546 aparms.subtype = parms->type; 547 aparms.index = parms->idx; 548 aparms.allocated = &allocated; 549 rc = tf_rm_is_allocated(&aparms); 550 if (rc) 551 return rc; 552 553 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) { 554 TFP_DRV_LOG(ERR, 555 "%s: Entry is not allocated, type:%d, index:%d\n", 556 tf_dir_2_str(parms->dir), 557 parms->type, 558 parms->idx); 559 return -EINVAL; 560 } 561 562 /* Convert TF type to HCAPI RM type */ 563 memset(&hparms, 0, sizeof(hparms)); 564 565 hparms.rm_db = tcam_db->tcam_db[parms->dir]; 566 hparms.subtype = parms->type; 567 hparms.hcapi_type = &parms->hcapi_type; 568 569 rc = tf_rm_get_hcapi_type(&hparms); 570 if (rc) 571 return rc; 572 573 rc = tf_msg_tcam_entry_set(tfp, dev, parms); 574 if (rc) { 575 /* Log error */ 576 TFP_DRV_LOG(ERR, 577 "%s: %s: Entry %d set failed, rc:%s", 578 tf_dir_2_str(parms->dir), 579 tf_tcam_tbl_2_str(parms->type), 580 parms->idx, 581 strerror(-rc)); 582 return rc; 583 } 584 return 0; 585 } 586 587 int 588 tf_tcam_get(struct tf *tfp __rte_unused, 589 struct tf_tcam_get_parms *parms) 590 { 591 int rc; 592 struct tf_session *tfs; 593 struct tf_dev_info *dev; 594 struct tf_rm_is_allocated_parms aparms; 595 struct tf_rm_get_hcapi_parms hparms; 596 int allocated = 0; 597 struct tcam_rm_db *tcam_db; 598 void *tcam_db_ptr = NULL; 599 600 TF_CHECK_PARMS2(tfp, parms); 601 602 /* Retrieve the session information */ 603 rc = tf_session_get_session_internal(tfp, &tfs); 604 if (rc) 605 return rc; 606 607 /* Retrieve the device information */ 608 rc = tf_session_get_device(tfs, &dev); 609 if (rc) 610 return rc; 611 612 /* If TCAM controlled by TCAM Manager */ 613 if (tfs->tcam_mgr_control[parms->dir][parms->type]) 614 return tf_tcam_mgr_get_msg(tfp, dev, parms); 615 616 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 617 if (rc) { 618 TFP_DRV_LOG(ERR, 619 "Failed to get em_ext_db from session, rc:%s\n", 620 strerror(-rc)); 621 return rc; 622 } 623 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 624 625 /* Check if element is in use */ 626 memset(&aparms, 0, sizeof(aparms)); 627 628 aparms.rm_db = tcam_db->tcam_db[parms->dir]; 629 aparms.subtype = parms->type; 630 aparms.index = parms->idx; 631 aparms.allocated = &allocated; 632 rc = tf_rm_is_allocated(&aparms); 633 if (rc) 634 return rc; 635 636 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) { 637 TFP_DRV_LOG(ERR, 638 "%s: Entry is not allocated, type:%d, index:%d\n", 639 tf_dir_2_str(parms->dir), 640 parms->type, 641 parms->idx); 642 return -EINVAL; 643 } 644 645 /* Convert TF type to HCAPI RM type */ 646 memset(&hparms, 0, sizeof(hparms)); 647 648 hparms.rm_db = tcam_db->tcam_db[parms->dir]; 649 hparms.subtype = parms->type; 650 hparms.hcapi_type = &parms->hcapi_type; 651 652 rc = tf_rm_get_hcapi_type(&hparms); 653 if (rc) 654 return rc; 655 656 rc = tf_msg_tcam_entry_get(tfp, dev, parms); 657 if (rc) { 658 /* Log error */ 659 TFP_DRV_LOG(ERR, 660 "%s: %s: Entry %d set failed, rc:%s", 661 tf_dir_2_str(parms->dir), 662 tf_tcam_tbl_2_str(parms->type), 663 parms->idx, 664 strerror(-rc)); 665 return rc; 666 } 667 668 return 0; 669 } 670 671 int 672 tf_tcam_get_resc_info(struct tf *tfp, 673 struct tf_tcam_resource_info *tcam) 674 { 675 int rc; 676 int d; 677 struct tf_resource_info *dinfo; 678 struct tf_rm_get_alloc_info_parms ainfo; 679 void *tcam_db_ptr = NULL; 680 struct tcam_rm_db *tcam_db; 681 682 TF_CHECK_PARMS2(tfp, tcam); 683 684 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 685 if (rc == -ENOMEM) 686 return 0; /* db doesn't exist */ 687 else if (rc) 688 return rc; /* error getting db */ 689 690 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 691 692 /* check if reserved resource for WC is multiple of num_slices */ 693 for (d = 0; d < TF_DIR_MAX; d++) { 694 ainfo.rm_db = tcam_db->tcam_db[d]; 695 696 if (!ainfo.rm_db) 697 continue; 698 699 dinfo = tcam[d].info; 700 701 ainfo.info = (struct tf_rm_alloc_info *)dinfo; 702 ainfo.subtype = 0; 703 rc = tf_rm_get_all_info(&ainfo, TF_TCAM_TBL_TYPE_MAX); 704 if (rc && rc != -ENOTSUP) 705 return rc; 706 } 707 708 return 0; 709 } 710