xref: /dpdk/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c (revision 7d32c003ac175d7ac8669dc11684c75cc7eb56b8)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2021 Broadcom
3  * All rights reserved.
4  */
5 
6 #include <rte_log.h>
7 #include <rte_malloc.h>
8 #include <rte_flow.h>
9 #include <rte_flow_driver.h>
10 #include <rte_tailq.h>
11 #include <rte_spinlock.h>
12 #include <rte_mtr.h>
13 #include <rte_version.h>
14 #include <rte_hash_crc.h>
15 
16 #include "bnxt.h"
17 #include "bnxt_ulp.h"
18 #include "bnxt_ulp_utils.h"
19 #include "bnxt_ulp_tf.h"
20 #include "bnxt_tf_common.h"
21 #include "hsi_struct_def_dpdk.h"
22 #include "tf_core.h"
23 #include "tf_ext_flow_handle.h"
24 
25 #include "ulp_template_db_enum.h"
26 #include "ulp_template_struct.h"
27 #include "ulp_mark_mgr.h"
28 #include "ulp_fc_mgr.h"
29 #include "ulp_flow_db.h"
30 #include "ulp_mapper.h"
31 #include "ulp_matcher.h"
32 #include "ulp_port_db.h"
33 #include "ulp_tun.h"
34 #include "ulp_ha_mgr.h"
35 #include "bnxt_tf_pmd_shim.h"
36 #include "ulp_template_db_tbl.h"
37 
38 /* Function to set the tfp session details from the ulp context. */
39 int32_t
40 bnxt_ulp_cntxt_tfp_set(struct bnxt_ulp_context *ulp,
41 		       enum bnxt_ulp_session_type s_type,
42 		       struct tf *tfp)
43 {
44 	uint32_t idx = 0;
45 	enum bnxt_ulp_tfo_type tfo_type = BNXT_ULP_TFO_TYPE_TF;
46 
47 	if (ulp == NULL)
48 		return -EINVAL;
49 
50 	if (ULP_MULTI_SHARED_IS_SUPPORTED(ulp)) {
51 		if (s_type & BNXT_ULP_SESSION_TYPE_SHARED)
52 			idx = 1;
53 		else if (s_type & BNXT_ULP_SESSION_TYPE_SHARED_WC)
54 			idx = 2;
55 
56 	} else {
57 		if ((s_type & BNXT_ULP_SESSION_TYPE_SHARED) ||
58 		    (s_type & BNXT_ULP_SESSION_TYPE_SHARED_WC))
59 			idx = 1;
60 	}
61 
62 	ulp->g_tfp[idx] = tfp;
63 
64 	if (tfp == NULL) {
65 		uint32_t i = 0;
66 		while (i < BNXT_ULP_SESSION_MAX && ulp->g_tfp[i] == NULL)
67 			i++;
68 		if (i == BNXT_ULP_SESSION_MAX)
69 			ulp->tfo_type = BNXT_ULP_TFO_TYPE_INVALID;
70 	} else {
71 		ulp->tfo_type = tfo_type;
72 	}
73 	return 0;
74 }
75 
76 /* Function to get the tfp session details from the ulp context. */
77 struct tf *
78 bnxt_ulp_cntxt_tfp_get(struct bnxt_ulp_context *ulp,
79 		       enum bnxt_ulp_session_type s_type)
80 {
81 	uint32_t idx = 0;
82 
83 	if (ulp == NULL)
84 		return NULL;
85 
86 	if (ulp->tfo_type != BNXT_ULP_TFO_TYPE_TF) {
87 		BNXT_DRV_DBG(ERR, "Wrong tf type %d != %d\n",
88 			     ulp->tfo_type, BNXT_ULP_TFO_TYPE_TF);
89 		return NULL;
90 	}
91 
92 	if (ULP_MULTI_SHARED_IS_SUPPORTED(ulp)) {
93 		if (s_type & BNXT_ULP_SESSION_TYPE_SHARED)
94 			idx = 1;
95 		else if (s_type & BNXT_ULP_SESSION_TYPE_SHARED_WC)
96 			idx = 2;
97 	} else {
98 		if ((s_type & BNXT_ULP_SESSION_TYPE_SHARED) ||
99 		    (s_type & BNXT_ULP_SESSION_TYPE_SHARED_WC))
100 			idx = 1;
101 	}
102 	return (struct tf *)ulp->g_tfp[idx];
103 }
104 
105 struct tf *bnxt_get_tfp_session(struct bnxt *bp, enum bnxt_session_type type)
106 {
107 	return (type >= BNXT_SESSION_TYPE_LAST) ?
108 		&bp->tfp[BNXT_SESSION_TYPE_REGULAR] : &bp->tfp[type];
109 }
110 
111 struct tf *
112 bnxt_ulp_bp_tfp_get(struct bnxt *bp, enum bnxt_ulp_session_type type)
113 {
114 	enum bnxt_session_type btype;
115 
116 	if (type & BNXT_ULP_SESSION_TYPE_SHARED)
117 		btype = BNXT_SESSION_TYPE_SHARED_COMMON;
118 	else if (type & BNXT_ULP_SESSION_TYPE_SHARED_WC)
119 		btype = BNXT_SESSION_TYPE_SHARED_WC;
120 	else
121 		btype = BNXT_SESSION_TYPE_REGULAR;
122 
123 	return bnxt_get_tfp_session(bp, btype);
124 }
125 
126 static int32_t
127 ulp_tf_named_resources_calc(struct bnxt_ulp_context *ulp_ctx,
128 			    struct bnxt_ulp_glb_resource_info *info,
129 			    uint32_t num,
130 			    enum bnxt_ulp_session_type stype,
131 			    struct tf_session_resources *res)
132 {
133 	uint32_t dev_id = BNXT_ULP_DEVICE_ID_LAST, res_type, i;
134 	enum tf_dir dir;
135 	uint8_t app_id;
136 	int32_t rc = 0;
137 
138 	if (ulp_ctx == NULL || info == NULL || res == NULL || num == 0) {
139 		BNXT_DRV_DBG(ERR, "Invalid parms to named resources calc.\n");
140 		return -EINVAL;
141 	}
142 
143 	rc = bnxt_ulp_cntxt_app_id_get(ulp_ctx, &app_id);
144 	if (rc) {
145 		BNXT_DRV_DBG(ERR, "Unable to get the app id from ulp.\n");
146 		return -EINVAL;
147 	}
148 
149 	rc = bnxt_ulp_cntxt_dev_id_get(ulp_ctx, &dev_id);
150 	if (rc) {
151 		BNXT_DRV_DBG(ERR, "Unable to get the dev id from ulp.\n");
152 		return -EINVAL;
153 	}
154 
155 	for (i = 0; i < num; i++) {
156 		if (dev_id != info[i].device_id || app_id != info[i].app_id)
157 			continue;
158 		/* check to see if the session type matches only then include */
159 		if ((stype || info[i].session_type) &&
160 		    !(info[i].session_type & stype))
161 			continue;
162 
163 		dir = info[i].direction;
164 		res_type = info[i].resource_type;
165 
166 		switch (info[i].resource_func) {
167 		case BNXT_ULP_RESOURCE_FUNC_IDENTIFIER:
168 			res->ident_cnt[dir].cnt[res_type]++;
169 			break;
170 		case BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE:
171 			res->tbl_cnt[dir].cnt[res_type]++;
172 			break;
173 		case BNXT_ULP_RESOURCE_FUNC_TCAM_TABLE:
174 			res->tcam_cnt[dir].cnt[res_type]++;
175 			break;
176 		case BNXT_ULP_RESOURCE_FUNC_EM_TABLE:
177 			res->em_cnt[dir].cnt[res_type]++;
178 			break;
179 		default:
180 			BNXT_DRV_DBG(ERR, "Unknown resource func (0x%x)\n,",
181 				     info[i].resource_func);
182 			continue;
183 		}
184 	}
185 
186 	return 0;
187 }
188 
189 static int32_t
190 ulp_tf_unnamed_resources_calc(struct bnxt_ulp_context *ulp_ctx,
191 			      struct bnxt_ulp_resource_resv_info *info,
192 			      uint32_t num,
193 			      enum bnxt_ulp_session_type stype,
194 			      struct tf_session_resources *res)
195 {
196 	uint32_t dev_id, res_type, i;
197 	enum tf_dir dir;
198 	uint8_t app_id;
199 	int32_t rc = 0;
200 
201 	if (ulp_ctx == NULL || res == NULL || info == NULL || num == 0) {
202 		BNXT_DRV_DBG(ERR, "Invalid arguments to get resources.\n");
203 		return -EINVAL;
204 	}
205 
206 	rc = bnxt_ulp_cntxt_app_id_get(ulp_ctx, &app_id);
207 	if (rc) {
208 		BNXT_DRV_DBG(ERR, "Unable to get the app id from ulp.\n");
209 		return -EINVAL;
210 	}
211 
212 	rc = bnxt_ulp_cntxt_dev_id_get(ulp_ctx, &dev_id);
213 	if (rc) {
214 		BNXT_DRV_DBG(ERR, "Unable to get the dev id from ulp.\n");
215 		return -EINVAL;
216 	}
217 
218 	for (i = 0; i < num; i++) {
219 		if (app_id != info[i].app_id || dev_id != info[i].device_id)
220 			continue;
221 
222 		/* check to see if the session type matches only then include */
223 		if ((stype || info[i].session_type) &&
224 		    !(info[i].session_type & stype))
225 			continue;
226 
227 		dir = info[i].direction;
228 		res_type = info[i].resource_type;
229 
230 		switch (info[i].resource_func) {
231 		case BNXT_ULP_RESOURCE_FUNC_IDENTIFIER:
232 			res->ident_cnt[dir].cnt[res_type] = info[i].count;
233 			break;
234 		case BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE:
235 			res->tbl_cnt[dir].cnt[res_type] = info[i].count;
236 			break;
237 		case BNXT_ULP_RESOURCE_FUNC_TCAM_TABLE:
238 			res->tcam_cnt[dir].cnt[res_type] = info[i].count;
239 			break;
240 		case BNXT_ULP_RESOURCE_FUNC_EM_TABLE:
241 			res->em_cnt[dir].cnt[res_type] = info[i].count;
242 			break;
243 		default:
244 			break;
245 		}
246 	}
247 	return 0;
248 }
249 
250 static int32_t
251 ulp_tf_resources_get(struct bnxt_ulp_context *ulp_ctx,
252 		     enum bnxt_ulp_session_type stype,
253 		     struct tf_session_resources *res)
254 {
255 	struct bnxt_ulp_resource_resv_info *unnamed = NULL;
256 	uint32_t unum;
257 	int32_t rc = 0;
258 
259 	if (ulp_ctx == NULL || res == NULL) {
260 		BNXT_DRV_DBG(ERR, "Invalid arguments to get resources.\n");
261 		return -EINVAL;
262 	}
263 
264 	/* use DEFAULT_NON_HA instead of DEFAULT resources if HA is disabled */
265 	if (ULP_APP_HA_IS_DYNAMIC(ulp_ctx))
266 		stype = ulp_ctx->cfg_data->def_session_type;
267 
268 	unnamed = bnxt_ulp_resource_resv_list_get(&unum);
269 	if (unnamed == NULL) {
270 		BNXT_DRV_DBG(ERR, "Unable to get resource resv list.\n");
271 		return -EINVAL;
272 	}
273 
274 	rc = ulp_tf_unnamed_resources_calc(ulp_ctx, unnamed, unum, stype, res);
275 	if (rc)
276 		BNXT_DRV_DBG(ERR, "Unable to calc resources for session.\n");
277 
278 	return rc;
279 }
280 
281 static int32_t
282 ulp_tf_shared_session_resources_get(struct bnxt_ulp_context *ulp_ctx,
283 				    enum bnxt_ulp_session_type stype,
284 				    struct tf_session_resources *res)
285 {
286 	struct bnxt_ulp_resource_resv_info *unnamed;
287 	struct bnxt_ulp_glb_resource_info *named;
288 	uint32_t unum = 0, nnum = 0;
289 	int32_t rc;
290 
291 	if (ulp_ctx == NULL || res == NULL) {
292 		BNXT_DRV_DBG(ERR, "Invalid arguments to get resources.\n");
293 		return -EINVAL;
294 	}
295 
296 	/* Make sure the resources are zero before accumulating. */
297 	memset(res, 0, sizeof(struct tf_session_resources));
298 
299 	if (bnxt_ulp_cntxt_ha_enabled(ulp_ctx) &&
300 	    stype == BNXT_ULP_SESSION_TYPE_SHARED)
301 		stype = ulp_ctx->cfg_data->hu_session_type;
302 
303 	/*
304 	 * Shared resources are comprised of both named and unnamed resources.
305 	 * First get the unnamed counts, and then add the named to the result.
306 	 */
307 	/* Get the baseline counts */
308 	unnamed = bnxt_ulp_app_resource_resv_list_get(&unum);
309 	if (unum) {
310 		rc = ulp_tf_unnamed_resources_calc(ulp_ctx, unnamed,
311 						   unum, stype, res);
312 		if (rc) {
313 			BNXT_DRV_DBG(ERR,
314 				     "Unable to calc resources for shared session.\n");
315 			return -EINVAL;
316 		}
317 	}
318 
319 	/* Get the named list and add the totals */
320 	named = bnxt_ulp_app_glb_resource_info_list_get(&nnum);
321 	/* No need to calc resources, none to calculate */
322 	if (!nnum)
323 		return 0;
324 
325 	rc = ulp_tf_named_resources_calc(ulp_ctx, named, nnum, stype, res);
326 	if (rc)
327 		BNXT_DRV_DBG(ERR, "Unable to calc named resources\n");
328 
329 	return rc;
330 }
331 
332 /* Function to set the hot upgrade support into the context */
333 static int
334 ulp_tf_multi_shared_session_support_set(struct bnxt *bp,
335 					enum bnxt_ulp_device_id devid,
336 					uint32_t fw_hu_update)
337 {
338 	struct bnxt_ulp_context *ulp_ctx = bp->ulp_ctx;
339 	struct tf_get_version_parms v_params = { 0 };
340 	struct tf *tfp;
341 	int32_t rc = 0;
342 	int32_t new_fw = 0;
343 
344 	v_params.device_type = bnxt_ulp_cntxt_convert_dev_id(devid);
345 	v_params.bp = bp;
346 
347 	tfp = bnxt_ulp_bp_tfp_get(bp, BNXT_ULP_SESSION_TYPE_DEFAULT);
348 	rc = tf_get_version(tfp, &v_params);
349 	if (rc) {
350 		BNXT_DRV_DBG(ERR, "Unable to get tf version.\n");
351 		return rc;
352 	}
353 
354 	if (v_params.major == 1 && v_params.minor == 0 &&
355 	    v_params.update == 1) {
356 		new_fw = 1;
357 	}
358 	/* if the version update is greater than 0 then set support for
359 	 * multiple version
360 	 */
361 	if (new_fw) {
362 		ulp_ctx->cfg_data->ulp_flags |= BNXT_ULP_MULTI_SHARED_SUPPORT;
363 		ulp_ctx->cfg_data->hu_session_type =
364 			BNXT_ULP_SESSION_TYPE_SHARED;
365 	}
366 	if (!new_fw && fw_hu_update) {
367 		ulp_ctx->cfg_data->ulp_flags &= ~BNXT_ULP_HIGH_AVAIL_ENABLED;
368 		ulp_ctx->cfg_data->hu_session_type =
369 			BNXT_ULP_SESSION_TYPE_SHARED |
370 			BNXT_ULP_SESSION_TYPE_SHARED_OWC;
371 	}
372 
373 	if (!new_fw && !fw_hu_update) {
374 		ulp_ctx->cfg_data->hu_session_type =
375 			BNXT_ULP_SESSION_TYPE_SHARED |
376 			BNXT_ULP_SESSION_TYPE_SHARED_OWC;
377 	}
378 
379 	return rc;
380 }
381 
382 static int32_t
383 ulp_tf_cntxt_app_caps_init(struct bnxt *bp,
384 			   uint8_t app_id, uint32_t dev_id)
385 {
386 	struct bnxt_ulp_app_capabilities_info *info;
387 	uint32_t num = 0, fw = 0;
388 	uint16_t i;
389 	bool found = false;
390 	struct bnxt_ulp_context *ulp_ctx = bp->ulp_ctx;
391 
392 	if (ULP_APP_DEV_UNSUPPORTED_ENABLED(ulp_ctx->cfg_data->ulp_flags)) {
393 		BNXT_DRV_DBG(ERR, "APP ID %d, Device ID: 0x%x not supported.\n",
394 			     app_id, dev_id);
395 		return -EINVAL;
396 	}
397 
398 	info = bnxt_ulp_app_cap_list_get(&num);
399 	if (!info || !num) {
400 		BNXT_DRV_DBG(ERR, "Failed to get app capabilities.\n");
401 		return -EINVAL;
402 	}
403 
404 	for (i = 0; i < num; i++) {
405 		if (info[i].app_id != app_id || info[i].device_id != dev_id)
406 			continue;
407 		found = true;
408 		if (info[i].flags & BNXT_ULP_APP_CAP_SHARED_EN)
409 			ulp_ctx->cfg_data->ulp_flags |=
410 				BNXT_ULP_SHARED_SESSION_ENABLED;
411 		if (info[i].flags & BNXT_ULP_APP_CAP_HOT_UPGRADE_EN)
412 			ulp_ctx->cfg_data->ulp_flags |=
413 				BNXT_ULP_HIGH_AVAIL_ENABLED;
414 		if (info[i].flags & BNXT_ULP_APP_CAP_UNICAST_ONLY)
415 			ulp_ctx->cfg_data->ulp_flags |=
416 				BNXT_ULP_APP_UNICAST_ONLY;
417 		if (info[i].flags & BNXT_ULP_APP_CAP_IP_TOS_PROTO_SUPPORT)
418 			ulp_ctx->cfg_data->ulp_flags |=
419 				BNXT_ULP_APP_TOS_PROTO_SUPPORT;
420 		if (info[i].flags & BNXT_ULP_APP_CAP_BC_MC_SUPPORT)
421 			ulp_ctx->cfg_data->ulp_flags |=
422 				BNXT_ULP_APP_BC_MC_SUPPORT;
423 		if (info[i].flags & BNXT_ULP_APP_CAP_SOCKET_DIRECT) {
424 			/* Enable socket direction only if MR is enabled in fw*/
425 			if (BNXT_MULTIROOT_EN(bp)) {
426 				ulp_ctx->cfg_data->ulp_flags |=
427 					BNXT_ULP_APP_SOCKET_DIRECT;
428 				BNXT_DRV_DBG(INFO,
429 					     "Socket Direct feature is enabled\n");
430 			}
431 		}
432 		if (info[i].flags & BNXT_ULP_APP_CAP_HA_DYNAMIC) {
433 			/* Read the environment variable to determine hot up */
434 			if (!bnxt_pmd_get_hot_up_config()) {
435 				ulp_ctx->cfg_data->ulp_flags |=
436 					BNXT_ULP_APP_HA_DYNAMIC;
437 				/* reset Hot upgrade, dynamically disabled */
438 				ulp_ctx->cfg_data->ulp_flags &=
439 					~BNXT_ULP_HIGH_AVAIL_ENABLED;
440 				ulp_ctx->cfg_data->def_session_type =
441 					BNXT_ULP_SESSION_TYPE_DEFAULT_NON_HA;
442 				BNXT_DRV_DBG(INFO, "Hot upgrade disabled.\n");
443 			}
444 		}
445 		if (info[i].flags & BNXT_ULP_APP_CAP_SRV6)
446 			ulp_ctx->cfg_data->ulp_flags |=
447 				BNXT_ULP_APP_SRV6;
448 
449 		if (info[i].flags & BNXT_ULP_APP_CAP_L2_ETYPE)
450 			ulp_ctx->cfg_data->ulp_flags |=
451 				BNXT_ULP_APP_L2_ETYPE;
452 
453 		bnxt_ulp_cntxt_vxlan_ip_port_set(ulp_ctx, info[i].vxlan_ip_port);
454 		bnxt_ulp_cntxt_vxlan_port_set(ulp_ctx, info[i].vxlan_port);
455 		bnxt_ulp_cntxt_ecpri_udp_port_set(ulp_ctx, info[i].ecpri_udp_port);
456 		bnxt_ulp_vxlan_gpe_next_proto_set(ulp_ctx, info[i].tunnel_next_proto);
457 		bnxt_ulp_num_key_recipes_set(ulp_ctx,
458 					     info[i].num_key_recipes_per_dir);
459 
460 		/* set the shared session support from firmware */
461 		fw = info[i].upgrade_fw_update;
462 		if (ULP_HIGH_AVAIL_IS_ENABLED(ulp_ctx->cfg_data->ulp_flags) &&
463 		    ulp_tf_multi_shared_session_support_set(bp, dev_id, fw)) {
464 			BNXT_DRV_DBG(ERR,
465 				     "Unable to get shared session support\n");
466 			return -EINVAL;
467 		}
468 		bnxt_ulp_cntxt_ha_reg_set(ulp_ctx, info[i].ha_reg_state,
469 				    info[i].ha_reg_cnt);
470 		ulp_ctx->cfg_data->ha_pool_id = info[i].ha_pool_id;
471 		bnxt_ulp_default_app_priority_set(ulp_ctx,
472 						  info[i].default_priority);
473 		bnxt_ulp_max_def_priority_set(ulp_ctx,
474 					      info[i].max_def_priority);
475 		bnxt_ulp_min_flow_priority_set(ulp_ctx,
476 					       info[i].min_flow_priority);
477 		bnxt_ulp_max_flow_priority_set(ulp_ctx,
478 					       info[i].max_flow_priority);
479 		/* Update the capability feature bits*/
480 		if (bnxt_ulp_cap_feat_process(info[i].feature_bits,
481 					      &ulp_ctx->cfg_data->feature_bits))
482 			return -EINVAL;
483 
484 		bnxt_ulp_cntxt_ptr2_default_class_bits_set(ulp_ctx,
485 							   info[i].default_class_bits);
486 		bnxt_ulp_cntxt_ptr2_default_act_bits_set(ulp_ctx,
487 							 info[i].default_act_bits);
488 	}
489 	if (!found) {
490 		BNXT_DRV_DBG(ERR, "APP ID %d, Device ID: 0x%x not supported.\n",
491 			     app_id, dev_id);
492 		ulp_ctx->cfg_data->ulp_flags |= BNXT_ULP_APP_DEV_UNSUPPORTED;
493 		return -EINVAL;
494 	}
495 
496 	return 0;
497 }
498 
499 static inline uint32_t
500 ulp_tf_session_idx_get(enum bnxt_ulp_session_type session_type) {
501 	if (session_type & BNXT_ULP_SESSION_TYPE_SHARED)
502 		return 1;
503 	else if (session_type & BNXT_ULP_SESSION_TYPE_SHARED_WC)
504 		return 2;
505 	return 0;
506 }
507 
508 /* Function to set the tfp session details in session */
509 static int32_t
510 ulp_tf_session_tfp_set(struct bnxt_ulp_session_state *session,
511 		       enum bnxt_ulp_session_type session_type,
512 		       struct tf *tfp)
513 {
514 	uint32_t idx = ulp_tf_session_idx_get(session_type);
515 	struct tf *local_tfp;
516 	int32_t rc = 0;
517 
518 	if (!session->session_opened[idx]) {
519 		local_tfp = rte_zmalloc("bnxt_ulp_session_tfp",
520 					sizeof(struct tf), 0);
521 
522 		if (local_tfp == NULL) {
523 			BNXT_DRV_DBG(DEBUG, "Failed to alloc session tfp\n");
524 			return -ENOMEM;
525 		}
526 		local_tfp->session = tfp->session;
527 		session->g_tfp[idx] = local_tfp;
528 		session->session_opened[idx] = 1;
529 	}
530 	return rc;
531 }
532 
533 /* Function to get the tfp session details in session */
534 static struct tf_session_info *
535 ulp_tf_session_tfp_get(struct bnxt_ulp_session_state *session,
536 		       enum bnxt_ulp_session_type session_type)
537 {
538 	uint32_t idx = ulp_tf_session_idx_get(session_type);
539 	struct tf *local_tfp = session->g_tfp[idx];
540 
541 	if (session->session_opened[idx])
542 		return local_tfp->session;
543 	return NULL;
544 }
545 
546 static uint32_t
547 ulp_tf_session_is_open(struct bnxt_ulp_session_state *session,
548 		       enum bnxt_ulp_session_type session_type)
549 {
550 	uint32_t idx = ulp_tf_session_idx_get(session_type);
551 
552 	return session->session_opened[idx];
553 }
554 
555 /* Function to reset the tfp session details in session */
556 static void
557 ulp_tf_session_tfp_reset(struct bnxt_ulp_session_state *session,
558 			 enum bnxt_ulp_session_type session_type)
559 {
560 	uint32_t idx = ulp_tf_session_idx_get(session_type);
561 
562 	if (session->session_opened[idx]) {
563 		session->session_opened[idx] = 0;
564 		rte_free(session->g_tfp[idx]);
565 		session->g_tfp[idx] = NULL;
566 	}
567 }
568 
569 static void
570 ulp_tf_ctx_shared_session_close(struct bnxt *bp,
571 				enum bnxt_ulp_session_type session_type,
572 				struct bnxt_ulp_session_state *session)
573 {
574 	struct tf *tfp;
575 	int32_t rc;
576 
577 	tfp = bnxt_ulp_cntxt_tfp_get(bp->ulp_ctx, session_type);
578 	if (!tfp) {
579 		/*
580 		 * Log it under debug since this is likely a case of the
581 		 * shared session not being created.  For example, a failed
582 		 * initialization.
583 		 */
584 		BNXT_DRV_DBG(DEBUG, "Failed to get shared tfp on close.\n");
585 		return;
586 	}
587 	rc = tf_close_session(tfp);
588 	if (rc)
589 		BNXT_DRV_DBG(ERR, "Failed to close the shared session rc=%d.\n",
590 			     rc);
591 	(void)bnxt_ulp_cntxt_tfp_set(bp->ulp_ctx, session_type, NULL);
592 	ulp_tf_session_tfp_reset(session, session_type);
593 }
594 
595 static int32_t
596 ulp_tf_ctx_shared_session_open(struct bnxt *bp,
597 			       enum bnxt_ulp_session_type session_type,
598 			       struct bnxt_ulp_session_state *session)
599 {
600 	struct rte_eth_dev *ethdev = bp->eth_dev;
601 	struct tf_session_resources *resources;
602 	struct tf_open_session_parms parms;
603 	size_t nb;
604 	uint32_t ulp_dev_id = BNXT_ULP_DEVICE_ID_LAST;
605 	int32_t	rc = 0;
606 	uint8_t app_id;
607 	struct tf *tfp;
608 	uint8_t pool_id;
609 
610 	memset(&parms, 0, sizeof(parms));
611 	rc = rte_eth_dev_get_name_by_port(ethdev->data->port_id,
612 					  parms.ctrl_chan_name);
613 	if (rc) {
614 		BNXT_DRV_DBG(ERR, "Invalid port %d, rc = %d\n",
615 			     ethdev->data->port_id, rc);
616 		return rc;
617 	}
618 
619 	/* On multi-host system, adjust ctrl_chan_name to avoid confliction */
620 	if (BNXT_MH(bp)) {
621 		rc = ulp_ctx_mh_get_session_name(bp, &parms);
622 		if (rc)
623 			return rc;
624 	}
625 
626 	resources = &parms.resources;
627 
628 	/*
629 	 * Need to account for size of ctrl_chan_name and 1 extra for Null
630 	 * terminator
631 	 */
632 	nb = sizeof(parms.ctrl_chan_name) - strlen(parms.ctrl_chan_name) - 1;
633 
634 	/*
635 	 * Build the ctrl_chan_name with shared token.
636 	 * When HA is enabled, the WC TCAM needs extra management by the core,
637 	 * so add the wc_tcam string to the control channel.
638 	 */
639 	pool_id = bp->ulp_ctx->cfg_data->ha_pool_id;
640 	if (!bnxt_ulp_cntxt_multi_shared_session_enabled(bp->ulp_ctx)) {
641 		if (bnxt_ulp_cntxt_ha_enabled(bp->ulp_ctx))
642 			strncat(parms.ctrl_chan_name, "-tf_shared-wc_tcam", nb);
643 		else
644 			strncat(parms.ctrl_chan_name, "-tf_shared", nb);
645 	} else if (bnxt_ulp_cntxt_multi_shared_session_enabled(bp->ulp_ctx)) {
646 		if (session_type == BNXT_ULP_SESSION_TYPE_SHARED) {
647 			strncat(parms.ctrl_chan_name, "-tf_shared", nb);
648 		} else if (session_type == BNXT_ULP_SESSION_TYPE_SHARED_WC) {
649 			char session_pool_name[64];
650 
651 			sprintf(session_pool_name, "-tf_shared-pool%d",
652 				pool_id);
653 
654 			if (nb >= strlen(session_pool_name)) {
655 				strncat(parms.ctrl_chan_name, session_pool_name, nb);
656 			} else {
657 				BNXT_DRV_DBG(ERR, "No space left for session_name\n");
658 				return -EINVAL;
659 			}
660 		}
661 	}
662 
663 	rc = ulp_tf_shared_session_resources_get(bp->ulp_ctx, session_type,
664 						 resources);
665 	if (rc)
666 		return rc;
667 
668 	rc = bnxt_ulp_cntxt_app_id_get(bp->ulp_ctx, &app_id);
669 	if (rc) {
670 		BNXT_DRV_DBG(ERR, "Unable to get the app id from ulp.\n");
671 		return -EINVAL;
672 	}
673 
674 	rc = bnxt_ulp_cntxt_dev_id_get(bp->ulp_ctx, &ulp_dev_id);
675 	if (rc) {
676 		BNXT_DRV_DBG(ERR, "Unable to get device id from ulp.\n");
677 		return rc;
678 	}
679 
680 	tfp = bnxt_ulp_bp_tfp_get(bp, session_type);
681 	parms.device_type = bnxt_ulp_cntxt_convert_dev_id(ulp_dev_id);
682 	parms.bp = bp;
683 
684 	/*
685 	 * Open the session here, but the collect the resources during the
686 	 * mapper initialization.
687 	 */
688 	rc = tf_open_session(tfp, &parms);
689 	if (rc)
690 		return rc;
691 
692 	if (parms.shared_session_creator)
693 		BNXT_DRV_DBG(DEBUG, "Shared session creator.\n");
694 	else
695 		BNXT_DRV_DBG(DEBUG, "Shared session attached.\n");
696 
697 	/* Save the shared session in global data */
698 	rc = ulp_tf_session_tfp_set(session, session_type, tfp);
699 	if (rc) {
700 		BNXT_DRV_DBG(ERR, "Failed to add shared tfp to session\n");
701 		return rc;
702 	}
703 
704 	rc = bnxt_ulp_cntxt_tfp_set(bp->ulp_ctx, session_type, tfp);
705 	if (rc) {
706 		BNXT_DRV_DBG(ERR, "Failed to add shared tfp to ulp (%d)\n", rc);
707 		return rc;
708 	}
709 
710 	return rc;
711 }
712 
713 static int32_t
714 ulp_tf_ctx_shared_session_attach(struct bnxt *bp,
715 				 struct bnxt_ulp_session_state *ses)
716 {
717 	enum bnxt_ulp_session_type type;
718 	struct tf *tfp;
719 	int32_t rc = 0;
720 
721 	/* Simply return success if shared session not enabled */
722 	if (bnxt_ulp_cntxt_shared_session_enabled(bp->ulp_ctx)) {
723 		type = BNXT_ULP_SESSION_TYPE_SHARED;
724 		tfp = bnxt_ulp_bp_tfp_get(bp, type);
725 		tfp->session = ulp_tf_session_tfp_get(ses, type);
726 		rc = ulp_tf_ctx_shared_session_open(bp, type, ses);
727 	}
728 
729 	if (bnxt_ulp_cntxt_multi_shared_session_enabled(bp->ulp_ctx)) {
730 		type = BNXT_ULP_SESSION_TYPE_SHARED_WC;
731 		tfp = bnxt_ulp_bp_tfp_get(bp, type);
732 		tfp->session = ulp_tf_session_tfp_get(ses, type);
733 		rc = ulp_tf_ctx_shared_session_open(bp, type, ses);
734 	}
735 
736 	if (!rc)
737 		bnxt_ulp_cntxt_num_shared_clients_set(bp->ulp_ctx, true);
738 
739 	return rc;
740 }
741 
742 static void
743 ulp_tf_ctx_shared_session_detach(struct bnxt *bp)
744 {
745 	struct tf *tfp;
746 
747 	if (bnxt_ulp_cntxt_shared_session_enabled(bp->ulp_ctx)) {
748 		tfp = bnxt_ulp_bp_tfp_get(bp, BNXT_ULP_SESSION_TYPE_SHARED);
749 		if (tfp->session) {
750 			tf_close_session(tfp);
751 			tfp->session = NULL;
752 		}
753 	}
754 	if (bnxt_ulp_cntxt_multi_shared_session_enabled(bp->ulp_ctx)) {
755 		tfp = bnxt_ulp_bp_tfp_get(bp, BNXT_ULP_SESSION_TYPE_SHARED_WC);
756 		if (tfp->session) {
757 			tf_close_session(tfp);
758 			tfp->session = NULL;
759 		}
760 	}
761 	bnxt_ulp_cntxt_num_shared_clients_set(bp->ulp_ctx, false);
762 }
763 
764 /*
765  * Initialize an ULP session.
766  * An ULP session will contain all the resources needed to support rte flow
767  * offloads. A session is initialized as part of rte_eth_device start.
768  * A single vswitch instance can have multiple uplinks which means
769  * rte_eth_device start will be called for each of these devices.
770  * ULP session manager will make sure that a single ULP session is only
771  * initialized once. Apart from this, it also initializes MARK database,
772  * EEM table & flow database. ULP session manager also manages a list of
773  * all opened ULP sessions.
774  */
775 static int32_t
776 ulp_tf_ctx_session_open(struct bnxt *bp,
777 			struct bnxt_ulp_session_state *session)
778 {
779 	struct rte_eth_dev		*ethdev = bp->eth_dev;
780 	int32_t				rc = 0;
781 	struct tf_open_session_parms	params;
782 	struct tf_session_resources	*resources;
783 	uint32_t ulp_dev_id = BNXT_ULP_DEVICE_ID_LAST;
784 	uint8_t app_id;
785 	struct tf *tfp;
786 
787 	memset(&params, 0, sizeof(params));
788 
789 	rc = rte_eth_dev_get_name_by_port(ethdev->data->port_id,
790 					  params.ctrl_chan_name);
791 	if (rc) {
792 		BNXT_DRV_DBG(ERR, "Invalid port %d, rc = %d\n",
793 			     ethdev->data->port_id, rc);
794 		return rc;
795 	}
796 
797 	/* On multi-host system, adjust ctrl_chan_name to avoid confliction */
798 	if (BNXT_MH(bp)) {
799 		rc = ulp_ctx_mh_get_session_name(bp, &params);
800 		if (rc)
801 			return rc;
802 	}
803 
804 	rc = bnxt_ulp_cntxt_app_id_get(bp->ulp_ctx, &app_id);
805 	if (rc) {
806 		BNXT_DRV_DBG(ERR, "Unable to get the app id from ulp.\n");
807 		return -EINVAL;
808 	}
809 
810 	rc = bnxt_ulp_cntxt_dev_id_get(bp->ulp_ctx, &ulp_dev_id);
811 	if (rc) {
812 		BNXT_DRV_DBG(ERR, "Unable to get device id from ulp.\n");
813 		return rc;
814 	}
815 
816 	params.device_type = bnxt_ulp_cntxt_convert_dev_id(ulp_dev_id);
817 	resources = &params.resources;
818 	rc = ulp_tf_resources_get(bp->ulp_ctx,
819 				  BNXT_ULP_SESSION_TYPE_DEFAULT,
820 				  resources);
821 	if (rc)
822 		return rc;
823 
824 	params.bp = bp;
825 
826 	tfp = bnxt_ulp_bp_tfp_get(bp, BNXT_ULP_SESSION_TYPE_DEFAULT);
827 	rc = tf_open_session(tfp, &params);
828 	if (rc) {
829 		BNXT_DRV_DBG(ERR, "Failed to open TF session - %s, rc = %d\n",
830 			     params.ctrl_chan_name, rc);
831 		return -EINVAL;
832 	}
833 	rc = ulp_tf_session_tfp_set(session, BNXT_ULP_SESSION_TYPE_DEFAULT, tfp);
834 	if (rc) {
835 		BNXT_DRV_DBG(ERR, "Failed to set TF session - %s, rc = %d\n",
836 			     params.ctrl_chan_name, rc);
837 		return -EINVAL;
838 	}
839 	return rc;
840 }
841 
842 /*
843  * Close the ULP session.
844  * It takes the ulp context pointer.
845  */
846 static void
847 ulp_tf_ctx_session_close(struct bnxt *bp,
848 			 struct bnxt_ulp_session_state *session)
849 {
850 	struct tf *tfp;
851 
852 	/* close the session in the hardware */
853 	if (ulp_tf_session_is_open(session, BNXT_ULP_SESSION_TYPE_DEFAULT)) {
854 		tfp = bnxt_ulp_bp_tfp_get(bp, BNXT_ULP_SESSION_TYPE_DEFAULT);
855 		tf_close_session(tfp);
856 	}
857 	ulp_tf_session_tfp_reset(session, BNXT_ULP_SESSION_TYPE_DEFAULT);
858 }
859 
860 static void
861 ulp_tf_init_tbl_scope_parms(struct bnxt *bp,
862 			    struct tf_alloc_tbl_scope_parms *params)
863 {
864 	struct bnxt_ulp_device_params	*dparms;
865 	uint32_t dev_id;
866 	int rc;
867 
868 	rc = bnxt_ulp_cntxt_dev_id_get(bp->ulp_ctx, &dev_id);
869 	if (rc)
870 		/* TBD: For now, just use default. */
871 		dparms = 0;
872 	else
873 		dparms = bnxt_ulp_device_params_get(dev_id);
874 
875 	/*
876 	 * Set the flush timer for EEM entries. The value is in 100ms intervals,
877 	 * so 100 is 10s.
878 	 */
879 	params->hw_flow_cache_flush_timer = 100;
880 
881 	if (!dparms) {
882 		params->rx_max_key_sz_in_bits = BNXT_ULP_DFLT_RX_MAX_KEY;
883 		params->rx_max_action_entry_sz_in_bits =
884 			BNXT_ULP_DFLT_RX_MAX_ACTN_ENTRY;
885 		params->rx_mem_size_in_mb = BNXT_ULP_DFLT_RX_MEM;
886 		params->rx_num_flows_in_k = BNXT_ULP_RX_NUM_FLOWS;
887 
888 		params->tx_max_key_sz_in_bits = BNXT_ULP_DFLT_TX_MAX_KEY;
889 		params->tx_max_action_entry_sz_in_bits =
890 			BNXT_ULP_DFLT_TX_MAX_ACTN_ENTRY;
891 		params->tx_mem_size_in_mb = BNXT_ULP_DFLT_TX_MEM;
892 		params->tx_num_flows_in_k = BNXT_ULP_TX_NUM_FLOWS;
893 	} else {
894 		params->rx_max_key_sz_in_bits = BNXT_ULP_DFLT_RX_MAX_KEY;
895 		params->rx_max_action_entry_sz_in_bits =
896 			BNXT_ULP_DFLT_RX_MAX_ACTN_ENTRY;
897 		params->rx_mem_size_in_mb = BNXT_ULP_DFLT_RX_MEM;
898 		params->rx_num_flows_in_k =
899 			dparms->ext_flow_db_num_entries / 1024;
900 
901 		params->tx_max_key_sz_in_bits = BNXT_ULP_DFLT_TX_MAX_KEY;
902 		params->tx_max_action_entry_sz_in_bits =
903 			BNXT_ULP_DFLT_TX_MAX_ACTN_ENTRY;
904 		params->tx_mem_size_in_mb = BNXT_ULP_DFLT_TX_MEM;
905 		params->tx_num_flows_in_k =
906 			dparms->ext_flow_db_num_entries / 1024;
907 	}
908 	BNXT_DRV_DBG(INFO, "Table Scope initialized with %uK flows.\n",
909 		     params->rx_num_flows_in_k);
910 }
911 
912 /* Initialize Extended Exact Match host memory. */
913 static int32_t
914 ulp_tf_eem_tbl_scope_init(struct bnxt *bp)
915 {
916 	struct tf_alloc_tbl_scope_parms params = {0};
917 	struct bnxt_ulp_device_params *dparms;
918 	enum bnxt_ulp_flow_mem_type mtype;
919 	uint32_t dev_id;
920 	struct tf *tfp;
921 	int rc;
922 
923 	/* Get the dev specific number of flows that needed to be supported. */
924 	if (bnxt_ulp_cntxt_dev_id_get(bp->ulp_ctx, &dev_id)) {
925 		BNXT_DRV_DBG(ERR, "Invalid device id\n");
926 		return -EINVAL;
927 	}
928 
929 	dparms = bnxt_ulp_device_params_get(dev_id);
930 	if (!dparms) {
931 		BNXT_DRV_DBG(ERR, "could not fetch the device params\n");
932 		return -ENODEV;
933 	}
934 
935 	if (bnxt_ulp_cntxt_mem_type_get(bp->ulp_ctx, &mtype))
936 		return -EINVAL;
937 	if (mtype != BNXT_ULP_FLOW_MEM_TYPE_EXT) {
938 		BNXT_DRV_DBG(INFO, "Table Scope alloc is not required\n");
939 		return 0;
940 	}
941 
942 	ulp_tf_init_tbl_scope_parms(bp, &params);
943 	tfp = bnxt_ulp_bp_tfp_get(bp, BNXT_ULP_SESSION_TYPE_DEFAULT);
944 	rc = tf_alloc_tbl_scope(tfp, &params);
945 	if (rc) {
946 		BNXT_DRV_DBG(ERR,
947 			     "Unable to allocate eem table scope rc = %d\n",
948 			     rc);
949 		return rc;
950 	}
951 
952 #ifdef RTE_LIBRTE_BNXT_TRUFLOW_DEBUG
953 	BNXT_DRV_DBG(DEBUG, "TableScope=0x%0x %d\n",
954 		     params.tbl_scope_id,
955 		     params.tbl_scope_id);
956 #endif
957 
958 	rc = bnxt_ulp_cntxt_tbl_scope_id_set(bp->ulp_ctx, params.tbl_scope_id);
959 	if (rc) {
960 		BNXT_DRV_DBG(ERR, "Unable to set table scope id\n");
961 		return rc;
962 	}
963 
964 	return 0;
965 }
966 
967 /* Free Extended Exact Match host memory */
968 static int32_t
969 ulp_tf_eem_tbl_scope_deinit(struct bnxt *bp, struct bnxt_ulp_context *ulp_ctx)
970 {
971 	struct tf_free_tbl_scope_parms	params = {0};
972 	struct tf			*tfp;
973 	int32_t				rc = 0;
974 	struct bnxt_ulp_device_params *dparms;
975 	enum bnxt_ulp_flow_mem_type mtype;
976 	uint32_t dev_id;
977 
978 	if (!ulp_ctx || !ulp_ctx->cfg_data)
979 		return -EINVAL;
980 
981 	tfp = bnxt_ulp_cntxt_tfp_get(ulp_ctx, BNXT_ULP_SESSION_TYPE_DEFAULT);
982 	if (!tfp) {
983 		BNXT_DRV_DBG(ERR, "Failed to get the truflow pointer\n");
984 		return -EINVAL;
985 	}
986 
987 	/* Get the dev specific number of flows that needed to be supported. */
988 	if (bnxt_ulp_cntxt_dev_id_get(bp->ulp_ctx, &dev_id)) {
989 		BNXT_DRV_DBG(ERR, "Invalid device id\n");
990 		return -EINVAL;
991 	}
992 
993 	dparms = bnxt_ulp_device_params_get(dev_id);
994 	if (!dparms) {
995 		BNXT_DRV_DBG(ERR, "could not fetch the device params\n");
996 		return -ENODEV;
997 	}
998 
999 	if (bnxt_ulp_cntxt_mem_type_get(ulp_ctx, &mtype))
1000 		return -EINVAL;
1001 	if (mtype != BNXT_ULP_FLOW_MEM_TYPE_EXT) {
1002 		BNXT_DRV_DBG(INFO, "Table Scope free is not required\n");
1003 		return 0;
1004 	}
1005 
1006 	rc = bnxt_ulp_cntxt_tbl_scope_id_get(ulp_ctx, &params.tbl_scope_id);
1007 	if (rc) {
1008 		BNXT_DRV_DBG(ERR, "Failed to get the table scope id\n");
1009 		return -EINVAL;
1010 	}
1011 
1012 	rc = tf_free_tbl_scope(tfp, &params);
1013 	if (rc) {
1014 		BNXT_DRV_DBG(ERR, "Unable to free table scope\n");
1015 		return -EINVAL;
1016 	}
1017 	return rc;
1018 }
1019 
1020 /* The function to free and deinit the ulp context data. */
1021 static int32_t
1022 ulp_tf_ctx_deinit(struct bnxt *bp,
1023 		  struct bnxt_ulp_session_state *session)
1024 {
1025 	/* close the tf session */
1026 	ulp_tf_ctx_session_close(bp, session);
1027 
1028 	/* The shared session must be closed last. */
1029 	if (bnxt_ulp_cntxt_shared_session_enabled(bp->ulp_ctx))
1030 		ulp_tf_ctx_shared_session_close(bp, BNXT_ULP_SESSION_TYPE_SHARED,
1031 						session);
1032 
1033 	if (bnxt_ulp_cntxt_multi_shared_session_enabled(bp->ulp_ctx))
1034 		ulp_tf_ctx_shared_session_close(bp,
1035 						BNXT_ULP_SESSION_TYPE_SHARED_WC,
1036 						session);
1037 
1038 	bnxt_ulp_cntxt_num_shared_clients_set(bp->ulp_ctx, false);
1039 
1040 	/* Free the contents */
1041 	if (session->cfg_data) {
1042 		rte_free(session->cfg_data);
1043 		bp->ulp_ctx->cfg_data = NULL;
1044 		session->cfg_data = NULL;
1045 	}
1046 	return 0;
1047 }
1048 
1049 /* The function to allocate and initialize the ulp context data. */
1050 static int32_t
1051 ulp_tf_ctx_init(struct bnxt *bp,
1052 		struct bnxt_ulp_session_state *session)
1053 {
1054 	struct bnxt_ulp_data	*ulp_data;
1055 	int32_t			rc = 0;
1056 	enum bnxt_ulp_device_id devid;
1057 	enum bnxt_ulp_session_type stype;
1058 	struct tf *tfp;
1059 
1060 	/* Initialize the context entries list */
1061 	bnxt_ulp_cntxt_list_init();
1062 
1063 	/* Allocate memory to hold ulp context data. */
1064 	ulp_data = rte_zmalloc("bnxt_ulp_data",
1065 			       sizeof(struct bnxt_ulp_data), 0);
1066 	if (!ulp_data) {
1067 		BNXT_DRV_DBG(ERR, "Failed to allocate memory for ulp data\n");
1068 		return -ENOMEM;
1069 	}
1070 
1071 	/* Increment the ulp context data reference count usage. */
1072 	bp->ulp_ctx->cfg_data = ulp_data;
1073 	session->cfg_data = ulp_data;
1074 	ulp_data->ref_cnt++;
1075 	ulp_data->ulp_flags |= BNXT_ULP_VF_REP_ENABLED;
1076 
1077 	/* Add the context to the context entries list */
1078 	rc = bnxt_ulp_cntxt_list_add(bp->ulp_ctx);
1079 	if (rc) {
1080 		BNXT_DRV_DBG(ERR, "Failed to add the context list entry\n");
1081 		goto error_deinit;
1082 	}
1083 
1084 	rc = bnxt_ulp_devid_get(bp, &devid);
1085 	if (rc) {
1086 		BNXT_DRV_DBG(ERR, "Unable to determine device for ULP init.\n");
1087 		goto error_deinit;
1088 	}
1089 
1090 	rc = bnxt_ulp_cntxt_dev_id_set(bp->ulp_ctx, devid);
1091 	if (rc) {
1092 		BNXT_DRV_DBG(ERR, "Unable to set device for ULP init.\n");
1093 		goto error_deinit;
1094 	}
1095 
1096 	rc = bnxt_ulp_cntxt_app_id_set(bp->ulp_ctx, bp->app_id);
1097 	if (rc) {
1098 		BNXT_DRV_DBG(ERR, "Unable to set app_id for ULP init.\n");
1099 		goto error_deinit;
1100 	}
1101 	BNXT_DRV_DBG(DEBUG, "Ulp initialized with app id %d\n", bp->app_id);
1102 
1103 	rc = ulp_tf_cntxt_app_caps_init(bp, bp->app_id, devid);
1104 	if (rc) {
1105 		BNXT_DRV_DBG(ERR, "Unable to set caps for app(%x)/dev(%x)\n",
1106 			     bp->app_id, devid);
1107 		goto error_deinit;
1108 	}
1109 
1110 	if (BNXT_TESTPMD_EN(bp)) {
1111 		ulp_data->ulp_flags &= ~BNXT_ULP_VF_REP_ENABLED;
1112 		BNXT_DRV_DBG(ERR, "Enabled Testpmd forward mode\n");
1113 	}
1114 
1115 	/*
1116 	 * Shared session must be created before first regular session but after
1117 	 * the ulp_ctx is valid.
1118 	 */
1119 	if (bnxt_ulp_cntxt_shared_session_enabled(bp->ulp_ctx)) {
1120 		rc = ulp_tf_ctx_shared_session_open(bp,
1121 						    BNXT_ULP_SESSION_TYPE_SHARED,
1122 						    session);
1123 		if (rc) {
1124 			BNXT_DRV_DBG(ERR, "Unable to open shared session (%d)\n",
1125 				     rc);
1126 			goto error_deinit;
1127 		}
1128 	}
1129 
1130 	/* Multiple session support */
1131 	if (bnxt_ulp_cntxt_multi_shared_session_enabled(bp->ulp_ctx)) {
1132 		stype = BNXT_ULP_SESSION_TYPE_SHARED_WC;
1133 		rc = ulp_tf_ctx_shared_session_open(bp, stype, session);
1134 		if (rc) {
1135 			BNXT_DRV_DBG(ERR,
1136 				     "Unable to open shared wc session (%d)\n",
1137 				     rc);
1138 			goto error_deinit;
1139 		}
1140 	}
1141 	bnxt_ulp_cntxt_num_shared_clients_set(bp->ulp_ctx, true);
1142 
1143 	/* Open the ulp session. */
1144 	rc = ulp_tf_ctx_session_open(bp, session);
1145 	if (rc)
1146 		goto error_deinit;
1147 
1148 	tfp = bnxt_ulp_bp_tfp_get(bp, BNXT_ULP_SESSION_TYPE_DEFAULT);
1149 	bnxt_ulp_cntxt_tfp_set(bp->ulp_ctx, BNXT_ULP_SESSION_TYPE_DEFAULT, tfp);
1150 	return rc;
1151 
1152 error_deinit:
1153 	session->session_opened[BNXT_ULP_SESSION_TYPE_DEFAULT] = 1;
1154 	(void)ulp_tf_ctx_deinit(bp, session);
1155 	return rc;
1156 }
1157 
1158 /* The function to initialize ulp dparms with devargs */
1159 static int32_t
1160 ulp_tf_dparms_init(struct bnxt *bp, struct bnxt_ulp_context *ulp_ctx)
1161 {
1162 	struct bnxt_ulp_device_params *dparms;
1163 	uint32_t dev_id = BNXT_ULP_DEVICE_ID_LAST;
1164 
1165 	if (!bp->max_num_kflows) {
1166 		/* Defaults to Internal */
1167 		bnxt_ulp_cntxt_mem_type_set(ulp_ctx,
1168 					    BNXT_ULP_FLOW_MEM_TYPE_INT);
1169 		return 0;
1170 	}
1171 
1172 	/* The max_num_kflows were set, so move to external */
1173 	if (bnxt_ulp_cntxt_mem_type_set(ulp_ctx, BNXT_ULP_FLOW_MEM_TYPE_EXT))
1174 		return -EINVAL;
1175 
1176 	if (bnxt_ulp_cntxt_dev_id_get(ulp_ctx, &dev_id)) {
1177 		BNXT_DRV_DBG(DEBUG, "Failed to get device id\n");
1178 		return -EINVAL;
1179 	}
1180 
1181 	dparms = bnxt_ulp_device_params_get(dev_id);
1182 	if (!dparms) {
1183 		BNXT_DRV_DBG(DEBUG, "Failed to get device parms\n");
1184 		return -EINVAL;
1185 	}
1186 
1187 	/* num_flows = max_num_kflows * 1024 */
1188 	dparms->ext_flow_db_num_entries = bp->max_num_kflows * 1024;
1189 	/* GFID =  2 * num_flows */
1190 	dparms->mark_db_gfid_entries = dparms->ext_flow_db_num_entries * 2;
1191 	BNXT_DRV_DBG(DEBUG, "Set the number of flows = %" PRIu64 "\n",
1192 		     dparms->ext_flow_db_num_entries);
1193 
1194 	return 0;
1195 }
1196 
1197 static int32_t
1198 ulp_tf_ctx_attach(struct bnxt *bp,
1199 	       struct bnxt_ulp_session_state *session)
1200 {
1201 	int32_t rc = 0;
1202 	uint32_t flags, dev_id = BNXT_ULP_DEVICE_ID_LAST;
1203 	struct tf *tfp;
1204 	uint8_t app_id;
1205 
1206 	/* Increment the ulp context data reference count usage. */
1207 	bp->ulp_ctx->cfg_data = session->cfg_data;
1208 	bp->ulp_ctx->cfg_data->ref_cnt++;
1209 
1210 	/* update the session details in bnxt tfp */
1211 	tfp = bnxt_ulp_bp_tfp_get(bp, BNXT_ULP_SESSION_TYPE_DEFAULT);
1212 	tfp->session = ulp_tf_session_tfp_get(session,
1213 					      BNXT_ULP_SESSION_TYPE_DEFAULT);
1214 
1215 	/* Add the context to the context entries list */
1216 	rc = bnxt_ulp_cntxt_list_add(bp->ulp_ctx);
1217 	if (rc) {
1218 		BNXT_DRV_DBG(ERR, "Failed to add the context list entry\n");
1219 		return -EINVAL;
1220 	}
1221 
1222 	/*
1223 	 * The supported flag will be set during the init. Use it now to
1224 	 * know if we should go through the attach.
1225 	 */
1226 	rc = bnxt_ulp_cntxt_app_id_get(bp->ulp_ctx, &app_id);
1227 	if (rc) {
1228 		BNXT_DRV_DBG(ERR, "Unable to get the app id from ulp.\n");
1229 		return -EINVAL;
1230 	}
1231 
1232 	rc = bnxt_ulp_cntxt_dev_id_get(bp->ulp_ctx, &dev_id);
1233 	if (rc) {
1234 		BNXT_DRV_DBG(ERR, "Unable do get the dev_id.\n");
1235 		return -EINVAL;
1236 	}
1237 
1238 	flags = bp->ulp_ctx->cfg_data->ulp_flags;
1239 	if (ULP_APP_DEV_UNSUPPORTED_ENABLED(flags)) {
1240 		BNXT_DRV_DBG(ERR, "APP ID %d, Device ID: 0x%x not supported.\n",
1241 			     app_id, dev_id);
1242 		return -EINVAL;
1243 	}
1244 
1245 	/* Create a TF Client */
1246 	rc = ulp_tf_ctx_session_open(bp, session);
1247 	if (rc) {
1248 		BNXT_DRV_DBG(ERR, "Failed to open ctxt session, rc:%d\n", rc);
1249 		tfp->session = NULL;
1250 		return rc;
1251 	}
1252 	tfp = bnxt_ulp_bp_tfp_get(bp, BNXT_ULP_SESSION_TYPE_DEFAULT);
1253 	bnxt_ulp_cntxt_tfp_set(bp->ulp_ctx, BNXT_ULP_SESSION_TYPE_DEFAULT, tfp);
1254 
1255 	/*
1256 	 * Attach to the shared session, must be called after the
1257 	 * ulp_ctx_attach in order to ensure that ulp data is available
1258 	 * for attaching.
1259 	 */
1260 	rc = ulp_tf_ctx_shared_session_attach(bp, session);
1261 	if (rc)
1262 		BNXT_DRV_DBG(ERR, "Failed attach to shared session (%d)", rc);
1263 
1264 	return rc;
1265 }
1266 
1267 static void
1268 ulp_tf_ctx_detach(struct bnxt *bp,
1269 		  struct bnxt_ulp_session_state *session __rte_unused)
1270 {
1271 	struct tf *tfp;
1272 
1273 	tfp = bnxt_ulp_bp_tfp_get(bp, BNXT_ULP_SESSION_TYPE_DEFAULT);
1274 	if (tfp->session) {
1275 		tf_close_session(tfp);
1276 		tfp->session = NULL;
1277 	}
1278 
1279 	/* always detach/close shared after the session. */
1280 	ulp_tf_ctx_shared_session_detach(bp);
1281 }
1282 
1283 /*
1284  * Internal api to enable NAT feature.
1285  * Set set_flag to 1 to set the value or zero to reset the value.
1286  * returns 0 on success.
1287  */
1288 static int32_t
1289 ulp_tf_global_cfg_update(struct bnxt *bp,
1290 			 enum tf_dir dir,
1291 			 enum tf_global_config_type type,
1292 			 uint32_t offset,
1293 			 uint32_t value,
1294 			 uint32_t set_flag)
1295 {
1296 	uint32_t global_cfg = 0;
1297 	int rc;
1298 	struct tf_global_cfg_parms parms = { 0 };
1299 	struct tf *tfp;
1300 
1301 	/* Initialize the params */
1302 	parms.dir = dir,
1303 	parms.type = type,
1304 	parms.offset = offset,
1305 	parms.config = (uint8_t *)&global_cfg,
1306 	parms.config_sz_in_bytes = sizeof(global_cfg);
1307 
1308 	tfp = bnxt_ulp_bp_tfp_get(bp, BNXT_ULP_SESSION_TYPE_DEFAULT);
1309 	rc = tf_get_global_cfg(tfp, &parms);
1310 	if (rc) {
1311 		BNXT_DRV_DBG(ERR, "Failed to get global cfg 0x%x rc:%d\n",
1312 			     type, rc);
1313 		return rc;
1314 	}
1315 
1316 	if (set_flag)
1317 		global_cfg |= value;
1318 	else
1319 		global_cfg &= ~value;
1320 
1321 	/* SET the register RE_CFA_REG_ACT_TECT */
1322 	rc = tf_set_global_cfg(tfp, &parms);
1323 	if (rc) {
1324 		BNXT_DRV_DBG(ERR, "Failed to set global cfg 0x%x rc:%d\n",
1325 			     type, rc);
1326 		return rc;
1327 	}
1328 	return rc;
1329 }
1330 
1331 /**
1332  * When a port is initialized by dpdk. This functions is called
1333  * to enable the meter and initializes the meter global configurations.
1334  */
1335 #define BNXT_THOR_FMTCR_NUM_MET_MET_1K (0x7UL << 20)
1336 #define BNXT_THOR_FMTCR_CNTRS_ENABLE (0x1UL << 25)
1337 #define BNXT_THOR_FMTCR_INTERVAL_1K (1024)
1338 static int32_t
1339 ulp_tf_flow_mtr_init(struct bnxt *bp)
1340 {
1341 	int rc = 0;
1342 
1343 	/*
1344 	 * Enable metering. Set the meter global configuration register.
1345 	 * Set number of meter to 1K. Disable the drop counter for now.
1346 	 */
1347 	rc = ulp_tf_global_cfg_update(bp, TF_DIR_RX, TF_METER_CFG,
1348 				      0,
1349 				      BNXT_THOR_FMTCR_NUM_MET_MET_1K,
1350 				      1);
1351 	if (rc) {
1352 		BNXT_DRV_DBG(ERR, "Failed to set rx meter configuration\n");
1353 		goto jump_to_error;
1354 	}
1355 
1356 	rc = ulp_tf_global_cfg_update(bp, TF_DIR_TX, TF_METER_CFG,
1357 				      0,
1358 				      BNXT_THOR_FMTCR_NUM_MET_MET_1K,
1359 				      1);
1360 	if (rc) {
1361 		BNXT_DRV_DBG(ERR, "Failed to set tx meter configuration\n");
1362 		goto jump_to_error;
1363 	}
1364 
1365 	/*
1366 	 * Set meter refresh rate to 1024 clock cycle. This value works for
1367 	 * most bit rates especially for high rates.
1368 	 */
1369 	rc = ulp_tf_global_cfg_update(bp, TF_DIR_RX, TF_METER_INTERVAL_CFG,
1370 				      0,
1371 				      BNXT_THOR_FMTCR_INTERVAL_1K,
1372 				      1);
1373 	if (rc) {
1374 		BNXT_DRV_DBG(ERR, "Failed to set rx meter interval\n");
1375 		goto jump_to_error;
1376 	}
1377 
1378 	rc = bnxt_flow_mtr_init(bp);
1379 	if (rc) {
1380 		BNXT_DRV_DBG(ERR, "Failed to config meter\n");
1381 		goto jump_to_error;
1382 	}
1383 
1384 	return rc;
1385 
1386 jump_to_error:
1387 	return rc;
1388 }
1389 
1390 /*
1391  * When a port is deinit'ed by dpdk. This function is called
1392  * and this function clears the ULP context and rest of the
1393  * infrastructure associated with it.
1394  */
1395 static void
1396 ulp_tf_deinit(struct bnxt *bp,
1397 	      struct bnxt_ulp_session_state *session)
1398 {
1399 	bool ha_enabled;
1400 
1401 	if (!bp->ulp_ctx || !bp->ulp_ctx->cfg_data)
1402 		return;
1403 
1404 	ha_enabled = bnxt_ulp_cntxt_ha_enabled(bp->ulp_ctx);
1405 	if (ha_enabled &&
1406 	    ulp_tf_session_is_open(session, BNXT_ULP_SESSION_TYPE_DEFAULT)) {
1407 		int32_t rc = ulp_ha_mgr_close(bp->ulp_ctx);
1408 		if (rc)
1409 			BNXT_DRV_DBG(ERR, "Failed to close HA (%d)\n", rc);
1410 	}
1411 
1412 	/* cleanup the eem table scope */
1413 	ulp_tf_eem_tbl_scope_deinit(bp, bp->ulp_ctx);
1414 
1415 	/* cleanup the flow database */
1416 	ulp_flow_db_deinit(bp->ulp_ctx);
1417 
1418 	/* Delete the Mark database */
1419 	ulp_mark_db_deinit(bp->ulp_ctx);
1420 
1421 	/* cleanup the ulp mapper */
1422 	ulp_mapper_deinit(bp->ulp_ctx);
1423 
1424 	/* cleanup the ulp matcher */
1425 	ulp_matcher_deinit(bp->ulp_ctx);
1426 
1427 	/* Delete the Flow Counter Manager */
1428 	ulp_fc_mgr_deinit(bp->ulp_ctx);
1429 
1430 	/* Delete the Port database */
1431 	ulp_port_db_deinit(bp->ulp_ctx);
1432 
1433 	/* Disable NAT feature */
1434 	(void)ulp_tf_global_cfg_update(bp, TF_DIR_RX, TF_TUNNEL_ENCAP,
1435 				       TF_TUNNEL_ENCAP_NAT,
1436 				       BNXT_ULP_NAT_OUTER_MOST_FLAGS, 0);
1437 
1438 	(void)ulp_tf_global_cfg_update(bp, TF_DIR_TX, TF_TUNNEL_ENCAP,
1439 				       TF_TUNNEL_ENCAP_NAT,
1440 				       BNXT_ULP_NAT_OUTER_MOST_FLAGS, 0);
1441 
1442 	/* free the flow db lock */
1443 	pthread_mutex_destroy(&bp->ulp_ctx->cfg_data->flow_db_lock);
1444 
1445 	if (ha_enabled)
1446 		ulp_ha_mgr_deinit(bp->ulp_ctx);
1447 
1448 	/* Delete the ulp context and tf session and free the ulp context */
1449 	ulp_tf_ctx_deinit(bp, session);
1450 	BNXT_DRV_DBG(DEBUG, "ulp ctx has been deinitialized\n");
1451 }
1452 
1453 /*
1454  * When a port is initialized by dpdk. This functions is called
1455  * and this function initializes the ULP context and rest of the
1456  * infrastructure associated with it.
1457  */
1458 static int32_t
1459 ulp_tf_init(struct bnxt *bp,
1460 	    struct bnxt_ulp_session_state *session)
1461 {
1462 	int rc;
1463 	uint32_t ulp_dev_id = BNXT_ULP_DEVICE_ID_LAST;
1464 
1465 	/* Select 64bit SSE4.2 intrinsic if available */
1466 	rte_hash_crc_set_alg(CRC32_SSE42_x64);
1467 
1468 	/* Allocate and Initialize the ulp context. */
1469 	rc = ulp_tf_ctx_init(bp, session);
1470 	if (rc) {
1471 		BNXT_DRV_DBG(ERR, "Failed to create the ulp context\n");
1472 		goto jump_to_error;
1473 	}
1474 
1475 	pthread_mutex_init(&bp->ulp_ctx->cfg_data->flow_db_lock, NULL);
1476 
1477 	/* Initialize ulp dparms with values devargs passed */
1478 	rc = ulp_tf_dparms_init(bp, bp->ulp_ctx);
1479 	if (rc) {
1480 		BNXT_DRV_DBG(ERR, "Failed to initialize the dparms\n");
1481 		goto jump_to_error;
1482 	}
1483 
1484 	/* create the port database */
1485 	rc = ulp_port_db_init(bp->ulp_ctx, bp->port_cnt);
1486 	if (rc) {
1487 		BNXT_DRV_DBG(ERR, "Failed to create the port database\n");
1488 		goto jump_to_error;
1489 	}
1490 
1491 	/* Create the Mark database. */
1492 	rc = ulp_mark_db_init(bp->ulp_ctx);
1493 	if (rc) {
1494 		BNXT_DRV_DBG(ERR, "Failed to create the mark database\n");
1495 		goto jump_to_error;
1496 	}
1497 
1498 	/* Create the flow database. */
1499 	rc = ulp_flow_db_init(bp->ulp_ctx);
1500 	if (rc) {
1501 		BNXT_DRV_DBG(ERR, "Failed to create the flow database\n");
1502 		goto jump_to_error;
1503 	}
1504 
1505 	/* Create the eem table scope. */
1506 	rc = ulp_tf_eem_tbl_scope_init(bp);
1507 	if (rc) {
1508 		BNXT_DRV_DBG(ERR, "Failed to create the eem scope table\n");
1509 		goto jump_to_error;
1510 	}
1511 
1512 	rc = ulp_matcher_init(bp->ulp_ctx);
1513 	if (rc) {
1514 		BNXT_DRV_DBG(ERR, "Failed to initialize ulp matcher\n");
1515 		goto jump_to_error;
1516 	}
1517 
1518 	rc = ulp_mapper_init(bp->ulp_ctx);
1519 	if (rc) {
1520 		BNXT_DRV_DBG(ERR, "Failed to initialize ulp mapper\n");
1521 		goto jump_to_error;
1522 	}
1523 
1524 	rc = ulp_fc_mgr_init(bp->ulp_ctx);
1525 	if (rc) {
1526 		BNXT_DRV_DBG(ERR, "Failed to initialize ulp flow counter mgr\n");
1527 		goto jump_to_error;
1528 	}
1529 
1530 	/*
1531 	 * Enable NAT feature. Set the global configuration register
1532 	 * Tunnel encap to enable NAT with the reuse of existing inner
1533 	 * L2 header smac and dmac
1534 	 */
1535 	rc = ulp_tf_global_cfg_update(bp, TF_DIR_RX, TF_TUNNEL_ENCAP,
1536 				      TF_TUNNEL_ENCAP_NAT,
1537 				      BNXT_ULP_NAT_OUTER_MOST_FLAGS, 1);
1538 	if (rc) {
1539 		BNXT_DRV_DBG(ERR, "Failed to set rx global configuration\n");
1540 		goto jump_to_error;
1541 	}
1542 
1543 	rc = ulp_tf_global_cfg_update(bp, TF_DIR_TX, TF_TUNNEL_ENCAP,
1544 				      TF_TUNNEL_ENCAP_NAT,
1545 				      BNXT_ULP_NAT_OUTER_MOST_FLAGS, 1);
1546 	if (rc) {
1547 		BNXT_DRV_DBG(ERR, "Failed to set tx global configuration\n");
1548 		goto jump_to_error;
1549 	}
1550 
1551 	if (bnxt_ulp_cntxt_ha_enabled(bp->ulp_ctx)) {
1552 		rc = ulp_ha_mgr_init(bp->ulp_ctx);
1553 		if (rc) {
1554 			BNXT_DRV_DBG(ERR, "Failed to initialize HA %d\n", rc);
1555 			goto jump_to_error;
1556 		}
1557 		rc = ulp_ha_mgr_open(bp->ulp_ctx);
1558 		if (rc) {
1559 			BNXT_DRV_DBG(ERR, "Failed to Process HA Open %d\n", rc);
1560 			goto jump_to_error;
1561 		}
1562 	}
1563 
1564 	rc = bnxt_ulp_cntxt_dev_id_get(bp->ulp_ctx, &ulp_dev_id);
1565 	if (rc) {
1566 		BNXT_DRV_DBG(ERR, "Unable to get device id from ulp.\n");
1567 		return rc;
1568 	}
1569 
1570 	if (ulp_dev_id == BNXT_ULP_DEVICE_ID_THOR) {
1571 		rc = ulp_tf_flow_mtr_init(bp);
1572 		if (rc) {
1573 			BNXT_DRV_DBG(ERR, "Failed to config meter\n");
1574 			goto jump_to_error;
1575 		}
1576 	}
1577 
1578 	BNXT_DRV_DBG(DEBUG, "ulp ctx has been initialized\n");
1579 	return rc;
1580 
1581 jump_to_error:
1582 	bp->ulp_ctx->ops->ulp_deinit(bp, session);
1583 	return rc;
1584 }
1585 
1586 /**
1587  * Get meter capabilities.
1588  */
1589 #define MAX_FLOW_PER_METER 1024
1590 #define MAX_METER_RATE_100GBPS ((1ULL << 30) * 100 / 8)
1591 static int
1592 ulp_tf_mtr_cap_get(struct bnxt *bp,
1593 		   struct rte_mtr_capabilities *cap)
1594 {
1595 	struct tf_get_session_info_parms iparms;
1596 	struct tf *tfp;
1597 	int32_t rc = 0;
1598 
1599 	/* Get number of meter reserved for this session */
1600 	memset(&iparms, 0, sizeof(iparms));
1601 	tfp = bnxt_ulp_bp_tfp_get(bp, BNXT_ULP_SESSION_TYPE_DEFAULT);
1602 	rc = tf_get_session_info(tfp, &iparms);
1603 	if (rc != 0) {
1604 		BNXT_DRV_DBG(ERR, "Failed to get session resource info\n");
1605 		return rc;
1606 	}
1607 
1608 	memset(cap, 0, sizeof(struct rte_mtr_capabilities));
1609 
1610 	cap->n_max = iparms.session_info.tbl[TF_DIR_RX].info[TF_TBL_TYPE_METER_INST].stride;
1611 	if (!cap->n_max) {
1612 		BNXT_DRV_DBG(ERR, "Meter is not supported\n");
1613 		return -EINVAL;
1614 	}
1615 
1616 #if (RTE_VERSION_NUM(21, 05, 0, 0) <= RTE_VERSION)
1617 	cap->srtcm_rfc2697_byte_mode_supported = 1;
1618 #endif
1619 	cap->n_shared_max = cap->n_max;
1620 	/* No meter is identical */
1621 	cap->identical = 1;
1622 	cap->shared_identical = 1;
1623 	cap->shared_n_flows_per_mtr_max = MAX_FLOW_PER_METER;
1624 	cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */
1625 	cap->meter_srtcm_rfc2697_n_max = cap->n_max;
1626 	cap->meter_rate_max = MAX_METER_RATE_100GBPS;
1627 	/* No stats supported now */
1628 	cap->stats_mask = 0;
1629 
1630 	return 0;
1631 }
1632 
1633 const struct bnxt_ulp_core_ops bnxt_ulp_tf_core_ops = {
1634 	.ulp_ctx_attach = ulp_tf_ctx_attach,
1635 	.ulp_ctx_detach = ulp_tf_ctx_detach,
1636 	.ulp_deinit =  ulp_tf_deinit,
1637 	.ulp_init =  ulp_tf_init,
1638 	.ulp_vfr_session_fid_add = NULL,
1639 	.ulp_vfr_session_fid_rem = NULL,
1640 	.ulp_mtr_cap_get = ulp_tf_mtr_cap_get
1641 };
1642