eal: add synchronous interrupt unregister
[dpdk.git] / drivers / bus / pci / linux / pci_uio.c
index 8cf6218..39ebeac 100644 (file)
@@ -1,34 +1,5 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
  */
 
 #include <string.h>
 #include <sys/io.h>
 #endif
 
+#include <rte_string_fns.h>
 #include <rte_log.h>
 #include <rte_pci.h>
 #include <rte_bus_pci.h>
-#include <rte_eal_memconfig.h>
 #include <rte_common.h>
 #include <rte_malloc.h>
 
 #include "eal_filesystem.h"
 #include "pci_init.h"
+#include "private.h"
 
 void *pci_map_addr = NULL;
 
@@ -164,14 +136,14 @@ pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
         * or uio:uioX */
 
        snprintf(dirname, sizeof(dirname),
-                       "%s/" PCI_PRI_FMT "/uio", pci_get_sysfs_path(),
+                       "%s/" PCI_PRI_FMT "/uio", rte_pci_get_sysfs_path(),
                        loc->domain, loc->bus, loc->devid, loc->function);
 
        dir = opendir(dirname);
        if (dir == NULL) {
                /* retry with the parent directory */
                snprintf(dirname, sizeof(dirname),
-                               "%s/" PCI_PRI_FMT, pci_get_sysfs_path(),
+                               "%s/" PCI_PRI_FMT, rte_pci_get_sysfs_path(),
                                loc->domain, loc->bus, loc->devid, loc->function);
                dir = opendir(dirname);
 
@@ -277,7 +249,7 @@ pci_uio_alloc_resource(struct rte_pci_device *dev,
                goto error;
        }
 
-       if (dev->kdrv == RTE_KDRV_IGB_UIO)
+       if (dev->kdrv == RTE_PCI_KDRV_IGB_UIO)
                dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
        else {
                dev->intr_handle.type = RTE_INTR_HANDLE_UIO_INTX;
@@ -297,7 +269,7 @@ pci_uio_alloc_resource(struct rte_pci_device *dev,
                goto error;
        }
 
-       snprintf((*uio_res)->path, sizeof((*uio_res)->path), "%s", devname);
+       strlcpy((*uio_res)->path, devname, sizeof((*uio_res)->path));
        memcpy(&(*uio_res)->pci_addr, &dev->addr, sizeof((*uio_res)->pci_addr));
 
        return 0;
@@ -311,24 +283,21 @@ int
 pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx,
                struct mapped_pci_resource *uio_res, int map_idx)
 {
-       int fd;
+       int fd = -1;
        char devname[PATH_MAX];
        void *mapaddr;
        struct rte_pci_addr *loc;
        struct pci_map *maps;
+       int wc_activate = 0;
+
+       if (dev->driver != NULL)
+               wc_activate = dev->driver->drv_flags & RTE_PCI_DRV_WC_ACTIVATE;
 
        loc = &dev->addr;
        maps = uio_res->maps;
 
-       /* update devname for mmap  */
-       snprintf(devname, sizeof(devname),
-                       "%s/" PCI_PRI_FMT "/resource%d",
-                       pci_get_sysfs_path(),
-                       loc->domain, loc->bus, loc->devid,
-                       loc->function, res_idx);
-
        /* allocate memory to keep path */
-       maps[map_idx].path = rte_malloc(NULL, strlen(devname) + 1, 0);
+       maps[map_idx].path = rte_malloc(NULL, sizeof(devname), 0);
        if (maps[map_idx].path == NULL) {
                RTE_LOG(ERR, EAL, "Cannot allocate memory for path: %s\n",
                                strerror(errno));
@@ -338,11 +307,36 @@ pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx,
        /*
         * open resource file, to mmap it
         */
-       fd = open(devname, O_RDWR);
-       if (fd < 0) {
-               RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
+       if (wc_activate) {
+               /* update devname for mmap  */
+               snprintf(devname, sizeof(devname),
+                       "%s/" PCI_PRI_FMT "/resource%d_wc",
+                       rte_pci_get_sysfs_path(),
+                       loc->domain, loc->bus, loc->devid,
+                       loc->function, res_idx);
+
+               fd = open(devname, O_RDWR);
+               if (fd < 0 && errno != ENOENT) {
+                       RTE_LOG(INFO, EAL, "%s cannot be mapped. "
+                               "Fall-back to non prefetchable mode.\n",
+                               devname);
+               }
+       }
+
+       if (!wc_activate || fd < 0) {
+               snprintf(devname, sizeof(devname),
+                       "%s/" PCI_PRI_FMT "/resource%d",
+                       rte_pci_get_sysfs_path(),
+                       loc->domain, loc->bus, loc->devid,
+                       loc->function, res_idx);
+
+               /* then try to map resource file */
+               fd = open(devname, O_RDWR);
+               if (fd < 0) {
+                       RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
                                devname, strerror(errno));
-               goto error;
+                       goto error;
+               }
        }
 
        /* try mapping somewhere close to the end of hugepages */
@@ -352,12 +346,14 @@ pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx,
        mapaddr = pci_map_resource(pci_map_addr, fd, 0,
                        (size_t)dev->mem_resource[res_idx].len, 0);
        close(fd);
-       if (mapaddr == MAP_FAILED)
+       if (mapaddr == NULL)
                goto error;
 
        pci_map_addr = RTE_PTR_ADD(mapaddr,
                        (size_t)dev->mem_resource[res_idx].len);
 
+       pci_map_addr = RTE_PTR_ALIGN(pci_map_addr, sysconf(_SC_PAGE_SIZE));
+
        maps[map_idx].phaddr = dev->mem_resource[res_idx].phys_addr;
        maps[map_idx].size = dev->mem_resource[res_idx].len;
        maps[map_idx].addr = mapaddr;
@@ -372,51 +368,93 @@ error:
        return -1;
 }
 
+#define PIO_MAX 0x10000
+
 #if defined(RTE_ARCH_X86)
 int
 pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
                   struct rte_pci_ioport *p)
 {
+       FILE *f = NULL;
        char dirname[PATH_MAX];
        char filename[PATH_MAX];
-       int uio_num;
-       unsigned long start;
+       char buf[BUFSIZ];
+       uint64_t phys_addr, end_addr, flags;
+       unsigned long base;
+       int i;
 
-       uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 0);
-       if (uio_num < 0)
+       /* open and read addresses of the corresponding resource in sysfs */
+       snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource",
+               rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
+               dev->addr.devid, dev->addr.function);
+       f = fopen(filename, "r");
+       if (f == NULL) {
+               RTE_LOG(ERR, EAL, "%s(): Cannot open sysfs resource: %s\n",
+                       __func__, strerror(errno));
                return -1;
+       }
 
