1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019-2020 Broadcom
7 #include <rte_malloc.h>
9 #include <rte_flow_driver.h>
10 #include <rte_tailq.h>
13 #include "bnxt_tf_common.h"
16 #include "tf_ext_flow_handle.h"
18 #include "ulp_template_db.h"
19 #include "ulp_template_struct.h"
20 #include "ulp_mark_mgr.h"
21 #include "ulp_flow_db.h"
23 /* Linked list of all TF sessions. */
24 STAILQ_HEAD(, bnxt_ulp_session_state) bnxt_ulp_session_list =
25 STAILQ_HEAD_INITIALIZER(bnxt_ulp_session_list);
27 /* Mutex to synchronize bnxt_ulp_session_list operations. */
28 static pthread_mutex_t bnxt_ulp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
31 * Initialize an ULP session.
32 * An ULP session will contain all the resources needed to support rte flow
33 * offloads. A session is initialized as part of rte_eth_device start.
34 * A single vswitch instance can have multiple uplinks which means
35 * rte_eth_device start will be called for each of these devices.
36 * ULP session manager will make sure that a single ULP session is only
37 * initialized once. Apart from this, it also initializes MARK database,
38 * EEM table & flow database. ULP session manager also manages a list of
39 * all opened ULP sessions.
42 ulp_ctx_session_open(struct bnxt *bp,
43 struct bnxt_ulp_session_state *session)
45 struct rte_eth_dev *ethdev = bp->eth_dev;
47 struct tf_open_session_parms params;
49 memset(¶ms, 0, sizeof(params));
51 rc = rte_eth_dev_get_name_by_port(ethdev->data->port_id,
52 params.ctrl_chan_name);
54 BNXT_TF_DBG(ERR, "Invalid port %d, rc = %d\n",
55 ethdev->data->port_id, rc);
59 rc = tf_open_session(&bp->tfp, ¶ms);
61 BNXT_TF_DBG(ERR, "Failed to open TF session - %s, rc = %d\n",
62 params.ctrl_chan_name, rc);
65 session->session_opened = 1;
66 session->g_tfp = &bp->tfp;
71 bnxt_init_tbl_scope_parms(struct bnxt *bp,
72 struct tf_alloc_tbl_scope_parms *params)
74 struct bnxt_ulp_device_params *dparms;
78 rc = bnxt_ulp_cntxt_dev_id_get(&bp->ulp_ctx, &dev_id);
80 /* TBD: For now, just use default. */
83 dparms = bnxt_ulp_device_params_get(dev_id);
86 params->rx_max_key_sz_in_bits = BNXT_ULP_DFLT_RX_MAX_KEY;
87 params->rx_max_action_entry_sz_in_bits =
88 BNXT_ULP_DFLT_RX_MAX_ACTN_ENTRY;
89 params->rx_mem_size_in_mb = BNXT_ULP_DFLT_RX_MEM;
90 params->rx_num_flows_in_k = BNXT_ULP_RX_NUM_FLOWS;
91 params->rx_tbl_if_id = BNXT_ULP_RX_TBL_IF_ID;
93 params->tx_max_key_sz_in_bits = BNXT_ULP_DFLT_TX_MAX_KEY;
94 params->tx_max_action_entry_sz_in_bits =
95 BNXT_ULP_DFLT_TX_MAX_ACTN_ENTRY;
96 params->tx_mem_size_in_mb = BNXT_ULP_DFLT_TX_MEM;
97 params->tx_num_flows_in_k = BNXT_ULP_TX_NUM_FLOWS;
98 params->tx_tbl_if_id = BNXT_ULP_TX_TBL_IF_ID;
100 params->rx_max_key_sz_in_bits = BNXT_ULP_DFLT_RX_MAX_KEY;
101 params->rx_max_action_entry_sz_in_bits =
102 BNXT_ULP_DFLT_RX_MAX_ACTN_ENTRY;
103 params->rx_mem_size_in_mb = BNXT_ULP_DFLT_RX_MEM;
104 params->rx_num_flows_in_k = dparms->num_flows / (1024);
105 params->rx_tbl_if_id = BNXT_ULP_RX_TBL_IF_ID;
107 params->tx_max_key_sz_in_bits = BNXT_ULP_DFLT_TX_MAX_KEY;
108 params->tx_max_action_entry_sz_in_bits =
109 BNXT_ULP_DFLT_TX_MAX_ACTN_ENTRY;
110 params->tx_mem_size_in_mb = BNXT_ULP_DFLT_TX_MEM;
111 params->tx_num_flows_in_k = dparms->num_flows / (1024);
112 params->tx_tbl_if_id = BNXT_ULP_TX_TBL_IF_ID;
116 /* Initialize Extended Exact Match host memory. */
118 ulp_eem_tbl_scope_init(struct bnxt *bp)
120 struct tf_alloc_tbl_scope_parms params = {0};
123 bnxt_init_tbl_scope_parms(bp, ¶ms);
125 rc = tf_alloc_tbl_scope(&bp->tfp, ¶ms);
127 BNXT_TF_DBG(ERR, "Unable to allocate eem table scope rc = %d\n",
132 rc = bnxt_ulp_cntxt_tbl_scope_id_set(&bp->ulp_ctx, params.tbl_scope_id);
134 BNXT_TF_DBG(ERR, "Unable to set table scope id\n");
141 /* The function to free and deinit the ulp context data. */
143 ulp_ctx_deinit(struct bnxt *bp,
144 struct bnxt_ulp_session_state *session)
146 if (!session || !bp) {
147 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
151 /* Free the contents */
152 if (session->cfg_data) {
153 rte_free(session->cfg_data);
154 bp->ulp_ctx.cfg_data = NULL;
155 session->cfg_data = NULL;
160 /* The function to allocate and initialize the ulp context data. */
162 ulp_ctx_init(struct bnxt *bp,
163 struct bnxt_ulp_session_state *session)
165 struct bnxt_ulp_data *ulp_data;
168 if (!session || !bp) {
169 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
173 /* Allocate memory to hold ulp context data. */
174 ulp_data = rte_zmalloc("bnxt_ulp_data",
175 sizeof(struct bnxt_ulp_data), 0);
177 BNXT_TF_DBG(ERR, "Failed to allocate memory for ulp data\n");
181 /* Increment the ulp context data reference count usage. */
182 bp->ulp_ctx.cfg_data = ulp_data;
183 session->cfg_data = ulp_data;
186 /* Open the ulp session. */
187 rc = ulp_ctx_session_open(bp, session);
189 (void)ulp_ctx_deinit(bp, session);
192 bnxt_ulp_cntxt_tfp_set(&bp->ulp_ctx, session->g_tfp);
197 ulp_ctx_attach(struct bnxt_ulp_context *ulp_ctx,
198 struct bnxt_ulp_session_state *session)
200 if (!ulp_ctx || !session) {
201 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
205 /* Increment the ulp context data reference count usage. */
206 ulp_ctx->cfg_data = session->cfg_data;
207 ulp_ctx->cfg_data->ref_cnt++;
209 /* TBD call TF_session_attach. */
210 ulp_ctx->g_tfp = session->g_tfp;
215 * Initialize the state of an ULP session.
216 * If the state of an ULP session is not initialized, set it's state to
217 * initialized. If the state is already initialized, do nothing.
220 ulp_context_initialized(struct bnxt_ulp_session_state *session, bool *init)
222 pthread_mutex_lock(&session->bnxt_ulp_mutex);
224 if (!session->bnxt_ulp_init) {
225 session->bnxt_ulp_init = true;
231 pthread_mutex_unlock(&session->bnxt_ulp_mutex);
235 * Check if an ULP session is already allocated for a specific PCI
236 * domain & bus. If it is already allocated simply return the session
237 * pointer, otherwise allocate a new session.
239 static struct bnxt_ulp_session_state *
240 ulp_get_session(struct rte_pci_addr *pci_addr)
242 struct bnxt_ulp_session_state *session;
244 STAILQ_FOREACH(session, &bnxt_ulp_session_list, next) {
245 if (session->pci_info.domain == pci_addr->domain &&
246 session->pci_info.bus == pci_addr->bus) {
254 * Allocate and Initialize an ULP session and set it's state to INITIALIZED.
255 * If it's already initialized simply return the already existing session.
257 static struct bnxt_ulp_session_state *
258 ulp_session_init(struct bnxt *bp,
261 struct rte_pci_device *pci_dev;
262 struct rte_pci_addr *pci_addr;
263 struct bnxt_ulp_session_state *session;
268 pci_dev = RTE_DEV_TO_PCI(bp->eth_dev->device);
269 pci_addr = &pci_dev->addr;
271 pthread_mutex_lock(&bnxt_ulp_global_mutex);
273 session = ulp_get_session(pci_addr);
275 /* Not Found the session Allocate a new one */
276 session = rte_zmalloc("bnxt_ulp_session",
277 sizeof(struct bnxt_ulp_session_state),
281 "Allocation failed for bnxt_ulp_session\n");
282 pthread_mutex_unlock(&bnxt_ulp_global_mutex);
286 /* Add it to the queue */
287 session->pci_info.domain = pci_addr->domain;
288 session->pci_info.bus = pci_addr->bus;
289 pthread_mutex_init(&session->bnxt_ulp_mutex, NULL);
290 STAILQ_INSERT_TAIL(&bnxt_ulp_session_list,
294 ulp_context_initialized(session, init);
295 pthread_mutex_unlock(&bnxt_ulp_global_mutex);
300 * When a port is initialized by dpdk. This functions is called
301 * and this function initializes the ULP context and rest of the
302 * infrastructure associated with it.
305 bnxt_ulp_init(struct bnxt *bp)
307 struct bnxt_ulp_session_state *session;
312 * Multiple uplink ports can be associated with a single vswitch.
313 * Make sure only the port that is started first will initialize
316 session = ulp_session_init(bp, &init);
318 BNXT_TF_DBG(ERR, "Failed to initialize the tf session\n");
323 * If ULP is already initialized for a specific domain then simply
324 * assign the ulp context to this rte_eth_dev.
327 rc = ulp_ctx_attach(&bp->ulp_ctx, session);
330 "Failed to attach the ulp context\n");
335 /* Allocate and Initialize the ulp context. */
336 rc = ulp_ctx_init(bp, session);
338 BNXT_TF_DBG(ERR, "Failed to create the ulp context\n");
342 /* Create the Mark database. */
343 rc = ulp_mark_db_init(&bp->ulp_ctx);
345 BNXT_TF_DBG(ERR, "Failed to create the mark database\n");
349 /* Create the flow database. */
350 rc = ulp_flow_db_init(&bp->ulp_ctx);
352 BNXT_TF_DBG(ERR, "Failed to create the flow database\n");
356 /* Create the eem table scope. */
357 rc = ulp_eem_tbl_scope_init(bp);
359 BNXT_TF_DBG(ERR, "Failed to create the eem scope table\n");
369 /* Below are the access functions to access internal data of ulp context. */
371 /* Function to set the Mark DB into the context. */
373 bnxt_ulp_cntxt_ptr2_mark_db_set(struct bnxt_ulp_context *ulp_ctx,
374 struct bnxt_ulp_mark_tbl *mark_tbl)
376 if (!ulp_ctx || !ulp_ctx->cfg_data) {
377 BNXT_TF_DBG(ERR, "Invalid ulp context data\n");
381 ulp_ctx->cfg_data->mark_tbl = mark_tbl;
386 /* Function to retrieve the Mark DB from the context. */
387 struct bnxt_ulp_mark_tbl *
388 bnxt_ulp_cntxt_ptr2_mark_db_get(struct bnxt_ulp_context *ulp_ctx)
390 if (!ulp_ctx || !ulp_ctx->cfg_data)
393 return ulp_ctx->cfg_data->mark_tbl;
396 /* Function to set the device id of the hardware. */
398 bnxt_ulp_cntxt_dev_id_set(struct bnxt_ulp_context *ulp_ctx,
401 if (ulp_ctx && ulp_ctx->cfg_data) {
402 ulp_ctx->cfg_data->dev_id = dev_id;
409 /* Function to get the device id of the hardware. */
411 bnxt_ulp_cntxt_dev_id_get(struct bnxt_ulp_context *ulp_ctx,
414 if (ulp_ctx && ulp_ctx->cfg_data) {
415 *dev_id = ulp_ctx->cfg_data->dev_id;
422 /* Function to get the table scope id of the EEM table. */
424 bnxt_ulp_cntxt_tbl_scope_id_get(struct bnxt_ulp_context *ulp_ctx,
425 uint32_t *tbl_scope_id)
427 if (ulp_ctx && ulp_ctx->cfg_data) {
428 *tbl_scope_id = ulp_ctx->cfg_data->tbl_scope_id;
435 /* Function to set the table scope id of the EEM table. */
437 bnxt_ulp_cntxt_tbl_scope_id_set(struct bnxt_ulp_context *ulp_ctx,
438 uint32_t tbl_scope_id)
440 if (ulp_ctx && ulp_ctx->cfg_data) {
441 ulp_ctx->cfg_data->tbl_scope_id = tbl_scope_id;
448 /* Function to set the tfp session details from the ulp context. */
450 bnxt_ulp_cntxt_tfp_set(struct bnxt_ulp_context *ulp, struct tf *tfp)
453 BNXT_TF_DBG(ERR, "Invalid arguments\n");
457 /* TBD The tfp should be removed once tf_attach is implemented. */
462 /* Function to get the tfp session details from the ulp context. */
464 bnxt_ulp_cntxt_tfp_get(struct bnxt_ulp_context *ulp)
467 BNXT_TF_DBG(ERR, "Invalid arguments\n");
470 /* TBD The tfp should be removed once tf_attach is implemented. */
475 * Get the device table entry based on the device id.
477 * dev_id [in] The device id of the hardware
479 * Returns the pointer to the device parameters.
481 struct bnxt_ulp_device_params *
482 bnxt_ulp_device_params_get(uint32_t dev_id)
484 if (dev_id < BNXT_ULP_MAX_NUM_DEVICES)
485 return &ulp_device_params[dev_id];
489 /* Function to set the flow database to the ulp context. */
491 bnxt_ulp_cntxt_ptr2_flow_db_set(struct bnxt_ulp_context *ulp_ctx,
492 struct bnxt_ulp_flow_db *flow_db)
494 if (!ulp_ctx || !ulp_ctx->cfg_data) {
495 BNXT_TF_DBG(ERR, "Invalid ulp context data\n");
499 ulp_ctx->cfg_data->flow_db = flow_db;
503 /* Function to get the flow database from the ulp context. */
504 struct bnxt_ulp_flow_db *
505 bnxt_ulp_cntxt_ptr2_flow_db_get(struct bnxt_ulp_context *ulp_ctx)
507 if (!ulp_ctx || !ulp_ctx->cfg_data) {
508 BNXT_TF_DBG(ERR, "Invalid ulp context data\n");
512 return ulp_ctx->cfg_data->flow_db;
515 /* Function to get the ulp context from eth device. */
516 struct bnxt_ulp_context *
517 bnxt_ulp_eth_dev_ptr2_cntxt_get(struct rte_eth_dev *dev)
521 bp = (struct bnxt *)dev->data->dev_private;
523 BNXT_TF_DBG(ERR, "Bnxt private data is not initialized\n");