net/bnxt: update multi device design
[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_util.h"
14 #include "tf_session.h"
15 #include "tf_device.h"
16 #include "tfp.h"
17 #include "tf_msg.h"
18
19 /**
20  * Generic RM Element data type that an RM DB is build upon.
21  */
22 struct tf_rm_element {
23         /**
24          * RM Element configuration type. If Private then the
25          * hcapi_type can be ignored. If Null then the element is not
26          * valid for the device.
27          */
28         enum tf_rm_elem_cfg_type cfg_type;
29
30         /**
31          * HCAPI RM Type for the element.
32          */
33         uint16_t hcapi_type;
34
35         /**
36          * HCAPI RM allocated range information for the element.
37          */
38         struct tf_rm_alloc_info alloc;
39
40         /**
41          * Bit allocator pool for the element. Pool size is controlled
42          * by the struct tf_session_resources at time of session creation.
43          * Null indicates that the element is not used for the device.
44          */
45         struct bitalloc *pool;
46 };
47
48 /**
49  * TF RM DB definition
50  */
51 struct tf_rm_new_db {
52         /**
53          * Number of elements in the DB
54          */
55         uint16_t num_entries;
56
57         /**
58          * Direction this DB controls.
59          */
60         enum tf_dir dir;
61
62         /**
63          * The DB consists of an array of elements
64          */
65         struct tf_rm_element *db;
66 };
67
68
69 /**
70  * Resource Manager Adjust of base index definitions.
71  */
72 enum tf_rm_adjust_type {
73         TF_RM_ADJUST_ADD_BASE, /**< Adds base to the index */
74         TF_RM_ADJUST_RM_BASE   /**< Removes base from the index */
75 };
76
77 /**
78  * Adjust an index according to the allocation information.
79  *
80  * All resources are controlled in a 0 based pool. Some resources, by
81  * design, are not 0 based, i.e. Full Action Records (SRAM) thus they
82  * need to be adjusted before they are handed out.
83  *
84  * [in] db
85  *   Pointer to the db, used for the lookup
86  *
87  * [in] action
88  *   Adjust action
89  *
90  * [in] db_index
91  *   DB index for the element type
92  *
93  * [in] index
94  *   Index to convert
95  *
96  * [out] adj_index
97  *   Adjusted index
98  *
99  * Returns:
100  *     0          - Success
101  *   - EOPNOTSUPP - Operation not supported
102  */
103 static int
104 tf_rm_adjust_index(struct tf_rm_element *db,
105                    enum tf_rm_adjust_type action,
106                    uint32_t db_index,
107                    uint32_t index,
108                    uint32_t *adj_index)
109 {
110         int rc = 0;
111         uint32_t base_index;
112
113         base_index = db[db_index].alloc.entry.start;
114
115         switch (action) {
116         case TF_RM_ADJUST_RM_BASE:
117                 *adj_index = index - base_index;
118                 break;
119         case TF_RM_ADJUST_ADD_BASE:
120                 *adj_index = index + base_index;
121                 break;
122         default:
123                 return -EOPNOTSUPP;
124         }
125
126         return rc;
127 }
128
129 int
130 tf_rm_create_db(struct tf *tfp,
131                 struct tf_rm_create_db_parms *parms)
132 {
133         int rc;
134         int i;
135         struct tf_session *tfs;
136         struct tf_dev_info *dev;
137         uint16_t max_types;
138         struct tfp_calloc_parms cparms;
139         struct tf_rm_resc_req_entry *query;
140         enum tf_rm_resc_resv_strategy resv_strategy;
141         struct tf_rm_resc_req_entry *req;
142         struct tf_rm_resc_entry *resv;
143         struct tf_rm_new_db *rm_db;
144         struct tf_rm_element *db;
145         uint32_t pool_size;
146
147         /* Retrieve the session information */
148         rc = tf_session_get_session(tfp, &tfs);
149         if (rc)
150                 return rc;
151
152         /* Retrieve device information */
153         rc = tf_session_get_device(tfs, &dev);
154         if (rc)
155                 return rc;
156
157         /* Need device max number of elements for the RM QCAPS */
158         rc = dev->ops->tf_dev_get_max_types(tfp, &max_types);
159         if (rc)
160                 return rc;
161
162         cparms.nitems = max_types;
163         cparms.size = sizeof(struct tf_rm_resc_req_entry);
164         cparms.alignment = 0;
165         rc = tfp_calloc(&cparms);
166         if (rc)
167                 return rc;
168
169         query = (struct tf_rm_resc_req_entry *)cparms.mem_va;
170
171         /* Get Firmware Capabilities */
172         rc = tf_msg_session_resc_qcaps(tfp,
173                                        parms->dir,
174                                        max_types,
175                                        query,
176                                        &resv_strategy);
177         if (rc)
178                 return rc;
179
180         /* Process capabilities against db requirements */
181
182         /* Alloc request, alignment already set */
183         cparms.nitems = parms->num_elements;
184         cparms.size = sizeof(struct tf_rm_resc_req_entry);
185         rc = tfp_calloc(&cparms);
186         if (rc)
187                 return rc;
188         req = (struct tf_rm_resc_req_entry *)cparms.mem_va;
189
190         /* Alloc reservation, alignment and nitems already set */
191         cparms.size = sizeof(struct tf_rm_resc_entry);
192         rc = tfp_calloc(&cparms);
193         if (rc)
194                 return rc;
195         resv = (struct tf_rm_resc_entry *)cparms.mem_va;
196
197         /* Build the request */
198         for (i = 0; i < parms->num_elements; i++) {
199                 /* Skip any non HCAPI cfg elements */
200                 if (parms->cfg[i].cfg_type == TF_RM_ELEM_CFG_HCAPI) {
201                         req[i].type = parms->cfg[i].hcapi_type;
202                         /* Check that we can get the full amount allocated */
203                         if (parms->alloc_num[i] <=
204                             query[parms->cfg[i].hcapi_type].max) {
205                                 req[i].min = parms->alloc_num[i];
206                                 req[i].max = parms->alloc_num[i];
207                         } else {
208                                 TFP_DRV_LOG(ERR,
209                                             "%s: Resource failure, type:%d\n",
210                                             tf_dir_2_str(parms->dir),
211                                             parms->cfg[i].hcapi_type);
212                                 TFP_DRV_LOG(ERR,
213                                         "req:%d, avail:%d\n",
214                                         parms->alloc_num[i],
215                                         query[parms->cfg[i].hcapi_type].max);
216                                 return -EINVAL;
217                         }
218                 } else {
219                         /* Skip the element */
220                         req[i].type = CFA_RESOURCE_TYPE_INVALID;
221                 }
222         }
223
224         rc = tf_msg_session_resc_alloc(tfp,
225                                        parms->dir,
226                                        parms->num_elements,
227                                        req,
228                                        resv);
229         if (rc)
230                 return rc;
231
232         /* Build the RM DB per the request */
233         cparms.nitems = 1;
234         cparms.size = sizeof(struct tf_rm_new_db);
235         rc = tfp_calloc(&cparms);
236         if (rc)
237                 return rc;
238         rm_db = (void *)cparms.mem_va;
239
240         /* Build the DB within RM DB */
241         cparms.nitems = parms->num_elements;
242         cparms.size = sizeof(struct tf_rm_element);
243         rc = tfp_calloc(&cparms);
244         if (rc)
245                 return rc;
246         rm_db->db = (struct tf_rm_element *)cparms.mem_va;
247
248         db = rm_db->db;
249         for (i = 0; i < parms->num_elements; i++) {
250                 /* If allocation failed for a single entry the DB
251                  * creation is considered a failure.
252                  */
253                 if (parms->alloc_num[i] != resv[i].stride) {
254                         TFP_DRV_LOG(ERR,
255                                     "%s: Alloc failed, type:%d\n",
256                                     tf_dir_2_str(parms->dir),
257                                     i);
258                         TFP_DRV_LOG(ERR,
259                                     "req:%d, alloc:%d\n",
260                                     parms->alloc_num[i],
261                                     resv[i].stride);
262                         goto fail;
263                 }
264
265                 db[i].cfg_type = parms->cfg[i].cfg_type;
266                 db[i].hcapi_type = parms->cfg[i].hcapi_type;
267                 db[i].alloc.entry.start = resv[i].start;
268                 db[i].alloc.entry.stride = resv[i].stride;
269
270                 /* Create pool */
271                 pool_size = (BITALLOC_SIZEOF(resv[i].stride) /
272                              sizeof(struct bitalloc));
273                 /* Alloc request, alignment already set */
274                 cparms.nitems = pool_size;
275                 cparms.size = sizeof(struct bitalloc);
276                 rc = tfp_calloc(&cparms);
277                 if (rc)
278                         return rc;
279                 db[i].pool = (struct bitalloc *)cparms.mem_va;
280         }
281
282         rm_db->num_entries = i;
283         rm_db->dir = parms->dir;
284         parms->rm_db = (void *)rm_db;
285
286         tfp_free((void *)req);
287         tfp_free((void *)resv);
288
289         return 0;
290
291  fail:
292         tfp_free((void *)req);
293         tfp_free((void *)resv);
294         tfp_free((void *)db->pool);
295         tfp_free((void *)db);
296         tfp_free((void *)rm_db);
297         parms->rm_db = NULL;
298
299         return -EINVAL;
300 }
301
302 int
303 tf_rm_free_db(struct tf *tfp __rte_unused,
304               struct tf_rm_free_db_parms *parms)
305 {
306         int rc = 0;
307         int i;
308         struct tf_rm_new_db *rm_db;
309
310         /* Traverse the DB and clear each pool.
311          * NOTE:
312          *   Firmware is not cleared. It will be cleared on close only.
313          */
314         rm_db = (struct tf_rm_new_db *)parms->rm_db;
315         for (i = 0; i < rm_db->num_entries; i++)
316                 tfp_free((void *)rm_db->db->pool);
317
318         tfp_free((void *)parms->rm_db);
319
320         return rc;
321 }
322
323 int
324 tf_rm_allocate(struct tf_rm_allocate_parms *parms)
325 {
326         int rc = 0;
327         int id;
328         struct tf_rm_new_db *rm_db;
329         enum tf_rm_elem_cfg_type cfg_type;
330
331         if (parms == NULL || parms->rm_db == NULL)
332                 return -EINVAL;
333
334         rm_db = (struct tf_rm_new_db *)parms->rm_db;
335         cfg_type = rm_db->db[parms->db_index].cfg_type;
336
337         /* Bail out if not controlled by RM */
338         if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
339             cfg_type != TF_RM_ELEM_CFG_PRIVATE)
340                 return -ENOTSUP;
341
342         id = ba_alloc(rm_db->db[parms->db_index].pool);
343         if (id == BA_FAIL) {
344                 TFP_DRV_LOG(ERR,
345                             "%s: Allocation failed, rc:%s\n",
346                             tf_dir_2_str(rm_db->dir),
347                             strerror(-rc));
348                 return -ENOMEM;
349         }
350
351         /* Adjust for any non zero start value */
352         rc = tf_rm_adjust_index(rm_db->db,
353                                 TF_RM_ADJUST_ADD_BASE,
354                                 parms->db_index,
355                                 id,
356                                 parms->index);
357         if (rc) {
358                 TFP_DRV_LOG(ERR,
359                             "%s: Alloc adjust of base index failed, rc:%s\n",
360                             tf_dir_2_str(rm_db->dir),
361                             strerror(-rc));
362                 return -1;
363         }
364
365         return rc;
366 }
367
368 int
369 tf_rm_free(struct tf_rm_free_parms *parms)
370 {
371         int rc = 0;
372         uint32_t adj_index;
373         struct tf_rm_new_db *rm_db;
374         enum tf_rm_elem_cfg_type cfg_type;
375
376         if (parms == NULL || parms->rm_db == NULL)
377                 return -EINVAL;
378
379         rm_db = (struct tf_rm_new_db *)parms->rm_db;
380         cfg_type = rm_db->db[parms->db_index].cfg_type;
381
382         /* Bail out if not controlled by RM */
383         if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
384             cfg_type != TF_RM_ELEM_CFG_PRIVATE)
385                 return -ENOTSUP;
386
387         /* Adjust for any non zero start value */
388         rc = tf_rm_adjust_index(rm_db->db,
389                                 TF_RM_ADJUST_RM_BASE,
390                                 parms->db_index,
391                                 parms->index,
392                                 &adj_index);
393         if (rc)
394                 return rc;
395
396         rc = ba_free(rm_db->db[parms->db_index].pool, adj_index);
397         /* No logging direction matters and that is not available here */
398         if (rc)
399                 return rc;
400
401         return rc;
402 }
403
404 int
405 tf_rm_is_allocated(struct tf_rm_is_allocated_parms *parms)
406 {
407         int rc = 0;
408         uint32_t adj_index;
409         struct tf_rm_new_db *rm_db;
410         enum tf_rm_elem_cfg_type cfg_type;
411
412         if (parms == NULL || parms->rm_db == NULL)
413                 return -EINVAL;
414
415         rm_db = (struct tf_rm_new_db *)parms->rm_db;
416         cfg_type = rm_db->db[parms->db_index].cfg_type;
417
418         /* Bail out if not controlled by RM */
419         if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
420             cfg_type != TF_RM_ELEM_CFG_PRIVATE)
421                 return -ENOTSUP;
422
423         /* Adjust for any non zero start value */
424         rc = tf_rm_adjust_index(rm_db->db,
425                                 TF_RM_ADJUST_RM_BASE,
426                                 parms->db_index,
427                                 parms->index,
428                                 &adj_index);
429         if (rc)
430                 return rc;
431
432         *parms->allocated = ba_inuse(rm_db->db[parms->db_index].pool,
433                                      adj_index);
434
435         return rc;
436 }
437
438 int
439 tf_rm_get_info(struct tf_rm_get_alloc_info_parms *parms)
440 {
441         int rc = 0;
442         struct tf_rm_new_db *rm_db;
443         enum tf_rm_elem_cfg_type cfg_type;
444
445         if (parms == NULL || parms->rm_db == NULL)
446                 return -EINVAL;
447
448         rm_db = (struct tf_rm_new_db *)parms->rm_db;
449         cfg_type = rm_db->db[parms->db_index].cfg_type;
450
451         /* Bail out if not controlled by RM */
452         if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
453             cfg_type != TF_RM_ELEM_CFG_PRIVATE)
454                 return -ENOTSUP;
455
456         parms->info = &rm_db->db[parms->db_index].alloc;
457
458         return rc;
459 }
460
461 int
462 tf_rm_get_hcapi_type(struct tf_rm_get_hcapi_parms *parms)
463 {
464         int rc = 0;
465         struct tf_rm_new_db *rm_db;
466         enum tf_rm_elem_cfg_type cfg_type;
467
468         if (parms == NULL || parms->rm_db == NULL)
469                 return -EINVAL;
470
471         rm_db = (struct tf_rm_new_db *)parms->rm_db;
472         cfg_type = rm_db->db[parms->db_index].cfg_type;
473
474         /* Bail out if not controlled by RM */
475         if (cfg_type != TF_RM_ELEM_CFG_HCAPI &&
476             cfg_type != TF_RM_ELEM_CFG_PRIVATE)
477                 return -ENOTSUP;
478
479         *parms->hcapi_type = rm_db->db[parms->db_index].hcapi_type;
480
481         return rc;
482 }