-       /* get portio start */
-       snprintf(filename, sizeof(filename),
-                "%s/portio/port%d/start", dirname, bar);
-       if (eal_parse_sysfs_value(filename, &start) < 0) {
-               RTE_LOG(ERR, EAL, "%s(): cannot parse portio start\n",
-                       __func__);
-               return -1;
+       for (i = 0; i < bar + 1; i++) {
+               if (fgets(buf, sizeof(buf), f) == NULL) {
+                       RTE_LOG(ERR, EAL, "%s(): Cannot read sysfs resource\n", __func__);
+                       goto error;
+               }
+       }
+       if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr,
+               &end_addr, &flags) < 0)
+               goto error;
+
+       if (flags & IORESOURCE_IO) {
+               if (rte_eal_iopl_init()) {
+                       RTE_LOG(ERR, EAL, "%s(): insufficient ioport permissions for PCI device %s\n",
+                               __func__, dev->name);
+                       goto error;
+               }
+
+               base = (unsigned long)phys_addr;
+               if (base > PIO_MAX) {
+                       RTE_LOG(ERR, EAL, "%s(): %08lx too large PIO resource\n", __func__, base);
+                       goto error;
+               }
+
+               RTE_LOG(DEBUG, EAL, "%s(): PIO BAR %08lx detected\n", __func__, base);
+       } else if (flags & IORESOURCE_MEM) {
+               base = (unsigned long)dev->mem_resource[bar].addr;
+               RTE_LOG(DEBUG, EAL, "%s(): MMIO BAR %08lx detected\n", __func__, base);
+       } else {
+               RTE_LOG(ERR, EAL, "%s(): unknown BAR type\n", __func__);
+               goto error;
        }
