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
ulp_mark_db_idx_get(bool is_gfid,uint32_t fid,struct bnxt_ulp_mark_tbl * mtbl)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
ulp_mark_db_init(struct bnxt_ulp_context * ctxt)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
ulp_mark_db_deinit(struct bnxt_ulp_context * ctxt)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
ulp_mark_db_mark_get(struct bnxt_ulp_context * ctxt,bool is_gfid,uint32_t fid,uint32_t * vfr_flag,uint32_t * mark)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
ulp_mark_db_mark_add(struct bnxt_ulp_context * ctxt,uint32_t mark_flag,uint32_t fid,uint32_t mark)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
ulp_mark_db_mark_del(struct bnxt_ulp_context * ctxt,uint32_t mark_flag,uint32_t fid)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