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