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.h" 15 #include "ulp_template_struct.h" 16 17 static inline uint32_t 18 ulp_mark_db_idx_get(bool is_gfid, uint32_t fid, struct bnxt_ulp_mark_tbl *mtbl) 19 { 20 uint32_t idx = 0, hashtype = 0; 21 22 if (is_gfid) { 23 TF_GET_HASH_TYPE_FROM_GFID(fid, hashtype); 24 TF_GET_HASH_INDEX_FROM_GFID(fid, idx); 25 26 /* Need to truncate anything beyond supported flows */ 27 idx &= mtbl->gfid_mask; 28 29 if (hashtype) 30 idx |= mtbl->gfid_type_bit; 31 } else { 32 idx = fid; 33 } 34 35 return idx; 36 } 37 38 static int32_t 39 ulp_mark_db_mark_set(struct bnxt_ulp_context *ctxt, 40 bool is_gfid, 41 uint32_t fid, 42 uint32_t mark) 43 { 44 struct bnxt_ulp_mark_tbl *mtbl; 45 uint32_t idx = 0; 46 47 if (!ctxt) { 48 BNXT_TF_DBG(ERR, "Invalid ulp context\n"); 49 return -EINVAL; 50 } 51 52 mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt); 53 if (!mtbl) { 54 BNXT_TF_DBG(ERR, "Unable to get Mark DB\n"); 55 return -EINVAL; 56 } 57 58 idx = ulp_mark_db_idx_get(is_gfid, fid, mtbl); 59 60 if (is_gfid) { 61 BNXT_TF_DBG(DEBUG, "Set GFID[0x%0x] = 0x%0x\n", idx, mark); 62 63 mtbl->gfid_tbl[idx].mark_id = mark; 64 mtbl->gfid_tbl[idx].valid = true; 65 } else { 66 /* For the LFID, the FID is used as the index */ 67 mtbl->lfid_tbl[fid].mark_id = mark; 68 mtbl->lfid_tbl[fid].valid = true; 69 } 70 71 return 0; 72 } 73 74 /* 75 * Allocate and Initialize all Mark Manager resources for this ulp context. 76 * 77 * ctxt [in] The ulp context for the mark manager. 78 * 79 */ 80 int32_t 81 ulp_mark_db_init(struct bnxt_ulp_context *ctxt) 82 { 83 struct bnxt_ulp_device_params *dparms; 84 struct bnxt_ulp_mark_tbl *mark_tbl = NULL; 85 uint32_t dev_id; 86 87 if (!ctxt) { 88 BNXT_TF_DBG(DEBUG, "Invalid ULP CTXT\n"); 89 return -EINVAL; 90 } 91 92 if (bnxt_ulp_cntxt_dev_id_get(ctxt, &dev_id)) { 93 BNXT_TF_DBG(DEBUG, "Failed to get device id\n"); 94 return -EINVAL; 95 } 96 97 dparms = bnxt_ulp_device_params_get(dev_id); 98 if (!dparms) { 99 BNXT_TF_DBG(DEBUG, "Failed to device parms\n"); 100 return -EINVAL; 101 } 102 103 mark_tbl = rte_zmalloc("ulp_rx_mark_tbl_ptr", 104 sizeof(struct bnxt_ulp_mark_tbl), 0); 105 if (!mark_tbl) 106 goto mem_error; 107 108 /* Need to allocate 2 * Num flows to account for hash type bit. */ 109 mark_tbl->lfid_tbl = rte_zmalloc("ulp_rx_em_flow_mark_table", 110 dparms->lfid_entries * 111 sizeof(struct bnxt_lfid_mark_info), 112 0); 113 114 if (!mark_tbl->lfid_tbl) 115 goto mem_error; 116 117 /* Need to allocate 2 * Num flows to account for hash type bit. */ 118 mark_tbl->gfid_tbl = rte_zmalloc("ulp_rx_eem_flow_mark_table", 119 2 * dparms->num_flows * 120 sizeof(struct bnxt_gfid_mark_info), 121 0); 122 if (!mark_tbl->gfid_tbl) 123 goto mem_error; 124 125 /* 126 * TBD: This needs to be generalized for better mark handling 127 * These values are used to compress the FID to the allowable index 128 * space. The FID from hw may be the full hash. 129 */ 130 mark_tbl->gfid_max = dparms->gfid_entries - 1; 131 mark_tbl->gfid_mask = (dparms->gfid_entries / 2) - 1; 132 mark_tbl->gfid_type_bit = (dparms->gfid_entries / 2); 133 134 BNXT_TF_DBG(DEBUG, "GFID Max = 0x%08x\nGFID MASK = 0x%08x\n", 135 mark_tbl->gfid_max, 136 mark_tbl->gfid_mask); 137 138 /* Add the mark tbl to the ulp context. */ 139 bnxt_ulp_cntxt_ptr2_mark_db_set(ctxt, mark_tbl); 140 141 return 0; 142 143 mem_error: 144 rte_free(mark_tbl->gfid_tbl); 145 rte_free(mark_tbl->lfid_tbl); 146 rte_free(mark_tbl); 147 BNXT_TF_DBG(DEBUG, 148 "Failed to allocate memory for mark mgr\n"); 149 150 return -ENOMEM; 151 } 152 153 /* 154 * Release all resources in the Mark Manager for this ulp context 155 * 156 * ctxt [in] The ulp context for the mark manager 157 * 158 */ 159 int32_t 160 ulp_mark_db_deinit(struct bnxt_ulp_context *ctxt) 161 { 162 struct bnxt_ulp_mark_tbl *mtbl; 163 164 mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt); 165 166 if (mtbl) { 167 rte_free(mtbl->gfid_tbl); 168 rte_free(mtbl->lfid_tbl); 169 rte_free(mtbl); 170 171 /* Safe to ignore on deinit */ 172 (void)bnxt_ulp_cntxt_ptr2_mark_db_set(ctxt, NULL); 173 } 174 175 return 0; 176 } 177 178 /* 179 * Get a Mark from the Mark Manager 180 * 181 * ctxt [in] The ulp context for the mark manager 182 * 183 * is_gfid [in] The type of fid (GFID or LFID) 184 * 185 * fid [in] The flow id that is returned by HW in BD 186 * 187 * mark [out] The mark that is associated with the FID 188 * 189 */ 190 int32_t 191 ulp_mark_db_mark_get(struct bnxt_ulp_context *ctxt, 192 bool is_gfid, 193 uint32_t fid, 194 uint32_t *mark) 195 { 196 struct bnxt_ulp_mark_tbl *mtbl; 197 uint32_t idx = 0; 198 199 if (!ctxt || !mark) 200 return -EINVAL; 201 202 mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt); 203 if (!mtbl) { 204 BNXT_TF_DBG(ERR, "Unable to get Mark Table\n"); 205 return -EINVAL; 206 } 207 208 idx = ulp_mark_db_idx_get(is_gfid, fid, mtbl); 209 210 if (is_gfid) { 211 if (!mtbl->gfid_tbl[idx].valid) 212 return -EINVAL; 213 214 BNXT_TF_DBG(DEBUG, "Get GFID[0x%0x] = 0x%0x\n", 215 idx, mtbl->gfid_tbl[idx].mark_id); 216 217 *mark = mtbl->gfid_tbl[idx].mark_id; 218 } else { 219 if (!mtbl->gfid_tbl[idx].valid) 220 return -EINVAL; 221 222 BNXT_TF_DBG(DEBUG, "Get LFID[0x%0x] = 0x%0x\n", 223 idx, mtbl->lfid_tbl[idx].mark_id); 224 225 *mark = mtbl->lfid_tbl[idx].mark_id; 226 } 227 228 return 0; 229 } 230 231 /* 232 * Adds a Mark to the Mark Manager 233 * 234 * ctxt [in] The ulp context for the mark manager 235 * 236 * is_gfid [in] The type of fid (GFID or LFID) 237 * 238 * fid [in] The flow id that is returned by HW in BD 239 * 240 * mark [in] The mark to be associated with the FID 241 * 242 */ 243 int32_t 244 ulp_mark_db_mark_add(struct bnxt_ulp_context *ctxt, 245 bool is_gfid, 246 uint32_t gfid, 247 uint32_t mark) 248 { 249 return ulp_mark_db_mark_set(ctxt, is_gfid, gfid, mark); 250 } 251 252 /* 253 * Removes a Mark from the Mark Manager 254 * 255 * ctxt [in] The ulp context for the mark manager 256 * 257 * is_gfid [in] The type of fid (GFID or LFID) 258 * 259 * fid [in] The flow id that is returned by HW in BD 260 * 261 * mark [in] The mark to be associated with the FID 262 * 263 */ 264 int32_t 265 ulp_mark_db_mark_del(struct bnxt_ulp_context *ctxt, 266 bool is_gfid, 267 uint32_t gfid, 268 uint32_t mark __rte_unused) 269 { 270 return ulp_mark_db_mark_set(ctxt, is_gfid, gfid, ULP_MARK_INVALID); 271 } 272