1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2019-2021 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 18 struct tf; 19 20 int 21 tf_tcam_bind(struct tf *tfp, 22 struct tf_tcam_cfg_parms *parms) 23 { 24 int rc; 25 int db_rc[TF_DIR_MAX] = { 0 }; 26 int i, d; 27 struct tf_rm_alloc_info info; 28 struct tf_rm_free_db_parms fparms; 29 struct tf_rm_create_db_parms db_cfg; 30 struct tf_tcam_resources *tcam_cnt; 31 struct tf_rm_get_alloc_info_parms ainfo; 32 uint16_t num_slices = parms->wc_num_slices; 33 struct tf_session *tfs; 34 struct tf_dev_info *dev; 35 struct tcam_rm_db *tcam_db; 36 struct tfp_calloc_parms cparms; 37 38 TF_CHECK_PARMS2(tfp, parms); 39 40 /* Retrieve the session information */ 41 rc = tf_session_get_session_internal(tfp, &tfs); 42 if (rc) 43 return rc; 44 45 /* Retrieve the device information */ 46 rc = tf_session_get_device(tfs, &dev); 47 if (rc) 48 return rc; 49 50 if (dev->ops->tf_dev_set_tcam_slice_info == NULL) { 51 rc = -EOPNOTSUPP; 52 TFP_DRV_LOG(ERR, 53 "Operation not supported, rc:%s\n", 54 strerror(-rc)); 55 return rc; 56 } 57 58 rc = dev->ops->tf_dev_set_tcam_slice_info(tfp, 59 num_slices); 60 if (rc) 61 return rc; 62 63 tcam_cnt = parms->resources->tcam_cnt; 64 if ((tcam_cnt[TF_DIR_RX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] % num_slices) || 65 (tcam_cnt[TF_DIR_TX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] % num_slices)) { 66 TFP_DRV_LOG(ERR, 67 "Requested num of WC TCAM entries has to be multiple %d\n", 68 num_slices); 69 return -EINVAL; 70 } 71 72 memset(&db_cfg, 0, sizeof(db_cfg)); 73 cparms.nitems = 1; 74 cparms.size = sizeof(struct tcam_rm_db); 75 cparms.alignment = 0; 76 if (tfp_calloc(&cparms) != 0) { 77 TFP_DRV_LOG(ERR, "tcam_rm_db alloc error %s\n", 78 strerror(ENOMEM)); 79 return -ENOMEM; 80 } 81 82 tcam_db = cparms.mem_va; 83 for (i = 0; i < TF_DIR_MAX; i++) 84 tcam_db->tcam_db[i] = NULL; 85 tf_session_set_db(tfp, TF_MODULE_TYPE_TCAM, tcam_db); 86 87 db_cfg.module = TF_MODULE_TYPE_TCAM; 88 db_cfg.num_elements = parms->num_elements; 89 db_cfg.cfg = parms->cfg; 90 91 for (d = 0; d < TF_DIR_MAX; d++) { 92 db_cfg.dir = d; 93 db_cfg.alloc_cnt = parms->resources->tcam_cnt[d].cnt; 94 db_cfg.rm_db = (void *)&tcam_db->tcam_db[d]; 95 if (tf_session_is_shared_session(tfs) && 96 (!tf_session_is_shared_session_creator(tfs))) 97 db_rc[d] = tf_rm_create_db_no_reservation(tfp, &db_cfg); 98 else 99 db_rc[d] = tf_rm_create_db(tfp, &db_cfg); 100 } 101 102 /* No db created */ 103 if (db_rc[TF_DIR_RX] && db_rc[TF_DIR_TX]) { 104 TFP_DRV_LOG(ERR, "No TCAM DB created\n"); 105 return db_rc[TF_DIR_RX]; 106 } 107 108 /* check if reserved resource for WC is multiple of num_slices */ 109 for (d = 0; d < TF_DIR_MAX; d++) { 110 if (!tcam_db->tcam_db[d]) 111 continue; 112 113 memset(&info, 0, sizeof(info)); 114 ainfo.rm_db = tcam_db->tcam_db[d]; 115 ainfo.subtype = TF_TCAM_TBL_TYPE_WC_TCAM; 116 ainfo.info = &info; 117 rc = tf_rm_get_info(&ainfo); 118 if (rc) 119 goto error; 120 121 if (info.entry.start % num_slices != 0 || 122 info.entry.stride % num_slices != 0) { 123 TFP_DRV_LOG(ERR, 124 "%s: TCAM reserved resource is not multiple of %d\n", 125 tf_dir_2_str(d), 126 num_slices); 127 rc = -EINVAL; 128 goto error; 129 } 130 } 131 132 /* Initialize the TCAM manager. */ 133 TFP_DRV_LOG(INFO, 134 "TCAM - initialized\n"); 135 136 return 0; 137 error: 138 for (i = 0; i < TF_DIR_MAX; i++) { 139 memset(&fparms, 0, sizeof(fparms)); 140 fparms.dir = i; 141 fparms.rm_db = tcam_db->tcam_db[i]; 142 /* Ignoring return here since we are in the error case */ 143 (void)tf_rm_free_db(tfp, &fparms); 144 tcam_db->tcam_db[i] = NULL; 145 tf_session_set_db(tfp, TF_MODULE_TYPE_TCAM, NULL); 146 } 147 148 return rc; 149 } 150 151 int 152 tf_tcam_unbind(struct tf *tfp) 153 { 154 int rc; 155 int i; 156 struct tf_rm_free_db_parms fparms; 157 struct tcam_rm_db *tcam_db; 158 void *tcam_db_ptr = NULL; 159 TF_CHECK_PARMS1(tfp); 160 161 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 162 if (rc) { 163 return 0; 164 } 165 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 166 167 for (i = 0; i < TF_DIR_MAX; i++) { 168 if (tcam_db->tcam_db[i] == NULL) 169 continue; 170 memset(&fparms, 0, sizeof(fparms)); 171 fparms.dir = i; 172 fparms.rm_db = tcam_db->tcam_db[i]; 173 rc = tf_rm_free_db(tfp, &fparms); 174 if (rc) 175 return rc; 176 177 tcam_db->tcam_db[i] = NULL; 178 } 179 180 return 0; 181 } 182 183 int 184 tf_tcam_alloc(struct tf *tfp, 185 struct tf_tcam_alloc_parms *parms) 186 { 187 int rc, i; 188 struct tf_session *tfs; 189 struct tf_dev_info *dev; 190 struct tf_rm_allocate_parms aparms; 191 uint16_t num_slices = 1; 192 uint32_t index; 193 struct tcam_rm_db *tcam_db; 194 void *tcam_db_ptr = NULL; 195 196 TF_CHECK_PARMS2(tfp, parms); 197 198 /* Retrieve the session information */ 199 rc = tf_session_get_session_internal(tfp, &tfs); 200 if (rc) 201 return rc; 202 203 /* Retrieve the device information */ 204 rc = tf_session_get_device(tfs, &dev); 205 if (rc) 206 return rc; 207 208 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 209 rc = -EOPNOTSUPP; 210 TFP_DRV_LOG(ERR, 211 "%s: Operation not supported, rc:%s\n", 212 tf_dir_2_str(parms->dir), 213 strerror(-rc)); 214 return rc; 215 } 216 217 /* Need to retrieve number of slices based on the key_size */ 218 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, 219 parms->type, 220 parms->key_size, 221 &num_slices); 222 if (rc) 223 return rc; 224 225 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 226 if (rc) { 227 TFP_DRV_LOG(ERR, 228 "Failed to get tcam_db from session, rc:%s\n", 229 strerror(-rc)); 230 return rc; 231 } 232 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 233 234 /* 235 * For WC TCAM, number of slices could be 4, 2, 1 based on 236 * the key_size. For other TCAM, it is always 1 237 */ 238 for (i = 0; i < num_slices; i++) { 239 memset(&aparms, 0, sizeof(aparms)); 240 aparms.rm_db = tcam_db->tcam_db[parms->dir]; 241 aparms.subtype = parms->type; 242 aparms.priority = parms->priority; 243 aparms.index = &index; 244 rc = tf_rm_allocate(&aparms); 245 if (rc) { 246 TFP_DRV_LOG(ERR, 247 "%s: Failed tcam, type:%d\n", 248 tf_dir_2_str(parms->dir), 249 parms->type); 250 return rc; 251 } 252 253 /* return the start index of each row */ 254 if (parms->priority == 0) { 255 if (i == 0) 256 parms->idx = index; 257 } else { 258 parms->idx = index; 259 } 260 } 261 262 return 0; 263 } 264 265 int 266 tf_tcam_free(struct tf *tfp, 267 struct tf_tcam_free_parms *parms) 268 { 269 int rc; 270 struct tf_session *tfs; 271 struct tf_dev_info *dev; 272 struct tf_rm_is_allocated_parms aparms; 273 struct tf_rm_free_parms fparms; 274 struct tf_rm_get_hcapi_parms hparms; 275 uint16_t num_slices = 1; 276 int allocated = 0; 277 int i; 278 struct tcam_rm_db *tcam_db; 279 void *tcam_db_ptr = NULL; 280 281 TF_CHECK_PARMS2(tfp, parms); 282 283 /* Retrieve the session information */ 284 rc = tf_session_get_session_internal(tfp, &tfs); 285 if (rc) 286 return rc; 287 288 /* Retrieve the device information */ 289 rc = tf_session_get_device(tfs, &dev); 290 if (rc) 291 return rc; 292 293 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 294 rc = -EOPNOTSUPP; 295 TFP_DRV_LOG(ERR, 296 "%s: Operation not supported, rc:%s\n", 297 tf_dir_2_str(parms->dir), 298 strerror(-rc)); 299 return rc; 300 } 301 302 /* Need to retrieve row size etc */ 303 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, 304 parms->type, 305 0, 306 &num_slices); 307 if (rc) 308 return rc; 309 310 if (parms->idx % num_slices) { 311 TFP_DRV_LOG(ERR, 312 "%s: TCAM reserved resource is not multiple of %d\n", 313 tf_dir_2_str(parms->dir), 314 num_slices); 315 return -EINVAL; 316 } 317 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 em_ext_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 /* Check if element is in use */ 328 memset(&aparms, 0, sizeof(aparms)); 329 aparms.rm_db = tcam_db->tcam_db[parms->dir]; 330 aparms.subtype = parms->type; 331 aparms.index = parms->idx; 332 aparms.allocated = &allocated; 333 rc = tf_rm_is_allocated(&aparms); 334 if (rc) 335 return rc; 336 337 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) { 338 TFP_DRV_LOG(ERR, 339 "%s: Entry already free, type:%d, index:%d\n", 340 tf_dir_2_str(parms->dir), 341 parms->type, 342 parms->idx); 343 return -EINVAL; 344 } 345 346 for (i = 0; i < num_slices; i++) { 347 /* Free requested element */ 348 memset(&fparms, 0, sizeof(fparms)); 349 fparms.rm_db = tcam_db->tcam_db[parms->dir]; 350 fparms.subtype = parms->type; 351 fparms.index = parms->idx + i; 352 rc = tf_rm_free(&fparms); 353 if (rc) { 354 TFP_DRV_LOG(ERR, 355 "%s: Free failed, type:%d, index:%d\n", 356 tf_dir_2_str(parms->dir), 357 parms->type, 358 parms->idx); 359 return rc; 360 } 361 } 362 363 /* Convert TF type to HCAPI RM type */ 364 memset(&hparms, 0, sizeof(hparms)); 365 366 hparms.rm_db = tcam_db->tcam_db[parms->dir]; 367 hparms.subtype = parms->type; 368 hparms.hcapi_type = &parms->hcapi_type; 369 370 rc = tf_rm_get_hcapi_type(&hparms); 371 if (rc) 372 return rc; 373 374 rc = tf_msg_tcam_entry_free(tfp, dev, parms); 375 if (rc) { 376 /* Log error */ 377 TFP_DRV_LOG(ERR, 378 "%s: %s: Entry %d free failed, rc:%s\n", 379 tf_dir_2_str(parms->dir), 380 tf_tcam_tbl_2_str(parms->type), 381 parms->idx, 382 strerror(-rc)); 383 return rc; 384 } 385 386 return 0; 387 } 388 389 int 390 tf_tcam_set(struct tf *tfp __rte_unused, 391 struct tf_tcam_set_parms *parms __rte_unused) 392 { 393 int rc; 394 struct tf_session *tfs; 395 struct tf_dev_info *dev; 396 struct tf_rm_is_allocated_parms aparms; 397 struct tf_rm_get_hcapi_parms hparms; 398 uint16_t num_slice_per_row = 1; 399 int allocated = 0; 400 struct tcam_rm_db *tcam_db; 401 void *tcam_db_ptr = NULL; 402 403 TF_CHECK_PARMS2(tfp, parms); 404 405 /* Retrieve the session information */ 406 rc = tf_session_get_session_internal(tfp, &tfs); 407 if (rc) 408 return rc; 409 410 /* Retrieve the device information */ 411 rc = tf_session_get_device(tfs, &dev); 412 if (rc) 413 return rc; 414 415 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 416 rc = -EOPNOTSUPP; 417 TFP_DRV_LOG(ERR, 418 "%s: Operation not supported, rc:%s\n", 419 tf_dir_2_str(parms->dir), 420 strerror(-rc)); 421 return rc; 422 } 423 424 /* Need to retrieve row size etc */ 425 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, 426 parms->type, 427 parms->key_size, 428 &num_slice_per_row); 429 if (rc) 430 return rc; 431 432 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 433 if (rc) { 434 TFP_DRV_LOG(ERR, 435 "Failed to get em_ext_db from session, rc:%s\n", 436 strerror(-rc)); 437 return rc; 438 } 439 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 440 441 /* Check if element is in use */ 442 memset(&aparms, 0, sizeof(aparms)); 443 444 aparms.rm_db = tcam_db->tcam_db[parms->dir]; 445 aparms.subtype = parms->type; 446 aparms.index = parms->idx; 447 aparms.allocated = &allocated; 448 rc = tf_rm_is_allocated(&aparms); 449 if (rc) 450 return rc; 451 452 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) { 453 TFP_DRV_LOG(ERR, 454 "%s: Entry is not allocated, type:%d, index:%d\n", 455 tf_dir_2_str(parms->dir), 456 parms->type, 457 parms->idx); 458 return -EINVAL; 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_set(tfp, dev, parms); 473 if (rc) { 474 /* Log error */ 475 TFP_DRV_LOG(ERR, 476 "%s: %s: Entry %d set failed, rc:%s", 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 return 0; 484 } 485 486 int 487 tf_tcam_get(struct tf *tfp __rte_unused, 488 struct tf_tcam_get_parms *parms) 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 int allocated = 0; 496 struct tcam_rm_db *tcam_db; 497 void *tcam_db_ptr = NULL; 498 499 TF_CHECK_PARMS2(tfp, parms); 500 501 /* Retrieve the session information */ 502 rc = tf_session_get_session_internal(tfp, &tfs); 503 if (rc) 504 return rc; 505 506 /* Retrieve the device information */ 507 rc = tf_session_get_device(tfs, &dev); 508 if (rc) 509 return rc; 510 511 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 512 if (rc) { 513 TFP_DRV_LOG(ERR, 514 "Failed to get em_ext_db from session, rc:%s\n", 515 strerror(-rc)); 516 return rc; 517 } 518 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 519 520 /* Check if element is in use */ 521 memset(&aparms, 0, sizeof(aparms)); 522 523 aparms.rm_db = tcam_db->tcam_db[parms->dir]; 524 aparms.subtype = parms->type; 525 aparms.index = parms->idx; 526 aparms.allocated = &allocated; 527 rc = tf_rm_is_allocated(&aparms); 528 if (rc) 529 return rc; 530 531 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) { 532 TFP_DRV_LOG(ERR, 533 "%s: Entry is not allocated, type:%d, index:%d\n", 534 tf_dir_2_str(parms->dir), 535 parms->type, 536 parms->idx); 537 return -EINVAL; 538 } 539 540 /* Convert TF type to HCAPI RM type */ 541 memset(&hparms, 0, sizeof(hparms)); 542 543 hparms.rm_db = tcam_db->tcam_db[parms->dir]; 544 hparms.subtype = parms->type; 545 hparms.hcapi_type = &parms->hcapi_type; 546 547 rc = tf_rm_get_hcapi_type(&hparms); 548 if (rc) 549 return rc; 550 551 rc = tf_msg_tcam_entry_get(tfp, dev, parms); 552 if (rc) { 553 /* Log error */ 554 TFP_DRV_LOG(ERR, 555 "%s: %s: Entry %d set failed, rc:%s", 556 tf_dir_2_str(parms->dir), 557 tf_tcam_tbl_2_str(parms->type), 558 parms->idx, 559 strerror(-rc)); 560 return rc; 561 } 562 563 return 0; 564 } 565 566 int 567 tf_tcam_get_resc_info(struct tf *tfp, 568 struct tf_tcam_resource_info *tcam) 569 { 570 int rc; 571 int d; 572 struct tf_resource_info *dinfo; 573 struct tf_rm_get_alloc_info_parms ainfo; 574 void *tcam_db_ptr = NULL; 575 struct tcam_rm_db *tcam_db; 576 577 TF_CHECK_PARMS2(tfp, tcam); 578 579 rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr); 580 if (rc == -ENOMEM) 581 return 0; /* db doesn't exist */ 582 else if (rc) 583 return rc; /* error getting db */ 584 585 tcam_db = (struct tcam_rm_db *)tcam_db_ptr; 586 587 /* check if reserved resource for WC is multiple of num_slices */ 588 for (d = 0; d < TF_DIR_MAX; d++) { 589 ainfo.rm_db = tcam_db->tcam_db[d]; 590 591 if (!ainfo.rm_db) 592 continue; 593 594 dinfo = tcam[d].info; 595 596 ainfo.info = (struct tf_rm_alloc_info *)dinfo; 597 ainfo.subtype = 0; 598 rc = tf_rm_get_all_info(&ainfo, TF_TCAM_TBL_TYPE_MAX); 599 if (rc && rc != -ENOTSUP) 600 return rc; 601 } 602 603 return 0; 604 } 605