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