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