xref: /dpdk/drivers/net/bnxt/tf_ulp/bnxt_ulp.c (revision cfe4ca10)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2020 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 
12 #include "bnxt_ulp.h"
13 #include "bnxt_tf_common.h"
14 #include "bnxt.h"
15 #include "tf_core.h"
16 #include "tf_ext_flow_handle.h"
17 
18 #include "ulp_template_db_enum.h"
19 #include "ulp_template_struct.h"
20 #include "ulp_mark_mgr.h"
21 #include "ulp_fc_mgr.h"
22 #include "ulp_flow_db.h"
23 #include "ulp_mapper.h"
24 #include "ulp_port_db.h"
25 
26 /* Linked list of all TF sessions. */
27 STAILQ_HEAD(, bnxt_ulp_session_state) bnxt_ulp_session_list =
28 			STAILQ_HEAD_INITIALIZER(bnxt_ulp_session_list);
29 
30 /* Mutex to synchronize bnxt_ulp_session_list operations. */
31 static pthread_mutex_t bnxt_ulp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
32 
33 /*
34  * Allow the deletion of context only for the bnxt device that
35  * created the session
36  * TBD - The implementation of the function should change to
37  * using the reference count once tf_session_attach functionality
38  * is fixed.
39  */
40 bool
41 ulp_ctx_deinit_allowed(void *ptr)
42 {
43 	struct bnxt *bp = (struct bnxt *)ptr;
44 
45 	if (!bp)
46 		return 0;
47 
48 	if (&bp->tfp == bp->ulp_ctx->g_tfp)
49 		return 1;
50 
51 	return 0;
52 }
53 
54 /*
55  * Initialize an ULP session.
56  * An ULP session will contain all the resources needed to support rte flow
57  * offloads. A session is initialized as part of rte_eth_device start.
58  * A single vswitch instance can have multiple uplinks which means
59  * rte_eth_device start will be called for each of these devices.
60  * ULP session manager will make sure that a single ULP session is only
61  * initialized once. Apart from this, it also initializes MARK database,
62  * EEM table & flow database. ULP session manager also manages a list of
63  * all opened ULP sessions.
64  */
65 static int32_t
66 ulp_ctx_session_open(struct bnxt *bp,
67 		     struct bnxt_ulp_session_state *session)
68 {
69 	struct rte_eth_dev		*ethdev = bp->eth_dev;
70 	int32_t				rc = 0;
71 	struct tf_open_session_parms	params;
72 	struct tf_session_resources	*resources;
73 
74 	memset(&params, 0, sizeof(params));
75 
76 	rc = rte_eth_dev_get_name_by_port(ethdev->data->port_id,
77 					  params.ctrl_chan_name);
78 	if (rc) {
79 		BNXT_TF_DBG(ERR, "Invalid port %d, rc = %d\n",
80 			    ethdev->data->port_id, rc);
81 		return rc;
82 	}
83 
84 	params.shadow_copy = false;
85 	params.device_type = TF_DEVICE_TYPE_WH;
86 	resources = &params.resources;
87 	/** RX **/
88 	/* Identifiers */
89 	resources->ident_cnt[TF_DIR_RX].cnt[TF_IDENT_TYPE_L2_CTXT] = 16;
90 	resources->ident_cnt[TF_DIR_RX].cnt[TF_IDENT_TYPE_WC_PROF] = 8;
91 	resources->ident_cnt[TF_DIR_RX].cnt[TF_IDENT_TYPE_PROF_FUNC] = 8;
92 	resources->ident_cnt[TF_DIR_RX].cnt[TF_IDENT_TYPE_EM_PROF] = 8;
93 
94 	/* Table Types */
95 	resources->tbl_cnt[TF_DIR_RX].cnt[TF_TBL_TYPE_FULL_ACT_RECORD] = 720;
96 	resources->tbl_cnt[TF_DIR_RX].cnt[TF_TBL_TYPE_ACT_STATS_64] = 720;
97 
98 	/* TCAMs */
99 	resources->tcam_cnt[TF_DIR_RX].cnt[TF_TCAM_TBL_TYPE_L2_CTXT_TCAM] = 16;
100 	resources->tcam_cnt[TF_DIR_RX].cnt[TF_TCAM_TBL_TYPE_PROF_TCAM] = 8;
101 	resources->tcam_cnt[TF_DIR_RX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] = 416;
102 
103 	/* EM */
104 	resources->em_cnt[TF_DIR_RX].cnt[TF_EM_TBL_TYPE_EM_RECORD] = 2048;
105 
106 	/* EEM */
107 	resources->em_cnt[TF_DIR_RX].cnt[TF_EM_TBL_TYPE_TBL_SCOPE] = 1;
108 
109 	/** TX **/
110 	/* Identifiers */
111 	resources->ident_cnt[TF_DIR_TX].cnt[TF_IDENT_TYPE_L2_CTXT] = 8;
112 	resources->ident_cnt[TF_DIR_TX].cnt[TF_IDENT_TYPE_WC_PROF] = 8;
113 	resources->ident_cnt[TF_DIR_TX].cnt[TF_IDENT_TYPE_PROF_FUNC] = 8;
114 	resources->ident_cnt[TF_DIR_TX].cnt[TF_IDENT_TYPE_EM_PROF] = 8;
115 
116 	/* Table Types */
117 	resources->tbl_cnt[TF_DIR_TX].cnt[TF_TBL_TYPE_FULL_ACT_RECORD] = 16;
118 	resources->tbl_cnt[TF_DIR_TX].cnt[TF_TBL_TYPE_ACT_STATS_64] = 16;
119 
120 	/* ENCAP */
121 	resources->tbl_cnt[TF_DIR_TX].cnt[TF_TBL_TYPE_ACT_ENCAP_64B] = 16;
122 	resources->tbl_cnt[TF_DIR_TX].cnt[TF_TBL_TYPE_ACT_ENCAP_16B] = 16;
123 
124 	/* TCAMs */
125 	resources->tcam_cnt[TF_DIR_TX].cnt[TF_TCAM_TBL_TYPE_L2_CTXT_TCAM] = 8;
126 	resources->tcam_cnt[TF_DIR_TX].cnt[TF_TCAM_TBL_TYPE_PROF_TCAM] = 8;
127 	resources->tcam_cnt[TF_DIR_TX].cnt[TF_TCAM_TBL_TYPE_WC_TCAM] = 8;
128 
129 	/* EM */
130 	resources->em_cnt[TF_DIR_TX].cnt[TF_EM_TBL_TYPE_EM_RECORD] = 8;
131 
132 	/* EEM */
133 	resources->em_cnt[TF_DIR_TX].cnt[TF_EM_TBL_TYPE_TBL_SCOPE] = 1;
134 
135 	/* SP */
136 	resources->tbl_cnt[TF_DIR_TX].cnt[TF_TBL_TYPE_ACT_SP_SMAC_IPV4] = 128;
137 
138 	rc = tf_open_session(&bp->tfp, &params);
139 	if (rc) {
140 		BNXT_TF_DBG(ERR, "Failed to open TF session - %s, rc = %d\n",
141 			    params.ctrl_chan_name, rc);
142 		return -EINVAL;
143 	}
144 	session->session_opened = 1;
145 	session->g_tfp = &bp->tfp;
146 	return rc;
147 }
148 
149 /*
150  * Close the ULP session.
151  * It takes the ulp context pointer.
152  */
153 static void
154 ulp_ctx_session_close(struct bnxt *bp,
155 		      struct bnxt_ulp_session_state *session)
156 {
157 	/* close the session in the hardware */
158 	if (session->session_opened)
159 		tf_close_session(&bp->tfp);
160 	session->session_opened = 0;
161 	session->g_tfp = NULL;
162 	bp->ulp_ctx->g_tfp = NULL;
163 }
164 
165 static void
166 bnxt_init_tbl_scope_parms(struct bnxt *bp,
167 			  struct tf_alloc_tbl_scope_parms *params)
168 {
169 	struct bnxt_ulp_device_params	*dparms;
170 	uint32_t dev_id;
171 	int rc;
172 
173 	rc = bnxt_ulp_cntxt_dev_id_get(bp->ulp_ctx, &dev_id);
174 	if (rc)
175 		/* TBD: For now, just use default. */
176 		dparms = 0;
177 	else
178 		dparms = bnxt_ulp_device_params_get(dev_id);
179 
180 	/*
181 	 * Set the flush timer for EEM entries. The value is in 100ms intervals,
182 	 * so 100 is 10s.
183 	 */
184 	params->hw_flow_cache_flush_timer = 100;
185 
186 	if (!dparms) {
187 		params->rx_max_key_sz_in_bits = BNXT_ULP_DFLT_RX_MAX_KEY;
188 		params->rx_max_action_entry_sz_in_bits =
189 			BNXT_ULP_DFLT_RX_MAX_ACTN_ENTRY;
190 		params->rx_mem_size_in_mb = BNXT_ULP_DFLT_RX_MEM;
191 		params->rx_num_flows_in_k = BNXT_ULP_RX_NUM_FLOWS;
192 		params->rx_tbl_if_id = BNXT_ULP_RX_TBL_IF_ID;
193 
194 		params->tx_max_key_sz_in_bits = BNXT_ULP_DFLT_TX_MAX_KEY;
195 		params->tx_max_action_entry_sz_in_bits =
196 			BNXT_ULP_DFLT_TX_MAX_ACTN_ENTRY;
197 		params->tx_mem_size_in_mb = BNXT_ULP_DFLT_TX_MEM;
198 		params->tx_num_flows_in_k = BNXT_ULP_TX_NUM_FLOWS;
199 		params->tx_tbl_if_id = BNXT_ULP_TX_TBL_IF_ID;
200 	} else {
201 		params->rx_max_key_sz_in_bits = BNXT_ULP_DFLT_RX_MAX_KEY;
202 		params->rx_max_action_entry_sz_in_bits =
203 			BNXT_ULP_DFLT_RX_MAX_ACTN_ENTRY;
204 		params->rx_mem_size_in_mb = BNXT_ULP_DFLT_RX_MEM;
205 		params->rx_num_flows_in_k = dparms->flow_db_num_entries / 1024;
206 		params->rx_tbl_if_id = BNXT_ULP_RX_TBL_IF_ID;
207 
208 		params->tx_max_key_sz_in_bits = BNXT_ULP_DFLT_TX_MAX_KEY;
209 		params->tx_max_action_entry_sz_in_bits =
210 			BNXT_ULP_DFLT_TX_MAX_ACTN_ENTRY;
211 		params->tx_mem_size_in_mb = BNXT_ULP_DFLT_TX_MEM;
212 		params->tx_num_flows_in_k = dparms->flow_db_num_entries / 1024;
213 		params->tx_tbl_if_id = BNXT_ULP_TX_TBL_IF_ID;
214 	}
215 }
216 
217 /* Initialize Extended Exact Match host memory. */
218 static int32_t
219 ulp_eem_tbl_scope_init(struct bnxt *bp)
220 {
221 	struct tf_alloc_tbl_scope_parms params = {0};
222 	uint32_t dev_id;
223 	struct bnxt_ulp_device_params *dparms;
224 	int rc;
225 
226 	/* Get the dev specific number of flows that needed to be supported. */
227 	if (bnxt_ulp_cntxt_dev_id_get(bp->ulp_ctx, &dev_id)) {
228 		BNXT_TF_DBG(ERR, "Invalid device id\n");
229 		return -EINVAL;
230 	}
231 
232 	dparms = bnxt_ulp_device_params_get(dev_id);
233 	if (!dparms) {
234 		BNXT_TF_DBG(ERR, "could not fetch the device params\n");
235 		return -ENODEV;
236 	}
237 
238 	if (dparms->flow_mem_type != BNXT_ULP_FLOW_MEM_TYPE_EXT) {
239 		BNXT_TF_DBG(INFO, "Table Scope alloc is not required\n");
240 		return 0;
241 	}
242 
243 	bnxt_init_tbl_scope_parms(bp, &params);
244 
245 	rc = tf_alloc_tbl_scope(&bp->tfp, &params);
246 	if (rc) {
247 		BNXT_TF_DBG(ERR, "Unable to allocate eem table scope rc = %d\n",
248 			    rc);
249 		return rc;
250 	}
251 
252 	rc = bnxt_ulp_cntxt_tbl_scope_id_set(bp->ulp_ctx, params.tbl_scope_id);
253 	if (rc) {
254 		BNXT_TF_DBG(ERR, "Unable to set table scope id\n");
255 		return rc;
256 	}
257 
258 	return 0;
259 }
260 
261 /* Free Extended Exact Match host memory */
262 static int32_t
263 ulp_eem_tbl_scope_deinit(struct bnxt *bp, struct bnxt_ulp_context *ulp_ctx)
264 {
265 	struct tf_free_tbl_scope_parms	params = {0};
266 	struct tf			*tfp;
267 	int32_t				rc = 0;
268 	struct bnxt_ulp_device_params *dparms;
269 	uint32_t dev_id;
270 
271 	if (!ulp_ctx || !ulp_ctx->cfg_data)
272 		return -EINVAL;
273 
274 	/* Free the resources for the last device */
275 	if (!ulp_ctx_deinit_allowed(bp))
276 		return rc;
277 
278 	tfp = bnxt_ulp_cntxt_tfp_get(ulp_ctx);
279 	if (!tfp) {
280 		BNXT_TF_DBG(ERR, "Failed to get the truflow pointer\n");
281 		return -EINVAL;
282 	}
283 
284 	/* Get the dev specific number of flows that needed to be supported. */
285 	if (bnxt_ulp_cntxt_dev_id_get(bp->ulp_ctx, &dev_id)) {
286 		BNXT_TF_DBG(ERR, "Invalid device id\n");
287 		return -EINVAL;
288 	}
289 
290 	dparms = bnxt_ulp_device_params_get(dev_id);
291 	if (!dparms) {
292 		BNXT_TF_DBG(ERR, "could not fetch the device params\n");
293 		return -ENODEV;
294 	}
295 
296 	if (dparms->flow_mem_type != BNXT_ULP_FLOW_MEM_TYPE_EXT) {
297 		BNXT_TF_DBG(INFO, "Table Scope free is not required\n");
298 		return 0;
299 	}
300 
301 	rc = bnxt_ulp_cntxt_tbl_scope_id_get(ulp_ctx, &params.tbl_scope_id);
302 	if (rc) {
303 		BNXT_TF_DBG(ERR, "Failed to get the table scope id\n");
304 		return -EINVAL;
305 	}
306 
307 	rc = tf_free_tbl_scope(tfp, &params);
308 	if (rc) {
309 		BNXT_TF_DBG(ERR, "Unable to free table scope\n");
310 		return -EINVAL;
311 	}
312 	return rc;
313 }
314 
315 /* The function to free and deinit the ulp context data. */
316 static int32_t
317 ulp_ctx_deinit(struct bnxt *bp,
318 	       struct bnxt_ulp_session_state *session)
319 {
320 	if (!session || !bp) {
321 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
322 		return -EINVAL;
323 	}
324 
325 	/* close the tf session */
326 	ulp_ctx_session_close(bp, session);
327 
328 	/* Free the contents */
329 	if (session->cfg_data) {
330 		rte_free(session->cfg_data);
331 		bp->ulp_ctx->cfg_data = NULL;
332 		session->cfg_data = NULL;
333 	}
334 	return 0;
335 }
336 
337 /* The function to allocate and initialize the ulp context data. */
338 static int32_t
339 ulp_ctx_init(struct bnxt *bp,
340 	     struct bnxt_ulp_session_state *session)
341 {
342 	struct bnxt_ulp_data	*ulp_data;
343 	int32_t			rc = 0;
344 
345 	if (!session || !bp) {
346 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
347 		return -EINVAL;
348 	}
349 
350 	/* Allocate memory to hold ulp context data. */
351 	ulp_data = rte_zmalloc("bnxt_ulp_data",
352 			       sizeof(struct bnxt_ulp_data), 0);
353 	if (!ulp_data) {
354 		BNXT_TF_DBG(ERR, "Failed to allocate memory for ulp data\n");
355 		return -ENOMEM;
356 	}
357 
358 	/* Increment the ulp context data reference count usage. */
359 	bp->ulp_ctx->cfg_data = ulp_data;
360 	session->cfg_data = ulp_data;
361 	ulp_data->ref_cnt++;
362 
363 	/* Open the ulp session. */
364 	rc = ulp_ctx_session_open(bp, session);
365 	if (rc) {
366 		(void)ulp_ctx_deinit(bp, session);
367 		return rc;
368 	}
369 	bnxt_ulp_cntxt_tfp_set(bp->ulp_ctx, session->g_tfp);
370 	return rc;
371 }
372 
373 /* The function to initialize ulp dparms with devargs */
374 static int32_t
375 ulp_dparms_init(struct bnxt *bp,
376 		struct bnxt_ulp_context *ulp_ctx)
377 {
378 	struct bnxt_ulp_device_params *dparms;
379 	uint32_t dev_id;
380 
381 	if (!bp->max_num_kflows)
382 		return -EINVAL;
383 
384 	if (bnxt_ulp_cntxt_dev_id_get(ulp_ctx, &dev_id)) {
385 		BNXT_TF_DBG(DEBUG, "Failed to get device id\n");
386 		return -EINVAL;
387 	}
388 
389 	dparms = bnxt_ulp_device_params_get(dev_id);
390 	if (!dparms) {
391 		BNXT_TF_DBG(DEBUG, "Failed to get device parms\n");
392 		return -EINVAL;
393 	}
394 
395 	/* num_flows = max_num_kflows * 1024 */
396 	dparms->flow_db_num_entries = bp->max_num_kflows * 1024;
397 	/* GFID =  2 * num_flows */
398 	dparms->mark_db_gfid_entries = dparms->flow_db_num_entries * 2;
399 	BNXT_TF_DBG(DEBUG, "Set the number of flows = %"PRIu64"\n",
400 		    dparms->flow_db_num_entries);
401 
402 	return 0;
403 }
404 
405 /* The function to initialize bp flags with truflow features */
406 static int32_t
407 ulp_dparms_dev_port_intf_update(struct bnxt *bp,
408 				struct bnxt_ulp_context *ulp_ctx)
409 {
410 	struct bnxt_ulp_device_params *dparms;
411 	uint32_t dev_id;
412 
413 	if (bnxt_ulp_cntxt_dev_id_get(ulp_ctx, &dev_id)) {
414 		BNXT_TF_DBG(DEBUG, "Failed to get device id\n");
415 		return -EINVAL;
416 	}
417 
418 	dparms = bnxt_ulp_device_params_get(dev_id);
419 	if (!dparms) {
420 		BNXT_TF_DBG(DEBUG, "Failed to get device parms\n");
421 		return -EINVAL;
422 	}
423 
424 	/* Update the bp flag with gfid flag */
425 	if (dparms->flow_mem_type == BNXT_ULP_FLOW_MEM_TYPE_EXT)
426 		bp->flags |= BNXT_FLAG_GFID_ENABLE;
427 
428 	return 0;
429 }
430 
431 static int32_t
432 ulp_ctx_attach(struct bnxt_ulp_context *ulp_ctx,
433 	       struct bnxt_ulp_session_state *session)
434 {
435 	if (!ulp_ctx || !session) {
436 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
437 		return -EINVAL;
438 	}
439 
440 	/* Increment the ulp context data reference count usage. */
441 	ulp_ctx->cfg_data = session->cfg_data;
442 	ulp_ctx->cfg_data->ref_cnt++;
443 
444 	/* TBD call TF_session_attach. */
445 	ulp_ctx->g_tfp = session->g_tfp;
446 	return 0;
447 }
448 
449 static int32_t
450 ulp_ctx_detach(struct bnxt *bp,
451 	       struct bnxt_ulp_session_state *session)
452 {
453 	struct bnxt_ulp_context *ulp_ctx;
454 
455 	if (!bp || !session) {
456 		BNXT_TF_DBG(ERR, "Invalid Arguments\n");
457 		return -EINVAL;
458 	}
459 	ulp_ctx = bp->ulp_ctx;
460 
461 	if (!ulp_ctx->cfg_data)
462 		return 0;
463 
464 	/* TBD call TF_session_detach */
465 
466 	/* Increment the ulp context data reference count usage. */
467 	if (ulp_ctx->cfg_data->ref_cnt >= 1) {
468 		ulp_ctx->cfg_data->ref_cnt--;
469 		if (ulp_ctx_deinit_allowed(bp))
470 			ulp_ctx_deinit(bp, session);
471 		ulp_ctx->cfg_data = NULL;
472 		ulp_ctx->g_tfp = NULL;
473 		return 0;
474 	}
475 	BNXT_TF_DBG(ERR, "context deatach on invalid data\n");
476 	return 0;
477 }
478 
479 /*
480  * Initialize the state of an ULP session.
481  * If the state of an ULP session is not initialized, set it's state to
482  * initialized. If the state is already initialized, do nothing.
483  */
484 static void
485 ulp_context_initialized(struct bnxt_ulp_session_state *session, bool *init)
486 {
487 	pthread_mutex_lock(&session->bnxt_ulp_mutex);
488 
489 	if (!session->bnxt_ulp_init) {
490 		session->bnxt_ulp_init = true;
491 		*init = false;
492 	} else {
493 		*init = true;
494 	}
495 
496 	pthread_mutex_unlock(&session->bnxt_ulp_mutex);
497 }
498 
499 /*
500  * Check if an ULP session is already allocated for a specific PCI
501  * domain & bus. If it is already allocated simply return the session
502  * pointer, otherwise allocate a new session.
503  */
504 static struct bnxt_ulp_session_state *
505 ulp_get_session(struct rte_pci_addr *pci_addr)
506 {
507 	struct bnxt_ulp_session_state *session;
508 
509 	STAILQ_FOREACH(session, &bnxt_ulp_session_list, next) {
510 		if (session->pci_info.domain == pci_addr->domain &&
511 		    session->pci_info.bus == pci_addr->bus) {
512 			return session;
513 		}
514 	}
515 	return NULL;
516 }
517 
518 /*
519  * Allocate and Initialize an ULP session and set it's state to INITIALIZED.
520  * If it's already initialized simply return the already existing session.
521  */
522 static struct bnxt_ulp_session_state *
523 ulp_session_init(struct bnxt *bp,
524 		 bool *init)
525 {
526 	struct rte_pci_device		*pci_dev;
527 	struct rte_pci_addr		*pci_addr;
528 	struct bnxt_ulp_session_state	*session;
529 
530 	if (!bp)
531 		return NULL;
532 
533 	pci_dev = RTE_DEV_TO_PCI(bp->eth_dev->device);
534 	pci_addr = &pci_dev->addr;
535 
536 	pthread_mutex_lock(&bnxt_ulp_global_mutex);
537 
538 	session = ulp_get_session(pci_addr);
539 	if (!session) {
540 		/* Not Found the session  Allocate a new one */
541 		session = rte_zmalloc("bnxt_ulp_session",
542 				      sizeof(struct bnxt_ulp_session_state),
543 				      0);
544 		if (!session) {
545 			BNXT_TF_DBG(ERR,
546 				    "Allocation failed for bnxt_ulp_session\n");
547 			pthread_mutex_unlock(&bnxt_ulp_global_mutex);
548 			return NULL;
549 
550 		} else {
551 			/* Add it to the queue */
552 			session->pci_info.domain = pci_addr->domain;
553 			session->pci_info.bus = pci_addr->bus;
554 			pthread_mutex_init(&session->bnxt_ulp_mutex, NULL);
555 			STAILQ_INSERT_TAIL(&bnxt_ulp_session_list,
556 					   session, next);
557 		}
558 	}
559 	ulp_context_initialized(session, init);
560 	pthread_mutex_unlock(&bnxt_ulp_global_mutex);
561 	return session;
562 }
563 
564 /*
565  * When a device is closed, remove it's associated session from the global
566  * session list.
567  */
568 static void
569 ulp_session_deinit(struct bnxt_ulp_session_state *session)
570 {
571 	if (!session)
572 		return;
573 
574 	if (!session->cfg_data) {
575 		pthread_mutex_lock(&bnxt_ulp_global_mutex);
576 		STAILQ_REMOVE(&bnxt_ulp_session_list, session,
577 			      bnxt_ulp_session_state, next);
578 		pthread_mutex_destroy(&session->bnxt_ulp_mutex);
579 		rte_free(session);
580 		pthread_mutex_unlock(&bnxt_ulp_global_mutex);
581 	}
582 }
583 
584 /*
585  * When a port is initialized by dpdk. This functions is called
586  * and this function initializes the ULP context and rest of the
587  * infrastructure associated with it.
588  */
589 int32_t
590 bnxt_ulp_init(struct bnxt *bp)
591 {
592 	struct bnxt_ulp_session_state *session;
593 	bool init;
594 	int rc;
595 
596 	if (bp->ulp_ctx) {
597 		BNXT_TF_DBG(DEBUG, "ulp ctx already allocated\n");
598 		return -EINVAL;
599 	}
600 
601 	/*
602 	 * Multiple uplink ports can be associated with a single vswitch.
603 	 * Make sure only the port that is started first will initialize
604 	 * the TF session.
605 	 */
606 	session = ulp_session_init(bp, &init);
607 	if (!session) {
608 		BNXT_TF_DBG(ERR, "Failed to initialize the tf session\n");
609 		return -EINVAL;
610 	}
611 
612 	bp->ulp_ctx = rte_zmalloc("bnxt_ulp_ctx",
613 				  sizeof(struct bnxt_ulp_context), 0);
614 	if (!bp->ulp_ctx) {
615 		BNXT_TF_DBG(ERR, "Failed to allocate ulp ctx\n");
616 		ulp_session_deinit(session);
617 		return -ENOMEM;
618 	}
619 
620 	/*
621 	 * If ULP is already initialized for a specific domain then simply
622 	 * assign the ulp context to this rte_eth_dev.
623 	 */
624 	if (init) {
625 		rc = ulp_ctx_attach(bp->ulp_ctx, session);
626 		if (rc) {
627 			BNXT_TF_DBG(ERR,
628 				    "Failed to attach the ulp context\n");
629 			ulp_session_deinit(session);
630 			rte_free(bp->ulp_ctx);
631 			return rc;
632 		}
633 
634 		/* Update bnxt driver flags */
635 		rc = ulp_dparms_dev_port_intf_update(bp, bp->ulp_ctx);
636 		if (rc) {
637 			BNXT_TF_DBG(ERR, "Failed to update driver flags\n");
638 			ulp_ctx_detach(bp, session);
639 			ulp_session_deinit(session);
640 			rte_free(bp->ulp_ctx);
641 			return rc;
642 		}
643 
644 		/* update the port database */
645 		rc = ulp_port_db_dev_port_intf_update(bp->ulp_ctx, bp->eth_dev);
646 		if (rc) {
647 			BNXT_TF_DBG(ERR,
648 				    "Failed to update port database\n");
649 			ulp_ctx_detach(bp, session);
650 			ulp_session_deinit(session);
651 			rte_free(bp->ulp_ctx);
652 		}
653 		return rc;
654 	}
655 
656 	/* Allocate and Initialize the ulp context. */
657 	rc = ulp_ctx_init(bp, session);
658 	if (rc) {
659 		BNXT_TF_DBG(ERR, "Failed to create the ulp context\n");
660 		goto jump_to_error;
661 	}
662 
663 	/* Initialize ulp dparms with values devargs passed */
664 	rc = ulp_dparms_init(bp, bp->ulp_ctx);
665 
666 	/* create the port database */
667 	rc = ulp_port_db_init(bp->ulp_ctx, bp->port_cnt);
668 	if (rc) {
669 		BNXT_TF_DBG(ERR, "Failed to create the port database\n");
670 		goto jump_to_error;
671 	}
672 
673 	/* Update bnxt driver flags */
674 	rc = ulp_dparms_dev_port_intf_update(bp, bp->ulp_ctx);
675 	if (rc) {
676 		BNXT_TF_DBG(ERR, "Failed to update driver flags\n");
677 		goto jump_to_error;
678 	}
679 
680 	/* update the port database */
681 	rc = ulp_port_db_dev_port_intf_update(bp->ulp_ctx, bp->eth_dev);
682 	if (rc) {
683 		BNXT_TF_DBG(ERR, "Failed to update port database\n");
684 		goto jump_to_error;
685 	}
686 
687 	/* Create the Mark database. */
688 	rc = ulp_mark_db_init(bp->ulp_ctx);
689 	if (rc) {
690 		BNXT_TF_DBG(ERR, "Failed to create the mark database\n");
691 		goto jump_to_error;
692 	}
693 
694 	/* Create the flow database. */
695 	rc = ulp_flow_db_init(bp->ulp_ctx);
696 	if (rc) {
697 		BNXT_TF_DBG(ERR, "Failed to create the flow database\n");
698 		goto jump_to_error;
699 	}
700 
701 	/* Create the eem table scope. */
702 	rc = ulp_eem_tbl_scope_init(bp);
703 	if (rc) {
704 		BNXT_TF_DBG(ERR, "Failed to create the eem scope table\n");
705 		goto jump_to_error;
706 	}
707 
708 	rc = ulp_mapper_init(bp->ulp_ctx);
709 	if (rc) {
710 		BNXT_TF_DBG(ERR, "Failed to initialize ulp mapper\n");
711 		goto jump_to_error;
712 	}
713 
714 	rc = ulp_fc_mgr_init(bp->ulp_ctx);
715 	if (rc) {
716 		BNXT_TF_DBG(ERR, "Failed to initialize ulp flow counter mgr\n");
717 		goto jump_to_error;
718 	}
719 
720 	return rc;
721 
722 jump_to_error:
723 	bnxt_ulp_deinit(bp);
724 	return -ENOMEM;
725 }
726 
727 /* Below are the access functions to access internal data of ulp context. */
728 
729 /*
730  * When a port is deinit'ed by dpdk. This function is called
731  * and this function clears the ULP context and rest of the
732  * infrastructure associated with it.
733  */
734 void
735 bnxt_ulp_deinit(struct bnxt *bp)
736 {
737 	struct bnxt_ulp_session_state	*session;
738 	struct rte_pci_device		*pci_dev;
739 	struct rte_pci_addr		*pci_addr;
740 
741 	/* Get the session first */
742 	pci_dev = RTE_DEV_TO_PCI(bp->eth_dev->device);
743 	pci_addr = &pci_dev->addr;
744 	pthread_mutex_lock(&bnxt_ulp_global_mutex);
745 	session = ulp_get_session(pci_addr);
746 	pthread_mutex_unlock(&bnxt_ulp_global_mutex);
747 
748 	/* session not found then just exit */
749 	if (!session)
750 		return;
751 
752 	/* clean up regular flows */
753 	ulp_flow_db_flush_flows(bp->ulp_ctx, BNXT_ULP_REGULAR_FLOW_TABLE);
754 
755 	/* cleanup the eem table scope */
756 	ulp_eem_tbl_scope_deinit(bp, bp->ulp_ctx);
757 
758 	/* cleanup the flow database */
759 	ulp_flow_db_deinit(bp->ulp_ctx);
760 
761 	/* Delete the Mark database */
762 	ulp_mark_db_deinit(bp->ulp_ctx);
763 
764 	/* cleanup the ulp mapper */
765 	ulp_mapper_deinit(bp->ulp_ctx);
766 
767 	/* Delete the Flow Counter Manager */
768 	ulp_fc_mgr_deinit(bp->ulp_ctx);
769 
770 	/* Delete the Port database */
771 	ulp_port_db_deinit(bp->ulp_ctx);
772 
773 	/* Delete the ulp context and tf session */
774 	ulp_ctx_detach(bp, session);
775 
776 	/* Finally delete the bnxt session*/
777 	ulp_session_deinit(session);
778 
779 	rte_free(bp->ulp_ctx);
780 }
781 
782 /* Function to set the Mark DB into the context */
783 int32_t
784 bnxt_ulp_cntxt_ptr2_mark_db_set(struct bnxt_ulp_context *ulp_ctx,
785 				struct bnxt_ulp_mark_tbl *mark_tbl)
786 {
787 	if (!ulp_ctx || !ulp_ctx->cfg_data) {
788 		BNXT_TF_DBG(ERR, "Invalid ulp context data\n");
789 		return -EINVAL;
790 	}
791 
792 	ulp_ctx->cfg_data->mark_tbl = mark_tbl;
793 
794 	return 0;
795 }
796 
797 /* Function to retrieve the Mark DB from the context. */
798 struct bnxt_ulp_mark_tbl *
799 bnxt_ulp_cntxt_ptr2_mark_db_get(struct bnxt_ulp_context *ulp_ctx)
800 {
801 	if (!ulp_ctx || !ulp_ctx->cfg_data)
802 		return NULL;
803 
804 	return ulp_ctx->cfg_data->mark_tbl;
805 }
806 
807 /* Function to set the device id of the hardware. */
808 int32_t
809 bnxt_ulp_cntxt_dev_id_set(struct bnxt_ulp_context *ulp_ctx,
810 			  uint32_t dev_id)
811 {
812 	if (ulp_ctx && ulp_ctx->cfg_data) {
813 		ulp_ctx->cfg_data->dev_id = dev_id;
814 		return 0;
815 	}
816 
817 	return -EINVAL;
818 }
819 
820 /* Function to get the device id of the hardware. */
821 int32_t
822 bnxt_ulp_cntxt_dev_id_get(struct bnxt_ulp_context *ulp_ctx,
823 			  uint32_t *dev_id)
824 {
825 	if (ulp_ctx && ulp_ctx->cfg_data) {
826 		*dev_id = ulp_ctx->cfg_data->dev_id;
827 		return 0;
828 	}
829 
830 	return -EINVAL;
831 }
832 
833 /* Function to get the table scope id of the EEM table. */
834 int32_t
835 bnxt_ulp_cntxt_tbl_scope_id_get(struct bnxt_ulp_context *ulp_ctx,
836 				uint32_t *tbl_scope_id)
837 {
838 	if (ulp_ctx && ulp_ctx->cfg_data) {
839 		*tbl_scope_id = ulp_ctx->cfg_data->tbl_scope_id;
840 		return 0;
841 	}
842 
843 	return -EINVAL;
844 }
845 
846 /* Function to set the table scope id of the EEM table. */
847 int32_t
848 bnxt_ulp_cntxt_tbl_scope_id_set(struct bnxt_ulp_context *ulp_ctx,
849 				uint32_t tbl_scope_id)
850 {
851 	if (ulp_ctx && ulp_ctx->cfg_data) {
852 		ulp_ctx->cfg_data->tbl_scope_id = tbl_scope_id;
853 		return 0;
854 	}
855 
856 	return -EINVAL;
857 }
858 
859 /* Function to set the tfp session details from the ulp context. */
860 int32_t
861 bnxt_ulp_cntxt_tfp_set(struct bnxt_ulp_context *ulp, struct tf *tfp)
862 {
863 	if (!ulp) {
864 		BNXT_TF_DBG(ERR, "Invalid arguments\n");
865 		return -EINVAL;
866 	}
867 
868 	/* TBD The tfp should be removed once tf_attach is implemented. */
869 	ulp->g_tfp = tfp;
870 	return 0;
871 }
872 
873 /* Function to get the tfp session details from the ulp context. */
874 struct tf *
875 bnxt_ulp_cntxt_tfp_get(struct bnxt_ulp_context *ulp)
876 {
877 	if (!ulp) {
878 		BNXT_TF_DBG(ERR, "Invalid arguments\n");
879 		return NULL;
880 	}
881 	/* TBD The tfp should be removed once tf_attach is implemented. */
882 	return ulp->g_tfp;
883 }
884 
885 /*
886  * Get the device table entry based on the device id.
887  *
888  * dev_id [in] The device id of the hardware
889  *
890  * Returns the pointer to the device parameters.
891  */
892 struct bnxt_ulp_device_params *
893 bnxt_ulp_device_params_get(uint32_t dev_id)
894 {
895 	if (dev_id < BNXT_ULP_MAX_NUM_DEVICES)
896 		return &ulp_device_params[dev_id];
897 	return NULL;
898 }
899 
900 /* Function to set the flow database to the ulp context. */
901 int32_t
902 bnxt_ulp_cntxt_ptr2_flow_db_set(struct bnxt_ulp_context	*ulp_ctx,
903 				struct bnxt_ulp_flow_db	*flow_db)
904 {
905 	if (!ulp_ctx || !ulp_ctx->cfg_data)
906 		return -EINVAL;
907 
908 	ulp_ctx->cfg_data->flow_db = flow_db;
909 	return 0;
910 }
911 
912 /* Function to get the flow database from the ulp context. */
913 struct bnxt_ulp_flow_db	*
914 bnxt_ulp_cntxt_ptr2_flow_db_get(struct bnxt_ulp_context	*ulp_ctx)
915 {
916 	if (!ulp_ctx || !ulp_ctx->cfg_data)
917 		return NULL;
918 
919 	return ulp_ctx->cfg_data->flow_db;
920 }
921 
922 /* Function to get the ulp context from eth device. */
923 struct bnxt_ulp_context	*
924 bnxt_ulp_eth_dev_ptr2_cntxt_get(struct rte_eth_dev	*dev)
925 {
926 	struct bnxt *bp = (struct bnxt *)dev->data->dev_private;
927 
928 	if (BNXT_ETH_DEV_IS_REPRESENTOR(dev)) {
929 		struct bnxt_vf_representor *vfr = dev->data->dev_private;
930 		bp = vfr->parent_dev->data->dev_private;
931 	}
932 
933 	if (!bp) {
934 		BNXT_TF_DBG(ERR, "Bnxt private data is not initialized\n");
935 		return NULL;
936 	}
937 	return bp->ulp_ctx;
938 }
939 
940 int32_t
941 bnxt_ulp_cntxt_ptr2_mapper_data_set(struct bnxt_ulp_context *ulp_ctx,
942 				    void *mapper_data)
943 {
944 	if (!ulp_ctx || !ulp_ctx->cfg_data) {
945 		BNXT_TF_DBG(ERR, "Invalid ulp context data\n");
946 		return -EINVAL;
947 	}
948 
949 	ulp_ctx->cfg_data->mapper_data = mapper_data;
950 	return 0;
951 }
952 
953 void *
954 bnxt_ulp_cntxt_ptr2_mapper_data_get(struct bnxt_ulp_context *ulp_ctx)
955 {
956 	if (!ulp_ctx || !ulp_ctx->cfg_data) {
957 		BNXT_TF_DBG(ERR, "Invalid ulp context data\n");
958 		return NULL;
959 	}
960 
961 	return ulp_ctx->cfg_data->mapper_data;
962 }
963 
964 /* Function to set the port database to the ulp context. */
965 int32_t
966 bnxt_ulp_cntxt_ptr2_port_db_set(struct bnxt_ulp_context	*ulp_ctx,
967 				struct bnxt_ulp_port_db	*port_db)
968 {
969 	if (!ulp_ctx || !ulp_ctx->cfg_data)
970 		return -EINVAL;
971 
972 	ulp_ctx->cfg_data->port_db = port_db;
973 	return 0;
974 }
975 
976 /* Function to get the port database from the ulp context. */
977 struct bnxt_ulp_port_db *
978 bnxt_ulp_cntxt_ptr2_port_db_get(struct bnxt_ulp_context	*ulp_ctx)
979 {
980 	if (!ulp_ctx || !ulp_ctx->cfg_data)
981 		return NULL;
982 
983 	return ulp_ctx->cfg_data->port_db;
984 }
985 
986 /* Function to set the flow counter info into the context */
987 int32_t
988 bnxt_ulp_cntxt_ptr2_fc_info_set(struct bnxt_ulp_context *ulp_ctx,
989 				struct bnxt_ulp_fc_info *ulp_fc_info)
990 {
991 	if (!ulp_ctx || !ulp_ctx->cfg_data) {
992 		BNXT_TF_DBG(ERR, "Invalid ulp context data\n");
993 		return -EINVAL;
994 	}
995 
996 	ulp_ctx->cfg_data->fc_info = ulp_fc_info;
997 
998 	return 0;
999 }
1000 
1001 /* Function to retrieve the flow counter info from the context. */
1002 struct bnxt_ulp_fc_info *
1003 bnxt_ulp_cntxt_ptr2_fc_info_get(struct bnxt_ulp_context *ulp_ctx)
1004 {
1005 	if (!ulp_ctx || !ulp_ctx->cfg_data)
1006 		return NULL;
1007 
1008 	return ulp_ctx->cfg_data->fc_info;
1009 }
1010