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 267 rc = tf_tcam_mgr_unbind_msg(tfp, dev); 268 if (rc) 269 return rc; 270 271 return 0; 272 } 273 274 int 275 tf_tcam_alloc(struct tf *tfp, 276 struct tf_tcam_alloc_parms *parms) 277 { 278 int rc, i; 279 struct tf_session *tfs; 280 struct tf_dev_info *dev; 281 struct tf_rm_allocate_parms aparms; 282 uint16_t num_slices = 1; 283 uint32_t index; 284 struct tcam_rm_db *tcam_db; 285 void *tcam_db_ptr = NULL; 286 287 TF_CHECK_PARMS2(tfp, parms); 288 289 /* Retrieve the session information */ 290 rc = tf_session_get_session_internal(tfp, &tfs); 291 if (rc) 292 return rc; 293 294 /* Retrieve the device information */ 295 rc = tf_session_get_device(tfs, &dev); 296 if (rc) 297 return rc; 298 299 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 300 rc = -EOPNOTSUPP; 301 TFP_DRV_LOG(ERR, 302 "%s: Operation not supported, rc:%s\n", 303 tf_dir_2_str(parms->dir), 304 strerror(-rc)); 305 return rc; 306 } 307 308 /* Need to retrieve number of slices based on the key_size */ 309 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, 310 parms->type, 311 parms->key_size, 312 &num_slices); 313 if (rc) 314 return rc; 315 316 /* If TCAM controlled by TCAM Manager */ 317 if (tfs->tcam_mgr_control[parms->dir][parms->type]) 318 return tf_tcam_mgr_alloc_msg(tfp, dev, parms); 319 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 320 if (rc) { 321 TFP_DRV_LOG(ERR, 322 "Failed to get tcam_db from session, rc:%s\n", 323 strerror(-rc)); 324 return rc; 325 } 326 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 327 328 /* 329 * For WC TCAM, number of slices could be 4, 2, 1 based on 330 * the key_size. For other TCAM, it is always 1 331 */ 332 for (i = 0; i < num_slices; i++) { 333 memset(&aparms, 0, sizeof(aparms)); 334 aparms.rm_db = tcam_db->tcam_db[parms->dir]; 335 aparms.subtype = parms->type; 336 aparms.priority = parms->priority; 337 aparms.index = &index; 338 rc = tf_rm_allocate(&aparms); 339 if (rc) { 340 TFP_DRV_LOG(ERR, 341 "%s: Failed tcam, type:%d\n", 342 tf_dir_2_str(parms->dir), 343 parms->type); 344 return rc; 345 } 346 347 /* return the start index of each row */ 348 if (i == 0) 349 parms->idx = index; 350 } 351 352 return 0; 353 } 354 355 int 356 tf_tcam_free(struct tf *tfp, 357 struct tf_tcam_free_parms *parms) 358 { 359 int rc; 360 struct tf_session *tfs; 361 struct tf_dev_info *dev; 362 struct tf_rm_is_allocated_parms aparms; 363 struct tf_rm_free_parms fparms; 364 struct tf_rm_get_hcapi_parms hparms; 365 uint16_t num_slices = 1; 366 int allocated = 0; 367 int i; 368 struct tcam_rm_db *tcam_db; 369 void *tcam_db_ptr = NULL; 370 371 TF_CHECK_PARMS2(tfp, parms); 372 373 /* Retrieve the session information */ 374 rc = tf_session_get_session_internal(tfp, &tfs); 375 if (rc) 376 return rc; 377 378 /* Retrieve the device information */ 379 rc = tf_session_get_device(tfs, &dev); 380 if (rc) 381 return rc; 382 383 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 384 rc = -EOPNOTSUPP; 385 TFP_DRV_LOG(ERR, 386 "%s: Operation not supported, rc:%s\n", 387 tf_dir_2_str(parms->dir), 388 strerror(-rc)); 389 return rc; 390 } 391 392 /* Need to retrieve row size etc */ 393 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, 394 parms->type, 395 0, 396 &num_slices); 397 if (rc) 398 return rc; 399 400 /* If TCAM controlled by TCAM Manager */ 401 if (tfs->tcam_mgr_control[parms->dir][parms->type]) 402 /* 403 * If a session can have multiple references to an entry, check 404 * the reference count here before actually freeing the entry. 405 */ 406 return tf_tcam_mgr_free_msg(tfp, dev, parms); 407 408 if (parms->idx % num_slices) { 409 TFP_DRV_LOG(ERR, 410 "%s: TCAM reserved resource is not multiple of %d\n", 411 tf_dir_2_str(parms->dir), 412 num_slices); 413 return -EINVAL; 414 } 415 416 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 417 if (rc) { 418 TFP_DRV_LOG(ERR, 419 "Failed to get em_ext_db from session, rc:%s\n", 420 strerror(-rc)); 421 return rc; 422 } 423 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 424 425 /* Check if element is in use */ 426 memset(&aparms, 0, sizeof(aparms)); 427 aparms.rm_db = tcam_db->tcam_db[parms->dir]; 428 aparms.subtype = parms->type; 429 aparms.index = parms->idx; 430 aparms.allocated = &allocated; 431 rc = tf_rm_is_allocated(&aparms); 432 if (rc) 433 return rc; 434 435 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) { 436 TFP_DRV_LOG(ERR, 437 "%s: Entry already free, type:%d, index:%d\n", 438 tf_dir_2_str(parms->dir), 439 parms->type, 440 parms->idx); 441 return -EINVAL; 442 } 443 444 for (i = 0; i < num_slices; i++) { 445 /* Free requested element */ 446 memset(&fparms, 0, sizeof(fparms)); 447 fparms.rm_db = tcam_db->tcam_db[parms->dir]; 448 fparms.subtype = parms->type; 449 fparms.index = parms->idx + i; 450 rc = tf_rm_free(&fparms); 451 if (rc) { 452 TFP_DRV_LOG(ERR, 453 "%s: Free failed, type:%d, index:%d\n", 454 tf_dir_2_str(parms->dir), 455 parms->type, 456 parms->idx); 457 return rc; 458 } 459 } 460 461 /* Convert TF type to HCAPI RM type */ 462 memset(&hparms, 0, sizeof(hparms)); 463 464 hparms.rm_db = tcam_db->tcam_db[parms->dir]; 465 hparms.subtype = parms->type; 466 hparms.hcapi_type = &parms->hcapi_type; 467 468 rc = tf_rm_get_hcapi_type(&hparms); 469 if (rc) 470 return rc; 471 472 rc = tf_msg_tcam_entry_free(tfp, dev, parms); 473 if (rc) { 474 /* Log error */ 475 TFP_DRV_LOG(ERR, 476 "%s: %s: Entry %d free failed, rc:%s\n", 477 tf_dir_2_str(parms->dir), 478 tf_tcam_tbl_2_str(parms->type), 479 parms->idx, 480 strerror(-rc)); 481 return rc; 482 } 483 484 return 0; 485 } 486 487 int 488 tf_tcam_set(struct tf *tfp __rte_unused, 489 struct tf_tcam_set_parms *parms __rte_unused) 490 { 491 int rc; 492 struct tf_session *tfs; 493 struct tf_dev_info *dev; 494 struct tf_rm_is_allocated_parms aparms; 495 struct tf_rm_get_hcapi_parms hparms; 496 uint16_t num_slice_per_row = 1; 497 int allocated = 0; 498 struct tcam_rm_db *tcam_db; 499 void *tcam_db_ptr = NULL; 500 501 TF_CHECK_PARMS2(tfp, parms); 502 503 /* Retrieve the session information */ 504 rc = tf_session_get_session_internal(tfp, &tfs); 505 if (rc) 506 return rc; 507 508 /* Retrieve the device information */ 509 rc = tf_session_get_device(tfs, &dev); 510 if (rc) 511 return rc; 512 513 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 514 rc = -EOPNOTSUPP; 515 TFP_DRV_LOG(ERR, 516 "%s: Operation not supported, rc:%s\n", 517 tf_dir_2_str(parms->dir), 518 strerror(-rc)); 519 return rc; 520 } 521 522 /* Need to retrieve row size etc */ 523 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, 524 parms->type, 525 parms->key_size, 526 &num_slice_per_row); 527 if (rc) 528 return rc; 529 530 /* If TCAM controlled by TCAM Manager */ 531 if (tfs->tcam_mgr_control[parms->dir][parms->type]) 532 return tf_tcam_mgr_set_msg(tfp, dev, parms); 533 534 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 535 if (rc) { 536 TFP_DRV_LOG(ERR, 537 "Failed to get em_ext_db from session, rc:%s\n", 538 strerror(-rc)); 539 return rc; 540 } 541 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 542 543 /* Check if element is in use */ 544 memset(&aparms, 0, sizeof(aparms)); 545 546 aparms.rm_db = tcam_db->tcam_db[parms->dir]; 547 aparms.subtype = parms->type; 548 aparms.index = parms->idx; 549 aparms.allocated = &allocated; 550 rc = tf_rm_is_allocated(&aparms); 551 if (rc) 552 return rc; 553 554 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) { 555 TFP_DRV_LOG(ERR, 556 "%s: Entry is not allocated, type:%d, index:%d\n", 557 tf_dir_2_str(parms->dir), 558 parms->type, 559 parms->idx); 560 return -EINVAL; 561 } 562 563 /* Convert TF type to HCAPI RM type */ 564 memset(&hparms, 0, sizeof(hparms)); 565 566 hparms.rm_db = tcam_db->tcam_db[parms->dir]; 567 hparms.subtype = parms->type; 568 hparms.hcapi_type = &parms->hcapi_type; 569 570 rc = tf_rm_get_hcapi_type(&hparms); 571 if (rc) 572 return rc; 573 574 rc = tf_msg_tcam_entry_set(tfp, dev, parms); 575 if (rc) { 576 /* Log error */ 577 TFP_DRV_LOG(ERR, 578 "%s: %s: Entry %d set failed, rc:%s", 579 tf_dir_2_str(parms->dir), 580 tf_tcam_tbl_2_str(parms->type), 581 parms->idx, 582 strerror(-rc)); 583 return rc; 584 } 585 return 0; 586 } 587 588 int 589 tf_tcam_get(struct tf *tfp __rte_unused, 590 struct tf_tcam_get_parms *parms) 591 { 592 int rc; 593 struct tf_session *tfs; 594 struct tf_dev_info *dev; 595 struct tf_rm_is_allocated_parms aparms; 596 struct tf_rm_get_hcapi_parms hparms; 597 int allocated = 0; 598 struct tcam_rm_db *tcam_db; 599 void *tcam_db_ptr = NULL; 600 601 TF_CHECK_PARMS2(tfp, parms); 602 603 /* Retrieve the session information */ 604 rc = tf_session_get_session_internal(tfp, &tfs); 605 if (rc) 606 return rc; 607 608 /* Retrieve the device information */ 609 rc = tf_session_get_device(tfs, &dev); 610 if (rc) 611 return rc; 612 613 /* If TCAM controlled by TCAM Manager */ 614 if (tfs->tcam_mgr_control[parms->dir][parms->type]) 615 return tf_tcam_mgr_get_msg(tfp, dev, parms); 616 617 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 618 if (rc) { 619 TFP_DRV_LOG(ERR, 620 "Failed to get em_ext_db from session, rc:%s\n", 621 strerror(-rc)); 622 return rc; 623 } 624 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 625 626 /* Check if element is in use */ 627 memset(&aparms, 0, sizeof(aparms)); 628 629 aparms.rm_db = tcam_db->tcam_db[parms->dir]; 630 aparms.subtype = parms->type; 631 aparms.index = parms->idx; 632 aparms.allocated = &allocated; 633 rc = tf_rm_is_allocated(&aparms); 634 if (rc) 635 return rc; 636 637 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) { 638 TFP_DRV_LOG(ERR, 639 "%s: Entry is not allocated, type:%d, index:%d\n", 640 tf_dir_2_str(parms->dir), 641 parms->type, 642 parms->idx); 643 return -EINVAL; 644 } 645 646 /* Convert TF type to HCAPI RM type */ 647 memset(&hparms, 0, sizeof(hparms)); 648 649 hparms.rm_db = tcam_db->tcam_db[parms->dir]; 650 hparms.subtype = parms->type; 651 hparms.hcapi_type = &parms->hcapi_type; 652 653 rc = tf_rm_get_hcapi_type(&hparms); 654 if (rc) 655 return rc; 656 657 rc = tf_msg_tcam_entry_get(tfp, dev, parms); 658 if (rc) { 659 /* Log error */ 660 TFP_DRV_LOG(ERR, 661 "%s: %s: Entry %d set failed, rc:%s", 662 tf_dir_2_str(parms->dir), 663 tf_tcam_tbl_2_str(parms->type), 664 parms->idx, 665 strerror(-rc)); 666 return rc; 667 } 668 669 return 0; 670 } 671 672 int 673 tf_tcam_get_resc_info(struct tf *tfp, 674 struct tf_tcam_resource_info *tcam) 675 { 676 int rc; 677 int d; 678 struct tf_resource_info *dinfo; 679 struct tf_rm_get_alloc_info_parms ainfo; 680 void *tcam_db_ptr = NULL; 681 struct tcam_rm_db *tcam_db; 682 683 TF_CHECK_PARMS2(tfp, tcam); 684 685 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 686 if (rc == -ENOMEM) 687 return 0; /* db doesn't exist */ 688 else if (rc) 689 return rc; /* error getting db */ 690 691 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 692 693 /* check if reserved resource for WC is multiple of num_slices */ 694 for (d = 0; d < TF_DIR_MAX; d++) { 695 ainfo.rm_db = tcam_db->tcam_db[d]; 696 697 if (!ainfo.rm_db) 698 continue; 699 700 dinfo = tcam[d].info; 701 702 ainfo.info = (struct tf_rm_alloc_info *)dinfo; 703 ainfo.subtype = 0; 704 rc = tf_rm_get_all_info(&ainfo, TF_TCAM_TBL_TYPE_MAX); 705 if (rc && rc != -ENOTSUP) 706 return rc; 707 } 708 709 return 0; 710 } 711