bus/fslmc: update MC to 10.3.x
[dpdk.git] / drivers / bus / fslmc / fslmc_vfio.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) 2015-2016 Freescale Semiconductor, Inc. All rights reserved.
5  *   Copyright 2016 NXP.
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
34 #include <unistd.h>
35 #include <stdio.h>
36 #include <sys/types.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <fcntl.h>
40 #include <errno.h>
41 #include <sys/ioctl.h>
42 #include <sys/stat.h>
43 #include <sys/mman.h>
44 #include <sys/vfs.h>
45 #include <libgen.h>
46 #include <dirent.h>
47 #include <sys/eventfd.h>
48
49 #include <rte_mbuf.h>
50 #include <rte_ethdev.h>
51 #include <rte_malloc.h>
52 #include <rte_memcpy.h>
53 #include <rte_string_fns.h>
54 #include <rte_cycles.h>
55 #include <rte_kvargs.h>
56 #include <rte_dev.h>
57 #include <rte_bus.h>
58
59 #include "rte_fslmc.h"
60 #include "fslmc_vfio.h"
61 #include <mc/fsl_dpmng.h>
62
63 #include "portal/dpaa2_hw_pvt.h"
64 #include "portal/dpaa2_hw_dpio.h"
65
66 #define FSLMC_VFIO_LOG(level, fmt, args...) \
67         RTE_LOG(level, EAL, fmt "\n", ##args)
68
69 /** Pathname of FSL-MC devices directory. */
70 #define SYSFS_FSL_MC_DEVICES "/sys/bus/fsl-mc/devices"
71
72 #define FSLMC_CONTAINER_MAX_LEN 8 /**< Of the format dprc.XX */
73
74 /* Number of VFIO containers & groups with in */
75 static struct fslmc_vfio_group vfio_group;
76 static struct fslmc_vfio_container vfio_container;
77 static int container_device_fd;
78 static char *g_container;
79 static uint32_t *msi_intr_vaddr;
80 void *(*rte_mcp_ptr_list);
81 static int is_dma_done;
82
83 static struct rte_dpaa2_object_list dpaa2_obj_list =
84         TAILQ_HEAD_INITIALIZER(dpaa2_obj_list);
85
86 /*register a fslmc bus based dpaa2 driver */
87 void
88 rte_fslmc_object_register(struct rte_dpaa2_object *object)
89 {
90         RTE_VERIFY(object);
91
92         TAILQ_INSERT_TAIL(&dpaa2_obj_list, object, next);
93 }
94
95 int
96 fslmc_get_container_group(int *groupid)
97 {
98         int ret;
99         char *container;
100
101         if (!g_container) {
102                 container = getenv("DPRC");
103                 if (container == NULL) {
104                         RTE_LOG(WARNING, EAL, "DPAA2: DPRC not available\n");
105                         return -EINVAL;
106                 }
107
108                 if (strlen(container) >= FSLMC_CONTAINER_MAX_LEN) {
109                         FSLMC_VFIO_LOG(ERR, "Invalid container name: %s\n",
110                                        container);
111                         return -1;
112                 }
113
114                 g_container = strdup(container);
115                 if (!g_container) {
116                         FSLMC_VFIO_LOG(ERR, "Out of memory.");
117                         return -ENOMEM;
118                 }
119         }
120
121         /* get group number */
122         ret = vfio_get_group_no(SYSFS_FSL_MC_DEVICES, g_container, groupid);
123         if (ret <= 0) {
124                 FSLMC_VFIO_LOG(ERR, "Unable to find %s IOMMU group",
125                                g_container);
126                 return -1;
127         }
128
129         FSLMC_VFIO_LOG(DEBUG, "Container: %s has VFIO iommu group id = %d",
130                        g_container, *groupid);
131
132         return 0;
133 }
134
135 static int
136 vfio_connect_container(void)
137 {
138         int fd, ret;
139
140         if (vfio_container.used) {
141                 FSLMC_VFIO_LOG(DEBUG, "No container available.");
142                 return -1;
143         }
144
145         /* Try connecting to vfio container if already created */
146         if (!ioctl(vfio_group.fd, VFIO_GROUP_SET_CONTAINER,
147                 &vfio_container.fd)) {
148                 FSLMC_VFIO_LOG(INFO,
149                     "Container pre-exists with FD[0x%x] for this group",
150                     vfio_container.fd);
151                 vfio_group.container = &vfio_container;
152                 return 0;
153         }
154
155         /* Opens main vfio file descriptor which represents the "container" */
156         fd = vfio_get_container_fd();
157         if (fd < 0) {
158                 FSLMC_VFIO_LOG(ERR, "Failed to open VFIO container");
159                 return -errno;
160         }
161
162         /* Check whether support for SMMU type IOMMU present or not */
163         if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)) {
164                 /* Connect group to container */
165                 ret = ioctl(vfio_group.fd, VFIO_GROUP_SET_CONTAINER, &fd);
166                 if (ret) {
167                         FSLMC_VFIO_LOG(ERR, "Failed to setup group container");
168                         close(fd);
169                         return -errno;
170                 }
171
172                 ret = ioctl(fd, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU);
173                 if (ret) {
174                         FSLMC_VFIO_LOG(ERR, "Failed to setup VFIO iommu");
175                         close(fd);
176                         return -errno;
177                 }
178         } else {
179                 FSLMC_VFIO_LOG(ERR, "No supported IOMMU available");
180                 close(fd);
181                 return -EINVAL;
182         }
183
184         vfio_container.used = 1;
185         vfio_container.fd = fd;
186         vfio_container.group = &vfio_group;
187         vfio_group.container = &vfio_container;
188
189         return 0;
190 }
191
192 static int vfio_map_irq_region(struct fslmc_vfio_group *group)
193 {
194         int ret;
195         unsigned long *vaddr = NULL;
196         struct vfio_iommu_type1_dma_map map = {
197                 .argsz = sizeof(map),
198                 .flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE,
199                 .vaddr = 0x6030000,
200                 .iova = 0x6030000,
201                 .size = 0x1000,
202         };
203
204         vaddr = (unsigned long *)mmap(NULL, 0x1000, PROT_WRITE |
205                 PROT_READ, MAP_SHARED, container_device_fd, 0x6030000);
206         if (vaddr == MAP_FAILED) {
207                 FSLMC_VFIO_LOG(ERR, "Unable to map region (errno = %d)", errno);
208                 return -errno;
209         }
210
211         msi_intr_vaddr = (uint32_t *)((char *)(vaddr) + 64);
212         map.vaddr = (unsigned long)vaddr;
213         ret = ioctl(group->container->fd, VFIO_IOMMU_MAP_DMA, &map);
214         if (ret == 0)
215                 return 0;
216
217         FSLMC_VFIO_LOG(ERR, "VFIO_IOMMU_MAP_DMA fails (errno = %d)", errno);
218         return -errno;
219 }
220
221 int rte_fslmc_vfio_dmamap(void)
222 {
223         int ret;
224         struct fslmc_vfio_group *group;
225         struct vfio_iommu_type1_dma_map dma_map = {
226                 .argsz = sizeof(struct vfio_iommu_type1_dma_map),
227                 .flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE,
228         };
229
230         int i;
231         const struct rte_memseg *memseg;
232
233         if (is_dma_done)
234                 return 0;
235
236         memseg = rte_eal_get_physmem_layout();
237         if (memseg == NULL) {
238                 FSLMC_VFIO_LOG(ERR, "Cannot get physical layout.");
239                 return -ENODEV;
240         }
241
242         for (i = 0; i < RTE_MAX_MEMSEG; i++) {
243                 if (memseg[i].addr == NULL && memseg[i].len == 0) {
244                         FSLMC_VFIO_LOG(DEBUG, "Total %d segments found.", i);
245                         break;
246                 }
247
248                 dma_map.size = memseg[i].len;
249                 dma_map.vaddr = memseg[i].addr_64;
250 #ifdef RTE_LIBRTE_DPAA2_USE_PHYS_IOVA
251                 dma_map.iova = memseg[i].phys_addr;
252 #else
253                 dma_map.iova = dma_map.vaddr;
254 #endif
255
256                 /* SET DMA MAP for IOMMU */
257                 group = &vfio_group;
258
259                 if (!group->container) {
260                         FSLMC_VFIO_LOG(ERR, "Container is not connected ");
261                         return -1;
262                 }
263
264                 FSLMC_VFIO_LOG(DEBUG, "-->Initial SHM Virtual ADDR %llX",
265                              dma_map.vaddr);
266                 FSLMC_VFIO_LOG(DEBUG, "-----> DMA size 0x%llX", dma_map.size);
267                 ret = ioctl(group->container->fd, VFIO_IOMMU_MAP_DMA,
268                             &dma_map);
269                 if (ret) {
270                         FSLMC_VFIO_LOG(ERR, "VFIO_IOMMU_MAP_DMA API(errno = %d)",
271                                        errno);
272                         return ret;
273                 }
274         }
275
276         /* Verifying that at least single segment is available */
277         if (i <= 0) {
278                 FSLMC_VFIO_LOG(ERR, "No Segments found for VFIO Mapping");
279                 return -1;
280         }
281
282         /* TODO - This is a W.A. as VFIO currently does not add the mapping of
283          * the interrupt region to SMMU. This should be removed once the
284          * support is added in the Kernel.
285          */
286         vfio_map_irq_region(group);
287
288         is_dma_done = 1;
289
290         return 0;
291 }
292
293 static int64_t vfio_map_mcp_obj(struct fslmc_vfio_group *group, char *mcp_obj)
294 {
295         int64_t v_addr = (int64_t)MAP_FAILED;
296         int32_t ret, mc_fd;
297
298         struct vfio_device_info d_info = { .argsz = sizeof(d_info) };
299         struct vfio_region_info reg_info = { .argsz = sizeof(reg_info) };
300
301         /* getting the mcp object's fd*/
302         mc_fd = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, mcp_obj);
303         if (mc_fd < 0) {
304                 FSLMC_VFIO_LOG(ERR, "error in VFIO get dev %s fd from group %d",
305                                mcp_obj, group->fd);
306                 return v_addr;
307         }
308
309         /* getting device info*/
310         ret = ioctl(mc_fd, VFIO_DEVICE_GET_INFO, &d_info);
311         if (ret < 0) {
312                 FSLMC_VFIO_LOG(ERR, "error in VFIO getting DEVICE_INFO");
313                 goto MC_FAILURE;
314         }
315
316         /* getting device region info*/
317         ret = ioctl(mc_fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info);
318         if (ret < 0) {
319                 FSLMC_VFIO_LOG(ERR, "error in VFIO getting REGION_INFO");
320                 goto MC_FAILURE;
321         }
322
323         FSLMC_VFIO_LOG(DEBUG, "region offset = %llx  , region size = %llx",
324                        reg_info.offset, reg_info.size);
325
326         v_addr = (uint64_t)mmap(NULL, reg_info.size,
327                 PROT_WRITE | PROT_READ, MAP_SHARED,
328                 mc_fd, reg_info.offset);
329
330 MC_FAILURE:
331         close(mc_fd);
332
333         return v_addr;
334 }
335
336 #define IRQ_SET_BUF_LEN  (sizeof(struct vfio_irq_set) + sizeof(int))
337
338 int rte_dpaa2_intr_enable(struct rte_intr_handle *intr_handle,
339                           uint32_t index)
340 {
341         struct vfio_irq_set *irq_set;
342         char irq_set_buf[IRQ_SET_BUF_LEN];
343         int *fd_ptr, fd, ret;
344
345         /* Prepare vfio_irq_set structure and SET the IRQ in VFIO */
346         /* Give the eventfd to VFIO */
347         fd = eventfd(0, 0);
348         irq_set = (struct vfio_irq_set *)irq_set_buf;
349         irq_set->argsz = sizeof(irq_set_buf);
350         irq_set->count = 1;
351         irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
352                          VFIO_IRQ_SET_ACTION_TRIGGER;
353         irq_set->index = index;
354         irq_set->start = 0;
355         fd_ptr = (int *)&irq_set->data;
356         *fd_ptr = fd;
357
358         ret = ioctl(intr_handle->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
359         if (ret < 0) {
360                 FSLMC_VFIO_LOG(ERR, "Unable to set IRQ in VFIO, ret: %d\n",
361                                ret);
362                 return -1;
363         }
364
365         /* Set the FD and update the flags */
366         intr_handle->fd = fd;
367         return 0;
368 }
369
370 /*
371  * fslmc_process_iodevices for processing only IO (ETH, CRYPTO, and possibly
372  * EVENT) devices.
373  */
374 static int
375 fslmc_process_iodevices(struct rte_dpaa2_device *dev)
376 {
377         int dev_fd;
378         struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
379         struct rte_dpaa2_object *object = NULL;
380
381         dev_fd = ioctl(vfio_group.fd, VFIO_GROUP_GET_DEVICE_FD,
382                        dev->device.name);
383         if (dev_fd <= 0) {
384                 FSLMC_VFIO_LOG(ERR, "Unable to obtain device FD for device:%s",
385                                dev->device.name);
386                 return -1;
387         }
388
389         if (ioctl(dev_fd, VFIO_DEVICE_GET_INFO, &device_info)) {
390                 FSLMC_VFIO_LOG(ERR, "DPAA2 VFIO_DEVICE_GET_INFO fail");
391                 return -1;
392         }
393
394         switch (dev->dev_type) {
395         case DPAA2_CON:
396         case DPAA2_IO:
397         case DPAA2_CI:
398         case DPAA2_BPOOL:
399                 TAILQ_FOREACH(object, &dpaa2_obj_list, next) {
400                         if (dev->dev_type == object->dev_type)
401                                 object->create(dev_fd, &device_info,
402                                                dev->object_id);
403                         else
404                                 continue;
405                 }
406                 break;
407         default:
408                 break;
409         }
410
411         FSLMC_VFIO_LOG(DEBUG, "Device (%s) abstracted from VFIO",
412                        dev->device.name);
413         return 0;
414 }
415
416 static int
417 fslmc_process_mcp(struct rte_dpaa2_device *dev)
418 {
419         int64_t v_addr;
420         char *dev_name;
421         struct fsl_mc_io dpmng  = {0};
422         struct mc_version mc_ver_info = {0};
423
424         rte_mcp_ptr_list = malloc(sizeof(void *) * 1);
425         if (!rte_mcp_ptr_list) {
426                 FSLMC_VFIO_LOG(ERR, "Out of memory");
427                 return -ENOMEM;
428         }
429
430         dev_name = strdup(dev->device.name);
431         if (!dev_name) {
432                 FSLMC_VFIO_LOG(ERR, "Out of memory.");
433                 free(rte_mcp_ptr_list);
434                 rte_mcp_ptr_list = NULL;
435                 return -ENOMEM;
436         }
437
438         v_addr = vfio_map_mcp_obj(&vfio_group, dev_name);
439         if (v_addr == (int64_t)MAP_FAILED) {
440                 FSLMC_VFIO_LOG(ERR, "Error mapping region  (errno = %d)",
441                                errno);
442                 free(rte_mcp_ptr_list);
443                 rte_mcp_ptr_list = NULL;
444                 return -1;
445         }
446
447         /* check the MC version compatibility */
448         dpmng.regs = (void *)v_addr;
449         if (mc_get_version(&dpmng, CMD_PRI_LOW, &mc_ver_info))
450                 RTE_LOG(WARNING, PMD, "\tmc_get_version failed\n");
451
452         if ((mc_ver_info.major != MC_VER_MAJOR) ||
453             (mc_ver_info.minor < MC_VER_MINOR)) {
454                 RTE_LOG(ERR, PMD, "DPAA2 MC version not compatible!"
455                         " Expected %d.%d.x, Detected %d.%d.%d\n",
456                         MC_VER_MAJOR, MC_VER_MINOR,
457                         mc_ver_info.major, mc_ver_info.minor,
458                         mc_ver_info.revision);
459                 free(rte_mcp_ptr_list);
460                 rte_mcp_ptr_list = NULL;
461                 return -1;
462         }
463         rte_mcp_ptr_list[0] = (void *)v_addr;
464
465         return 0;
466 }
467
468 int
469 fslmc_vfio_process_group(void)
470 {
471         int ret;
472         int found_mportal = 0;
473         struct rte_dpaa2_device *dev, *dev_temp;
474
475         /* Search the MCP as that should be initialized first. */
476         TAILQ_FOREACH_SAFE(dev, &rte_fslmc_bus.device_list, next, dev_temp) {
477                 if (dev->dev_type == DPAA2_MPORTAL) {
478                         ret = fslmc_process_mcp(dev);
479                         if (ret) {
480                                 FSLMC_VFIO_LOG(DEBUG, "Unable to map Portal.");
481                                 return -1;
482                         }
483                         if (!found_mportal)
484                                 found_mportal = 1;
485
486                         TAILQ_REMOVE(&rte_fslmc_bus.device_list, dev, next);
487                         free(dev);
488                         dev = NULL;
489                         /* Ideally there is only a single dpmcp, but in case
490                          * multiple exists, looping on remaining devices.
491                          */
492                 }
493         }
494
495         /* Cannot continue if there is not even a single mportal */
496         if (!found_mportal) {
497                 FSLMC_VFIO_LOG(DEBUG,
498                                "No MC Portal device found. Not continuing.");
499                 return -1;
500         }
501
502         TAILQ_FOREACH_SAFE(dev, &rte_fslmc_bus.device_list, next, dev_temp) {
503                 if (!dev)
504                         break;
505
506                 switch (dev->dev_type) {
507                 case DPAA2_ETH:
508                 case DPAA2_CRYPTO:
509                         ret = fslmc_process_iodevices(dev);
510                         if (ret) {
511                                 FSLMC_VFIO_LOG(DEBUG,
512                                                "Dev (%s) init failed.",
513                                                dev->device.name);
514                                 return ret;
515                         }
516                         break;
517                 case DPAA2_CON:
518                 case DPAA2_IO:
519                 case DPAA2_CI:
520                 case DPAA2_BPOOL:
521                         /* Call the object creation routine and remove the
522                          * device entry from device list
523                          */
524                         ret = fslmc_process_iodevices(dev);
525                         if (ret) {
526                                 FSLMC_VFIO_LOG(DEBUG,
527                                                "Dev (%s) init failed.",
528                                                dev->device.name);
529                                 return -1;
530                         }
531
532                         /* This device is not required to be in the DPDK
533                          * exposed device list.
534                          */
535                         TAILQ_REMOVE(&rte_fslmc_bus.device_list, dev, next);
536                         free(dev);
537                         dev = NULL;
538                         break;
539                 case DPAA2_UNKNOWN:
540                 default:
541                         /* Unknown - ignore */
542                         FSLMC_VFIO_LOG(DEBUG, "Found unknown device (%s).",
543                                        dev->device.name);
544                         TAILQ_REMOVE(&rte_fslmc_bus.device_list, dev, next);
545                         free(dev);
546                         dev = NULL;
547                 }
548         }
549
550         return 0;
551 }
552
553 int
554 fslmc_vfio_setup_group(void)
555 {
556         int groupid;
557         int ret;
558         struct vfio_group_status status = { .argsz = sizeof(status) };
559
560         /* if already done once */
561         if (container_device_fd)
562                 return 0;
563
564         ret = fslmc_get_container_group(&groupid);
565         if (ret)
566                 return ret;
567
568         /* In case this group was already opened, continue without any
569          * processing.
570          */
571         if (vfio_group.groupid == groupid) {
572                 FSLMC_VFIO_LOG(ERR, "groupid already exists %d", groupid);
573                 return 0;
574         }
575
576         /* Get the actual group fd */
577         ret = vfio_get_group_fd(groupid);
578         if (ret < 0)
579                 return ret;
580         vfio_group.fd = ret;
581
582         /* Check group viability */
583         ret = ioctl(vfio_group.fd, VFIO_GROUP_GET_STATUS, &status);
584         if (ret) {
585                 FSLMC_VFIO_LOG(ERR, "VFIO error getting group status");
586                 close(vfio_group.fd);
587                 return ret;
588         }
589
590         if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) {
591                 FSLMC_VFIO_LOG(ERR, "VFIO group not viable");
592                 close(vfio_group.fd);
593                 return -EPERM;
594         }
595         /* Since Group is VIABLE, Store the groupid */
596         vfio_group.groupid = groupid;
597
598         /* check if group does not have a container yet */
599         if (!(status.flags & VFIO_GROUP_FLAGS_CONTAINER_SET)) {
600                 /* Now connect this IOMMU group to given container */
601                 ret = vfio_connect_container();
602                 if (ret) {
603                         FSLMC_VFIO_LOG(ERR,
604                                 "Error connecting container with groupid %d",
605                                 groupid);
606                         close(vfio_group.fd);
607                         return ret;
608                 }
609         }
610
611         /* Get Device information */
612         ret = ioctl(vfio_group.fd, VFIO_GROUP_GET_DEVICE_FD, g_container);
613         if (ret < 0) {
614                 FSLMC_VFIO_LOG(ERR, "Error getting device %s fd from group %d",
615                                g_container, vfio_group.groupid);
616                 close(vfio_group.fd);
617                 return ret;
618         }
619         container_device_fd = ret;
620         FSLMC_VFIO_LOG(DEBUG, "VFIO Container FD is [0x%X]",
621                        container_device_fd);
622
623         return 0;
624 }