-       /* ensure we don't get anything funny here, read/write will cast to
-        * uin16_t */
-       if (start > UINT16_MAX)
-               return -1;
 
        /* FIXME only for primary process ? */
        if (dev->intr_handle.type == RTE_INTR_HANDLE_UNKNOWN) {
+               int uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 0);
+               if (uio_num < 0) {
+                       RTE_LOG(ERR, EAL, "cannot open %s: %s\n",
+                               dirname, strerror(errno));
+                       goto error;
+               }
 
                snprintf(filename, sizeof(filename), "/dev/uio%u", uio_num);
                dev->intr_handle.fd = open(filename, O_RDWR);
                if (dev->intr_handle.fd < 0) {
                        RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
                                filename, strerror(errno));
-                       return -1;
+                       goto error;
                }
                dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
        }
 
-       RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%lx\n", start);
+       RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%lx\n", base);
 
-       p->base = start;
+       p->base = base;
        p->len = 0;
+       fclose(f);
        return 0;
+error:
+       if (f)
+               fclose(f);
+       return -1;
 }
 #else
 int
@@ -432,7 +470,7 @@ pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
 
        /* open and read addresses of the corresponding resource in sysfs */
        snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource",
-               pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
+               rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
                dev->addr.devid, dev->addr.function);
        f = fopen(filename, "r");
        if (f == NULL) {
@@ -454,7 +492,7 @@ pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
                goto error;
        }
        snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource%d",
-               pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
+               rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
                dev->addr.devid, dev->addr.function, bar);
 
        /* mmap the pci resource */
@@ -487,6 +525,120 @@ error:
 }
 #endif
 
