net/bnxt: support multiple device
[dpdk.git] / drivers / net / bnxt / tf_core / tf_rm_new.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2020 Broadcom
3  * All rights reserved.
4  */
5
6 #include <string.h>
7
8 #include <rte_common.h>
9
10 #include <cfa_resource_types.h>
11
12 #include "tf_rm_new.h"
13 #include "tf_common.h"
14 #include "tf_util.h"
15 #include "tf_session.h"
16 #include "tf_device.h"
17 #include "tfp.h"
18 #include "tf_msg.h"
19
20 /**
21  * Generic RM Element data type that an RM DB is build upon.
22  */
23 struct tf_rm_element {
24         /**
25          * RM Element configuration type. If Private then the
26          * hcapi_type can be ignored. If Null then the element is not
27          * valid for the device.
28          */
29         enum tf_rm_elem_cfg_type cfg_type;
30
31         /**
32          * HCAPI RM Type for the element.
33          */
34         uint16_t hcapi_type;
35
36         /**
37          * HCAPI RM allocated range information for the element.
38          */
39         struct tf_rm_alloc_info alloc;
40
41         /**
42          * Bit allocator pool for the element. Pool size is controlled
43          * by the struct tf_session_resources at time of session creation.
44          * Null indicates that the element is not used for the device.
45          */
46         struct bitalloc *pool;
47 };
48
49 /**
50  * TF RM DB definition
51  */
52 struct tf_rm_new_db {
53         /**
54          * Number of elements in the DB
55          */
56         uint16_t num_entries;
57
58         /**
59          * Direction this DB controls.
60          */
61         enum tf_dir dir;
62
63         /**
64          * The DB consists of an array of elements
65          */
66         struct tf_rm_element *db;
67 };
68
69 /**
70  * Adjust an index according to the allocation information.
71  *
72  * All resources are controlled in a 0 based pool. Some resources, by
73  * design, are not 0 based, i.e. Full Action Records (SRAM) thus they
74  * need to be adjusted before they are handed out.
75  *
76  * [in] cfg
77  *   Pointer to the DB configuration
78  *
79  * [in] reservations
80  *   Pointer to the allocation values associated with the module
81  *
82  * [in] count
83  *   Number of DB configuration elements
84  *
85  * [out] valid_count
86  *   Number of HCAPI entries with a reservation value greater than 0
87  *
88  * Returns:
89  *     0          - Success
90  *   - EOPNOTSUPP - Operation not supported
91  */
92 static void
93 tf_rm_count_hcapi_reservations(struct tf_rm_element_cfg *cfg,
94                                uint16_t *reservations,
95                                uint16_t count,
96                                uint16_t *valid_count)
97 {
98         int i;
99         uint16_t cnt = 0;
100
101         for (i = 0; i < count; i++) {
102                 if (cfg[i].cfg_type == TF_RM_ELEM_CFG_HCAPI &&
103                     reservations[i] > 0)
104                         cnt++;
105         }
106
107         *valid_count = cnt;
108 }
109
110 /**
111  * Resource Manager Adjust of base index definitions.
112  */
113 enum tf_rm_adjust_type {
114         TF_RM_ADJUST_ADD_BASE, /**< Adds base to the index */
115         TF_RM_ADJUST_RM_BASE   /**< Removes base from the index */
116 };
117
118 /**
119  * Adjust an index according to the allocation information.
120  *
121  * All resources are controlled in a 0 based pool. Some resources, by
122  * design, are not 0 based, i.e. Full Action Records (SRAM) thus they
123  * need to be adjusted before they are handed out.
124  *
125  * [in] db
126  *   Pointer to the db, used for the lookup
127  *
128  * [in] action
129  *   Adjust action
130  *
131  * [in] db_index
132  *   DB index for the element type
133  *
134  * [in] index
135  *   Index to convert
136  *
137  * [out] adj_index
138  *   Adjusted index
139  *
140  * Returns:
141  *     0          - Success
142  *   - EOPNOTSUPP - Operation not supported
143  */
144 static int
145 tf_rm_adjust_index(struct tf_rm_element *db,
146                    enum tf_rm_adjust_type action,
147                    uint32_t db_index,
148                    uint32_t index,
149                    uint32_t *adj_index)
150 {
151         int rc = 0;
152         uint32_t base_index;
153
154         base_index = db[db_index].alloc.entry.start;
155
156         switch (action) {
157         case TF_RM_ADJUST_RM_BASE:
158                 *adj_index = index - base_index;
159                 break;
160         case TF_RM_ADJUST_ADD_BASE:
161                 *adj_index = index + base_index;
162                 break;
163         default:
164                 return -EOPNOTSUPP;
165         }
166
167         return rc;
168 }
169
170 int
171 tf_rm_create_db(struct tf *tfp,
172                 struct tf_rm_create_db_parms *parms)
173 {
174         int rc;
175         int i;
176         int j;
177         struct tf_session *tfs;
178         struct tf_dev_info *dev;
179         uint16_t max_types;
180         struct tfp_calloc_parms cparms;
181         struct tf_rm_resc_req_entry *query;
182         enum tf_rm_resc_resv_strategy resv_strategy;
183         struct tf_rm_resc_req_entry *req;
184         struct tf_rm_resc_entry *resv;
185         struct tf_rm_new_db *rm_db;
186         struct tf_rm_element *db;
187         uint32_t pool_size;
188         uint16_t hcapi_items;
189
190         TF_CHECK_PARMS2(tfp, parms);
191
192         /* Retrieve the session information */
193         rc = tf_session_get_session(tfp, &tfs);
194         if (rc)
195                 return rc;
196
197         /* Retrieve device information */
198         rc = tf_session_get_device(tfs, &dev);
199         if (rc)
200                 return rc;
201
202         /* Need device max number of elements for the RM QCAPS */
203         rc = dev->ops->tf_dev_get_max_types(tfp, &max_types);
204         if (rc)
205                 return rc;
206
207         cparms.nitems = max_types;
208         cparms.size = sizeof(struct tf_rm_resc_req_entry);
209         cparms.alignment = 0;
210         rc = tfp_calloc(&cparms);
211         if (rc)
212                 return rc;
213
214         query = (struct tf_rm_resc_req_entry *)cparms.mem_va;
215
216         /* Get Firmware Capabilities */
217         rc = tf_msg_session_resc_qcaps(tfp,
218                                        parms->dir,
219                                        max_types,
220                                        query,
221                                        &resv_strategy);
222         if (rc)
223                 return rc;
224
225         /* Process capabilities against DB requirements. However, as a
226          * DB can hold elements that are not HCAPI we can reduce the
227          * req msg content by removing those out of the request yet
228          * the DB holds them all as to give a fast lookup. We can also
229          * remove entries where there are no request for elements.
230          */
231         tf_rm_count_hcapi_reservations(parms->cfg,
232                                        parms->alloc_cnt,
233                                        parms->num_elements,
234                                        &hcapi_items);
235
236         /* Alloc request, alignment already set */
237         cparms.nitems = (size_t)hcapi_items;
238         cparms.size = sizeof(struct tf_rm_resc_req_entry);
239         rc = tfp_calloc(&cparms);
240         if (rc)
241                 return rc;
242         req = (struct tf_rm_resc_req_entry *)cparms.mem_va;
243
244         /* Alloc reservation, alignment and nitems already set */
245         cparms.size = sizeof(struct tf_rm_resc_entry);
246         rc = tfp_calloc(&cparms);
247         if (rc)
248                 return rc;
249         resv = (struct tf_rm_resc_entry *)cparms.mem_va;
250
251         /* Build the request */
252         for (i = 0, j = 0; i < parms->num_elements; i++) {
253                 /* Skip any non HCAPI cfg elements */
254                 if (parms->cfg[i].cfg_type == TF_RM_ELEM_CFG_HCAPI) {
255                         /* Only perform reservation for entries that
256                          * has been requested
257                          */
258                         if (parms->alloc_cnt[i] == 0)
259                                 continue;
260
261                         /* Verify that we can get the full amount
262                          * allocated per the qcaps availability.
263                          */
264                         if (parms->alloc_cnt[i] <=
265                             query[parms->cfg[i].hcapi_type].max) {
266                                 req[j].type = parms->cfg[i].hcapi_type;
267                                 req[j].min = parms->alloc_cnt[i];
268                                 req[j].max = parms->alloc_cnt[i];
269                                 j++;
270                         } else {
271                                 TFP_DRV_LOG(ERR,
272                                             "%s: Resource failure, type:%d\n",
273                                             tf_dir_2_str(parms->dir),
274                                             parms->cfg[i].hcapi_type);
275                                 TFP_DRV_LOG(ERR,
276                                         "req:%d, avail:%d\n",
277                                         parms->alloc_cnt[i],
278                                         query[parms->cfg[i].hcapi_type].max);
279                                 return -EINVAL;
280                         }
281                 }
282         }
283
284         rc = tf_msg_session_resc_alloc(tfp,
285                                        parms->dir,
286                                        hcapi_items,
287                                        req,
288                                        resv);
289         if (rc)
290                 return rc;
291
292         /* Build the RM DB per the request */
293         cparms.nitems = 1;
294         cparms.size = sizeof(struct tf_rm_new_db);
295         rc = tfp_calloc(&cparms);
296         if (rc)
297                 return rc;
298         rm_db = (void *)cparms.mem_va;
299
300         /* Build the DB within RM DB */
301         cparms.nitems = parms->num_elements;
302         cparms.size = sizeof(struct tf_rm_element);
303         rc = tfp_calloc(&cparms);
304         if (rc)
305                 return rc;
306         rm_db->db = (struct tf_rm_element *)cparms.mem_va;
307
308         db = rm_db->db;
309         for (i = 0, j = 0; i < parms->num_elements; i++) {
310                 db[i].cfg_type = parms->cfg[i].cfg_type;
311                 db[i].hcapi_type = parms->cfg[i].hcapi_type;
312
313                 /* Skip any non HCAPI types as we didn't include them
314                  * in the reservation request.
315                  */
316                 if (parms->cfg[i].cfg_type != TF_RM_ELEM_CFG_HCAPI)
317                         continue;
318
319                 /* If the element didn't request an allocation no need
320                  * to create a pool nor verify if we got a reservation.
321                  */
322                 if (parms->alloc_cnt[i] == 0)
323                         continue;
324
325                 /* If the element had requested an allocation and that
326                  * allocation was a success (full amount) then
327                  * allocate the pool.
328                  */
329                 if (parms->alloc_cnt[i] == resv[j].stride) {
330                         db[i].alloc.entry.start = resv[j].start;
331                         db[i].alloc.entry.stride = resv[j].stride;
332
333                         /* Create pool */
334                         pool_size = (BITALLOC_SIZEOF(resv[j].stride) /
335                                      sizeof(struct bitalloc));
336                         /* Alloc request, alignment already set */
337                         cparms.nitems = pool_size;
338                         cparms.size = sizeof(struct bitalloc);
339                         rc = tfp_calloc(&cparms);
340                         if (rc) {
341                                 TFP_DRV_LOG(ERR,
342                                             "%s: Pool alloc failed, type:%d\n",
343                                             tf_dir_2_str(parms->dir),
344                                             db[i].cfg_type);
345                                 goto fail;
346                         }
347                         db[i].pool = (struct bitalloc *)cparms.mem_va;
348
349                         rc = ba_init(db[i].pool, resv[j].stride);
350                         if (rc) {
351                                 TFP_DRV_LOG(ERR,
352                                             "%s: Pool init failed, type:%d\n",
353                                             tf_dir_2_str(parms->dir),
354                                             db[i].cfg_type);
355                                 goto fail;
356                         }
357                         j++;
358                 } else {
359                         /* Bail out as we want what we requested for
360                          * all elements, not any less.
361                          */
362                         TFP_DRV_LOG(ERR,
363                                     "%s: Alloc failed, type:%d\n",
364                                     tf_dir_2_str(parms->dir),
365                                     db[i].cfg_type);
366                         TFP_DRV_LOG(ERR,
367                                     "req:%d, alloc:%d\n",
368                                     parms->alloc_cnt[i],
369                                     resv[j].stride);
370                         goto fail;
371                 }
372         }
373
374         rm_db->num_entries = i;
375         rm_db->dir = parms->dir;
376         *parms->rm_db = (void *)rm_db;
377
378         tfp_free((void *)req);
379         tfp_free((void *)resv);
380
381         return 0;
382
383  fail:
384         tfp_free((void *)req);
385         tfp_free((void *)resv);
386         tfp_free((void *)db->pool);
387         tfp_free((void *)db);
388         tfp_free((void *)rm_db);
389         parms->rm_db = NULL;
390
391         return -EINVAL;
392 }
393
394 int
395 tf_rm_free_db(struct tf *tfp __rte_unused,
396               struct tf_rm_free_db_parms *parms)
397 {
398         int rc = 0;
399         int i;
400         struct tf_rm_new_db *rm_db;
401
402         TF_CHECK_PARMS1(parms);
403
404         /* Traverse the DB and clear each pool.
405          * NOTE:
406          *   Firmware is not cleared. It will be cleared on close only.
407          */
408         rm_db = (struct tf_rm_new_db *)parms->rm_db;
409         for (i = 0; i < rm_db->num_entries; i++)
410                 tfp_free((void *)rm_db->db[i].pool);
411
412         tfp_free((void *)parms->rm_db);
413
414         return rc;
415 }
416
417 int
418 tf_rm_allocate(struct tf_rm_allocate_parms *parms)
419 {
420         int rc = 0;
421         int id;
422         uint32_t index;
423         struct tf_rm_new_db *rm_db;
424         enum tf_rm_elem_cfg_type cfg_type;
425
426         TF_CHECK_PARMS2(parms, parms->rm_db);
427
428         rm_db = (struct tf_rm_new_db *)parms->rm_db;
429         cfg_type = rm_db->db[parms->db_index].cfg_type;
430
431         /* Bail out if not controlled by RM */
432         if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
433             cfg_type != TF_RM_ELEM_CFG_PRIVATE)
434                 return -ENOTSUP;
435
436         /* Bail out if the pool is not valid, should never happen */
437         if (rm_db->db[parms->db_index].pool == NULL) {
438                 rc = -ENOTSUP;
439                 TFP_DRV_LOG(ERR,
440                             "%s: Invalid pool for this type:%d, rc:%s\n",
441                             tf_dir_2_str(rm_db->dir),
442                             parms->db_index,
443                             strerror(-rc));
444                 return rc;
445         }
446
447         id = ba_alloc(rm_db->db[parms->db_index].pool);
448         if (id == BA_FAIL) {
449                 TFP_DRV_LOG(ERR,
450                             "%s: Allocation failed, rc:%s\n",
451                             tf_dir_2_str(rm_db->dir),
452                             strerror(-rc));
453                 return -ENOMEM;
454         }
455
456         /* Adjust for any non zero start value */
457         rc = tf_rm_adjust_index(rm_db->db,
458                                 TF_RM_ADJUST_ADD_BASE,
459                                 parms->db_index,
460                                 id,
461                                 &index);
462         if (rc) {
463                 TFP_DRV_LOG(ERR,
464                             "%s: Alloc adjust of base index failed, rc:%s\n",
465                             tf_dir_2_str(rm_db->dir),
466                             strerror(-rc));
467                 return -EINVAL;
468         }
469
470         *parms->index = index;
471
472         return rc;
473 }
474
475 int
476 tf_rm_free(struct tf_rm_free_parms *parms)
477 {
478         int rc = 0;
479         uint32_t adj_index;
480         struct tf_rm_new_db *rm_db;
481         enum tf_rm_elem_cfg_type cfg_type;
482
483         TF_CHECK_PARMS2(parms, parms->rm_db);
484
485         rm_db = (struct tf_rm_new_db *)parms->rm_db;
486         cfg_type = rm_db->db[parms->db_index].cfg_type;
487
488         /* Bail out if not controlled by RM */
489         if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
490             cfg_type != TF_RM_ELEM_CFG_PRIVATE)
491                 return -ENOTSUP;
492
493         /* Bail out if the pool is not valid, should never happen */
494         if (rm_db->db[parms->db_index].pool == NULL) {
495                 rc = -ENOTSUP;
496                 TFP_DRV_LOG(ERR,
497                             "%s: Invalid pool for this type:%d, rc:%s\n",
498                             tf_dir_2_str(rm_db->dir),
499                             parms->db_index,
500                             strerror(-rc));
501                 return rc;
502         }
503
504         /* Adjust for any non zero start value */
505         rc = tf_rm_adjust_index(rm_db->db,
506                                 TF_RM_ADJUST_RM_BASE,
507                                 parms->db_index,
508                                 parms->index,
509                                 &adj_index);
510         if (rc)
511                 return rc;
512
513         rc = ba_free(rm_db->db[parms->db_index].pool, adj_index);
514         /* No logging direction matters and that is not available here */
515         if (rc)
516                 return rc;
517
518         return rc;
519 }
520
521 int
522 tf_rm_is_allocated(struct tf_rm_is_allocated_parms *parms)
523 {
524         int rc = 0;
525         uint32_t adj_index;
526         struct tf_rm_new_db *rm_db;
527         enum tf_rm_elem_cfg_type cfg_type;
528
529         TF_CHECK_PARMS2(parms, parms->rm_db);
530
531         rm_db = (struct tf_rm_new_db *)parms->rm_db;
532         cfg_type = rm_db->db[parms->db_index].cfg_type;
533
534         /* Bail out if not controlled by RM */
535         if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
536             cfg_type != TF_RM_ELEM_CFG_PRIVATE)
537                 return -ENOTSUP;
538
539         /* Bail out if the pool is not valid, should never happen */
540         if (rm_db->db[parms->db_index].pool == NULL) {
541                 rc = -ENOTSUP;
542                 TFP_DRV_LOG(ERR,
543                             "%s: Invalid pool for this type:%d, rc:%s\n",
544                             tf_dir_2_str(rm_db->dir),
545                             parms->db_index,
546                             strerror(-rc));
547                 return rc;
548         }
549
550         /* Adjust for any non zero start value */
551         rc = tf_rm_adjust_index(rm_db->db,
552                                 TF_RM_ADJUST_RM_BASE,
553                                 parms->db_index,
554                                 parms->index,
555                                 &adj_index);
556         if (rc)
557                 return rc;
558
559         *parms->allocated = ba_inuse(rm_db->db[parms->db_index].pool,
560                                      adj_index);
561
562         return rc;
563 }
564
565 int
566 tf_rm_get_info(struct tf_rm_get_alloc_info_parms *parms)
567 {
568         int rc = 0;
569         struct tf_rm_new_db *rm_db;
570         enum tf_rm_elem_cfg_type cfg_type;
571
572         TF_CHECK_PARMS2(parms, parms->rm_db);
573
574         rm_db = (struct tf_rm_new_db *)parms->rm_db;
575         cfg_type = rm_db->db[parms->db_index].cfg_type;
576
577         /* Bail out if not controlled by RM */
578         if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
579             cfg_type != TF_RM_ELEM_CFG_PRIVATE)
580                 return -ENOTSUP;
581
582         parms->info = &rm_db->db[parms->db_index].alloc;
583
584         return rc;
585 }
586
587 int
588 tf_rm_get_hcapi_type(struct tf_rm_get_hcapi_parms *parms)
589 {
590         int rc = 0;
591         struct tf_rm_new_db *rm_db;
592         enum tf_rm_elem_cfg_type cfg_type;
593
594         TF_CHECK_PARMS2(parms, parms->rm_db);
595
596         rm_db = (struct tf_rm_new_db *)parms->rm_db;
597         cfg_type = rm_db->db[parms->db_index].cfg_type;
598
599         /* Bail out if not controlled by RM */
600         if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
601             cfg_type != TF_RM_ELEM_CFG_PRIVATE)
602                 return -ENOTSUP;
603
604         *parms->hcapi_type = rm_db->db[parms->db_index].hcapi_type;
605
606         return rc;
607 }