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