xref: /dpdk/drivers/net/bnxt/tf_ulp/ulp_mark_mgr.c (revision ca39d3a8)
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