bus/fslmc: optimize physical to virtual address search
[dpdk.git] / drivers / mempool / dpaa2 / dpaa2_hw_mempool.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  *   Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved.
4  *   Copyright 2016 NXP
5  *
6  */
7
8 #include <unistd.h>
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <fcntl.h>
14 #include <errno.h>
15
16 #include <rte_mbuf.h>
17 #include <rte_ethdev_driver.h>
18 #include <rte_malloc.h>
19 #include <rte_memcpy.h>
20 #include <rte_string_fns.h>
21 #include <rte_cycles.h>
22 #include <rte_kvargs.h>
23 #include <rte_dev.h>
24
25 #include <fslmc_logs.h>
26 #include <mc/fsl_dpbp.h>
27 #include <portal/dpaa2_hw_pvt.h>
28 #include <portal/dpaa2_hw_dpio.h>
29 #include "dpaa2_hw_mempool.h"
30 #include "dpaa2_hw_mempool_logs.h"
31
32 struct dpaa2_bp_info rte_dpaa2_bpid_info[MAX_BPID];
33 static struct dpaa2_bp_list *h_bp_list;
34
35 /* List of all the memseg information locally maintained in dpaa2 driver. This
36  * is to optimize the PA_to_VA searches until a better mechanism (algo) is
37  * available.
38  */
39 struct dpaa2_memseg_list rte_dpaa2_memsegs
40         = TAILQ_HEAD_INITIALIZER(rte_dpaa2_memsegs);
41
42 /* Dynamic logging identified for mempool */
43 int dpaa2_logtype_mempool;
44
45 static int
46 rte_hw_mbuf_create_pool(struct rte_mempool *mp)
47 {
48         struct dpaa2_bp_list *bp_list;
49         struct dpaa2_dpbp_dev *avail_dpbp;
50         struct dpaa2_bp_info *bp_info;
51         struct dpbp_attr dpbp_attr;
52         uint32_t bpid;
53         int ret;
54
55         avail_dpbp = dpaa2_alloc_dpbp_dev();
56
57         if (!avail_dpbp) {
58                 DPAA2_MEMPOOL_ERR("DPAA2 pool not available!");
59                 return -ENOENT;
60         }
61
62         if (unlikely(!DPAA2_PER_LCORE_DPIO)) {
63                 ret = dpaa2_affine_qbman_swp();
64                 if (ret) {
65                         DPAA2_MEMPOOL_ERR("Failure in affining portal");
66                         goto err1;
67                 }
68         }
69
70         ret = dpbp_enable(&avail_dpbp->dpbp, CMD_PRI_LOW, avail_dpbp->token);
71         if (ret != 0) {
72                 DPAA2_MEMPOOL_ERR("Resource enable failure with err code: %d",
73                                   ret);
74                 goto err1;
75         }
76
77         ret = dpbp_get_attributes(&avail_dpbp->dpbp, CMD_PRI_LOW,
78                                   avail_dpbp->token, &dpbp_attr);
79         if (ret != 0) {
80                 DPAA2_MEMPOOL_ERR("Resource read failure with err code: %d",
81                                   ret);
82                 goto err2;
83         }
84
85         bp_info = rte_malloc(NULL,
86                              sizeof(struct dpaa2_bp_info),
87                              RTE_CACHE_LINE_SIZE);
88         if (!bp_info) {
89                 DPAA2_MEMPOOL_ERR("Unable to allocate buffer pool memory");
90                 ret = -ENOMEM;
91                 goto err2;
92         }
93
94         /* Allocate the bp_list which will be added into global_bp_list */
95         bp_list = rte_malloc(NULL, sizeof(struct dpaa2_bp_list),
96                              RTE_CACHE_LINE_SIZE);
97         if (!bp_list) {
98                 DPAA2_MEMPOOL_ERR("Unable to allocate buffer pool memory");
99                 ret = -ENOMEM;
100                 goto err3;
101         }
102
103         /* Set parameters of buffer pool list */
104         bp_list->buf_pool.num_bufs = mp->size;
105         bp_list->buf_pool.size = mp->elt_size
106                         - sizeof(struct rte_mbuf) - rte_pktmbuf_priv_size(mp);
107         bp_list->buf_pool.bpid = dpbp_attr.bpid;
108         bp_list->buf_pool.h_bpool_mem = NULL;
109         bp_list->buf_pool.dpbp_node = avail_dpbp;
110         /* Identification for our offloaded pool_data structure */
111         bp_list->dpaa2_ops_index = mp->ops_index;
112         bp_list->next = h_bp_list;
113         bp_list->mp = mp;
114
115         bpid = dpbp_attr.bpid;
116
117         rte_dpaa2_bpid_info[bpid].meta_data_size = sizeof(struct rte_mbuf)
118                                 + rte_pktmbuf_priv_size(mp);
119         rte_dpaa2_bpid_info[bpid].bp_list = bp_list;
120         rte_dpaa2_bpid_info[bpid].bpid = bpid;
121
122         rte_memcpy(bp_info, (void *)&rte_dpaa2_bpid_info[bpid],
123                    sizeof(struct dpaa2_bp_info));
124         mp->pool_data = (void *)bp_info;
125
126         DPAA2_MEMPOOL_DEBUG("BP List created for bpid =%d", dpbp_attr.bpid);
127
128         h_bp_list = bp_list;
129         return 0;
130 err3:
131         rte_free(bp_info);
132 err2:
133         dpbp_disable(&avail_dpbp->dpbp, CMD_PRI_LOW, avail_dpbp->token);
134 err1:
135         dpaa2_free_dpbp_dev(avail_dpbp);
136
137         return ret;
138 }
139
140 static void
141 rte_hw_mbuf_free_pool(struct rte_mempool *mp)
142 {
143         struct dpaa2_bp_info *bpinfo;
144         struct dpaa2_bp_list *bp;
145         struct dpaa2_dpbp_dev *dpbp_node;
146
147         if (!mp->pool_data) {
148                 DPAA2_MEMPOOL_ERR("Not a valid dpaa2 buffer pool");
149                 return;
150         }
151
152         bpinfo = (struct dpaa2_bp_info *)mp->pool_data;
153         bp = bpinfo->bp_list;
154         dpbp_node = bp->buf_pool.dpbp_node;
155
156         dpbp_disable(&(dpbp_node->dpbp), CMD_PRI_LOW, dpbp_node->token);
157
158         if (h_bp_list == bp) {
159                 h_bp_list = h_bp_list->next;
160         } else { /* if it is not the first node */
161                 struct dpaa2_bp_list *prev = h_bp_list, *temp;
162                 temp = h_bp_list->next;
163                 while (temp) {
164                         if (temp == bp) {
165                                 prev->next = temp->next;
166                                 rte_free(bp);
167                                 break;
168                         }
169                         prev = temp;
170                         temp = temp->next;
171                 }
172         }
173
174         rte_free(mp->pool_data);
175         dpaa2_free_dpbp_dev(dpbp_node);
176 }
177
178 static void
179 rte_dpaa2_mbuf_release(struct rte_mempool *pool __rte_unused,
180                         void * const *obj_table,
181                         uint32_t bpid,
182                         uint32_t meta_data_size,
183                         int count)
184 {
185         struct qbman_release_desc releasedesc;
186         struct qbman_swp *swp;
187         int ret;
188         int i, n;
189         uint64_t bufs[DPAA2_MBUF_MAX_ACQ_REL];
190
191         if (unlikely(!DPAA2_PER_LCORE_DPIO)) {
192                 ret = dpaa2_affine_qbman_swp();
193                 if (ret != 0) {
194                         DPAA2_MEMPOOL_ERR("Failed to allocate IO portal");
195                         return;
196                 }
197         }
198         swp = DPAA2_PER_LCORE_PORTAL;
199
200         /* Create a release descriptor required for releasing
201          * buffers into QBMAN
202          */
203         qbman_release_desc_clear(&releasedesc);
204         qbman_release_desc_set_bpid(&releasedesc, bpid);
205
206         n = count % DPAA2_MBUF_MAX_ACQ_REL;
207         if (unlikely(!n))
208                 goto aligned;
209
210         /* convert mbuf to buffers for the remainder */
211         for (i = 0; i < n ; i++) {
212 #ifdef RTE_LIBRTE_DPAA2_USE_PHYS_IOVA
213                 bufs[i] = (uint64_t)rte_mempool_virt2iova(obj_table[i])
214                                 + meta_data_size;
215 #else
216                 bufs[i] = (uint64_t)obj_table[i] + meta_data_size;
217 #endif
218         }
219
220         /* feed them to bman */
221         do {
222                 ret = qbman_swp_release(swp, &releasedesc, bufs, n);
223         } while (ret == -EBUSY);
224
225 aligned:
226         /* if there are more buffers to free */
227         while (n < count) {
228                 /* convert mbuf to buffers */
229                 for (i = 0; i < DPAA2_MBUF_MAX_ACQ_REL; i++) {
230 #ifdef RTE_LIBRTE_DPAA2_USE_PHYS_IOVA
231                         bufs[i] = (uint64_t)
232                                   rte_mempool_virt2iova(obj_table[n + i])
233                                   + meta_data_size;
234 #else
235                         bufs[i] = (uint64_t)obj_table[n + i] + meta_data_size;
236 #endif
237                 }
238
239                 do {
240                         ret = qbman_swp_release(swp, &releasedesc, bufs,
241                                                 DPAA2_MBUF_MAX_ACQ_REL);
242                 } while (ret == -EBUSY);
243                 n += DPAA2_MBUF_MAX_ACQ_REL;
244         }
245 }
246
247 int
248 rte_dpaa2_mbuf_alloc_bulk(struct rte_mempool *pool,
249                           void **obj_table, unsigned int count)
250 {
251 #ifdef RTE_LIBRTE_DPAA2_DEBUG_DRIVER
252         static int alloc;
253 #endif
254         struct qbman_swp *swp;
255         uint16_t bpid;
256         size_t bufs[DPAA2_MBUF_MAX_ACQ_REL];
257         int i, ret;
258         unsigned int n = 0;
259         struct dpaa2_bp_info *bp_info;
260
261         bp_info = mempool_to_bpinfo(pool);
262
263         if (!(bp_info->bp_list)) {
264                 DPAA2_MEMPOOL_ERR("DPAA2 buffer pool not configured");
265                 return -ENOENT;
266         }
267
268         bpid = bp_info->bpid;
269
270         if (unlikely(!DPAA2_PER_LCORE_DPIO)) {
271                 ret = dpaa2_affine_qbman_swp();
272                 if (ret != 0) {
273                         DPAA2_MEMPOOL_ERR("Failed to allocate IO portal");
274                         return ret;
275                 }
276         }
277         swp = DPAA2_PER_LCORE_PORTAL;
278
279         while (n < count) {
280                 /* Acquire is all-or-nothing, so we drain in 7s,
281                  * then the remainder.
282                  */
283                 if ((count - n) > DPAA2_MBUF_MAX_ACQ_REL) {
284                         ret = qbman_swp_acquire(swp, bpid, (void *)bufs,
285                                                 DPAA2_MBUF_MAX_ACQ_REL);
286                 } else {
287                         ret = qbman_swp_acquire(swp, bpid, (void *)bufs,
288                                                 count - n);
289                 }
290                 /* In case of less than requested number of buffers available
291                  * in pool, qbman_swp_acquire returns 0
292                  */
293                 if (ret <= 0) {
294                         DPAA2_MEMPOOL_ERR("Buffer acquire failed with"
295                                           " err code: %d", ret);
296                         /* The API expect the exact number of requested bufs */
297                         /* Releasing all buffers allocated */
298                         rte_dpaa2_mbuf_release(pool, obj_table, bpid,
299                                            bp_info->meta_data_size, n);
300                         return -ENOBUFS;
301                 }
302                 /* assigning mbuf from the acquired objects */
303                 for (i = 0; (i < ret) && bufs[i]; i++) {
304                         DPAA2_MODIFY_IOVA_TO_VADDR(bufs[i], size_t);
305                         obj_table[n] = (struct rte_mbuf *)
306                                        (bufs[i] - bp_info->meta_data_size);
307                         DPAA2_MEMPOOL_DP_DEBUG(
308                                    "Acquired %p address %p from BMAN\n",
309                                    (void *)bufs[i], (void *)obj_table[n]);
310                         n++;
311                 }
312         }
313
314 #ifdef RTE_LIBRTE_DPAA2_DEBUG_DRIVER
315         alloc += n;
316         DPAA2_MEMPOOL_DP_DEBUG("Total = %d , req = %d done = %d\n",
317                                alloc, count, n);
318 #endif
319         return 0;
320 }
321
322 static int
323 rte_hw_mbuf_free_bulk(struct rte_mempool *pool,
324                   void * const *obj_table, unsigned int n)
325 {
326         struct dpaa2_bp_info *bp_info;
327
328         bp_info = mempool_to_bpinfo(pool);
329         if (!(bp_info->bp_list)) {
330                 DPAA2_MEMPOOL_ERR("DPAA2 buffer pool not configured");
331                 return -ENOENT;
332         }
333         rte_dpaa2_mbuf_release(pool, obj_table, bp_info->bpid,
334                            bp_info->meta_data_size, n);
335
336         return 0;
337 }
338
339 static unsigned int
340 rte_hw_mbuf_get_count(const struct rte_mempool *mp)
341 {
342         int ret;
343         unsigned int num_of_bufs = 0;
344         struct dpaa2_bp_info *bp_info;
345         struct dpaa2_dpbp_dev *dpbp_node;
346
347         if (!mp || !mp->pool_data) {
348                 DPAA2_MEMPOOL_ERR("Invalid mempool provided");
349                 return 0;
350         }
351
352         bp_info = (struct dpaa2_bp_info *)mp->pool_data;
353         dpbp_node = bp_info->bp_list->buf_pool.dpbp_node;
354
355         ret = dpbp_get_num_free_bufs(&dpbp_node->dpbp, CMD_PRI_LOW,
356                                      dpbp_node->token, &num_of_bufs);
357         if (ret) {
358                 DPAA2_MEMPOOL_ERR("Unable to obtain free buf count (err=%d)",
359                                   ret);
360                 return 0;
361         }
362
363         DPAA2_MEMPOOL_DP_DEBUG("Free bufs = %u\n", num_of_bufs);
364
365         return num_of_bufs;
366 }
367
368 static int
369 dpaa2_populate(struct rte_mempool *mp, unsigned int max_objs,
370               void *vaddr, rte_iova_t paddr, size_t len,
371               rte_mempool_populate_obj_cb_t *obj_cb, void *obj_cb_arg)
372 {
373         struct dpaa2_memseg *ms;
374
375         /* For each memory chunk pinned to the Mempool, a linked list of the
376          * contained memsegs is created for searching when PA to VA
377          * conversion is required.
378          */
379         ms = rte_zmalloc(NULL, sizeof(struct dpaa2_memseg), 0);
380         if (!ms) {
381                 DPAA2_MEMPOOL_ERR("Unable to allocate internal memory.");
382                 DPAA2_MEMPOOL_WARN("Fast Physical to Virtual Addr translation would not be available.");
383                 /* If the element is not added, it would only lead to failure
384                  * in searching for the element and the logic would Fallback
385                  * to traditional DPDK memseg traversal code. So, this is not
386                  * a blocking error - but, error would be printed on screen.
387                  */
388                 return 0;
389         }
390
391         ms->vaddr = vaddr;
392         ms->iova = paddr;
393         ms->len = len;
394         /* Head insertions are generally faster than tail insertions as the
395          * buffers pinned are picked from rear end.
396          */
397         TAILQ_INSERT_HEAD(&rte_dpaa2_memsegs, ms, next);
398
399         return rte_mempool_op_populate_default(mp, max_objs, vaddr, paddr, len,
400                                                obj_cb, obj_cb_arg);
401 }
402
403 struct rte_mempool_ops dpaa2_mpool_ops = {
404         .name = DPAA2_MEMPOOL_OPS_NAME,
405         .alloc = rte_hw_mbuf_create_pool,
406         .free = rte_hw_mbuf_free_pool,
407         .enqueue = rte_hw_mbuf_free_bulk,
408         .dequeue = rte_dpaa2_mbuf_alloc_bulk,
409         .get_count = rte_hw_mbuf_get_count,
410         .populate = dpaa2_populate,
411 };
412
413 MEMPOOL_REGISTER_OPS(dpaa2_mpool_ops);
414
415 RTE_INIT(dpaa2_mempool_init_log);
416 static void
417 dpaa2_mempool_init_log(void)
418 {
419         dpaa2_logtype_mempool = rte_log_register("mempool.dpaa2");
420         if (dpaa2_logtype_mempool >= 0)
421                 rte_log_set_level(dpaa2_logtype_mempool, RTE_LOG_NOTICE);
422 }