Imported Upstream version 16.07-rc1
[deb_dpdk.git] / lib / librte_eal / linuxapp / eal / eal_pci_uio.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   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 Intel Corporation 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 <string.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <dirent.h>
38 #include <inttypes.h>
39 #include <sys/stat.h>
40 #include <sys/mman.h>
41 #include <linux/pci_regs.h>
42
43 #if defined(RTE_ARCH_X86)
44 #include <sys/io.h>
45 #endif
46
47 #include <rte_log.h>
48 #include <rte_pci.h>
49 #include <rte_eal_memconfig.h>
50 #include <rte_common.h>
51 #include <rte_malloc.h>
52
53 #include "eal_filesystem.h"
54 #include "eal_pci_init.h"
55
56 void *pci_map_addr = NULL;
57
58 #define OFF_MAX              ((uint64_t)(off_t)-1)
59
60 int
61 pci_uio_read_config(const struct rte_intr_handle *intr_handle,
62                     void *buf, size_t len, off_t offset)
63 {
64         return pread(intr_handle->uio_cfg_fd, buf, len, offset);
65 }
66
67 int
68 pci_uio_write_config(const struct rte_intr_handle *intr_handle,
69                      const void *buf, size_t len, off_t offset)
70 {
71         return pwrite(intr_handle->uio_cfg_fd, buf, len, offset);
72 }
73
74 static int
75 pci_uio_set_bus_master(int dev_fd)
76 {
77         uint16_t reg;
78         int ret;
79
80         ret = pread(dev_fd, &reg, sizeof(reg), PCI_COMMAND);
81         if (ret != sizeof(reg)) {
82                 RTE_LOG(ERR, EAL,
83                         "Cannot read command from PCI config space!\n");
84                 return -1;
85         }
86
87         /* return if bus mastering is already on */
88         if (reg & PCI_COMMAND_MASTER)
89                 return 0;
90
91         reg |= PCI_COMMAND_MASTER;
92
93         ret = pwrite(dev_fd, &reg, sizeof(reg), PCI_COMMAND);
94         if (ret != sizeof(reg)) {
95                 RTE_LOG(ERR, EAL,
96                         "Cannot write command to PCI config space!\n");
97                 return -1;
98         }
99
100         return 0;
101 }
102
103 static int
104 pci_mknod_uio_dev(const char *sysfs_uio_path, unsigned uio_num)
105 {
106         FILE *f;
107         char filename[PATH_MAX];
108         int ret;
109         unsigned major, minor;
110         dev_t dev;
111
112         /* get the name of the sysfs file that contains the major and minor
113          * of the uio device and read its content */
114         snprintf(filename, sizeof(filename), "%s/dev", sysfs_uio_path);
115
116         f = fopen(filename, "r");
117         if (f == NULL) {
118                 RTE_LOG(ERR, EAL, "%s(): cannot open sysfs to get major:minor\n",
119                         __func__);
120                 return -1;
121         }
122
123         ret = fscanf(f, "%u:%u", &major, &minor);
124         if (ret != 2) {
125                 RTE_LOG(ERR, EAL, "%s(): cannot parse sysfs to get major:minor\n",
126                         __func__);
127                 fclose(f);
128                 return -1;
129         }
130         fclose(f);
131
132         /* create the char device "mknod /dev/uioX c major minor" */
133         snprintf(filename, sizeof(filename), "/dev/uio%u", uio_num);
134         dev = makedev(major, minor);
135         ret = mknod(filename, S_IFCHR | S_IRUSR | S_IWUSR, dev);
136         if (f == NULL) {
137                 RTE_LOG(ERR, EAL, "%s(): mknod() failed %s\n",
138                         __func__, strerror(errno));
139                 return -1;
140         }
141
142         return ret;
143 }
144
145 /*
146  * Return the uioX char device used for a pci device. On success, return
147  * the UIO number and fill dstbuf string with the path of the device in
148  * sysfs. On error, return a negative value. In this case dstbuf is
149  * invalid.
150  */
151 static int
152 pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
153                            unsigned int buflen, int create)
154 {
155         struct rte_pci_addr *loc = &dev->addr;
156         unsigned int uio_num;
157         struct dirent *e;
158         DIR *dir;
159         char dirname[PATH_MAX];
160
161         /* depending on kernel version, uio can be located in uio/uioX
162          * or uio:uioX */
163
164         snprintf(dirname, sizeof(dirname),
165                         "%s/" PCI_PRI_FMT "/uio", pci_get_sysfs_path(),
166                         loc->domain, loc->bus, loc->devid, loc->function);
167
168         dir = opendir(dirname);
169         if (dir == NULL) {
170                 /* retry with the parent directory */
171                 snprintf(dirname, sizeof(dirname),
172                                 "%s/" PCI_PRI_FMT, pci_get_sysfs_path(),
173                                 loc->domain, loc->bus, loc->devid, loc->function);
174                 dir = opendir(dirname);
175
176                 if (dir == NULL) {
177                         RTE_LOG(ERR, EAL, "Cannot opendir %s\n", dirname);
178                         return -1;
179                 }
180         }
181
182         /* take the first file starting with "uio" */
183         while ((e = readdir(dir)) != NULL) {
184                 /* format could be uio%d ...*/
185                 int shortprefix_len = sizeof("uio") - 1;
186                 /* ... or uio:uio%d */
187                 int longprefix_len = sizeof("uio:uio") - 1;
188                 char *endptr;
189
190                 if (strncmp(e->d_name, "uio", 3) != 0)
191                         continue;
192
193                 /* first try uio%d */
194                 errno = 0;
195                 uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10);
196                 if (errno == 0 && endptr != (e->d_name + shortprefix_len)) {
197                         snprintf(dstbuf, buflen, "%s/uio%u", dirname, uio_num);
198                         break;
199                 }
200
201                 /* then try uio:uio%d */
202                 errno = 0;
203                 uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10);
204                 if (errno == 0 && endptr != (e->d_name + longprefix_len)) {
205                         snprintf(dstbuf, buflen, "%s/uio:uio%u", dirname, uio_num);
206                         break;
207                 }
208         }
209         closedir(dir);
210
211         /* No uio resource found */
212         if (e == NULL)
213                 return -1;
214
215         /* create uio device if we've been asked to */
216         if (internal_config.create_uio_dev && create &&
217                         pci_mknod_uio_dev(dstbuf, uio_num) < 0)
218                 RTE_LOG(WARNING, EAL, "Cannot create /dev/uio%u\n", uio_num);
219
220         return uio_num;
221 }
222
223 void
224 pci_uio_free_resource(struct rte_pci_device *dev,
225                 struct mapped_pci_resource *uio_res)
226 {
227         rte_free(uio_res);
228
229         if (dev->intr_handle.uio_cfg_fd >= 0) {
230                 close(dev->intr_handle.uio_cfg_fd);
231                 dev->intr_handle.uio_cfg_fd = -1;
232         }
233         if (dev->intr_handle.fd) {
234                 close(dev->intr_handle.fd);
235                 dev->intr_handle.fd = -1;
236                 dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
237         }
238 }
239
240 int
241 pci_uio_alloc_resource(struct rte_pci_device *dev,
242                 struct mapped_pci_resource **uio_res)
243 {
244         char dirname[PATH_MAX];
245         char cfgname[PATH_MAX];
246         char devname[PATH_MAX]; /* contains the /dev/uioX */
247         int uio_num;
248         struct rte_pci_addr *loc;
249
250         loc = &dev->addr;
251
252         /* find uio resource */
253         uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 1);
254         if (uio_num < 0) {
255                 RTE_LOG(WARNING, EAL, "  "PCI_PRI_FMT" not managed by UIO driver, "
256                                 "skipping\n", loc->domain, loc->bus, loc->devid, loc->function);
257                 return 1;
258         }
259         snprintf(devname, sizeof(devname), "/dev/uio%u", uio_num);
260
261         /* save fd if in primary process */
262         dev->intr_handle.fd = open(devname, O_RDWR);
263         if (dev->intr_handle.fd < 0) {
264                 RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
265                         devname, strerror(errno));
266                 goto error;
267         }
268
269         snprintf(cfgname, sizeof(cfgname),
270                         "/sys/class/uio/uio%u/device/config", uio_num);
271         dev->intr_handle.uio_cfg_fd = open(cfgname, O_RDWR);
272         if (dev->intr_handle.uio_cfg_fd < 0) {
273                 RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
274                         cfgname, strerror(errno));
275                 goto error;
276         }
277
278         if (dev->kdrv == RTE_KDRV_IGB_UIO)
279                 dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
280         else {
281                 dev->intr_handle.type = RTE_INTR_HANDLE_UIO_INTX;
282
283                 /* set bus master that is not done by uio_pci_generic */
284                 if (pci_uio_set_bus_master(dev->intr_handle.uio_cfg_fd)) {
285                         RTE_LOG(ERR, EAL, "Cannot set up bus mastering!\n");
286                         goto error;
287                 }
288         }
289
290         /* allocate the mapping details for secondary processes*/
291         *uio_res = rte_zmalloc("UIO_RES", sizeof(**uio_res), 0);
292         if (*uio_res == NULL) {
293                 RTE_LOG(ERR, EAL,
294                         "%s(): cannot store uio mmap details\n", __func__);
295                 goto error;
296         }
297
298         snprintf((*uio_res)->path, sizeof((*uio_res)->path), "%s", devname);
299         memcpy(&(*uio_res)->pci_addr, &dev->addr, sizeof((*uio_res)->pci_addr));
300
301         return 0;
302
303 error:
304         pci_uio_free_resource(dev, *uio_res);
305         return -1;
306 }
307
308 int
309 pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx,
310                 struct mapped_pci_resource *uio_res, int map_idx)
311 {
312         int fd;
313         char devname[PATH_MAX];
314         void *mapaddr;
315         struct rte_pci_addr *loc;
316         struct pci_map *maps;
317
318         loc = &dev->addr;
319         maps = uio_res->maps;
320
321         /* update devname for mmap  */
322         snprintf(devname, sizeof(devname),
323                         "%s/" PCI_PRI_FMT "/resource%d",
324                         pci_get_sysfs_path(),
325                         loc->domain, loc->bus, loc->devid,
326                         loc->function, res_idx);
327
328         /* allocate memory to keep path */
329         maps[map_idx].path = rte_malloc(NULL, strlen(devname) + 1, 0);
330         if (maps[map_idx].path == NULL) {
331                 RTE_LOG(ERR, EAL, "Cannot allocate memory for path: %s\n",
332                                 strerror(errno));
333                 return -1;
334         }
335
336         /*
337          * open resource file, to mmap it
338          */
339         fd = open(devname, O_RDWR);
340         if (fd < 0) {
341                 RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
342                                 devname, strerror(errno));
343                 goto error;
344         }
345
346         /* try mapping somewhere close to the end of hugepages */
347         if (pci_map_addr == NULL)
348                 pci_map_addr = pci_find_max_end_va();
349
350         mapaddr = pci_map_resource(pci_map_addr, fd, 0,
351                         (size_t)dev->mem_resource[res_idx].len, 0);
352         close(fd);
353         if (mapaddr == MAP_FAILED)
354                 goto error;
355
356         pci_map_addr = RTE_PTR_ADD(mapaddr,
357                         (size_t)dev->mem_resource[res_idx].len);
358
359         maps[map_idx].phaddr = dev->mem_resource[res_idx].phys_addr;
360         maps[map_idx].size = dev->mem_resource[res_idx].len;
361         maps[map_idx].addr = mapaddr;
362         maps[map_idx].offset = 0;
363         strcpy(maps[map_idx].path, devname);
364         dev->mem_resource[res_idx].addr = mapaddr;
365
366         return 0;
367
368 error:
369         rte_free(maps[map_idx].path);
370         return -1;
371 }
372
373 #if defined(RTE_ARCH_X86)
374 int
375 pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
376                    struct rte_pci_ioport *p)
377 {
378         char dirname[PATH_MAX];
379         char filename[PATH_MAX];
380         int uio_num;
381         unsigned long start;
382
383         uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 0);
384         if (uio_num < 0)
385                 return -1;
386
387         /* get portio start */
388         snprintf(filename, sizeof(filename),
389                  "%s/portio/port%d/start", dirname, bar);
390         if (eal_parse_sysfs_value(filename, &start) < 0) {
391                 RTE_LOG(ERR, EAL, "%s(): cannot parse portio start\n",
392                         __func__);
393                 return -1;
394         }
395         /* ensure we don't get anything funny here, read/write will cast to
396          * uin16_t */
397         if (start > UINT16_MAX)
398                 return -1;
399
400         /* FIXME only for primary process ? */
401         if (dev->intr_handle.type == RTE_INTR_HANDLE_UNKNOWN) {
402
403                 snprintf(filename, sizeof(filename), "/dev/uio%u", uio_num);
404                 dev->intr_handle.fd = open(filename, O_RDWR);
405                 if (dev->intr_handle.fd < 0) {
406                         RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
407                                 filename, strerror(errno));
408                         return -1;
409                 }
410                 dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
411         }
412
413         RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%lx\n", start);
414
415         p->base = start;
416         p->len = 0;
417         return 0;
418 }
419 #else
420 int
421 pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
422                    struct rte_pci_ioport *p)
423 {
424         FILE *f;
425         char buf[BUFSIZ];
426         char filename[PATH_MAX];
427         uint64_t phys_addr, end_addr, flags;
428         int fd, i;
429         void *addr;
430
431         /* open and read addresses of the corresponding resource in sysfs */
432         snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource",
433                 pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
434                 dev->addr.devid, dev->addr.function);
435         f = fopen(filename, "r");
436         if (f == NULL) {
437                 RTE_LOG(ERR, EAL, "Cannot open sysfs resource: %s\n",
438                         strerror(errno));
439                 return -1;
440         }
441         for (i = 0; i < bar + 1; i++) {
442                 if (fgets(buf, sizeof(buf), f) == NULL) {
443                         RTE_LOG(ERR, EAL, "Cannot read sysfs resource\n");
444                         goto error;
445                 }
446         }
447         if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr,
448                         &end_addr, &flags) < 0)
449                 goto error;
450         if ((flags & IORESOURCE_IO) == 0) {
451                 RTE_LOG(ERR, EAL, "BAR %d is not an IO resource\n", bar);
452                 goto error;
453         }
454         snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource%d",
455                 pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
456                 dev->addr.devid, dev->addr.function, bar);
457
458         /* mmap the pci resource */
459         fd = open(filename, O_RDWR);
460         if (fd < 0) {
461                 RTE_LOG(ERR, EAL, "Cannot open %s: %s\n", filename,
462                         strerror(errno));
463                 goto error;
464         }
465         addr = mmap(NULL, end_addr + 1, PROT_READ | PROT_WRITE,
466                 MAP_SHARED, fd, 0);
467         close(fd);
468         if (addr == MAP_FAILED) {
469                 RTE_LOG(ERR, EAL, "Cannot mmap IO port resource: %s\n",
470                         strerror(errno));
471                 goto error;
472         }
473
474         /* strangely, the base address is mmap addr + phys_addr */
475         p->base = (uintptr_t)addr + phys_addr;
476         p->len = end_addr + 1;
477         RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%"PRIx64"\n", p->base);
478         fclose(f);
479
480         return 0;
481
482 error:
483         fclose(f);
484         return -1;
485 }
486 #endif
487
488 void
489 pci_uio_ioport_read(struct rte_pci_ioport *p,
490                     void *data, size_t len, off_t offset)
491 {
492         uint8_t *d;
493         int size;
494         uintptr_t reg = p->base + offset;
495
496         for (d = data; len > 0; d += size, reg += size, len -= size) {
497                 if (len >= 4) {
498                         size = 4;
499 #if defined(RTE_ARCH_X86)
500                         *(uint32_t *)d = inl(reg);
501 #else
502                         *(uint32_t *)d = *(volatile uint32_t *)reg;
503 #endif
504                 } else if (len >= 2) {
505                         size = 2;
506 #if defined(RTE_ARCH_X86)
507                         *(uint16_t *)d = inw(reg);
508 #else
509                         *(uint16_t *)d = *(volatile uint16_t *)reg;
510 #endif
511                 } else {
512                         size = 1;
513 #if defined(RTE_ARCH_X86)
514                         *d = inb(reg);
515 #else
516                         *d = *(volatile uint8_t *)reg;
517 #endif
518                 }
519         }
520 }
521
522 void
523 pci_uio_ioport_write(struct rte_pci_ioport *p,
524                      const void *data, size_t len, off_t offset)
525 {
526         const uint8_t *s;
527         int size;
528         uintptr_t reg = p->base + offset;
529
530         for (s = data; len > 0; s += size, reg += size, len -= size) {
531                 if (len >= 4) {
532                         size = 4;
533 #if defined(RTE_ARCH_X86)
534                         outl_p(*(const uint32_t *)s, reg);
535 #else
536                         *(volatile uint32_t *)reg = *(const uint32_t *)s;
537 #endif
538                 } else if (len >= 2) {
539                         size = 2;
540 #if defined(RTE_ARCH_X86)
541                         outw_p(*(const uint16_t *)s, reg);
542 #else
543                         *(volatile uint16_t *)reg = *(const uint16_t *)s;
544 #endif
545                 } else {
546                         size = 1;
547 #if defined(RTE_ARCH_X86)
548                         outb_p(*s, reg);
549 #else
550                         *(volatile uint8_t *)reg = *s;
551 #endif
552                 }
553         }
554 }
555
556 int
557 pci_uio_ioport_unmap(struct rte_pci_ioport *p)
558 {
559 #if defined(RTE_ARCH_X86)
560         RTE_SET_USED(p);
561         /* FIXME close intr fd ? */
562         return 0;
563 #else
564         return munmap((void *)(uintptr_t)p->base, p->len);
565 #endif
566 }