+#if defined(RTE_ARCH_X86)
+
+static inline uint8_t ioread8(void *addr)
+{
+       uint8_t val;
+
+       val = (uint64_t)(uintptr_t)addr >= PIO_MAX ?
+               *(volatile uint8_t *)addr :
+#ifdef __GLIBC__
+               inb_p((unsigned long)addr);
+#else
+               inb((unsigned long)addr);
+#endif
+
+       return val;
+}
+
+static inline uint16_t ioread16(void *addr)
+{
+       uint16_t val;
+
+       val = (uint64_t)(uintptr_t)addr >= PIO_MAX ?
+               *(volatile uint16_t *)addr :
+#ifdef __GLIBC__
+               inw_p((unsigned long)addr);
+#else
+               inw((unsigned long)addr);
+#endif
+
+       return val;
+}
+
+static inline uint32_t ioread32(void *addr)
+{
+       uint32_t val;
+
+       val = (uint64_t)(uintptr_t)addr >= PIO_MAX ?
+               *(volatile uint32_t *)addr :
+#ifdef __GLIBC__
+               inl_p((unsigned long)addr);
+#else
+               inl((unsigned long)addr);
+#endif
+
+       return val;
+}
+
+static inline void iowrite8(uint8_t val, void *addr)
+{
+       (uint64_t)(uintptr_t)addr >= PIO_MAX ?
+               *(volatile uint8_t *)addr = val :
+#ifdef __GLIBC__
+               outb_p(val, (unsigned long)addr);
+#else
+               outb(val, (unsigned long)addr);
+#endif
+}
+
+static inline void iowrite16(uint16_t val, void *addr)
+{
+       (uint64_t)(uintptr_t)addr >= PIO_MAX ?
+               *(volatile uint16_t *)addr = val :
+#ifdef __GLIBC__
+               outw_p(val, (unsigned long)addr);
+#else
+               outw(val, (unsigned long)addr);
+#endif
+}
+
+static inline void iowrite32(uint32_t val, void *addr)
+{
+       (uint64_t)(uintptr_t)addr >= PIO_MAX ?
+               *(volatile uint32_t *)addr = val :
+#ifdef __GLIBC__
+               outl_p(val, (unsigned long)addr);
+#else
+               outl(val, (unsigned long)addr);
+#endif
+}
+
+#else /* !RTE_ARCH_X86 */
+
+static inline uint8_t ioread8(void *addr)
+{
+       return *(volatile uint8_t *)addr;
+}
+
+static inline uint16_t ioread16(void *addr)
+{
+       return *(volatile uint16_t *)addr;
+}
+
+static inline uint32_t ioread32(void *addr)
+{
+       return *(volatile uint32_t *)addr;
+}
+
+static inline void iowrite8(uint8_t val, void *addr)
+{
+       *(volatile uint8_t *)addr = val;
+}
+
+static inline void iowrite16(uint16_t val, void *addr)
+{
+       *(volatile uint16_t *)addr = val;
+}
+
+static inline void iowrite32(uint32_t val, void *addr)
+{
+       *(volatile uint32_t *)addr = val;
+}
+
+#endif /* !RTE_ARCH_X86 */
+
 void
 pci_uio_ioport_read(struct rte_pci_ioport *p,
                    void *data, size_t len, off_t offset)
@@ -498,25 +650,13 @@ pci_uio_ioport_read(struct rte_pci_ioport *p,
        for (d = data; len > 0; d += size, reg += size, len -= size) {
                if (len >= 4) {
                        size = 4;
-#if defined(RTE_ARCH_X86)
-                       *(uint32_t *)d = inl(reg);
-#else
-                       *(uint32_t *)d = *(volatile uint32_t *)reg;
-#endif
+                       *(uint32_t *)d = ioread32((void *)reg);
                } else if (len >= 2) {
                        size = 2;
-#if defined(RTE_ARCH_X86)
-                       *(uint16_t *)d = inw(reg);
-#else
-                       *(uint16_t *)d = *(volatile uint16_t *)reg;
-#endif
+                       *(uint16_t *)d = ioread16((void *)reg);
                } else {
                        size = 1;
-#if defined(RTE_ARCH_X86)
-                       *d = inb(reg);
-#else
-                       *d = *(volatile uint8_t *)reg;
-#endif
+                       *d = ioread8((void *)reg);
                }
        }
 }
@@ -532,25 +672,13 @@ pci_uio_ioport_write(struct rte_pci_ioport *p,
        for (s = data; len > 0; s += size, reg += size, len -= size) {
                if (len >= 4) {
                        size = 4;
-#if defined(RTE_ARCH_X86)
-                       outl_p(*(const uint32_t *)s, reg);
-#else
-                       *(volatile uint32_t *)reg = *(const uint32_t *)s;
-#endif
+                       iowrite32(*(const uint32_t *)s, (void *)reg);
                } else if (len >= 2) {
                        size = 2;
-#if defined(RTE_ARCH_X86)
-                       outw_p(*(const uint16_t *)s, reg);
-#else
-                       *(volatile uint16_t *)reg = *(const uint16_t *)s;
-#endif
+                       iowrite16(*(const uint16_t *)s, (void *)reg);
                } else {
                        size = 1;
-#if defined(RTE_ARCH_X86)
-                       outb_p(*s, reg);
-#else
-                       *(volatile uint8_t *)reg = *s;
-#endif
+                       iowrite8(*s, (void *)reg);
                }
        }
 }