xref: /dpdk/drivers/net/bnxt/tf_ulp/ulp_mark_mgr.c (revision b071f1fa)
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_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 		BNXT_TF_DBG(DEBUG, "Get GFID[0x%0x] = 0x%0x\n",
198 			    idx, mtbl->gfid_tbl[idx].mark_id);
199 
200 		*vfr_flag = ULP_MARK_DB_ENTRY_IS_VFR_ID(&mtbl->gfid_tbl[idx]);
201 		*mark = mtbl->gfid_tbl[idx].mark_id;
202 	} else {
203 		if (idx >= mtbl->lfid_num_entries ||
204 		    ULP_MARK_DB_ENTRY_IS_INVALID(&mtbl->lfid_tbl[idx]))
205 			return -EINVAL;
206 
207 		BNXT_TF_DBG(DEBUG, "Get LFID[0x%0x] = 0x%0x\n",
208 			    idx, mtbl->lfid_tbl[idx].mark_id);
209 
210 		*vfr_flag = ULP_MARK_DB_ENTRY_IS_VFR_ID(&mtbl->lfid_tbl[idx]);
211 		*mark = mtbl->lfid_tbl[idx].mark_id;
212 	}
213 
214 	return 0;
215 }
216 
217 /*
218  * Adds a Mark to the Mark Manager
219  *
220  * ctxt [in] The ulp context for the mark manager
221  *
222  * mark_flag [in] mark flags.
223  *
224  * fid [in] The flow id that is returned by HW in BD
225  *
226  * mark [in] The mark to be associated with the FID
227  *
228  */
229 int32_t
230 ulp_mark_db_mark_add(struct bnxt_ulp_context *ctxt,
231 		     uint32_t mark_flag,
232 		     uint32_t fid,
233 		     uint32_t mark)
234 {
235 	struct bnxt_ulp_mark_tbl *mtbl;
236 	uint32_t idx = 0;
237 	bool is_gfid;
238 
239 	if (!ctxt) {
240 		BNXT_TF_DBG(ERR, "Invalid ulp context\n");
241 		return -EINVAL;
242 	}
243 
244 	mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt);
245 	if (!mtbl) {
246 		BNXT_TF_DBG(ERR, "Unable to get Mark DB\n");
247 		return -EINVAL;
248 	}
249 
250 	is_gfid = (mark_flag & BNXT_ULP_MARK_GLOBAL_HW_FID);
251 	if (is_gfid) {
252 		idx = ulp_mark_db_idx_get(is_gfid, fid, mtbl);
253 		if (idx >= mtbl->gfid_num_entries) {
254 			BNXT_TF_DBG(ERR, "Mark index greater than allocated\n");
255 			return -EINVAL;
256 		}
257 		BNXT_TF_DBG(DEBUG, "Set GFID[0x%0x] = 0x%0x\n", idx, mark);
258 		mtbl->gfid_tbl[idx].mark_id = mark;
259 		ULP_MARK_DB_ENTRY_SET_VALID(&mtbl->gfid_tbl[idx]);
260 
261 	} else {
262 		/* For the LFID, the FID is used as the index */
263 		if (fid >= mtbl->lfid_num_entries) {
264 			BNXT_TF_DBG(ERR, "Mark index greater than allocated\n");
265 			return -EINVAL;
266 		}
267 		BNXT_TF_DBG(DEBUG, "Set LFID[0x%0x] = 0x%0x\n", fid, mark);
268 		mtbl->lfid_tbl[fid].mark_id = mark;
269 		ULP_MARK_DB_ENTRY_SET_VALID(&mtbl->lfid_tbl[fid]);
270 
271 		if (mark_flag & BNXT_ULP_MARK_VFR_ID)
272 			ULP_MARK_DB_ENTRY_SET_VFR_ID(&mtbl->lfid_tbl[fid]);
273 	}
274 
275 	return 0;
276 }
277 
278 /*
279  * Removes a Mark from the Mark Manager
280  *
281  * ctxt [in] The ulp context for the mark manager
282  *
283  * mark_flag [in] mark flags.
284  *
285  * fid [in] The flow id that is returned by HW in BD
286  *
287  */
288 int32_t
289 ulp_mark_db_mark_del(struct bnxt_ulp_context *ctxt,
290 		     uint32_t mark_flag,
291 		     uint32_t fid)
292 {
293 	struct bnxt_ulp_mark_tbl *mtbl;
294 	uint32_t idx = 0;
295 	bool is_gfid;
296 
297 	if (!ctxt) {
298 		BNXT_TF_DBG(ERR, "Invalid ulp context\n");
299 		return -EINVAL;
300 	}
301 
302 	mtbl = bnxt_ulp_cntxt_ptr2_mark_db_get(ctxt);
303 	if (!mtbl) {
304 		BNXT_TF_DBG(ERR, "Unable to get Mark DB\n");
305 		return -EINVAL;
306 	}
307 
308 	is_gfid = (mark_flag & BNXT_ULP_MARK_GLOBAL_HW_FID);
309 	if (is_gfid) {
310 		idx = ulp_mark_db_idx_get(is_gfid, fid, mtbl);
311 		if (idx >= mtbl->gfid_num_entries) {
312 			BNXT_TF_DBG(ERR, "Mark index greater than allocated\n");
313 			return -EINVAL;
314 		}
315 		BNXT_TF_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_TF_DBG(ERR, "Mark index greater than allocated\n");
323 			return -EINVAL;
324 		}
325 		memset(&mtbl->lfid_tbl[fid], 0,
326 		       sizeof(struct bnxt_lfid_mark_info));
327 	}
328 
329 	return 0;
330 }
331