xref: /dpdk/drivers/net/bnxt/tf_core/tf_tcam.c (revision 0d63f20a3c75cce117c96dda80e228dcfada1d4f)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2021 Broadcom
3  * All rights reserved.
4  */
5 
6 #include <string.h>
7 #include <rte_common.h>
8 
9 #include "tf_tcam.h"
10 #include "tf_common.h"
11 #include "tf_util.h"
12 #include "tf_rm.h"
13 #include "tf_device.h"
14 #include "tfp.h"
15 #include "tf_session.h"
16 #include "tf_msg.h"
17 
18 struct tf;
19 
20 int
21 tf_tcam_bind(struct tf *tfp,
22 	     struct tf_tcam_cfg_parms *parms)
23 {
24 	int rc;
25 	int db_rc[TF_DIR_MAX] = { 0 };
26 	int i, d;
27 	struct tf_rm_alloc_info info;
28 	struct tf_rm_free_db_parms fparms;
29 	struct tf_rm_create_db_parms db_cfg;
30 	struct tf_tcam_resources *tcam_cnt;
31 	struct tf_rm_get_alloc_info_parms ainfo;
32 	uint16_t num_slices = parms->wc_num_slices;
33 	struct tf_session *tfs;
34 	struct tf_dev_info *dev;
35 	struct tcam_rm_db *tcam_db;
36 	struct tfp_calloc_parms cparms;
37 
38 	TF_CHECK_PARMS2(tfp, parms);
39 
40 	/* Retrieve the session information */
41 	rc = tf_session_get_session_internal(tfp, &tfs);
42 	if (rc)
43 		return rc;
44 
45 	/* Retrieve the device information */
46 	rc = tf_session_get_device(tfs, &dev);
47 	if (rc)
48 		return rc;
49 
50 	if (dev->ops->tf_dev_set_tcam_slice_info == NULL) {
51 		rc = -EOPNOTSUPP;
52 		TFP_DRV_LOG(ERR,
53 			    "Operation not supported, rc:%s\n",
54 			    strerror(-rc));
55 		return rc;
56 	}
57 
58 	rc = dev->ops->tf_dev_set_tcam_slice_info(tfp,
59 						  num_slices);
60 	if (rc)
61 		return rc;
62 
63 	tcam_cnt = parms->resources->tcam_cnt;
64 	if ((tcam_cnt[TF_DIR_RX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] % num_slices) ||
65 	    (tcam_cnt[TF_DIR_TX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] % num_slices)) {
66 		TFP_DRV_LOG(ERR,
67 			    "Requested num of WC TCAM entries has to be multiple %d\n",
68 			    num_slices);
69 		return -EINVAL;
70 	}
71 
72 	memset(&db_cfg, 0, sizeof(db_cfg));
73 	cparms.nitems = 1;
74 	cparms.size = sizeof(struct tcam_rm_db);
75 	cparms.alignment = 0;
76 	if (tfp_calloc(&cparms) != 0) {
77 		TFP_DRV_LOG(ERR, "tcam_rm_db alloc error %s\n",
78 			    strerror(ENOMEM));
79 		return -ENOMEM;
80 	}
81 
82 	tcam_db = cparms.mem_va;
83 	for (i = 0; i < TF_DIR_MAX; i++)
84 		tcam_db->tcam_db[i] = NULL;
85 	tf_session_set_db(tfp, TF_MODULE_TYPE_TCAM, tcam_db);
86 
87 	db_cfg.module = TF_MODULE_TYPE_TCAM;
88 	db_cfg.num_elements = parms->num_elements;
89 	db_cfg.cfg = parms->cfg;
90 
91 	for (d = 0; d < TF_DIR_MAX; d++) {
92 		db_cfg.dir = d;
93 		db_cfg.alloc_cnt = parms->resources->tcam_cnt[d].cnt;
94 		db_cfg.rm_db = (void *)&tcam_db->tcam_db[d];
95 		if (tf_session_is_shared_session(tfs) &&
96 			(!tf_session_is_shared_session_creator(tfs)))
97 			db_rc[d] = tf_rm_create_db_no_reservation(tfp, &db_cfg);
98 		else
99 			db_rc[d] = tf_rm_create_db(tfp, &db_cfg);
100 	}
101 
102 	/* No db created */
103 	if (db_rc[TF_DIR_RX] && db_rc[TF_DIR_TX]) {
104 		TFP_DRV_LOG(ERR, "No TCAM DB created\n");
105 		return db_rc[TF_DIR_RX];
106 	}
107 
108 	/* check if reserved resource for WC is multiple of num_slices */
109 	for (d = 0; d < TF_DIR_MAX; d++) {
110 		if (!tcam_db->tcam_db[d])
111 			continue;
112 
113 		memset(&info, 0, sizeof(info));
114 		ainfo.rm_db = tcam_db->tcam_db[d];
115 		ainfo.subtype = TF_TCAM_TBL_TYPE_WC_TCAM;
116 		ainfo.info = &info;
117 		rc = tf_rm_get_info(&ainfo);
118 		if (rc)
119 			goto error;
120 
121 		if (info.entry.start % num_slices != 0 ||
122 		    info.entry.stride % num_slices != 0) {
123 			TFP_DRV_LOG(ERR,
124 				    "%s: TCAM reserved resource is not multiple of %d\n",
125 				    tf_dir_2_str(d),
126 				    num_slices);
127 			rc = -EINVAL;
128 			goto error;
129 		}
130 	}
131 
132 	/* Initialize the TCAM manager. */
133 	TFP_DRV_LOG(INFO,
134 		    "TCAM - initialized\n");
135 
136 	return 0;
137 error:
138 	for (i = 0; i < TF_DIR_MAX; i++) {
139 		memset(&fparms, 0, sizeof(fparms));
140 		fparms.dir = i;
141 		fparms.rm_db = tcam_db->tcam_db[i];
142 		/* Ignoring return here since we are in the error case */
143 		(void)tf_rm_free_db(tfp, &fparms);
144 		tcam_db->tcam_db[i] = NULL;
145 		tf_session_set_db(tfp, TF_MODULE_TYPE_TCAM, NULL);
146 	}
147 
148 	return rc;
149 }
150 
151 int
152 tf_tcam_unbind(struct tf *tfp)
153 {
154 	int rc;
155 	int i;
156 	struct tf_rm_free_db_parms fparms;
157 	struct tcam_rm_db *tcam_db;
158 	void *tcam_db_ptr = NULL;
159 	TF_CHECK_PARMS1(tfp);
160 
161 	rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
162 	if (rc) {
163 		return 0;
164 	}
165 	tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
166 
167 	for (i = 0; i < TF_DIR_MAX; i++) {
168 		if (tcam_db->tcam_db[i] == NULL)
169 			continue;
170 		memset(&fparms, 0, sizeof(fparms));
171 		fparms.dir = i;
172 		fparms.rm_db = tcam_db->tcam_db[i];
173 		rc = tf_rm_free_db(tfp, &fparms);
174 		if (rc)
175 			return rc;
176 
177 		tcam_db->tcam_db[i] = NULL;
178 	}
179 
180 	return 0;
181 }
182 
183 int
184 tf_tcam_alloc(struct tf *tfp,
185 	      struct tf_tcam_alloc_parms *parms)
186 {
187 	int rc, i;
188 	struct tf_session *tfs;
189 	struct tf_dev_info *dev;
190 	struct tf_rm_allocate_parms aparms;
191 	uint16_t num_slices = 1;
192 	uint32_t index;
193 	struct tcam_rm_db *tcam_db;
194 	void *tcam_db_ptr = NULL;
195 
196 	TF_CHECK_PARMS2(tfp, parms);
197 
198 	/* Retrieve the session information */
199 	rc = tf_session_get_session_internal(tfp, &tfs);
200 	if (rc)
201 		return rc;
202 
203 	/* Retrieve the device information */
204 	rc = tf_session_get_device(tfs, &dev);
205 	if (rc)
206 		return rc;
207 
208 	if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
209 		rc = -EOPNOTSUPP;
210 		TFP_DRV_LOG(ERR,
211 			    "%s: Operation not supported, rc:%s\n",
212 			    tf_dir_2_str(parms->dir),
213 			    strerror(-rc));
214 		return rc;
215 	}
216 
217 	/* Need to retrieve number of slices based on the key_size */
218 	rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
219 						  parms->type,
220 						  parms->key_size,
221 						  &num_slices);
222 	if (rc)
223 		return rc;
224 
225 	rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
226 	if (rc) {
227 		TFP_DRV_LOG(ERR,
228 			    "Failed to get tcam_db from session, rc:%s\n",
229 			    strerror(-rc));
230 		return rc;
231 	}
232 	tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
233 
234 	/*
235 	 * For WC TCAM, number of slices could be 4, 2, 1 based on
236 	 * the key_size. For other TCAM, it is always 1
237 	 */
238 	for (i = 0; i < num_slices; i++) {
239 		memset(&aparms, 0, sizeof(aparms));
240 		aparms.rm_db = tcam_db->tcam_db[parms->dir];
241 		aparms.subtype = parms->type;
242 		aparms.priority = parms->priority;
243 		aparms.index = &index;
244 		rc = tf_rm_allocate(&aparms);
245 		if (rc) {
246 			TFP_DRV_LOG(ERR,
247 				    "%s: Failed tcam, type:%d\n",
248 				    tf_dir_2_str(parms->dir),
249 				    parms->type);
250 			return rc;
251 		}
252 
253 		/* return the start index of each row */
254 		if (parms->priority == 0) {
255 			if (i == 0)
256 				parms->idx = index;
257 		} else {
258 			parms->idx = index;
259 		}
260 	}
261 
262 	return 0;
263 }
264 
265 int
266 tf_tcam_free(struct tf *tfp,
267 	     struct tf_tcam_free_parms *parms)
268 {
269 	int rc;
270 	struct tf_session *tfs;
271 	struct tf_dev_info *dev;
272 	struct tf_rm_is_allocated_parms aparms;
273 	struct tf_rm_free_parms fparms;
274 	struct tf_rm_get_hcapi_parms hparms;
275 	uint16_t num_slices = 1;
276 	int allocated = 0;
277 	int i;
278 	struct tcam_rm_db *tcam_db;
279 	void *tcam_db_ptr = NULL;
280 
281 	TF_CHECK_PARMS2(tfp, parms);
282 
283 	/* Retrieve the session information */
284 	rc = tf_session_get_session_internal(tfp, &tfs);
285 	if (rc)
286 		return rc;
287 
288 	/* Retrieve the device information */
289 	rc = tf_session_get_device(tfs, &dev);
290 	if (rc)
291 		return rc;
292 
293 	if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
294 		rc = -EOPNOTSUPP;
295 		TFP_DRV_LOG(ERR,
296 			    "%s: Operation not supported, rc:%s\n",
297 			    tf_dir_2_str(parms->dir),
298 			    strerror(-rc));
299 		return rc;
300 	}
301 
302 	/* Need to retrieve row size etc */
303 	rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
304 						  parms->type,
305 						  0,
306 						  &num_slices);
307 	if (rc)
308 		return rc;
309 
310 	if (parms->idx % num_slices) {
311 		TFP_DRV_LOG(ERR,
312 			    "%s: TCAM reserved resource is not multiple of %d\n",
313 			    tf_dir_2_str(parms->dir),
314 			    num_slices);
315 		return -EINVAL;
316 	}
317 
318 	rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
319 	if (rc) {
320 		TFP_DRV_LOG(ERR,
321 			    "Failed to get em_ext_db from session, rc:%s\n",
322 			    strerror(-rc));
323 		return rc;
324 	}
325 	tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
326 
327 	/* Check if element is in use */
328 	memset(&aparms, 0, sizeof(aparms));
329 	aparms.rm_db = tcam_db->tcam_db[parms->dir];
330 	aparms.subtype = parms->type;
331 	aparms.index = parms->idx;
332 	aparms.allocated = &allocated;
333 	rc = tf_rm_is_allocated(&aparms);
334 	if (rc)
335 		return rc;
336 
337 	if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
338 		TFP_DRV_LOG(ERR,
339 			    "%s: Entry already free, type:%d, index:%d\n",
340 			    tf_dir_2_str(parms->dir),
341 			    parms->type,
342 			    parms->idx);
343 		return -EINVAL;
344 	}
345 
346 	for (i = 0; i < num_slices; i++) {
347 		/* Free requested element */
348 		memset(&fparms, 0, sizeof(fparms));
349 		fparms.rm_db = tcam_db->tcam_db[parms->dir];
350 		fparms.subtype = parms->type;
351 		fparms.index = parms->idx + i;
352 		rc = tf_rm_free(&fparms);
353 		if (rc) {
354 			TFP_DRV_LOG(ERR,
355 				    "%s: Free failed, type:%d, index:%d\n",
356 				    tf_dir_2_str(parms->dir),
357 				    parms->type,
358 				    parms->idx);
359 			return rc;
360 		}
361 	}
362 
363 	/* Convert TF type to HCAPI RM type */
364 	memset(&hparms, 0, sizeof(hparms));
365 
366 	hparms.rm_db = tcam_db->tcam_db[parms->dir];
367 	hparms.subtype = parms->type;
368 	hparms.hcapi_type = &parms->hcapi_type;
369 
370 	rc = tf_rm_get_hcapi_type(&hparms);
371 	if (rc)
372 		return rc;
373 
374 	rc = tf_msg_tcam_entry_free(tfp, dev, parms);
375 	if (rc) {
376 		/* Log error */
377 		TFP_DRV_LOG(ERR,
378 			    "%s: %s: Entry %d free failed, rc:%s\n",
379 			    tf_dir_2_str(parms->dir),
380 			    tf_tcam_tbl_2_str(parms->type),
381 			    parms->idx,
382 			    strerror(-rc));
383 		return rc;
384 	}
385 
386 	return 0;
387 }
388 
389 int
390 tf_tcam_set(struct tf *tfp __rte_unused,
391 	    struct tf_tcam_set_parms *parms __rte_unused)
392 {
393 	int rc;
394 	struct tf_session *tfs;
395 	struct tf_dev_info *dev;
396 	struct tf_rm_is_allocated_parms aparms;
397 	struct tf_rm_get_hcapi_parms hparms;
398 	uint16_t num_slice_per_row = 1;
399 	int allocated = 0;
400 	struct tcam_rm_db *tcam_db;
401 	void *tcam_db_ptr = NULL;
402 
403 	TF_CHECK_PARMS2(tfp, parms);
404 
405 	/* Retrieve the session information */
406 	rc = tf_session_get_session_internal(tfp, &tfs);
407 	if (rc)
408 		return rc;
409 
410 	/* Retrieve the device information */
411 	rc = tf_session_get_device(tfs, &dev);
412 	if (rc)
413 		return rc;
414 
415 	if (dev->ops->tf_dev_get_tcam_slice_info == NULL) {
416 		rc = -EOPNOTSUPP;
417 		TFP_DRV_LOG(ERR,
418 			    "%s: Operation not supported, rc:%s\n",
419 			    tf_dir_2_str(parms->dir),
420 			    strerror(-rc));
421 		return rc;
422 	}
423 
424 	/* Need to retrieve row size etc */
425 	rc = dev->ops->tf_dev_get_tcam_slice_info(tfp,
426 						  parms->type,
427 						  parms->key_size,
428 						  &num_slice_per_row);
429 	if (rc)
430 		return rc;
431 
432 	rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
433 	if (rc) {
434 		TFP_DRV_LOG(ERR,
435 			    "Failed to get em_ext_db from session, rc:%s\n",
436 			    strerror(-rc));
437 		return rc;
438 	}
439 	tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
440 
441 	/* Check if element is in use */
442 	memset(&aparms, 0, sizeof(aparms));
443 
444 	aparms.rm_db = tcam_db->tcam_db[parms->dir];
445 	aparms.subtype = parms->type;
446 	aparms.index = parms->idx;
447 	aparms.allocated = &allocated;
448 	rc = tf_rm_is_allocated(&aparms);
449 	if (rc)
450 		return rc;
451 
452 	if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
453 		TFP_DRV_LOG(ERR,
454 			    "%s: Entry is not allocated, type:%d, index:%d\n",
455 			    tf_dir_2_str(parms->dir),
456 			    parms->type,
457 			    parms->idx);
458 		return -EINVAL;
459 	}
460 
461 	/* Convert TF type to HCAPI RM type */
462 	memset(&hparms, 0, sizeof(hparms));
463 
464 	hparms.rm_db = tcam_db->tcam_db[parms->dir];
465 	hparms.subtype = parms->type;
466 	hparms.hcapi_type = &parms->hcapi_type;
467 
468 	rc = tf_rm_get_hcapi_type(&hparms);
469 	if (rc)
470 		return rc;
471 
472 	rc = tf_msg_tcam_entry_set(tfp, dev, parms);
473 	if (rc) {
474 		/* Log error */
475 		TFP_DRV_LOG(ERR,
476 			    "%s: %s: Entry %d set failed, rc:%s",
477 			    tf_dir_2_str(parms->dir),
478 			    tf_tcam_tbl_2_str(parms->type),
479 			    parms->idx,
480 			    strerror(-rc));
481 		return rc;
482 	}
483 	return 0;
484 }
485 
486 int
487 tf_tcam_get(struct tf *tfp __rte_unused,
488 	    struct tf_tcam_get_parms *parms)
489 {
490 	int rc;
491 	struct tf_session *tfs;
492 	struct tf_dev_info *dev;
493 	struct tf_rm_is_allocated_parms aparms;
494 	struct tf_rm_get_hcapi_parms hparms;
495 	int allocated = 0;
496 	struct tcam_rm_db *tcam_db;
497 	void *tcam_db_ptr = NULL;
498 
499 	TF_CHECK_PARMS2(tfp, parms);
500 
501 	/* Retrieve the session information */
502 	rc = tf_session_get_session_internal(tfp, &tfs);
503 	if (rc)
504 		return rc;
505 
506 	/* Retrieve the device information */
507 	rc = tf_session_get_device(tfs, &dev);
508 	if (rc)
509 		return rc;
510 
511 	rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
512 	if (rc) {
513 		TFP_DRV_LOG(ERR,
514 			    "Failed to get em_ext_db from session, rc:%s\n",
515 			    strerror(-rc));
516 		return rc;
517 	}
518 	tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
519 
520 	/* Check if element is in use */
521 	memset(&aparms, 0, sizeof(aparms));
522 
523 	aparms.rm_db = tcam_db->tcam_db[parms->dir];
524 	aparms.subtype = parms->type;
525 	aparms.index = parms->idx;
526 	aparms.allocated = &allocated;
527 	rc = tf_rm_is_allocated(&aparms);
528 	if (rc)
529 		return rc;
530 
531 	if (allocated != TF_RM_ALLOCATED_ENTRY_IN_USE) {
532 		TFP_DRV_LOG(ERR,
533 			    "%s: Entry is not allocated, type:%d, index:%d\n",
534 			    tf_dir_2_str(parms->dir),
535 			    parms->type,
536 			    parms->idx);
537 		return -EINVAL;
538 	}
539 
540 	/* Convert TF type to HCAPI RM type */
541 	memset(&hparms, 0, sizeof(hparms));
542 
543 	hparms.rm_db = tcam_db->tcam_db[parms->dir];
544 	hparms.subtype = parms->type;
545 	hparms.hcapi_type = &parms->hcapi_type;
546 
547 	rc = tf_rm_get_hcapi_type(&hparms);
548 	if (rc)
549 		return rc;
550 
551 	rc = tf_msg_tcam_entry_get(tfp, dev, parms);
552 	if (rc) {
553 		/* Log error */
554 		TFP_DRV_LOG(ERR,
555 			    "%s: %s: Entry %d set failed, rc:%s",
556 			    tf_dir_2_str(parms->dir),
557 			    tf_tcam_tbl_2_str(parms->type),
558 			    parms->idx,
559 			    strerror(-rc));
560 		return rc;
561 	}
562 
563 	return 0;
564 }
565 
566 int
567 tf_tcam_get_resc_info(struct tf *tfp,
568 		      struct tf_tcam_resource_info *tcam)
569 {
570 	int rc;
571 	int d;
572 	struct tf_resource_info *dinfo;
573 	struct tf_rm_get_alloc_info_parms ainfo;
574 	void *tcam_db_ptr = NULL;
575 	struct tcam_rm_db *tcam_db;
576 
577 	TF_CHECK_PARMS2(tfp, tcam);
578 
579 	rc = tf_session_get_db(tfp, TF_MODULE_TYPE_TCAM, &tcam_db_ptr);
580 	if (rc == -ENOMEM)
581 		return 0;  /* db doesn't exist */
582 	else if (rc)
583 		return rc; /* error getting db */
584 
585 	tcam_db = (struct tcam_rm_db *)tcam_db_ptr;
586 
587 	/* check if reserved resource for WC is multiple of num_slices */
588 	for (d = 0; d < TF_DIR_MAX; d++) {
589 		ainfo.rm_db = tcam_db->tcam_db[d];
590 
591 		if (!ainfo.rm_db)
592 			continue;
593 
594 		dinfo = tcam[d].info;
595 
596 		ainfo.info = (struct tf_rm_alloc_info *)dinfo;
597 		ainfo.subtype = 0;
598 		rc = tf_rm_get_all_info(&ainfo, TF_TCAM_TBL_TYPE_MAX);
599 		if (rc && rc != -ENOTSUP)
600 			return rc;
601 	}
602 
603 	return 0;
604 }
605