1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2020 Broadcom
3  * All rights reserved.
4  */
5 
6 #include <string.h>
7 #include <rte_common.h>
8 #include <rte_errno.h>
9 #include <rte_log.h>
10 
11 #include "tf_core.h"
12 #include "tf_util.h"
13 #include "tf_common.h"
14 #include "tf_em.h"
15 #include "tf_msg.h"
16 #include "tfp.h"
17 #include "tf_ext_flow_handle.h"
18 
19 #include "bnxt.h"
20 
21 /**
22  * EM DBs.
23  */
24 static void *em_db[TF_DIR_MAX];
25 
26 #define TF_EM_DB_EM_REC 0
27 
28 /**
29  * Init flag, set on bind and cleared on unbind
30  */
31 static uint8_t init;
32 
33 
34 /**
35  * EM Pool
36  */
37 static struct stack em_pool[TF_DIR_MAX];
38 
39 /**
40  * Create EM Tbl pool of memory indexes.
41  *
42  * [in] dir
43  *   direction
44  * [in] num_entries
45  *   number of entries to write
46  * [in] start
47  *   starting offset
48  *
49  * Return:
50  *  0       - Success, entry allocated - no search support
51  *  -ENOMEM -EINVAL -EOPNOTSUPP
52  *          - Failure, entry not allocated, out of resources
53  */
54 static int
tf_create_em_pool(enum tf_dir dir,uint32_t num_entries,uint32_t start)55 tf_create_em_pool(enum tf_dir dir,
56 		  uint32_t num_entries,
57 		  uint32_t start)
58 {
59 	struct tfp_calloc_parms parms;
60 	uint32_t i, j;
61 	int rc = 0;
62 	struct stack *pool = &em_pool[dir];
63 
64 	/* Assumes that num_entries has been checked before we get here */
65 	parms.nitems = num_entries / TF_SESSION_EM_ENTRY_SIZE;
66 	parms.size = sizeof(uint32_t);
67 	parms.alignment = 0;
68 
69 	rc = tfp_calloc(&parms);
70 
71 	if (rc) {
72 		TFP_DRV_LOG(ERR,
73 			    "%s, EM pool allocation failure %s\n",
74 			    tf_dir_2_str(dir),
75 			    strerror(-rc));
76 		return rc;
77 	}
78 
79 	/* Create empty stack
80 	 */
81 	rc = stack_init(num_entries / TF_SESSION_EM_ENTRY_SIZE,
82 			(uint32_t *)parms.mem_va,
83 			pool);
84 
85 	if (rc) {
86 		TFP_DRV_LOG(ERR,
87 			    "%s, EM pool stack init failure %s\n",
88 			    tf_dir_2_str(dir),
89 			    strerror(-rc));
90 		goto cleanup;
91 	}
92 
93 	/* Fill pool with indexes
94 	 */
95 	j = start + num_entries - TF_SESSION_EM_ENTRY_SIZE;
96 
97 	for (i = 0; i < (num_entries / TF_SESSION_EM_ENTRY_SIZE); i++) {
98 		rc = stack_push(pool, j);
99 		if (rc) {
100 			TFP_DRV_LOG(ERR,
101 				    "%s, EM pool stack push failure %s\n",
102 				    tf_dir_2_str(dir),
103 				    strerror(-rc));
104 			goto cleanup;
105 		}
106 
107 		j -= TF_SESSION_EM_ENTRY_SIZE;
108 	}
109 
110 	if (!stack_is_full(pool)) {
111 		rc = -EINVAL;
112 		TFP_DRV_LOG(ERR,
113 			    "%s, EM pool stack failure %s\n",
114 			    tf_dir_2_str(dir),
115 			    strerror(-rc));
116 		goto cleanup;
117 	}
118 
119 	return 0;
120 cleanup:
121 	tfp_free((void *)parms.mem_va);
122 	return rc;
123 }
124 
125 /**
126  * Create EM Tbl pool of memory indexes.
127  *
128  * [in] dir
129  *   direction
130  *
131  * Return:
132  */
133 static void
tf_free_em_pool(enum tf_dir dir)134 tf_free_em_pool(enum tf_dir dir)
135 {
136 	struct stack *pool = &em_pool[dir];
137 	uint32_t *ptr;
138 
139 	ptr = stack_items(pool);
140 
141 	if (ptr != NULL)
142 		tfp_free(ptr);
143 }
144 
145 /**
146  * Insert EM internal entry API
147  *
148  *  returns:
149  *     0 - Success
150  */
151 int
tf_em_insert_int_entry(struct tf * tfp,struct tf_insert_em_entry_parms * parms)152 tf_em_insert_int_entry(struct tf *tfp,
153 		       struct tf_insert_em_entry_parms *parms)
154 {
155 	int rc;
156 	uint32_t gfid;
157 	uint16_t rptr_index = 0;
158 	uint8_t rptr_entry = 0;
159 	uint8_t num_of_entries = 0;
160 	struct stack *pool = &em_pool[parms->dir];
161 	uint32_t index;
162 
163 	rc = stack_pop(pool, &index);
164 
165 	if (rc) {
166 		PMD_DRV_LOG(ERR,
167 			    "%s, EM entry index allocation failed\n",
168 			    tf_dir_2_str(parms->dir));
169 		return rc;
170 	}
171 
172 	rptr_index = index;
173 	rc = tf_msg_insert_em_internal_entry(tfp,
174 					     parms,
175 					     &rptr_index,
176 					     &rptr_entry,
177 					     &num_of_entries);
178 	if (rc) {
179 		/* Free the allocated index before returning */
180 		stack_push(pool, index);
181 		return -1;
182 	}
183 
184 	PMD_DRV_LOG
185 		  (DEBUG,
186 		   "%s, Internal entry @ Index:%d rptr_index:0x%x rptr_entry:0x%x num_of_entries:%d\n",
187 		   tf_dir_2_str(parms->dir),
188 		   index,
189 		   rptr_index,
190 		   rptr_entry,
191 		   num_of_entries);
192 
193 	TF_SET_GFID(gfid,
194 		    ((rptr_index << TF_EM_INTERNAL_INDEX_SHIFT) |
195 		     rptr_entry),
196 		    0); /* N/A for internal table */
197 
198 	TF_SET_FLOW_ID(parms->flow_id,
199 		       gfid,
200 		       TF_GFID_TABLE_INTERNAL,
201 		       parms->dir);
202 
203 	TF_SET_FIELDS_IN_FLOW_HANDLE(parms->flow_handle,
204 				     (uint32_t)num_of_entries,
205 				     0,
206 				     0,
207 				     rptr_index,
208 				     rptr_entry,
209 				     0);
210 	return 0;
211 }
212 
213 
214 /** Delete EM internal entry API
215  *
216  * returns:
217  * 0
218  * -EINVAL
219  */
220 int
tf_em_delete_int_entry(struct tf * tfp,struct tf_delete_em_entry_parms * parms)221 tf_em_delete_int_entry(struct tf *tfp,
222 		       struct tf_delete_em_entry_parms *parms)
223 {
224 	int rc = 0;
225 	struct stack *pool = &em_pool[parms->dir];
226 
227 	rc = tf_msg_delete_em_entry(tfp, parms);
228 
229 	/* Return resource to pool */
230 	if (rc == 0)
231 		stack_push(pool, parms->index);
232 
233 	return rc;
234 }
235 
236 int
tf_em_int_bind(struct tf * tfp,struct tf_em_cfg_parms * parms)237 tf_em_int_bind(struct tf *tfp,
238 	       struct tf_em_cfg_parms *parms)
239 {
240 	int rc;
241 	int i;
242 	struct tf_rm_create_db_parms db_cfg = { 0 };
243 	uint8_t db_exists = 0;
244 	struct tf_rm_get_alloc_info_parms iparms;
245 	struct tf_rm_alloc_info info;
246 
247 	TF_CHECK_PARMS2(tfp, parms);
248 
249 	if (init) {
250 		TFP_DRV_LOG(ERR,
251 			    "EM Int DB already initialized\n");
252 		return -EINVAL;
253 	}
254 
255 	db_cfg.type = TF_DEVICE_MODULE_TYPE_EM;
256 	db_cfg.num_elements = parms->num_elements;
257 	db_cfg.cfg = parms->cfg;
258 
259 	for (i = 0; i < TF_DIR_MAX; i++) {
260 		db_cfg.dir = i;
261 		db_cfg.alloc_cnt = parms->resources->em_cnt[i].cnt;
262 
263 		/* Check if we got any request to support EEM, if so
264 		 * we build an EM Int DB holding Table Scopes.
265 		 */
266 		if (db_cfg.alloc_cnt[TF_EM_TBL_TYPE_EM_RECORD] == 0)
267 			continue;
268 
269 		if (db_cfg.alloc_cnt[TF_EM_TBL_TYPE_EM_RECORD] %
270 		    TF_SESSION_EM_ENTRY_SIZE != 0) {
271 			rc = -ENOMEM;
272 			TFP_DRV_LOG(ERR,
273 				    "%s, EM Allocation must be in blocks of %d, failure %s\n",
274 				    tf_dir_2_str(i),
275 				    TF_SESSION_EM_ENTRY_SIZE,
276 				    strerror(-rc));
277 
278 			return rc;
279 		}
280 
281 		db_cfg.rm_db = &em_db[i];
282 		rc = tf_rm_create_db(tfp, &db_cfg);
283 		if (rc) {
284 			TFP_DRV_LOG(ERR,
285 				    "%s: EM Int DB creation failed\n",
286 				    tf_dir_2_str(i));
287 
288 			return rc;
289 		}
290 		db_exists = 1;
291 	}
292 
293 	if (db_exists)
294 		init = 1;
295 
296 	for (i = 0; i < TF_DIR_MAX; i++) {
297 		iparms.rm_db = em_db[i];
298 		iparms.db_index = TF_EM_DB_EM_REC;
299 		iparms.info = &info;
300 
301 		rc = tf_rm_get_info(&iparms);
302 		if (rc) {
303 			TFP_DRV_LOG(ERR,
304 				    "%s: EM DB get info failed\n",
305 				    tf_dir_2_str(i));
306 			return rc;
307 		}
308 
309 		rc = tf_create_em_pool(i,
310 				       iparms.info->entry.stride,
311 				       iparms.info->entry.start);
312 		/* Logging handled in tf_create_em_pool */
313 		if (rc)
314 			return rc;
315 	}
316 
317 
318 	return 0;
319 }
320 
321 int
tf_em_int_unbind(struct tf * tfp)322 tf_em_int_unbind(struct tf *tfp)
323 {
324 	int rc;
325 	int i;
326 	struct tf_rm_free_db_parms fparms = { 0 };
327 
328 	TF_CHECK_PARMS1(tfp);
329 
330 	/* Bail if nothing has been initialized */
331 	if (!init) {
332 		TFP_DRV_LOG(INFO,
333 			    "No EM Int DBs created\n");
334 		return 0;
335 	}
336 
337 	for (i = 0; i < TF_DIR_MAX; i++)
338 		tf_free_em_pool(i);
339 
340 	for (i = 0; i < TF_DIR_MAX; i++) {
341 		fparms.dir = i;
342 		fparms.rm_db = em_db[i];
343 		if (em_db[i] != NULL) {
344 			rc = tf_rm_free_db(tfp, &fparms);
345 			if (rc)
346 				return rc;
347 		}
348 
349 		em_db[i] = NULL;
350 	}
351 
352 	init = 0;
353 
354 	return 0;
355 }
356