1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2014-2023 Broadcom 3 * All rights reserved. 4 */ 5 6 #include <rte_common.h> 7 #include <rte_malloc.h> 8 #include <rte_log.h> 9 #include "bnxt.h" 10 #include "bnxt_ulp.h" 11 #include "bnxt_ulp_utils.h" 12 #include "tf_ext_flow_handle.h" 13 #include "ulp_mark_mgr.h" 14 #include "bnxt_tf_common.h" 15 #include "ulp_template_db_enum.h" 16 #include "ulp_template_struct.h" 17 18 #define ULP_MARK_DB_ENTRY_SET_VALID(mark_info) ((mark_info)->flags |=\ 19 BNXT_ULP_MARK_VALID) 20 #define ULP_MARK_DB_ENTRY_IS_INVALID(mark_info) (!((mark_info)->flags &\ 21 BNXT_ULP_MARK_VALID)) 22 #define ULP_MARK_DB_ENTRY_SET_VFR_ID(mark_info) ((mark_info)->flags |=\ 23 BNXT_ULP_MARK_VFR_ID) 24 #define ULP_MARK_DB_ENTRY_IS_VFR_ID(mark_info) ((mark_info)->flags &\ 25 BNXT_ULP_MARK_VFR_ID) 26 #define ULP_MARK_DB_ENTRY_IS_GLOBAL_HW_FID(mark_info) ((mark_info)->flags &\ 27 BNXT_ULP_MARK_GLOBAL_HW_FID) 28 29 static inline uint32_t 30 ulp_mark_db_idx_get(bool is_gfid, uint32_t fid, struct bnxt_ulp_mark_tbl *mtbl) 31 { 32 uint32_t idx = 0, hashtype = 0; 33 34 if (is_gfid) { 35 TF_GET_HASH_TYPE_FROM_GFID(fid, hashtype); 36 TF_GET_HASH_INDEX_FROM_GFID(fid, idx); 37 38 /* Need to truncate anything beyond supported flows */ 39 idx &= mtbl->gfid_mask; 40 if (hashtype) 41 idx |= mtbl->gfid_type_bit; 42 } else { 43 idx = fid; 44 } 45 return idx; 46 } 47 48 /* 49 * Allocate and Initialize all Mark Manager resources for this ulp context. 50 * 51 * ctxt [in] The ulp context for the mark manager. 52 * 53 */ 54 int32_t 55 ulp_mark_db_init(struct bnxt_ulp_context *ctxt) 56 { 57 struct bnxt_ulp_device_params *dparms; 58 struct bnxt_ulp_mark_tbl *mark_tbl = NULL; 59 uint32_t dev_id; 60 61 if (!ctxt) { 62 BNXT_DRV_DBG(DEBUG, "Invalid ULP CTXT\n"); 63 return -EINVAL; 64 } 65 66 if (bnxt_ulp_cntxt_dev_id_get(ctxt, &dev_id)) { 67 BNXT_DRV_DBG(DEBUG, "Failed to get device id\n"); 68 return -EINVAL; 69 } 70 71 dparms = bnxt_ulp_device_params_get(dev_id); 72 if (!dparms) { 73 BNXT_DRV_DBG(DEBUG, "Failed to device parms\n"); 74 return -EINVAL; 75 } 76 77 if (!dparms->mark_db_lfid_entries || !dparms->mark_db_gfid_entries) { 78 BNXT_DRV_DBG(DEBUG, "mark Table is not allocated\n"); 79 bnxt_ulp_cntxt_ptr2_mark_db_set(ctxt, NULL); 80 return 0; 81 } 82 83 mark_tbl = rte_zmalloc("ulp_rx_mark_tbl_ptr", 84 sizeof(struct bnxt_ulp_mark_tbl), 0); 85 if (!mark_tbl) 86 goto mem_error; 87 88 /* Need to allocate 2 * Num flows to account for hash type bit.*/ 89 mark_tbl->lfid_num_entries = dparms->mark_db_lfid_entries; 90 mark_tbl->lfid_tbl = rte_zmalloc("ulp_rx_em_flow_mark_table", 91 mark_tbl->lfid_num_entries * 92 sizeof(struct bnxt_lfid_mark_info), 93 0); 94 if (!mark_tbl->lfid_tbl) 95 goto mem_error; 96 97 /* Need to allocate 2 * Num flows to account for hash type bit */ 98 mark_tbl->gfid_num_entries = dparms->mark_db_gfid_entries; 99 if (!mark_tbl->gfid_num_entries) 100 goto gfid_not_required; 101 102 mark_tbl->gfid_tbl = rte_zmalloc("ulp_rx_eem_flow_mark_table", 103 mark_tbl->gfid_num_entries * 104 sizeof(struct bnxt_gfid_mark_info), 105 0); 106 if (!mark_tbl->gfid_tbl) 107 goto mem_error; 108 109 /* 110 * These values are used to compress the FID to the allowable index 111 * space. The FID from hw may be the full hash which may be a big 112 * value to allocate and so allocate only needed hash values. 113 * gfid mask is the number of flow entries for the each left/right 114 * hash The gfid type bit is used to get to the higher or lower hash 115 * entries. 116 */ 117 mark_tbl->gfid_mask = (mark_tbl->gfid_num_entries / 2) - 1; 118 mark_tbl->gfid_type_bit = (mark_tbl->gfid_num_entries / 2); 119 120 BNXT_DRV_DBG(DEBUG, "GFID Max = 0x%08x GFID MASK = 0x%08x\n", 121 mark_tbl->gfid_num_entries - 1, 122 mark_tbl->gfid_mask); 123 124 gfid_not_required: 125 /* Add the mark tbl to the ulp context. */ 126 bnxt_ulp_cntxt_ptr2_mark_db_set(ctxt, mark_tbl); 127 return 0; 128 129 mem_error: 130 if (mark_tbl) { 131 rte_free(mark_tbl->gfid_tbl); 132 rte_free(mark_tbl->lfid_tbl); 133 rte_free(mark_tbl); 134 } 135 BNXT_DRV_DBG(DEBUG, "Failed to allocate memory for mark mgr\n"); 136 return -ENOMEM; 137 } 138 139 /* 140 * Release all resources in the Mark Manager for this ulp context 141 * 142 * ctxt [in] The ulp context for the mark manager 143 * 144 */ 145 int32_t 146 ulp_mark_db_deinit(struct bnxt_ulp_context *ctxt) 147 { 148 struct bnxt_ulp_mark_tbl *mtbl; 149 150 mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt); 151 152 if (mtbl) { 153 rte_free(mtbl->gfid_tbl); 154 rte_free(mtbl->lfid_tbl); 155 rte_free(mtbl); 156 157 /* Safe to ignore on deinit */ 158 (void)bnxt_ulp_cntxt_ptr2_mark_db_set(ctxt, NULL); 159 } 160 161 return 0; 162 } 163 164 /* 165 * Get a Mark from the Mark Manager 166 * 167 * ctxt [in] The ulp context for the mark manager 168 * 169 * is_gfid [in] The type of fid (GFID or LFID) 170 * 171 * fid [in] The flow id that is returned by HW in BD 172 * 173 * vfr_flag [out].it indicatesif mark is vfr_id or mark id 174 * 175 * mark [out] The mark that is associated with the FID 176 * 177 */ 178 int32_t 179 ulp_mark_db_mark_get(struct bnxt_ulp_context *ctxt, 180 bool is_gfid, 181 uint32_t fid, 182 uint32_t *vfr_flag, 183 uint32_t *mark) 184 { 185 struct bnxt_ulp_mark_tbl *mtbl; 186 uint32_t idx = 0; 187 188 if (!ctxt || !mark) 189 return -EINVAL; 190 191 mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt); 192 if (!mtbl) 193 return -EINVAL; 194 195 idx = ulp_mark_db_idx_get(is_gfid, fid, mtbl); 196 197 if (is_gfid) { 198 if (idx >= mtbl->gfid_num_entries || 199 ULP_MARK_DB_ENTRY_IS_INVALID(&mtbl->gfid_tbl[idx])) 200 return -EINVAL; 201 202 *vfr_flag = ULP_MARK_DB_ENTRY_IS_VFR_ID(&mtbl->gfid_tbl[idx]); 203 *mark = mtbl->gfid_tbl[idx].mark_id; 204 } else { 205 if (idx >= mtbl->lfid_num_entries || 206 ULP_MARK_DB_ENTRY_IS_INVALID(&mtbl->lfid_tbl[idx])) 207 return -EINVAL; 208 209 *vfr_flag = ULP_MARK_DB_ENTRY_IS_VFR_ID(&mtbl->lfid_tbl[idx]); 210 *mark = mtbl->lfid_tbl[idx].mark_id; 211 } 212 213 return 0; 214 } 215 216 /* 217 * Adds a Mark to the Mark Manager 218 * 219 * ctxt [in] The ulp context for the mark manager 220 * 221 * mark_flag [in] mark flags. 222 * 223 * fid [in] The flow id that is returned by HW in BD 224 * 225 * mark [in] The mark to be associated with the FID 226 * 227 */ 228 int32_t 229 ulp_mark_db_mark_add(struct bnxt_ulp_context *ctxt, 230 uint32_t mark_flag, 231 uint32_t fid, 232 uint32_t mark) 233 { 234 struct bnxt_ulp_mark_tbl *mtbl; 235 uint32_t idx = 0; 236 bool is_gfid; 237 238 if (!ctxt) { 239 BNXT_DRV_DBG(ERR, "Invalid ulp context\n"); 240 return -EINVAL; 241 } 242 243 mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt); 244 if (!mtbl) { 245 BNXT_DRV_DBG(ERR, "Unable to get Mark DB\n"); 246 return -EINVAL; 247 } 248 249 is_gfid = (mark_flag & BNXT_ULP_MARK_GLOBAL_HW_FID); 250 if (is_gfid) { 251 idx = ulp_mark_db_idx_get(is_gfid, fid, mtbl); 252 if (idx >= mtbl->gfid_num_entries) { 253 BNXT_DRV_DBG(ERR, "Mark index greater than allocated\n"); 254 return -EINVAL; 255 } 256 BNXT_DRV_DBG(DEBUG, "Set GFID[0x%0x] = 0x%0x\n", idx, mark); 257 mtbl->gfid_tbl[idx].mark_id = mark; 258 ULP_MARK_DB_ENTRY_SET_VALID(&mtbl->gfid_tbl[idx]); 259 260 } else { 261 /* For the LFID, the FID is used as the index */ 262 if (fid >= mtbl->lfid_num_entries) { 263 BNXT_DRV_DBG(ERR, "Mark index greater than allocated\n"); 264 return -EINVAL; 265 } 266 BNXT_DRV_DBG(DEBUG, "Set LFID[0x%0x] = 0x%0x\n", fid, mark); 267 mtbl->lfid_tbl[fid].mark_id = mark; 268 ULP_MARK_DB_ENTRY_SET_VALID(&mtbl->lfid_tbl[fid]); 269 270 if (mark_flag & BNXT_ULP_MARK_VFR_ID) 271 ULP_MARK_DB_ENTRY_SET_VFR_ID(&mtbl->lfid_tbl[fid]); 272 } 273 274 return 0; 275 } 276 277 /* 278 * Removes a Mark from the Mark Manager 279 * 280 * ctxt [in] The ulp context for the mark manager 281 * 282 * mark_flag [in] mark flags. 283 * 284 * fid [in] The flow id that is returned by HW in BD 285 * 286 */ 287 int32_t 288 ulp_mark_db_mark_del(struct bnxt_ulp_context *ctxt, 289 uint32_t mark_flag, 290 uint32_t fid) 291 { 292 struct bnxt_ulp_mark_tbl *mtbl; 293 uint32_t idx = 0; 294 bool is_gfid; 295 296 if (!ctxt) { 297 BNXT_DRV_DBG(ERR, "Invalid ulp context\n"); 298 return -EINVAL; 299 } 300 301 mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt); 302 if (!mtbl) { 303 BNXT_DRV_DBG(ERR, "Unable to get Mark DB\n"); 304 return -EINVAL; 305 } 306 307 is_gfid = (mark_flag & BNXT_ULP_MARK_GLOBAL_HW_FID); 308 if (is_gfid) { 309 idx = ulp_mark_db_idx_get(is_gfid, fid, mtbl); 310 if (idx >= mtbl->gfid_num_entries) { 311 BNXT_DRV_DBG(ERR, 312 "Mark index greater than allocated\n"); 313 return -EINVAL; 314 } 315 BNXT_DRV_DBG(DEBUG, "Reset GFID[0x%0x]\n", idx); 316 memset(&mtbl->gfid_tbl[idx], 0, 317 sizeof(struct bnxt_gfid_mark_info)); 318 319 } else { 320 /* For the LFID, the FID is used as the index */ 321 if (fid >= mtbl->lfid_num_entries) { 322 BNXT_DRV_DBG(ERR, 323 "Mark index greater than allocated\n"); 324 return -EINVAL; 325 } 326 memset(&mtbl->lfid_tbl[fid], 0, 327 sizeof(struct bnxt_lfid_mark_info)); 328 } 329 330 return 0; 331 } 332