1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2019-2021 Broadcom 3 * All rights reserved. 4 */ 5 6 #include <memory.h> 7 8 #include "bnxt.h" 9 #include "bnxt_mpc.h" 10 11 #include "tfc.h" 12 #include "tfo.h" 13 #include "tfc_em.h" 14 #include "tfc_cpm.h" 15 #include "tfc_msg.h" 16 #include "tfc_priv.h" 17 #include "cfa_types.h" 18 #include "cfa_mm.h" 19 #include "cfa_bld_mpc_field_ids.h" 20 #include "tfc_flow_handle.h" 21 #include "sys_util.h" 22 #include "tfc_util.h" 23 24 #include "tfc_debug.h" 25 26 #define TFC_EM_DYNAMIC_BUCKET_RECORD_SIZE 1 27 28 /* Enable cache configuration */ 29 #define TFC_EM_CACHE_OPT_EN 0 30 /* Enable dynamic bucket support */ 31 32 #ifdef EM_DEBUG 33 char const *tfc_mpc_error_string[] = { 34 "OK", 35 "Unsupported Opcode", 36 "Format", 37 "Scope", 38 "Address", 39 "Cache", 40 "EM Miss", 41 "Duplicate", 42 "No Events", 43 "EM Abort" 44 }; 45 #endif 46 47 static int tfc_em_insert_response(struct cfa_bld_mpcinfo *mpc_info, 48 struct bnxt_mpc_mbuf *mpc_msg_out, 49 uint8_t *rx_msg, 50 uint32_t *hash) 51 { 52 int i; 53 int rc; 54 struct cfa_mpc_data_obj fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_MAX_FLD]; 55 56 /* Process response */ 57 for (i = 0; i < CFA_BLD_MPC_EM_INSERT_CMP_MAX_FLD; i++) 58 fields_cmp[i].field_id = INVALID_U16; 59 60 fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_STATUS_FLD].field_id = 61 CFA_BLD_MPC_EM_INSERT_CMP_STATUS_FLD; 62 fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_BKT_NUM_FLD].field_id = 63 CFA_BLD_MPC_EM_INSERT_CMP_BKT_NUM_FLD; 64 fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_NUM_ENTRIES_FLD].field_id = 65 CFA_BLD_MPC_EM_INSERT_CMP_NUM_ENTRIES_FLD; 66 fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_TABLE_INDEX3_FLD].field_id = 67 CFA_BLD_MPC_EM_INSERT_CMP_TABLE_INDEX3_FLD; 68 fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_CHAIN_UPD_FLD].field_id = 69 CFA_BLD_MPC_EM_INSERT_CMP_CHAIN_UPD_FLD; 70 fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_HASH_MSB_FLD].field_id = 71 CFA_BLD_MPC_EM_INSERT_CMP_HASH_MSB_FLD; 72 73 rc = mpc_info->mpcops->cfa_bld_mpc_parse_em_insert(rx_msg, 74 mpc_msg_out->msg_size, 75 fields_cmp); 76 if (rc) { 77 PMD_DRV_LOG_LINE(ERR, "EM insert parse failed: %d", rc); 78 return -EINVAL; 79 } 80 if (fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_STATUS_FLD].val != CFA_BLD_MPC_OK) { 81 #ifdef EM_DEBUG 82 PMD_DRV_LOG_LINE(ERR, "MPC failed with error:%s", 83 tfc_mpc_error_string[(uint32_t) 84 fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_STATUS_FLD].val]); 85 #else 86 PMD_DRV_LOG_LINE(ERR, "MPC failed with status code:%d", 87 (uint32_t) 88 fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_STATUS_FLD].val); 89 #endif 90 rc = ((int)fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_STATUS_FLD].val) * -1; 91 return rc; 92 } 93 94 #if TFC_EM_DYNAMIC_BUCKET_EN 95 /* If the dynamic bucket is unused then free it */ 96 if (bucket_offset && fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_CHAIN_UPD_FLD].val == 0) { 97 /* Free allocated resources */ 98 fparms.record_offset = bucket_offset; 99 fparms.num_contig_records = TFC_EM_DYNAMIC_BUCKET_RECORD_SIZE; 100 101 rc = cfa_mm_free(cmm, &fparms); 102 bucket_offset = 0; 103 } 104 #endif 105 106 *hash = fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_TABLE_INDEX3_FLD].val; 107 108 return rc; 109 } 110 111 int tfc_em_insert(struct tfc *tfcp, uint8_t tsid, 112 struct tfc_em_insert_parms *parms) 113 { 114 int rc; 115 int cleanup_rc; 116 struct tfc_cpm *cpm_lkup = NULL; 117 struct tfc_cpm *cpm_act = NULL; 118 uint16_t pool_id; 119 struct tfc_cmm *cmm = NULL; 120 bool is_bs_owner; 121 struct tfc_ts_mem_cfg mem_cfg; 122 uint32_t entry_offset; 123 uint32_t num_contig_records; 124 struct bnxt_mpc_mbuf mpc_msg_in; 125 struct bnxt_mpc_mbuf mpc_msg_out; 126 struct tfc_ts_pool_info pi; 127 struct cfa_mm_free_parms fparms; 128 struct cfa_mm_alloc_parms aparms; 129 uint32_t buff_len; 130 uint8_t tx_msg[TFC_MPC_MAX_TX_BYTES]; 131 uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES]; 132 uint32_t msg_count = BNXT_MPC_COMP_MSG_COUNT; 133 uint32_t i; 134 uint32_t hash = 0; 135 struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_MAX_FLD]; 136 bool is_shared; 137 struct cfa_bld_mpcinfo *mpc_info; 138 bool valid; 139 uint16_t max_pools; 140 #if TFC_EM_DYNAMIC_BUCKET_EN 141 struct cfa_mm_alloc_parms bucket_aparms; 142 bool shared = false; 143 uint32_t bucket_offset; 144 #endif 145 146 tfo_mpcinfo_get(tfcp->tfo, &mpc_info); 147 148 rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, &max_pools); 149 if (unlikely(rc)) { 150 PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc)); 151 return -EINVAL; 152 } 153 if (unlikely(!valid)) { 154 PMD_DRV_LOG_LINE(ERR, "tsid not allocated %d", tsid); 155 return -EINVAL; 156 } 157 if (unlikely(!max_pools)) { 158 PMD_DRV_LOG_LINE(ERR, "tsid(%d) Max pools must be greater than 0 %d", 159 tsid, max_pools); 160 return -EINVAL; 161 } 162 163 /* Check that MPC APIs are bound */ 164 if (unlikely(mpc_info->mpcops == NULL)) { 165 PMD_DRV_LOG_LINE(ERR, "MPC not initialized"); 166 return -EINVAL; 167 } 168 169 rc = tfo_ts_get_mem_cfg(tfcp->tfo, tsid, 170 parms->dir, 171 CFA_REGION_TYPE_LKUP, 172 &is_bs_owner, 173 &mem_cfg); /* Gets rec_cnt */ 174 if (unlikely(rc)) { 175 PMD_DRV_LOG_LINE(ERR, "tfo_ts_get_mem_cfg() failed: %s", 176 strerror(-rc)); 177 return -EINVAL; 178 } 179 180 181 /* Get CPM instances */ 182 rc = tfo_ts_get_cpm_inst(tfcp->tfo, tsid, parms->dir, &cpm_lkup, &cpm_act); 183 if (unlikely(rc)) { 184 PMD_DRV_LOG_LINE(ERR, "failed to get CPM instances: %s", 185 strerror(-rc)); 186 return -EINVAL; 187 } 188 189 num_contig_records = 1 << next_pow2(parms->lkup_key_sz_words); 190 191 tfo_ts_get_pool_info(tfcp->tfo, tsid, parms->dir, &pi); 192 193 rc = tfc_cpm_get_avail_pool(cpm_lkup, &pool_id); 194 195 /* if no pool available locally or all pools full */ 196 if (rc) { 197 /* Allocate a pool */ 198 struct cfa_mm_query_parms qparms; 199 struct cfa_mm_open_parms oparms; 200 uint16_t fid; 201 202 /* There is only 1 pool for a non-shared table scope and 203 * it is full. 204 */ 205 if (!is_shared) { 206 PMD_DRV_LOG_LINE(ERR, "no records remain"); 207 return -ENOMEM; 208 } 209 210 rc = tfc_get_fid(tfcp, &fid); 211 if (unlikely(rc)) 212 return rc; 213 214 rc = tfc_tbl_scope_pool_alloc(tfcp, 215 fid, 216 tsid, 217 CFA_REGION_TYPE_LKUP, 218 parms->dir, 219 NULL, 220 &pool_id); 221 222 if (unlikely(rc)) { 223 PMD_DRV_LOG_LINE(ERR, "table scope pool alloc failed: %s", 224 strerror(-rc)); 225 return -EINVAL; 226 } 227 228 /* 229 * Create pool CMM instance. 230 * rec_cnt is the total number of records which includes static buckets, 231 */ 232 qparms.max_records = (mem_cfg.rec_cnt - mem_cfg.lkup_rec_start_offset) / max_pools; 233 qparms.max_contig_records = pi.lkup_max_contig_rec; 234 rc = cfa_mm_query(&qparms); 235 if (unlikely(rc)) { 236 PMD_DRV_LOG_LINE(ERR, "cfa_mm_query() failed: %s", strerror(-rc)); 237 rte_free(cmm); 238 return -EINVAL; 239 } 240 241 cmm = rte_zmalloc("tf", qparms.db_size, 0); 242 oparms.db_mem_size = qparms.db_size; 243 oparms.max_contig_records = qparms.max_contig_records; 244 oparms.max_records = qparms.max_records; 245 rc = cfa_mm_open(cmm, &oparms); 246 if (unlikely(rc)) { 247 PMD_DRV_LOG_LINE(ERR, "cfa_mm_open() failed: %s", strerror(-rc)); 248 rte_free(cmm); 249 return -EINVAL; 250 } 251 252 /* Store CMM instance in the CPM */ 253 rc = tfc_cpm_set_cmm_inst(cpm_lkup, pool_id, cmm); 254 if (unlikely(rc)) { 255 PMD_DRV_LOG_LINE(ERR, "tfc_cpm_set_cmm_inst() failed: %s", 256 strerror(-rc)); 257 return -EINVAL; 258 } 259 260 /* Store the updated pool information */ 261 tfo_ts_set_pool_info(tfcp->tfo, tsid, parms->dir, &pi); 262 263 } else { 264 /* Get the pool instance and allocate an lkup rec index from the pool */ 265 rc = tfc_cpm_get_cmm_inst(cpm_lkup, pool_id, &cmm); 266 if (unlikely(rc)) { 267 PMD_DRV_LOG_LINE(ERR, "tfc_cpm_get_cmm_inst() failed: %s", 268 strerror(-rc)); 269 return -EINVAL; 270 } 271 } 272 273 aparms.num_contig_records = num_contig_records; 274 rc = cfa_mm_alloc(cmm, &aparms); 275 if (unlikely(rc)) { 276 PMD_DRV_LOG_LINE(ERR, "cfa_mm_alloc() failed: %s", strerror(-rc)); 277 return -EINVAL; 278 } 279 280 #if TFC_EM_DYNAMIC_BUCKET_EN 281 if (!shared) { 282 /* Allocate dynamic bucket */ 283 bucket_aparms.num_contig_records = TFC_EM_DYNAMIC_BUCKET_RECORD_SIZE; 284 rc = cfa_mm_alloc(cmm, &bucket_aparms); 285 if (unlikely(rc)) { 286 PMD_DRV_LOG_LINE(ERR, 287 "cfa_mm_alloc() for dynamic bucket failed: %s\n", 288 strerror(-rc)); 289 return -EINVAL; 290 } 291 292 bucket_offset = bucket_aparms.record_offset; 293 } 294 #endif 295 296 CREATE_OFFSET(&entry_offset, pi.lkup_pool_sz_exp, pool_id, aparms.record_offset); 297 298 /* Create MPC EM insert command using builder */ 299 for (i = 0; i < CFA_BLD_MPC_EM_INSERT_CMD_MAX_FLD; i++) 300 fields_cmd[i].field_id = INVALID_U16; 301 302 fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_OPAQUE_FLD].field_id = 303 CFA_BLD_MPC_EM_INSERT_CMD_OPAQUE_FLD; 304 fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_OPAQUE_FLD].val = 0xAA; 305 306 fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_TABLE_SCOPE_FLD].field_id = 307 CFA_BLD_MPC_EM_INSERT_CMD_TABLE_SCOPE_FLD; 308 fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_TABLE_SCOPE_FLD].val = tsid; 309 310 fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_DATA_SIZE_FLD].field_id = 311 CFA_BLD_MPC_EM_INSERT_CMD_DATA_SIZE_FLD; 312 fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_DATA_SIZE_FLD].val = parms->lkup_key_sz_words; 313 314 /* LREC address */ 315 fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_TABLE_INDEX_FLD].field_id = 316 CFA_BLD_MPC_EM_INSERT_CMD_TABLE_INDEX_FLD; 317 fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_TABLE_INDEX_FLD].val = entry_offset + 318 mem_cfg.lkup_rec_start_offset; 319 320 #if TFC_EM_DYNAMIC_BUCKET_EN 321 /* Dynamic bucket address */ 322 fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_TABLE_INDEX2_FLD].field_id = 323 CFA_BLD_MPC_EM_INSERT_CMD_TABLE_INDEX2_FLD; 324 fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_TABLE_INDEX2_FLD].val = bucket_offset; 325 #endif 326 fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_REPLACE_FLD].field_id = 327 CFA_BLD_MPC_EM_INSERT_CMD_REPLACE_FLD; 328 fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_REPLACE_FLD].val = 0x0; 329 330 buff_len = TFC_MPC_MAX_TX_BYTES; 331 332 rc = mpc_info->mpcops->cfa_bld_mpc_build_em_insert(tx_msg, 333 &buff_len, 334 parms->lkup_key_data, 335 fields_cmd); 336 337 if (unlikely(rc)) { 338 PMD_DRV_LOG_LINE(ERR, "EM insert build failed: %s", 339 strerror(-rc)); 340 goto cleanup; 341 } 342 343 /* Send MPC */ 344 mpc_msg_in.chnl_id = (parms->dir == CFA_DIR_TX ? 345 HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_TE_CFA : 346 HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_RE_CFA); 347 mpc_msg_in.msg_data = &tx_msg[TFC_MPC_HEADER_SIZE_BYTES]; 348 mpc_msg_in.msg_size = (parms->lkup_key_sz_words * 32) + 349 TFC_MPC_HEADER_SIZE_BYTES; 350 mpc_msg_out.cmp_type = CMPL_BASE_TYPE_MID_PATH_LONG; 351 mpc_msg_out.msg_data = &rx_msg[TFC_MPC_HEADER_SIZE_BYTES]; 352 mpc_msg_out.msg_size = TFC_MPC_MAX_RX_BYTES; 353 354 rc = tfc_mpc_send(tfcp->bp, 355 &mpc_msg_in, 356 &mpc_msg_out, 357 &msg_count, 358 TFC_MPC_EM_INSERT, 359 parms->batch_info); 360 361 if (unlikely(rc)) { 362 PMD_DRV_LOG_LINE(ERR, "EM insert send failed: %s", strerror(-rc)); 363 goto cleanup; 364 } 365 366 if (parms->batch_info && !parms->batch_info->enabled) { 367 rc = tfc_em_insert_response(mpc_info, 368 &mpc_msg_out, 369 rx_msg, 370 &hash); 371 if (rc) { 372 PMD_DRV_LOG_LINE(ERR, 373 "EM insert tfc_em_insert_response() failed: %d", 374 rc); 375 goto cleanup; 376 } 377 } 378 379 *parms->flow_handle = tfc_create_flow_handle(tsid, 380 num_contig_records, /* Based on key size */ 381 entry_offset, 382 hash); 383 384 /* Update CPM info so it will determine best pool to use next alloc */ 385 rc = tfc_cpm_set_usage(cpm_lkup, pool_id, aparms.used_count, aparms.all_used); 386 if (unlikely(rc)) { 387 PMD_DRV_LOG_LINE(ERR, 388 "EM insert tfc_cpm_set_usage() failed: %d", 389 rc); 390 goto cleanup; 391 } 392 393 if (!rc) 394 return 0; 395 396 cleanup: 397 /* 398 * Preserve the rc from the actual error rather than 399 * an error during cleanup. 400 */ 401 #if TFC_EM_DYNAMIC_BUCKET_EN 402 /* If the dynamic bucket set then free it */ 403 if (bucket_offset) { 404 /* Free allocated resources */ 405 fparms.record_offset = bucket_offset; 406 fparms.num_contig_records = TFC_EM_DYNAMIC_BUCKET_RECORD_SIZE; 407 408 cleanup_rc = cfa_mm_free(cmm, &fparms); 409 } 410 #endif 411 412 /* Free allocated resources */ 413 fparms.record_offset = aparms.record_offset; 414 fparms.num_contig_records = num_contig_records; 415 cleanup_rc = cfa_mm_free(cmm, &fparms); 416 if (cleanup_rc != 0) 417 PMD_DRV_LOG_LINE(ERR, "failed to free entry: %s", strerror(-rc)); 418 419 cleanup_rc = tfc_cpm_set_usage(cpm_lkup, pool_id, fparms.used_count, false); 420 if (cleanup_rc != 0) 421 PMD_DRV_LOG_LINE(ERR, "failed to set usage: %s", strerror(-rc)); 422 423 return rc; 424 } 425 426 static int tfc_em_delete_response(struct cfa_bld_mpcinfo *mpc_info, 427 struct bnxt_mpc_mbuf *mpc_msg_out, 428 uint8_t *rx_msg 429 #if TFC_EM_DYNAMIC_BUCKET_EN 430 , bool *db_unused, 431 uint32_t *db_offset 432 #endif 433 ) 434 { 435 int i; 436 int rc; 437 struct cfa_mpc_data_obj fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_MAX_FLD]; 438 439 /* Process response */ 440 for (i = 0; i < CFA_BLD_MPC_EM_DELETE_CMP_MAX_FLD; i++) 441 fields_cmp[i].field_id = INVALID_U16; 442 443 fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_STATUS_FLD].field_id = 444 CFA_BLD_MPC_EM_DELETE_CMP_STATUS_FLD; 445 #ifdef EM_DEBUF 446 fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_BKT_NUM_FLD].field_id = 447 CFA_BLD_MPC_EM_DELETE_CMP_BKT_NUM_FLD; 448 fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_NUM_ENTRIES_FLD].field_id = 449 CFA_BLD_MPC_EM_DELETE_CMP_NUM_ENTRIES_FLD; 450 fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_TABLE_INDEX3_FLD].field_id = 451 CFA_BLD_MPC_EM_DELETE_CMP_TABLE_INDEX3_FLD; 452 fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_CHAIN_UPD_FLD].field_id = 453 CFA_BLD_MPC_EM_DELETE_CMP_CHAIN_UPD_FLD; 454 #endif 455 rc = mpc_info->mpcops->cfa_bld_mpc_parse_em_delete(rx_msg, 456 mpc_msg_out->msg_size, 457 fields_cmp); 458 if (rc) { 459 PMD_DRV_LOG_LINE(ERR, "delete parse failed: %s", strerror(-rc)); 460 return -EINVAL; 461 } 462 463 if (fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_STATUS_FLD].val != CFA_BLD_MPC_OK) { 464 #ifdef EM_DEBUG 465 PMD_DRV_LOG_LINE(ERR, "MPC failed with error:%s", 466 tfc_mpc_error_string[(uint32_t) 467 fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_STATUS_FLD].val]); 468 #else 469 PMD_DRV_LOG_LINE(ERR, "MPC failed with status code:%d", 470 (uint32_t) 471 fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_STATUS_FLD].val); 472 #endif 473 rc = ((int)fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_STATUS_FLD].val) * -1; 474 return rc; 475 } 476 477 #if TFC_EM_DYNAMIC_BUCKET_EN 478 *db_unused = fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_CHAIN_UPD_FLD].val == 1 ? 479 true : false; 480 *db_offset = fields[CFA_BLD_MPC_EM_DELETE_CMP_TABLE_INDEX3_FLD].val; 481 #endif 482 return 0; 483 } 484 485 int tfc_em_delete_raw(struct tfc *tfcp, 486 uint8_t tsid, 487 enum cfa_dir dir, 488 uint32_t offset, 489 uint32_t static_bucket, 490 struct tfc_mpc_batch_info_t *batch_info 491 #if TFC_EM_DYNAMIC_BUCKET_EN 492 , bool *db_unused, 493 uint32_t *db_offset 494 #endif 495 ) 496 { 497 int rc = 0; 498 uint32_t buff_len; 499 struct bnxt_mpc_mbuf mpc_msg_in; 500 struct bnxt_mpc_mbuf mpc_msg_out; 501 uint8_t tx_msg[TFC_MPC_MAX_TX_BYTES]; 502 uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES]; 503 uint32_t msg_count = BNXT_MPC_COMP_MSG_COUNT; 504 int i; 505 struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_MAX_FLD]; 506 struct cfa_bld_mpcinfo *mpc_info; 507 508 tfo_mpcinfo_get(tfcp->tfo, &mpc_info); 509 if (mpc_info->mpcops == NULL) { 510 PMD_DRV_LOG_LINE(ERR, "MPC not initialized"); 511 return -EINVAL; 512 } 513 514 /* Create MPC EM delete command using builder */ 515 for (i = 0; i < CFA_BLD_MPC_EM_DELETE_CMD_MAX_FLD; i++) 516 fields_cmd[i].field_id = INVALID_U16; 517 518 fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_OPAQUE_FLD].field_id = 519 CFA_BLD_MPC_EM_DELETE_CMD_OPAQUE_FLD; 520 fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_OPAQUE_FLD].val = 0xAA; 521 fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_SCOPE_FLD].field_id = 522 CFA_BLD_MPC_EM_DELETE_CMD_TABLE_SCOPE_FLD; 523 fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_SCOPE_FLD].val = tsid; 524 525 /* LREC address to delete */ 526 fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX_FLD].field_id = 527 CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX_FLD; 528 fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX_FLD].val = offset; 529 530 fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX2_FLD].field_id = 531 CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX2_FLD; 532 fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX2_FLD].val = static_bucket; 533 534 #if TFC_EM_DYNAMIC_BUCKET_EN 535 /* Static bucket address */ 536 fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX2_FLD].field_id = 537 CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX2_FLD; 538 fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX2_FLD].val = 0x01222222; 539 #endif 540 541 /* Create MPC EM delete command using builder */ 542 buff_len = TFC_MPC_MAX_TX_BYTES; 543 544 rc = mpc_info->mpcops->cfa_bld_mpc_build_em_delete(tx_msg, 545 &buff_len, 546 fields_cmd); 547 548 if (rc) { 549 PMD_DRV_LOG_LINE(ERR, "delete mpc build failed: %s", 550 strerror(-rc)); 551 return -EINVAL; 552 } 553 554 /* Send MPC */ 555 mpc_msg_in.chnl_id = (dir == CFA_DIR_TX ? 556 HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_TE_CFA : 557 HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_RE_CFA); 558 mpc_msg_in.msg_data = &tx_msg[TFC_MPC_HEADER_SIZE_BYTES]; 559 mpc_msg_in.msg_size = 16; 560 mpc_msg_out.cmp_type = CMPL_BASE_TYPE_MID_PATH_LONG; 561 mpc_msg_out.msg_data = &rx_msg[TFC_MPC_HEADER_SIZE_BYTES]; 562 mpc_msg_out.msg_size = TFC_MPC_MAX_RX_BYTES; 563 564 rc = tfc_mpc_send(tfcp->bp, 565 &mpc_msg_in, 566 &mpc_msg_out, 567 &msg_count, 568 TFC_MPC_EM_DELETE, 569 batch_info); 570 if (rc) { 571 PMD_DRV_LOG_LINE(ERR, "delete MPC send failed: %s", 572 strerror(-rc)); 573 return -EINVAL; 574 } 575 576 if (!batch_info->enabled) 577 rc = tfc_em_delete_response(mpc_info, 578 &mpc_msg_out, 579 rx_msg 580 #if TFC_EM_DYNAMIC_BUCKET_EN 581 , db_unused, 582 db_offset 583 #endif 584 ); 585 return rc; 586 } 587 588 int tfc_em_delete(struct tfc *tfcp, struct tfc_em_delete_parms *parms) 589 { 590 int rc = 0; 591 uint32_t static_bucket; 592 uint32_t pool_id; 593 struct tfc_cpm *cpm_lkup = NULL; 594 struct tfc_cpm *cpm_act = NULL; 595 struct tfc_cmm *cmm; 596 uint32_t record_offset; 597 uint32_t record_size; 598 struct cfa_mm_free_parms fparms; 599 uint8_t tsid; 600 bool is_shared; 601 struct tfc_ts_pool_info pi; 602 bool is_bs_owner; 603 struct tfc_ts_mem_cfg mem_cfg; 604 bool valid; 605 606 #if TFC_EM_DYNAMIC_BUCKET_EN 607 bool db_unused; 608 uint32_t db_offset; 609 #endif 610 /* Get fields from MPC Flow handle */ 611 tfc_get_fields_from_flow_handle(&parms->flow_handle, 612 &tsid, 613 &record_size, 614 &record_offset, 615 &static_bucket); 616 617 rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL); 618 if (rc != 0) { 619 PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", 620 strerror(-rc)); 621 return -EINVAL; 622 } 623 if (!valid) { 624 PMD_DRV_LOG_LINE(ERR, "tsid not allocated %d", tsid); 625 return -EINVAL; 626 } 627 628 tfo_ts_get_pool_info(tfcp->tfo, tsid, parms->dir, &pi); 629 630 pool_id = TFC_FLOW_GET_POOL_ID(record_offset, pi.lkup_pool_sz_exp); 631 632 rc = tfo_ts_get_mem_cfg(tfcp->tfo, tsid, 633 parms->dir, 634 CFA_REGION_TYPE_LKUP, 635 &is_bs_owner, 636 &mem_cfg); /* Gets rec_cnt */ 637 if (rc != 0) { 638 PMD_DRV_LOG_LINE(ERR, "tfo_ts_get_mem_cfg() failed: %s", 639 strerror(-rc)); 640 return -EINVAL; 641 } 642 643 /* Get CPM instance for this table scope */ 644 rc = tfo_ts_get_cpm_inst(tfcp->tfo, tsid, parms->dir, &cpm_lkup, &cpm_act); 645 if (rc != 0) { 646 PMD_DRV_LOG_LINE(ERR, "failed to get CMM instance: %s", 647 strerror(-rc)); 648 return -EINVAL; 649 } 650 651 rc = tfc_em_delete_raw(tfcp, 652 tsid, 653 parms->dir, 654 record_offset + 655 mem_cfg.lkup_rec_start_offset, 656 static_bucket, 657 parms->batch_info 658 #if TFC_EM_DYNAMIC_BUCKET_EN 659 , &db_unused, 660 &db_offset 661 #endif 662 ); 663 664 #if TFC_EM_DYNAMIC_BUCKET_EN 665 /* If the dynamic bucket is unused then free it */ 666 if (db_unused) { 667 /* Free allocated resources */ 668 fparms.record_offset = db_offset; 669 fparms.num_contig_records = TFC_EM_DYNAMIC_BUCKET_RECORD_SIZE; 670 671 rc = cfa_mm_free(cmm, &fparms); 672 } 673 #endif 674 675 rc = tfc_cpm_get_cmm_inst(cpm_lkup, pool_id, &cmm); 676 if (rc != 0) { 677 PMD_DRV_LOG_LINE(ERR, "failed to get CMM instance: %s", 678 strerror(-rc)); 679 return -EINVAL; 680 } 681 682 fparms.record_offset = record_offset; 683 fparms.num_contig_records = 1 << next_pow2(record_size); 684 685 rc = cfa_mm_free(cmm, &fparms); 686 if (rc != 0) { 687 PMD_DRV_LOG_LINE(ERR, "failed to free CMM instance: %s", 688 strerror(-rc)); 689 return -EINVAL; 690 } 691 692 rc = tfc_cpm_set_usage(cpm_lkup, pool_id, fparms.used_count, false); 693 if (rc != 0) 694 PMD_DRV_LOG_LINE(ERR, "failed to set usage: %s", 695 strerror(-rc)); 696 697 return rc; 698 } 699 700 static void bucket_decode(uint32_t *bucket_ptr, 701 struct bucket_info_t *bucket_info) 702 { 703 int i; 704 int offset = 0; 705 706 bucket_info->valid = false; 707 bucket_info->chain = tfc_getbits(bucket_ptr, 254, 1); 708 bucket_info->chain_ptr = tfc_getbits(bucket_ptr, 228, 26); 709 710 if (bucket_info->chain || 711 bucket_info->chain_ptr) 712 bucket_info->valid = true; 713 714 for (i = 0; i < TFC_BUCKET_ENTRIES; i++) { 715 bucket_info->entries[i].entry_ptr = tfc_getbits(bucket_ptr, offset, 26); 716 offset += 26; 717 bucket_info->entries[i].hash_msb = tfc_getbits(bucket_ptr, offset, 12); 718 offset += 12; 719 if (bucket_info->entries[i].hash_msb || 720 bucket_info->entries[i].entry_ptr) { 721 bucket_info->valid = true; 722 } 723 } 724 } 725 726 int tfc_em_delete_entries_by_pool_id(struct tfc *tfcp, 727 uint8_t tsid, 728 enum cfa_dir dir, 729 uint16_t pool_id, 730 uint8_t debug, 731 uint8_t *data) 732 { 733 uint32_t offset; 734 int rc; 735 int i; 736 int j; 737 struct bucket_info_t bucket; 738 struct tfc_ts_pool_info pi; 739 struct tfc_ts_mem_cfg mem_cfg; 740 bool is_bs_owner; 741 #if TFC_EM_DYNAMIC_BUCKET_EN 742 bool db_unused; 743 uint32_t db_offset; 744 #endif 745 struct tfc_mpc_batch_info_t batch_info; 746 747 memset(&batch_info, 0, sizeof(batch_info)); 748 749 /* Get memory info */ 750 rc = tfo_ts_get_pool_info(tfcp->tfo, tsid, dir, &pi); 751 if (rc) { 752 PMD_DRV_LOG_LINE(ERR, 753 "Failed to get pool info for tsid:%d", 754 tsid); 755 return -EINVAL; 756 } 757 758 rc = tfo_ts_get_mem_cfg(tfcp->tfo, 759 tsid, 760 dir, 761 CFA_REGION_TYPE_LKUP, 762 &is_bs_owner, 763 &mem_cfg); 764 if (rc != 0) { 765 PMD_DRV_LOG_LINE(ERR, "tfo_ts_get_mem_cfg() failed: %s", 766 strerror(-rc)); 767 return -EINVAL; 768 } 769 770 /* Read static bucket entries */ 771 for (offset = 0; offset < mem_cfg.lkup_rec_start_offset; ) { 772 /* 773 * Read static bucket region of lookup table. 774 * A static bucket is 32B in size and must be 32B aligned. 775 * A table read can read up to 4 * 32B so in the interest 776 * of efficiency the max read size will be used. 777 */ 778 rc = tfc_mpc_table_read(tfcp, 779 tsid, 780 dir, 781 CFA_REGION_TYPE_LKUP, 782 offset, 783 TFC_MPC_MAX_TABLE_READ_WORDS, 784 data, 785 debug); 786 787 if (rc != 0) { 788 PMD_DRV_LOG_LINE(ERR, 789 "tfc_mpc_table_read() failed for offset:%d: %s", 790 offset, strerror(-rc)); 791 return -EINVAL; 792 } 793 794 for (i = 0; (i < TFC_MPC_MAX_TABLE_READ_WORDS) && 795 (offset < mem_cfg.lkup_rec_start_offset); i++) { 796 /* Walk static bucket entry pointers */ 797 bucket_decode((uint32_t *)&data[i * TFC_MPC_BYTES_PER_WORD], 798 &bucket); 799 800 for (j = 0; j < TFC_BUCKET_ENTRIES; j++) { 801 if (bucket.entries[j].entry_ptr != 0 && 802 pool_id == (bucket.entries[j].entry_ptr >> pi.lkup_pool_sz_exp)) { 803 /* Delete EM entry */ 804 rc = tfc_em_delete_raw(tfcp, 805 tsid, 806 dir, 807 bucket.entries[j].entry_ptr, 808 offset, 809 &batch_info 810 #if TFC_EM_DYNAMIC_BUCKET_EN 811 , &db_unused, 812 &db_offset 813 #endif 814 ); 815 if (rc) { 816 PMD_DRV_LOG_LINE(ERR, 817 "EM delete failed for offset:0x%08x %d", 818 offset, rc); 819 return -1; 820 } 821 } 822 } 823 824 offset++; 825 } 826 } 827 828 return rc; 829 } 830 831 int tfc_mpc_send(struct bnxt *bp, 832 struct bnxt_mpc_mbuf *in_msg, 833 struct bnxt_mpc_mbuf *out_msg, 834 uint32_t *opaque, 835 int type, 836 struct tfc_mpc_batch_info_t *batch_info) 837 { 838 int rc; 839 bool enabled = false; 840 841 if (batch_info) 842 enabled = batch_info->enabled; 843 844 rc = bnxt_mpc_send(bp, in_msg, out_msg, opaque, enabled); 845 846 if (rc) 847 return rc; 848 849 if (batch_info && batch_info->enabled) { 850 memcpy(&batch_info->comp_info[batch_info->count].out_msg, 851 out_msg, 852 sizeof(*out_msg)); 853 batch_info->comp_info[batch_info->count].mpc_queue = 854 bp->mpc->mpc_txq[in_msg->chnl_id]; 855 batch_info->comp_info[batch_info->count].type = type; 856 batch_info->count++; 857 } 858 859 return 0; 860 } 861 862 static int tfc_mpc_process_completions(uint8_t *rx_msg, 863 struct tfc_mpc_comp_info_t *comp_info) 864 { 865 int rc; 866 int retry = BNXT_MPC_RX_RETRY; 867 868 comp_info->out_msg.msg_data = rx_msg; 869 870 do { 871 rc = bnxt_mpc_cmd_cmpl(comp_info->mpc_queue, 872 &comp_info->out_msg); 873 874 if (likely(rc == 1)) { 875 #ifdef MPC_DEBUG 876 if (unlikely(retry != BNXT_MPC_RX_RETRY)) 877 PMD_DRV_LOG_LINE(ERR, "Retrys:%d", 878 BNXT_MPC_RX_RETRY - retry); 879 #endif 880 return 0; 881 } 882 #ifdef MPC_DEBUG 883 PMD_DRV_LOG_LINE(ERR, 884 "Received zero or more than one completion:%d", 885 rc); 886 #endif 887 retry--; 888 } while (retry); 889 890 PMD_DRV_LOG_LINE(ERR, "Retry timeout rc:%d", rc); 891 return -1; 892 } 893 894 int tfc_mpc_batch_start(struct tfc_mpc_batch_info_t *batch_info) 895 { 896 if (unlikely(batch_info->enabled)) 897 return -EBUSY; 898 899 batch_info->enabled = true; 900 batch_info->count = 0; 901 batch_info->error = false; 902 return 0; 903 } 904 905 bool tfc_mpc_batch_started(struct tfc_mpc_batch_info_t *batch_info) 906 { 907 if (unlikely(!batch_info)) 908 return false; 909 910 return (batch_info->enabled && batch_info->count > 0); 911 } 912 913 int tfc_mpc_batch_end(struct tfc *tfcp, 914 struct tfc_mpc_batch_info_t *batch_info) 915 { 916 uint32_t i; 917 int rc; 918 uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES]; 919 struct cfa_bld_mpcinfo *mpc_info; 920 uint32_t hash = 0; 921 #if TFC_EM_DYNAMIC_BUCKET_EN 922 bool *db_unused; 923 uint32_t *db_offset; 924 #endif 925 926 if (unlikely(!batch_info->enabled)) 927 return -EBUSY; 928 929 if (unlikely(!batch_info->count)) { 930 batch_info->enabled = false; 931 return 0; 932 } 933 934 tfo_mpcinfo_get(tfcp->tfo, &mpc_info); 935 936 if (unlikely(mpc_info->mpcops == NULL)) { 937 PMD_DRV_LOG_LINE(ERR, "MPC not initialized"); 938 return -EINVAL; 939 } 940 941 if (batch_info->count < (BNXT_MPC_COMP_MAX_COUNT / 4)) 942 rte_delay_us_block(BNXT_MPC_RX_US_DELAY * 4); 943 944 for (i = 0; i < batch_info->count; i++) { 945 rc = tfc_mpc_process_completions(&rx_msg[TFC_MPC_HEADER_SIZE_BYTES], 946 &batch_info->comp_info[i]); 947 if (unlikely(rc)) 948 return -1; 949 950 951 switch (batch_info->comp_info[i].type) { 952 case TFC_MPC_EM_INSERT: 953 rc = tfc_em_insert_response(mpc_info, 954 &batch_info->comp_info[i].out_msg, 955 rx_msg, 956 &hash); 957 /* 958 * If the handle is non NULL it should reference a 959 * flow DB entry that requires the flow_handle 960 * contained within to be updated. 961 */ 962 batch_info->em_hdl[i] = 963 tfc_create_flow_handle2(batch_info->em_hdl[i], 964 hash); 965 batch_info->em_error = rc; 966 break; 967 case TFC_MPC_EM_DELETE: 968 rc = tfc_em_delete_response(mpc_info, 969 &batch_info->comp_info[i].out_msg, 970 rx_msg 971 #if TFC_EM_DYNAMIC_BUCKET_EN 972 , bool *db_unused, 973 uint32_t *db_offset 974 #endif 975 ); 976 break; 977 case TFC_MPC_TABLE_WRITE: 978 rc = tfc_act_set_response(mpc_info, 979 &batch_info->comp_info[i].out_msg, 980 rx_msg); 981 break; 982 case TFC_MPC_TABLE_READ: 983 rc = tfc_act_get_only_response(mpc_info, 984 &batch_info->comp_info[i].out_msg, 985 rx_msg, 986 &batch_info->comp_info[i].read_words); 987 break; 988 989 case TFC_MPC_TABLE_READ_CLEAR: 990 rc = tfc_act_get_clear_response(mpc_info, 991 &batch_info->comp_info[i].out_msg, 992 rx_msg, 993 &batch_info->comp_info[i].read_words); 994 break; 995 996 default: 997 PMD_DRV_LOG_LINE(ERR, "MPC Batch not supported for type: %d", 998 batch_info->comp_info[i].type); 999 return -1; 1000 } 1001 1002 batch_info->result[i] = rc; 1003 if (rc) 1004 batch_info->error = true; 1005 } 1006 1007 batch_info->enabled = false; 1008 batch_info->count = 0; 1009 1010 return 0; 1011 } 1012