bus/fslmc: support for parallel Rx DQ requests
[dpdk.git] / drivers / bus / fslmc / portal / dpaa2_hw_dpio.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved.
5  *   Copyright (c) 2016 NXP. All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Freescale Semiconductor, Inc nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <stdarg.h>
40 #include <inttypes.h>
41 #include <signal.h>
42 #include <pthread.h>
43 #include <sys/types.h>
44 #include <sys/queue.h>
45 #include <sys/ioctl.h>
46 #include <sys/stat.h>
47 #include <sys/mman.h>
48 #include <sys/syscall.h>
49
50 #include <rte_mbuf.h>
51 #include <rte_ethdev.h>
52 #include <rte_malloc.h>
53 #include <rte_memcpy.h>
54 #include <rte_string_fns.h>
55 #include <rte_cycles.h>
56 #include <rte_kvargs.h>
57 #include <rte_dev.h>
58 #include <rte_ethdev.h>
59
60 #include <fslmc_logs.h>
61 #include <fslmc_vfio.h>
62 #include "dpaa2_hw_pvt.h"
63 #include "dpaa2_hw_dpio.h"
64
65 #define NUM_HOST_CPUS RTE_MAX_LCORE
66
67 struct dpaa2_io_portal_t dpaa2_io_portal[RTE_MAX_LCORE];
68 RTE_DEFINE_PER_LCORE(struct dpaa2_io_portal_t, _dpaa2_io);
69
70 struct swp_active_dqs rte_global_active_dqs_list[NUM_MAX_SWP];
71
72 TAILQ_HEAD(dpio_device_list, dpaa2_dpio_dev);
73 static struct dpio_device_list *dpio_dev_list; /*!< DPIO device list */
74 static uint32_t io_space_count;
75
76 /*Stashing Macros default for LS208x*/
77 static int dpaa2_core_cluster_base = 0x04;
78 static int dpaa2_cluster_sz = 2;
79
80 /* For LS208X platform There are four clusters with following mapping:
81  * Cluster 1 (ID = x04) : CPU0, CPU1;
82  * Cluster 2 (ID = x05) : CPU2, CPU3;
83  * Cluster 3 (ID = x06) : CPU4, CPU5;
84  * Cluster 4 (ID = x07) : CPU6, CPU7;
85  */
86 /* For LS108X platform There are two clusters with following mapping:
87  * Cluster 1 (ID = x02) : CPU0, CPU1, CPU2, CPU3;
88  * Cluster 2 (ID = x03) : CPU4, CPU5, CPU6, CPU7;
89  */
90
91 /* Set the STASH Destination depending on Current CPU ID.
92  * e.g. Valid values of SDEST are 4,5,6,7. Where,
93  * CPU 0-1 will have SDEST 4
94  * CPU 2-3 will have SDEST 5.....and so on.
95  */
96 static int
97 dpaa2_core_cluster_sdest(int cpu_id)
98 {
99         int x = cpu_id / dpaa2_cluster_sz;
100
101         if (x > 3)
102                 x = 3;
103
104         return dpaa2_core_cluster_base + x;
105 }
106
107 static int
108 configure_dpio_qbman_swp(struct dpaa2_dpio_dev *dpio_dev)
109 {
110         struct qbman_swp_desc p_des;
111         struct dpio_attr attr;
112
113         dpio_dev->dpio = malloc(sizeof(struct fsl_mc_io));
114         if (!dpio_dev->dpio) {
115                 PMD_INIT_LOG(ERR, "Memory allocation failure\n");
116                 return -1;
117         }
118
119         PMD_DRV_LOG(DEBUG, "\t Allocated  DPIO Portal[%p]", dpio_dev->dpio);
120         dpio_dev->dpio->regs = dpio_dev->mc_portal;
121         if (dpio_open(dpio_dev->dpio, CMD_PRI_LOW, dpio_dev->hw_id,
122                       &dpio_dev->token)) {
123                 PMD_INIT_LOG(ERR, "Failed to allocate IO space\n");
124                 free(dpio_dev->dpio);
125                 return -1;
126         }
127
128         if (dpio_reset(dpio_dev->dpio, CMD_PRI_LOW, dpio_dev->token)) {
129                 PMD_INIT_LOG(ERR, "Failed to reset dpio\n");
130                 dpio_close(dpio_dev->dpio, CMD_PRI_LOW, dpio_dev->token);
131                 free(dpio_dev->dpio);
132                 return -1;
133         }
134
135         if (dpio_enable(dpio_dev->dpio, CMD_PRI_LOW, dpio_dev->token)) {
136                 PMD_INIT_LOG(ERR, "Failed to Enable dpio\n");
137                 dpio_close(dpio_dev->dpio, CMD_PRI_LOW, dpio_dev->token);
138                 free(dpio_dev->dpio);
139                 return -1;
140         }
141
142         if (dpio_get_attributes(dpio_dev->dpio, CMD_PRI_LOW,
143                                 dpio_dev->token, &attr)) {
144                 PMD_INIT_LOG(ERR, "DPIO Get attribute failed\n");
145                 dpio_disable(dpio_dev->dpio, CMD_PRI_LOW, dpio_dev->token);
146                 dpio_close(dpio_dev->dpio, CMD_PRI_LOW,  dpio_dev->token);
147                 free(dpio_dev->dpio);
148                 return -1;
149         }
150
151         PMD_INIT_LOG(DEBUG, "Qbman Portal ID %d", attr.qbman_portal_id);
152         PMD_INIT_LOG(DEBUG, "Portal CE adr 0x%lX", attr.qbman_portal_ce_offset);
153         PMD_INIT_LOG(DEBUG, "Portal CI adr 0x%lX", attr.qbman_portal_ci_offset);
154
155         /* Configure & setup SW portal */
156         p_des.block = NULL;
157         p_des.idx = attr.qbman_portal_id;
158         p_des.cena_bar = (void *)(dpio_dev->qbman_portal_ce_paddr);
159         p_des.cinh_bar = (void *)(dpio_dev->qbman_portal_ci_paddr);
160         p_des.irq = -1;
161         p_des.qman_version = attr.qbman_version;
162
163         dpio_dev->sw_portal = qbman_swp_init(&p_des);
164         if (dpio_dev->sw_portal == NULL) {
165                 PMD_DRV_LOG(ERR, " QBMan SW Portal Init failed\n");
166                 dpio_close(dpio_dev->dpio, CMD_PRI_LOW, dpio_dev->token);
167                 free(dpio_dev->dpio);
168                 return -1;
169         }
170
171         PMD_INIT_LOG(DEBUG, "QBMan SW Portal 0x%p\n", dpio_dev->sw_portal);
172
173         return 0;
174 }
175
176 static int
177 dpaa2_configure_stashing(struct dpaa2_dpio_dev *dpio_dev)
178 {
179         int sdest;
180         int cpu_id, ret;
181
182         /* Set the Stashing Destination */
183         cpu_id = rte_lcore_id();
184         if (cpu_id < 0) {
185                 cpu_id = rte_get_master_lcore();
186                 if (cpu_id < 0) {
187                         RTE_LOG(ERR, PMD, "\tGetting CPU Index failed\n");
188                         return -1;
189                 }
190         }
191         /* Set the STASH Destination depending on Current CPU ID.
192          * Valid values of SDEST are 4,5,6,7. Where,
193          * CPU 0-1 will have SDEST 4
194          * CPU 2-3 will have SDEST 5.....and so on.
195          */
196
197         sdest = dpaa2_core_cluster_sdest(cpu_id);
198         PMD_DRV_LOG(DEBUG, "Portal= %d  CPU= %u SDEST= %d",
199                     dpio_dev->index, cpu_id, sdest);
200
201         ret = dpio_set_stashing_destination(dpio_dev->dpio, CMD_PRI_LOW,
202                                             dpio_dev->token, sdest);
203         if (ret) {
204                 PMD_DRV_LOG(ERR, "%d ERROR in SDEST\n",  ret);
205                 return -1;
206         }
207
208         return 0;
209 }
210
211 static inline struct dpaa2_dpio_dev *dpaa2_get_qbman_swp(void)
212 {
213         struct dpaa2_dpio_dev *dpio_dev = NULL;
214         int ret;
215
216         /* Get DPIO dev handle from list using index */
217         TAILQ_FOREACH(dpio_dev, dpio_dev_list, next) {
218                 if (dpio_dev && rte_atomic16_test_and_set(&dpio_dev->ref_count))
219                         break;
220         }
221         if (!dpio_dev)
222                 return NULL;
223
224         PMD_DRV_LOG(DEBUG, "New Portal=0x%x (%d) affined thread - %lu",
225                     dpio_dev, dpio_dev->index, syscall(SYS_gettid));
226
227         ret = dpaa2_configure_stashing(dpio_dev);
228         if (ret)
229                 PMD_DRV_LOG(ERR, "dpaa2_configure_stashing failed");
230
231         return dpio_dev;
232 }
233
234 int
235 dpaa2_affine_qbman_swp(void)
236 {
237         unsigned int lcore_id = rte_lcore_id();
238         uint64_t tid = syscall(SYS_gettid);
239
240         if (lcore_id == LCORE_ID_ANY)
241                 lcore_id = rte_get_master_lcore();
242         /* if the core id is not supported */
243         else if (lcore_id >= RTE_MAX_LCORE)
244                 return -1;
245
246         if (dpaa2_io_portal[lcore_id].dpio_dev) {
247                 PMD_DRV_LOG(INFO, "DPAA Portal=0x%x (%d) is being shared"
248                             " between thread %lu and current  %lu",
249                             dpaa2_io_portal[lcore_id].dpio_dev,
250                             dpaa2_io_portal[lcore_id].dpio_dev->index,
251                             dpaa2_io_portal[lcore_id].net_tid,
252                             tid);
253                 RTE_PER_LCORE(_dpaa2_io).dpio_dev
254                         = dpaa2_io_portal[lcore_id].dpio_dev;
255                 rte_atomic16_inc(&dpaa2_io_portal
256                                  [lcore_id].dpio_dev->ref_count);
257                 dpaa2_io_portal[lcore_id].net_tid = tid;
258
259                 PMD_DRV_LOG(DEBUG, "Old Portal=0x%x (%d) affined thread - %lu",
260                             dpaa2_io_portal[lcore_id].dpio_dev,
261                             dpaa2_io_portal[lcore_id].dpio_dev->index,
262                             tid);
263                 return 0;
264         }
265
266         /* Populate the dpaa2_io_portal structure */
267         dpaa2_io_portal[lcore_id].dpio_dev = dpaa2_get_qbman_swp();
268
269         if (dpaa2_io_portal[lcore_id].dpio_dev) {
270                 RTE_PER_LCORE(_dpaa2_io).dpio_dev
271                         = dpaa2_io_portal[lcore_id].dpio_dev;
272                 dpaa2_io_portal[lcore_id].net_tid = tid;
273
274                 return 0;
275         } else {
276                 return -1;
277         }
278 }
279
280 int
281 dpaa2_affine_qbman_swp_sec(void)
282 {
283         unsigned int lcore_id = rte_lcore_id();
284         uint64_t tid = syscall(SYS_gettid);
285
286         if (lcore_id == LCORE_ID_ANY)
287                 lcore_id = rte_get_master_lcore();
288         /* if the core id is not supported */
289         else if (lcore_id >= RTE_MAX_LCORE)
290                 return -1;
291
292         if (dpaa2_io_portal[lcore_id].sec_dpio_dev) {
293                 PMD_DRV_LOG(INFO, "DPAA Portal=0x%x (%d) is being shared"
294                             " between thread %lu and current  %lu",
295                             dpaa2_io_portal[lcore_id].sec_dpio_dev,
296                             dpaa2_io_portal[lcore_id].sec_dpio_dev->index,
297                             dpaa2_io_portal[lcore_id].sec_tid,
298                             tid);
299                 RTE_PER_LCORE(_dpaa2_io).sec_dpio_dev
300                         = dpaa2_io_portal[lcore_id].sec_dpio_dev;
301                 rte_atomic16_inc(&dpaa2_io_portal
302                                  [lcore_id].sec_dpio_dev->ref_count);
303                 dpaa2_io_portal[lcore_id].sec_tid = tid;
304
305                 PMD_DRV_LOG(DEBUG, "Old Portal=0x%x (%d) affined thread - %lu",
306                             dpaa2_io_portal[lcore_id].sec_dpio_dev,
307                             dpaa2_io_portal[lcore_id].sec_dpio_dev->index,
308                             tid);
309                 return 0;
310         }
311
312         /* Populate the dpaa2_io_portal structure */
313         dpaa2_io_portal[lcore_id].sec_dpio_dev = dpaa2_get_qbman_swp();
314
315         if (dpaa2_io_portal[lcore_id].sec_dpio_dev) {
316                 RTE_PER_LCORE(_dpaa2_io).sec_dpio_dev
317                         = dpaa2_io_portal[lcore_id].sec_dpio_dev;
318                 dpaa2_io_portal[lcore_id].sec_tid = tid;
319                 return 0;
320         } else {
321                 return -1;
322         }
323 }
324
325 int
326 dpaa2_create_dpio_device(struct fslmc_vfio_device *vdev,
327                          struct vfio_device_info *obj_info,
328                 int object_id)
329 {
330         struct dpaa2_dpio_dev *dpio_dev;
331         struct vfio_region_info reg_info = { .argsz = sizeof(reg_info)};
332
333         if (obj_info->num_regions < NUM_DPIO_REGIONS) {
334                 PMD_INIT_LOG(ERR, "ERROR, Not sufficient number "
335                                 "of DPIO regions.\n");
336                 return -1;
337         }
338
339         if (!dpio_dev_list) {
340                 dpio_dev_list = malloc(sizeof(struct dpio_device_list));
341                 if (!dpio_dev_list) {
342                         PMD_INIT_LOG(ERR, "Memory alloc failed in DPIO list\n");
343                         return -1;
344                 }
345
346                 /* Initialize the DPIO List */
347                 TAILQ_INIT(dpio_dev_list);
348         }
349
350         dpio_dev = malloc(sizeof(struct dpaa2_dpio_dev));
351         if (!dpio_dev) {
352                 PMD_INIT_LOG(ERR, "Memory allocation failed for DPIO Device\n");
353                 return -1;
354         }
355
356         PMD_DRV_LOG(INFO, "\t Aloocated DPIO [%p]", dpio_dev);
357         dpio_dev->dpio = NULL;
358         dpio_dev->hw_id = object_id;
359         dpio_dev->vfio_fd = vdev->fd;
360         rte_atomic16_init(&dpio_dev->ref_count);
361         /* Using single portal  for all devices */
362         dpio_dev->mc_portal = rte_mcp_ptr_list[MC_PORTAL_INDEX];
363
364         reg_info.index = 0;
365         if (ioctl(dpio_dev->vfio_fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info)) {
366                 PMD_INIT_LOG(ERR, "vfio: error getting region info\n");
367                 free(dpio_dev);
368                 return -1;
369         }
370
371         PMD_DRV_LOG(DEBUG, "\t  Region Offset = %llx", reg_info.offset);
372         PMD_DRV_LOG(DEBUG, "\t  Region Size = %llx", reg_info.size);
373         dpio_dev->ce_size = reg_info.size;
374         dpio_dev->qbman_portal_ce_paddr = (uint64_t)mmap(NULL, reg_info.size,
375                                 PROT_WRITE | PROT_READ, MAP_SHARED,
376                                 dpio_dev->vfio_fd, reg_info.offset);
377
378         /* Create Mapping for QBMan Cache Enabled area. This is a fix for
379          * SMMU fault for DQRR statshing transaction.
380          */
381         if (vfio_dmamap_mem_region(dpio_dev->qbman_portal_ce_paddr,
382                                    reg_info.offset, reg_info.size)) {
383                 PMD_INIT_LOG(ERR, "DMAMAP for Portal CE area failed.\n");
384                 free(dpio_dev);
385                 return -1;
386         }
387
388         reg_info.index = 1;
389         if (ioctl(dpio_dev->vfio_fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info)) {
390                 PMD_INIT_LOG(ERR, "vfio: error getting region info\n");
391                 free(dpio_dev);
392                 return -1;
393         }
394
395         PMD_DRV_LOG(DEBUG, "\t  Region Offset = %llx", reg_info.offset);
396         PMD_DRV_LOG(DEBUG, "\t  Region Size = %llx", reg_info.size);
397         dpio_dev->ci_size = reg_info.size;
398         dpio_dev->qbman_portal_ci_paddr = (uint64_t)mmap(NULL, reg_info.size,
399                                 PROT_WRITE | PROT_READ, MAP_SHARED,
400                                 dpio_dev->vfio_fd, reg_info.offset);
401
402         if (configure_dpio_qbman_swp(dpio_dev)) {
403                 PMD_INIT_LOG(ERR,
404                              "Fail to configure the dpio qbman portal for %d\n",
405                              dpio_dev->hw_id);
406                 free(dpio_dev);
407                 return -1;
408         }
409
410         io_space_count++;
411         dpio_dev->index = io_space_count;
412         TAILQ_INSERT_HEAD(dpio_dev_list, dpio_dev, next);
413
414         return 0;
415 }
416
417 void
418 dpaa2_free_dq_storage(struct queue_storage_info_t *q_storage)
419 {
420         int i = 0;
421
422         for (i = 0; i < NUM_DQS_PER_QUEUE; i++) {
423                 if (q_storage->dq_storage[i])
424                         rte_free(q_storage->dq_storage[i]);
425         }
426 }
427
428 int
429 dpaa2_alloc_dq_storage(struct queue_storage_info_t *q_storage)
430 {
431         int i = 0;
432
433         for (i = 0; i < NUM_DQS_PER_QUEUE; i++) {
434                 q_storage->dq_storage[i] = rte_malloc(NULL,
435                         DPAA2_DQRR_RING_SIZE * sizeof(struct qbman_result),
436                         RTE_CACHE_LINE_SIZE);
437                 if (!q_storage->dq_storage[i])
438                         goto fail;
439         }
440         return 0;
441 fail:
442         i -= 1;
443         while (i >= 0)
444                 rte_free(q_storage->dq_storage[i]);
445
446         return -1;
447 }