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 18 struct tf; 19 20 /** 21 * TCAM DBs. 22 */ 23 static void *tcam_db[TF_DIR_MAX]; 24 25 /** 26 * TCAM Shadow DBs 27 */ 28 /* static void *shadow_tcam_db[TF_DIR_MAX]; */ 29 30 /** 31 * Init flag, set on bind and cleared on unbind 32 */ 33 static uint8_t init; 34 35 /** 36 * Shadow init flag, set on bind and cleared on unbind 37 */ 38 /* static uint8_t shadow_init; */ 39 40 int 41 tf_tcam_bind(struct tf *tfp, 42 struct tf_tcam_cfg_parms *parms) 43 { 44 int rc; 45 int i; 46 struct tf_tcam_resources *tcam_cnt; 47 struct tf_rm_create_db_parms db_cfg = { 0 }; 48 49 TF_CHECK_PARMS2(tfp, parms); 50 51 if (init) { 52 TFP_DRV_LOG(ERR, 53 "TCAM DB already initialized\n"); 54 return -EINVAL; 55 } 56 57 tcam_cnt = parms->resources->tcam_cnt; 58 if ((tcam_cnt[TF_DIR_RX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] % 2) || 59 (tcam_cnt[TF_DIR_TX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] % 2)) { 60 TFP_DRV_LOG(ERR, 61 "Number of WC TCAM entries cannot be odd num\n"); 62 return -EINVAL; 63 } 64 65 db_cfg.type = TF_DEVICE_MODULE_TYPE_TCAM; 66 db_cfg.num_elements = parms->num_elements; 67 db_cfg.cfg = parms->cfg; 68 69 for (i = 0; i < TF_DIR_MAX; i++) { 70 db_cfg.dir = i; 71 db_cfg.alloc_cnt = parms->resources->tcam_cnt[i].cnt; 72 db_cfg.rm_db = &tcam_db[i]; 73 rc = tf_rm_create_db(tfp, &db_cfg); 74 if (rc) { 75 TFP_DRV_LOG(ERR, 76 "%s: TCAM DB creation failed\n", 77 tf_dir_2_str(i)); 78 return rc; 79 } 80 } 81 82 init = 1; 83 84 TFP_DRV_LOG(INFO, 85 "TCAM - initialized\n"); 86 87 return 0; 88 } 89 90 int 91 tf_tcam_unbind(struct tf *tfp) 92 { 93 int rc; 94 int i; 95 struct tf_rm_free_db_parms fparms = { 0 }; 96 97 TF_CHECK_PARMS1(tfp); 98 99 /* Bail if nothing has been initialized */ 100 if (!init) { 101 TFP_DRV_LOG(INFO, 102 "No TCAM DBs created\n"); 103 return 0; 104 } 105 106 for (i = 0; i < TF_DIR_MAX; i++) { 107 fparms.dir = i; 108 fparms.rm_db = tcam_db[i]; 109 rc = tf_rm_free_db(tfp, &fparms); 110 if (rc) 111 return rc; 112 113 tcam_db[i] = NULL; 114 } 115 116 init = 0; 117 118 return 0; 119 } 120 121 int 122 tf_tcam_alloc(struct tf *tfp, 123 struct tf_tcam_alloc_parms *parms) 124 { 125 int rc; 126 struct tf_session *tfs; 127 struct tf_dev_info *dev; 128 struct tf_rm_allocate_parms aparms = { 0 }; 129 uint16_t num_slice_per_row = 1; 130 131 TF_CHECK_PARMS2(tfp, parms); 132 133 if (!init) { 134 TFP_DRV_LOG(ERR, 135 "%s: No TCAM DBs created\n", 136 tf_dir_2_str(parms->dir)); 137 return -EINVAL; 138 } 139 140 /* Retrieve the session information */ 141 rc = tf_session_get_session_internal(tfp, &tfs); 142 if (rc) 143 return rc; 144 145 /* Retrieve the device information */ 146 rc = tf_session_get_device(tfs, &dev); 147 if (rc) 148 return rc; 149 150 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 151 rc = -EOPNOTSUPP; 152 TFP_DRV_LOG(ERR, 153 "%s: Operation not supported, rc:%s\n", 154 tf_dir_2_str(parms->dir), 155 strerror(-rc)); 156 return rc; 157 } 158 159 /* Need to retrieve row size etc */ 160 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, 161 parms->type, 162 parms->key_size, 163 &num_slice_per_row); 164 if (rc) 165 return rc; 166 167 /* Allocate requested element */ 168 aparms.rm_db = tcam_db[parms->dir]; 169 aparms.db_index = parms->type; 170 aparms.priority = parms->priority; 171 aparms.index = (uint32_t *)&parms->idx; 172 rc = tf_rm_allocate(&aparms); 173 if (rc) { 174 TFP_DRV_LOG(ERR, 175 "%s: Failed tcam, type:%d\n", 176 tf_dir_2_str(parms->dir), 177 parms->type); 178 return rc; 179 } 180 181 if (parms->type == TF_TCAM_TBL_TYPE_WC_TCAM && 182 (parms->idx % 2) != 0) { 183 rc = tf_rm_allocate(&aparms); 184 if (rc) { 185 TFP_DRV_LOG(ERR, 186 "%s: Failed tcam, type:%d\n", 187 tf_dir_2_str(parms->dir), 188 parms->type); 189 return rc; 190 } 191 } 192 193 parms->idx *= num_slice_per_row; 194 195 return 0; 196 } 197 198 int 199 tf_tcam_free(struct tf *tfp, 200 struct tf_tcam_free_parms *parms) 201 { 202 int rc; 203 struct tf_session *tfs; 204 struct tf_dev_info *dev; 205 struct tf_rm_is_allocated_parms aparms = { 0 }; 206 struct tf_rm_free_parms fparms = { 0 }; 207 struct tf_rm_get_hcapi_parms hparms = { 0 }; 208 uint16_t num_slice_per_row = 1; 209 int allocated = 0; 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 0, 243 &num_slice_per_row); 244 if (rc) 245 return rc; 246 247 /* Check if element is in use */ 248 aparms.rm_db = tcam_db[parms->dir]; 249 aparms.db_index = parms->type; 250 aparms.index = parms->idx / num_slice_per_row; 251 aparms.allocated = &allocated; 252 rc = tf_rm_is_allocated(&aparms); 253 if (rc) 254 return rc; 255 256 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) { 257 TFP_DRV_LOG(ERR, 258 "%s: Entry already free, type:%d, index:%d\n", 259 tf_dir_2_str(parms->dir), 260 parms->type, 261 parms->idx); 262 return -EINVAL; 263 } 264 265 /* Free requested element */ 266 fparms.rm_db = tcam_db[parms->dir]; 267 fparms.db_index = parms->type; 268 fparms.index = parms->idx / num_slice_per_row; 269 rc = tf_rm_free(&fparms); 270 if (rc) { 271 TFP_DRV_LOG(ERR, 272 "%s: Free failed, type:%d, index:%d\n", 273 tf_dir_2_str(parms->dir), 274 parms->type, 275 parms->idx); 276 return rc; 277 } 278 279 if (parms->type == TF_TCAM_TBL_TYPE_WC_TCAM) { 280 int i; 281 282 for (i = -1; i < 3; i += 3) { 283 aparms.index += i; 284 rc = tf_rm_is_allocated(&aparms); 285 if (rc) 286 return rc; 287 288 if (allocated == TF_RM_ALLOCATED_ENTRY_IN_USE) { 289 /* Free requested element */ 290 fparms.index = aparms.index; 291 rc = tf_rm_free(&fparms); 292 if (rc) { 293 TFP_DRV_LOG(ERR, 294 "%s: Free failed, type:%d, index:%d\n", 295 tf_dir_2_str(parms->dir), 296 parms->type, 297 fparms.index); 298 return rc; 299 } 300 } 301 } 302 } 303 304 /* Convert TF type to HCAPI RM type */ 305 hparms.rm_db = tcam_db[parms->dir]; 306 hparms.db_index = parms->type; 307 hparms.hcapi_type = &parms->hcapi_type; 308 309 rc = tf_rm_get_hcapi_type(&hparms); 310 if (rc) 311 return rc; 312 313 rc = tf_msg_tcam_entry_free(tfp, parms); 314 if (rc) { 315 /* Log error */ 316 TFP_DRV_LOG(ERR, 317 "%s: %s: Entry %d free failed, rc:%s\n", 318 tf_dir_2_str(parms->dir), 319 tf_tcam_tbl_2_str(parms->type), 320 parms->idx, 321 strerror(-rc)); 322 return rc; 323 } 324 325 return 0; 326 } 327 328 int 329 tf_tcam_alloc_search(struct tf *tfp __rte_unused, 330 struct tf_tcam_alloc_search_parms *parms __rte_unused) 331 { 332 return 0; 333 } 334 335 int 336 tf_tcam_set(struct tf *tfp __rte_unused, 337 struct tf_tcam_set_parms *parms __rte_unused) 338 { 339 int rc; 340 struct tf_session *tfs; 341 struct tf_dev_info *dev; 342 struct tf_rm_is_allocated_parms aparms = { 0 }; 343 struct tf_rm_get_hcapi_parms hparms = { 0 }; 344 uint16_t num_slice_per_row = 1; 345 int allocated = 0; 346 347 TF_CHECK_PARMS2(tfp, parms); 348 349 if (!init) { 350 TFP_DRV_LOG(ERR, 351 "%s: No TCAM DBs created\n", 352 tf_dir_2_str(parms->dir)); 353 return -EINVAL; 354 } 355 356 /* Retrieve the session information */ 357 rc = tf_session_get_session_internal(tfp, &tfs); 358 if (rc) 359 return rc; 360 361 /* Retrieve the device information */ 362 rc = tf_session_get_device(tfs, &dev); 363 if (rc) 364 return rc; 365 366 if (dev->ops->tf_dev_get_tcam_slice_info == NULL) { 367 rc = -EOPNOTSUPP; 368 TFP_DRV_LOG(ERR, 369 "%s: Operation not supported, rc:%s\n", 370 tf_dir_2_str(parms->dir), 371 strerror(-rc)); 372 return rc; 373 } 374 375 /* Need to retrieve row size etc */ 376 rc = dev->ops->tf_dev_get_tcam_slice_info(tfp, 377 parms->type, 378 parms->key_size, 379 &num_slice_per_row); 380 if (rc) 381 return rc; 382 383 /* Check if element is in use */ 384 aparms.rm_db = tcam_db[parms->dir]; 385 aparms.db_index = parms->type; 386 aparms.index = parms->idx / num_slice_per_row; 387 aparms.allocated = &allocated; 388 rc = tf_rm_is_allocated(&aparms); 389 if (rc) 390 return rc; 391 392 if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) { 393 TFP_DRV_LOG(ERR, 394 "%s: Entry is not allocated, type:%d, index:%d\n", 395 tf_dir_2_str(parms->dir), 396 parms->type, 397 parms->idx); 398 return -EINVAL; 399 } 400 401 /* Convert TF type to HCAPI RM type */ 402 hparms.rm_db = tcam_db[parms->dir]; 403 hparms.db_index = parms->type; 404 hparms.hcapi_type = &parms->hcapi_type; 405 406 rc = tf_rm_get_hcapi_type(&hparms); 407 if (rc) 408 return rc; 409 410 rc = tf_msg_tcam_entry_set(tfp, parms); 411 if (rc) { 412 /* Log error */ 413 TFP_DRV_LOG(ERR, 414 "%s: %s: Entry %d set failed, rc:%s", 415 tf_dir_2_str(parms->dir), 416 tf_tcam_tbl_2_str(parms->type), 417 parms->idx, 418 strerror(-rc)); 419 return rc; 420 } 421 422 return 0; 423 } 424 425 int 426 tf_tcam_get(struct tf *tfp __rte_unused, 427 struct tf_tcam_get_parms *parms __rte_unused) 428 { 429 return 0; 430 } 431