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 mark_tbl = rte_zmalloc("ulp_rx_mark_tbl_ptr", 77 sizeof(struct bnxt_ulp_mark_tbl), 0); 78 if (!mark_tbl) 79 goto mem_error; 80 81 /* Need to allocate 2 * Num flows to account for hash type bit.*/ 82 mark_tbl->lfid_num_entries = dparms->mark_db_lfid_entries; 83 mark_tbl->lfid_tbl = rte_zmalloc("ulp_rx_em_flow_mark_table", 84 mark_tbl->lfid_num_entries * 85 sizeof(struct bnxt_lfid_mark_info), 86 0); 87 if (!mark_tbl->lfid_tbl) 88 goto mem_error; 89 90 /* Need to allocate 2 * Num flows to account for hash type bit */ 91 mark_tbl->gfid_num_entries = dparms->mark_db_gfid_entries; 92 if (!mark_tbl->gfid_num_entries) 93 goto gfid_not_required; 94 95 mark_tbl->gfid_tbl = rte_zmalloc("ulp_rx_eem_flow_mark_table", 96 mark_tbl->gfid_num_entries * 97 sizeof(struct bnxt_gfid_mark_info), 98 0); 99 if (!mark_tbl->gfid_tbl) 100 goto mem_error; 101 102 /* 103 * These values are used to compress the FID to the allowable index 104 * space. The FID from hw may be the full hash which may be a big 105 * value to allocate and so allocate only needed hash values. 106 * gfid mask is the number of flow entries for the each left/right 107 * hash The gfid type bit is used to get to the higher or lower hash 108 * entries. 109 */ 110 mark_tbl->gfid_mask = (mark_tbl->gfid_num_entries / 2) - 1; 111 mark_tbl->gfid_type_bit = (mark_tbl->gfid_num_entries / 2); 112 113 BNXT_TF_DBG(DEBUG, "GFID Max = 0x%08x\nGFID MASK = 0x%08x\n", 114 mark_tbl->gfid_num_entries - 1, 115 mark_tbl->gfid_mask); 116 117 gfid_not_required: 118 /* Add the mark tbl to the ulp context. */ 119 bnxt_ulp_cntxt_ptr2_mark_db_set(ctxt, mark_tbl); 120 return 0; 121 122 mem_error: 123 if (mark_tbl) { 124 rte_free(mark_tbl->gfid_tbl); 125 rte_free(mark_tbl->lfid_tbl); 126 rte_free(mark_tbl); 127 } 128 BNXT_TF_DBG(DEBUG, "Failed to allocate memory for mark mgr\n"); 129 return -ENOMEM; 130 } 131 132 /* 133 * Release all resources in the Mark Manager for this ulp context 134 * 135 * ctxt [in] The ulp context for the mark manager 136 * 137 */ 138 int32_t 139 ulp_mark_db_deinit(struct bnxt_ulp_context *ctxt) 140 { 141 struct bnxt_ulp_mark_tbl *mtbl; 142 143 mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt); 144 145 if (mtbl) { 146 rte_free(mtbl->gfid_tbl); 147 rte_free(mtbl->lfid_tbl); 148 rte_free(mtbl); 149 150 /* Safe to ignore on deinit */ 151 (void)bnxt_ulp_cntxt_ptr2_mark_db_set(ctxt, NULL); 152 } 153 154 return 0; 155 } 156 157 /* 158 * Get a Mark from the Mark Manager 159 * 160 * ctxt [in] The ulp context for the mark manager 161 * 162 * is_gfid [in] The type of fid (GFID or LFID) 163 * 164 * fid [in] The flow id that is returned by HW in BD 165 * 166 * vfr_flag [out].it indicatesif mark is vfr_id or mark id 167 * 168 * mark [out] The mark that is associated with the FID 169 * 170 */ 171 int32_t 172 ulp_mark_db_mark_get(struct bnxt_ulp_context *ctxt, 173 bool is_gfid, 174 uint32_t fid, 175 uint32_t *vfr_flag, 176 uint32_t *mark) 177 { 178 struct bnxt_ulp_mark_tbl *mtbl; 179 uint32_t idx = 0; 180 181 if (!ctxt || !mark) 182 return -EINVAL; 183 184 mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt); 185 if (!mtbl) { 186 BNXT_TF_DBG(ERR, "Unable to get Mark Table\n"); 187 return -EINVAL; 188 } 189 190 idx = ulp_mark_db_idx_get(is_gfid, fid, mtbl); 191 192 if (is_gfid) { 193 if (idx >= mtbl->gfid_num_entries || 194 ULP_MARK_DB_ENTRY_IS_INVALID(&mtbl->gfid_tbl[idx])) 195 return -EINVAL; 196 197 *vfr_flag = ULP_MARK_DB_ENTRY_IS_VFR_ID(&mtbl->gfid_tbl[idx]); 198 *mark = mtbl->gfid_tbl[idx].mark_id; 199 } else { 200 if (idx >= mtbl->lfid_num_entries || 201 ULP_MARK_DB_ENTRY_IS_INVALID(&mtbl->lfid_tbl[idx])) 202 return -EINVAL; 203 204 *vfr_flag = ULP_MARK_DB_ENTRY_IS_VFR_ID(&mtbl->lfid_tbl[idx]); 205 *mark = mtbl->lfid_tbl[idx].mark_id; 206 } 207 208 return 0; 209 } 210 211 /* 212 * Adds a Mark to the Mark Manager 213 * 214 * ctxt [in] The ulp context for the mark manager 215 * 216 * mark_flag [in] mark flags. 217 * 218 * fid [in] The flow id that is returned by HW in BD 219 * 220 * mark [in] The mark to be associated with the FID 221 * 222 */ 223 int32_t 224 ulp_mark_db_mark_add(struct bnxt_ulp_context *ctxt, 225 uint32_t mark_flag, 226 uint32_t fid, 227 uint32_t mark) 228 { 229 struct bnxt_ulp_mark_tbl *mtbl; 230 uint32_t idx = 0; 231 bool is_gfid; 232 233 if (!ctxt) { 234 BNXT_TF_DBG(ERR, "Invalid ulp context\n"); 235 return -EINVAL; 236 } 237 238 mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt); 239 if (!mtbl) { 240 BNXT_TF_DBG(ERR, "Unable to get Mark DB\n"); 241 return -EINVAL; 242 } 243 244 is_gfid = (mark_flag & BNXT_ULP_MARK_GLOBAL_HW_FID); 245 if (is_gfid) { 246 idx = ulp_mark_db_idx_get(is_gfid, fid, mtbl); 247 if (idx >= mtbl->gfid_num_entries) { 248 BNXT_TF_DBG(ERR, "Mark index greater than allocated\n"); 249 return -EINVAL; 250 } 251 BNXT_TF_DBG(DEBUG, "Set GFID[0x%0x] = 0x%0x\n", idx, mark); 252 mtbl->gfid_tbl[idx].mark_id = mark; 253 ULP_MARK_DB_ENTRY_SET_VALID(&mtbl->gfid_tbl[idx]); 254 255 } else { 256 /* For the LFID, the FID is used as the index */ 257 if (fid >= mtbl->lfid_num_entries) { 258 BNXT_TF_DBG(ERR, "Mark index greater than allocated\n"); 259 return -EINVAL; 260 } 261 BNXT_TF_DBG(DEBUG, "Set LFID[0x%0x] = 0x%0x\n", fid, mark); 262 mtbl->lfid_tbl[fid].mark_id = mark; 263 ULP_MARK_DB_ENTRY_SET_VALID(&mtbl->lfid_tbl[fid]); 264 265 if (mark_flag & BNXT_ULP_MARK_VFR_ID) 266 ULP_MARK_DB_ENTRY_SET_VFR_ID(&mtbl->lfid_tbl[fid]); 267 } 268 269 return 0; 270 } 271 272 /* 273 * Removes a Mark from the Mark Manager 274 * 275 * ctxt [in] The ulp context for the mark manager 276 * 277 * mark_flag [in] mark flags. 278 * 279 * fid [in] The flow id that is returned by HW in BD 280 * 281 */ 282 int32_t 283 ulp_mark_db_mark_del(struct bnxt_ulp_context *ctxt, 284 uint32_t mark_flag, 285 uint32_t fid) 286 { 287 struct bnxt_ulp_mark_tbl *mtbl; 288 uint32_t idx = 0; 289 bool is_gfid; 290 291 if (!ctxt) { 292 BNXT_TF_DBG(ERR, "Invalid ulp context\n"); 293 return -EINVAL; 294 } 295 296 mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt); 297 if (!mtbl) { 298 BNXT_TF_DBG(ERR, "Unable to get Mark DB\n"); 299 return -EINVAL; 300 } 301 302 is_gfid = (mark_flag & BNXT_ULP_MARK_GLOBAL_HW_FID); 303 if (is_gfid) { 304 idx = ulp_mark_db_idx_get(is_gfid, fid, mtbl); 305 if (idx >= mtbl->gfid_num_entries) { 306 BNXT_TF_DBG(ERR, "Mark index greater than allocated\n"); 307 return -EINVAL; 308 } 309 BNXT_TF_DBG(DEBUG, "Reset GFID[0x%0x]\n", idx); 310 memset(&mtbl->gfid_tbl[idx], 0, 311 sizeof(struct bnxt_gfid_mark_info)); 312 313 } else { 314 /* For the LFID, the FID is used as the index */ 315 if (fid >= mtbl->lfid_num_entries) { 316 BNXT_TF_DBG(ERR, "Mark index greater than allocated\n"); 317 return -EINVAL; 318 } 319 memset(&mtbl->lfid_tbl[fid], 0, 320 sizeof(struct bnxt_lfid_mark_info)); 321 } 322 323 return 0; 324 } 325