7afc6bf07908e536b3647a92d8029d5a2a9d5c9f
[dpdk.git] / drivers / net / bnxt / tf_ulp / bnxt_ulp.c
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.h"
19 #include "ulp_template_struct.h"
20 #include "ulp_mark_mgr.h"
21 #include "ulp_flow_db.h"
22
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);
26
27 /* Mutex to synchronize bnxt_ulp_session_list operations. */
28 static pthread_mutex_t bnxt_ulp_global_mutex = PTHREAD_MUTEX_INITIALIZER;
29
30 /*
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.
40  */
41 static int32_t
42 ulp_ctx_session_open(struct bnxt *bp,
43                      struct bnxt_ulp_session_state *session)
44 {
45         struct rte_eth_dev              *ethdev = bp->eth_dev;
46         int32_t                         rc = 0;
47         struct tf_open_session_parms    params;
48
49         memset(&params, 0, sizeof(params));
50
51         rc = rte_eth_dev_get_name_by_port(ethdev->data->port_id,
52                                           params.ctrl_chan_name);
53         if (rc) {
54                 BNXT_TF_DBG(ERR, "Invalid port %d, rc = %d\n",
55                             ethdev->data->port_id, rc);
56                 return rc;
57         }
58
59         rc = tf_open_session(&bp->tfp, &params);
60         if (rc) {
61                 BNXT_TF_DBG(ERR, "Failed to open TF session - %s, rc = %d\n",
62                             params.ctrl_chan_name, rc);
63                 return -EINVAL;
64         }
65         session->session_opened = 1;
66         session->g_tfp = &bp->tfp;
67         return rc;
68 }
69
70 static void
71 bnxt_init_tbl_scope_parms(struct bnxt *bp,
72                           struct tf_alloc_tbl_scope_parms *params)
73 {
74         struct bnxt_ulp_device_params   *dparms;
75         uint32_t dev_id;
76         int rc;
77
78         rc = bnxt_ulp_cntxt_dev_id_get(&bp->ulp_ctx, &dev_id);
79         if (rc)
80                 /* TBD: For now, just use default. */
81                 dparms = 0;
82         else
83                 dparms = bnxt_ulp_device_params_get(dev_id);
84
85         if (!dparms) {
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;
92
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;
99         } else {
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;
106
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;
113         }
114 }
115
116 /* Initialize Extended Exact Match host memory. */
117 static int32_t
118 ulp_eem_tbl_scope_init(struct bnxt *bp)
119 {
120         struct tf_alloc_tbl_scope_parms params = {0};
121         int rc;
122
123         bnxt_init_tbl_scope_parms(bp, &params);
124
125         rc = tf_alloc_tbl_scope(&bp->tfp, &params);
126         if (rc) {
127                 BNXT_TF_DBG(ERR, "Unable to allocate eem table scope rc = %d\n",
128                             rc);
129                 return rc;
130         }
131
132         rc = bnxt_ulp_cntxt_tbl_scope_id_set(&bp->ulp_ctx, params.tbl_scope_id);
133         if (rc) {
134                 BNXT_TF_DBG(ERR, "Unable to set table scope id\n");
135                 return rc;
136         }
137
138         return 0;
139 }
140
141 /* The function to free and deinit the ulp context data. */
142 static int32_t
143 ulp_ctx_deinit(struct bnxt *bp,
144                struct bnxt_ulp_session_state *session)
145 {
146         if (!session || !bp) {
147                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
148                 return -EINVAL;
149         }
150
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;
156         }
157         return 0;
158 }
159
160 /* The function to allocate and initialize the ulp context data. */
161 static int32_t
162 ulp_ctx_init(struct bnxt *bp,
163              struct bnxt_ulp_session_state *session)
164 {
165         struct bnxt_ulp_data    *ulp_data;
166         int32_t                 rc = 0;
167
168         if (!session || !bp) {
169                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
170                 return -EINVAL;
171         }
172
173         /* Allocate memory to hold ulp context data. */
174         ulp_data = rte_zmalloc("bnxt_ulp_data",
175                                sizeof(struct bnxt_ulp_data), 0);
176         if (!ulp_data) {
177                 BNXT_TF_DBG(ERR, "Failed to allocate memory for ulp data\n");
178                 return -ENOMEM;
179         }
180
181         /* Increment the ulp context data reference count usage. */
182         bp->ulp_ctx.cfg_data = ulp_data;
183         session->cfg_data = ulp_data;
184         ulp_data->ref_cnt++;
185
186         /* Open the ulp session. */
187         rc = ulp_ctx_session_open(bp, session);
188         if (rc) {
189                 (void)ulp_ctx_deinit(bp, session);
190                 return rc;
191         }
192         bnxt_ulp_cntxt_tfp_set(&bp->ulp_ctx, session->g_tfp);
193         return rc;
194 }
195
196 static int32_t
197 ulp_ctx_attach(struct bnxt_ulp_context *ulp_ctx,
198                struct bnxt_ulp_session_state *session)
199 {
200         if (!ulp_ctx || !session) {
201                 BNXT_TF_DBG(ERR, "Invalid Arguments\n");
202                 return -EINVAL;
203         }
204
205         /* Increment the ulp context data reference count usage. */
206         ulp_ctx->cfg_data = session->cfg_data;
207         ulp_ctx->cfg_data->ref_cnt++;
208
209         /* TBD call TF_session_attach. */
210         ulp_ctx->g_tfp = session->g_tfp;
211         return 0;
212 }
213
214 /*
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.
218  */
219 static void
220 ulp_context_initialized(struct bnxt_ulp_session_state *session, bool *init)
221 {
222         pthread_mutex_lock(&session->bnxt_ulp_mutex);
223
224         if (!session->bnxt_ulp_init) {
225                 session->bnxt_ulp_init = true;
226                 *init = false;
227         } else {
228                 *init = true;
229         }
230
231         pthread_mutex_unlock(&session->bnxt_ulp_mutex);
232 }
233
234 /*
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.
238  */
239 static struct bnxt_ulp_session_state *
240 ulp_get_session(struct rte_pci_addr *pci_addr)
241 {
242         struct bnxt_ulp_session_state *session;
243
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) {
247                         return session;
248                 }
249         }
250         return NULL;
251 }
252
253 /*
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.
256  */
257 static struct bnxt_ulp_session_state *
258 ulp_session_init(struct bnxt *bp,
259                  bool *init)
260 {
261         struct rte_pci_device           *pci_dev;
262         struct rte_pci_addr             *pci_addr;
263         struct bnxt_ulp_session_state   *session;
264
265         if (!bp)
266                 return NULL;
267
268         pci_dev = RTE_DEV_TO_PCI(bp->eth_dev->device);
269         pci_addr = &pci_dev->addr;
270
271         pthread_mutex_lock(&bnxt_ulp_global_mutex);
272
273         session = ulp_get_session(pci_addr);
274         if (!session) {
275                 /* Not Found the session  Allocate a new one */
276                 session = rte_zmalloc("bnxt_ulp_session",
277                                       sizeof(struct bnxt_ulp_session_state),
278                                       0);
279                 if (!session) {
280                         BNXT_TF_DBG(ERR,
281                                     "Allocation failed for bnxt_ulp_session\n");
282                         pthread_mutex_unlock(&bnxt_ulp_global_mutex);
283                         return NULL;
284
285                 } else {
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,
291                                            session, next);
292                 }
293         }
294         ulp_context_initialized(session, init);
295         pthread_mutex_unlock(&bnxt_ulp_global_mutex);
296         return session;
297 }
298
299 /*
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.
303  */
304 int32_t
305 bnxt_ulp_init(struct bnxt *bp)
306 {
307         struct bnxt_ulp_session_state *session;
308         bool init;
309         int rc;
310
311         /*
312          * Multiple uplink ports can be associated with a single vswitch.
313          * Make sure only the port that is started first will initialize
314          * the TF session.
315          */
316         session = ulp_session_init(bp, &init);
317         if (!session) {
318                 BNXT_TF_DBG(ERR, "Failed to initialize the tf session\n");
319                 return -EINVAL;
320         }
321
322         /*
323          * If ULP is already initialized for a specific domain then simply
324          * assign the ulp context to this rte_eth_dev.
325          */
326         if (init) {
327                 rc = ulp_ctx_attach(&bp->ulp_ctx, session);
328                 if (rc) {
329                         BNXT_TF_DBG(ERR,
330                                     "Failed to attach the ulp context\n");
331                 }
332                 return rc;
333         }
334
335         /* Allocate and Initialize the ulp context. */
336         rc = ulp_ctx_init(bp, session);
337         if (rc) {
338                 BNXT_TF_DBG(ERR, "Failed to create the ulp context\n");
339                 goto jump_to_error;
340         }
341
342         /* Create the Mark database. */
343         rc = ulp_mark_db_init(&bp->ulp_ctx);
344         if (rc) {
345                 BNXT_TF_DBG(ERR, "Failed to create the mark database\n");
346                 goto jump_to_error;
347         }
348
349         /* Create the flow database. */
350         rc = ulp_flow_db_init(&bp->ulp_ctx);
351         if (rc) {
352                 BNXT_TF_DBG(ERR, "Failed to create the flow database\n");
353                 goto jump_to_error;
354         }
355
356         /* Create the eem table scope. */
357         rc = ulp_eem_tbl_scope_init(bp);
358         if (rc) {
359                 BNXT_TF_DBG(ERR, "Failed to create the eem scope table\n");
360                 goto jump_to_error;
361         }
362
363         return rc;
364
365 jump_to_error:
366         return -ENOMEM;
367 }
368
369 /* Below are the access functions to access internal data of ulp context. */
370
371 /* Function to set the Mark DB into the context. */
372 int32_t
373 bnxt_ulp_cntxt_ptr2_mark_db_set(struct bnxt_ulp_context *ulp_ctx,
374                                 struct bnxt_ulp_mark_tbl *mark_tbl)
375 {
376         if (!ulp_ctx || !ulp_ctx->cfg_data) {
377                 BNXT_TF_DBG(ERR, "Invalid ulp context data\n");
378                 return -EINVAL;
379         }
380
381         ulp_ctx->cfg_data->mark_tbl = mark_tbl;
382
383         return 0;
384 }
385
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)
389 {
390         if (!ulp_ctx || !ulp_ctx->cfg_data)
391                 return NULL;
392
393         return ulp_ctx->cfg_data->mark_tbl;
394 }
395
396 /* Function to set the device id of the hardware. */
397 int32_t
398 bnxt_ulp_cntxt_dev_id_set(struct bnxt_ulp_context *ulp_ctx,
399                           uint32_t dev_id)
400 {
401         if (ulp_ctx && ulp_ctx->cfg_data) {
402                 ulp_ctx->cfg_data->dev_id = dev_id;
403                 return 0;
404         }
405
406         return -EINVAL;
407 }
408
409 /* Function to get the device id of the hardware. */
410 int32_t
411 bnxt_ulp_cntxt_dev_id_get(struct bnxt_ulp_context *ulp_ctx,
412                           uint32_t *dev_id)
413 {
414         if (ulp_ctx && ulp_ctx->cfg_data) {
415                 *dev_id = ulp_ctx->cfg_data->dev_id;
416                 return 0;
417         }
418
419         return -EINVAL;
420 }
421
422 /* Function to get the table scope id of the EEM table. */
423 int32_t
424 bnxt_ulp_cntxt_tbl_scope_id_get(struct bnxt_ulp_context *ulp_ctx,
425                                 uint32_t *tbl_scope_id)
426 {
427         if (ulp_ctx && ulp_ctx->cfg_data) {
428                 *tbl_scope_id = ulp_ctx->cfg_data->tbl_scope_id;
429                 return 0;
430         }
431
432         return -EINVAL;
433 }
434
435 /* Function to set the table scope id of the EEM table. */
436 int32_t
437 bnxt_ulp_cntxt_tbl_scope_id_set(struct bnxt_ulp_context *ulp_ctx,
438                                 uint32_t tbl_scope_id)
439 {
440         if (ulp_ctx && ulp_ctx->cfg_data) {
441                 ulp_ctx->cfg_data->tbl_scope_id = tbl_scope_id;
442                 return 0;
443         }
444
445         return -EINVAL;
446 }
447
448 /* Function to set the tfp session details from the ulp context. */
449 int32_t
450 bnxt_ulp_cntxt_tfp_set(struct bnxt_ulp_context *ulp, struct tf *tfp)
451 {
452         if (!ulp) {
453                 BNXT_TF_DBG(ERR, "Invalid arguments\n");
454                 return -EINVAL;
455         }
456
457         /* TBD The tfp should be removed once tf_attach is implemented. */
458         ulp->g_tfp = tfp;
459         return 0;
460 }
461
462 /* Function to get the tfp session details from the ulp context. */
463 struct tf *
464 bnxt_ulp_cntxt_tfp_get(struct bnxt_ulp_context *ulp)
465 {
466         if (!ulp) {
467                 BNXT_TF_DBG(ERR, "Invalid arguments\n");
468                 return NULL;
469         }
470         /* TBD The tfp should be removed once tf_attach is implemented. */
471         return ulp->g_tfp;
472 }
473
474 /*
475  * Get the device table entry based on the device id.
476  *
477  * dev_id [in] The device id of the hardware
478  *
479  * Returns the pointer to the device parameters.
480  */
481 struct bnxt_ulp_device_params *
482 bnxt_ulp_device_params_get(uint32_t dev_id)
483 {
484         if (dev_id < BNXT_ULP_MAX_NUM_DEVICES)
485                 return &ulp_device_params[dev_id];
486         return NULL;
487 }
488
489 /* Function to set the flow database to the ulp context. */
490 int32_t
491 bnxt_ulp_cntxt_ptr2_flow_db_set(struct bnxt_ulp_context *ulp_ctx,
492                                 struct bnxt_ulp_flow_db *flow_db)
493 {
494         if (!ulp_ctx || !ulp_ctx->cfg_data) {
495                 BNXT_TF_DBG(ERR, "Invalid ulp context data\n");
496                 return -EINVAL;
497         }
498
499         ulp_ctx->cfg_data->flow_db = flow_db;
500         return 0;
501 }
502
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)
506 {
507         if (!ulp_ctx || !ulp_ctx->cfg_data) {
508                 BNXT_TF_DBG(ERR, "Invalid ulp context data\n");
509                 return NULL;
510         }
511
512         return ulp_ctx->cfg_data->flow_db;
513 }
514
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)
518 {
519         struct bnxt     *bp;
520
521         bp = (struct bnxt *)dev->data->dev_private;
522         if (!bp) {
523                 BNXT_TF_DBG(ERR, "Bnxt private data is not initialized\n");
524                 return NULL;
525         }
526         return &bp->ulp_ctx;
527 }