From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by dpdk.org (Postfix) with ESMTP id C54FF58DA for ; Tue, 27 May 2014 04:25:20 +0200 (CEST) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga101.jf.intel.com with ESMTP; 26 May 2014 19:25:30 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.98,916,1392192000"; d="scan'208,217";a="546878648" Received: from fmsmsx107.amr.corp.intel.com ([10.19.9.54]) by orsmga002.jf.intel.com with ESMTP; 26 May 2014 19:25:27 -0700 Received: from FMSMSX109.amr.corp.intel.com (10.18.116.9) by FMSMSX107.amr.corp.intel.com (10.19.9.54) with Microsoft SMTP Server (TLS) id 14.3.123.3; Mon, 26 May 2014 19:25:21 -0700 Received: from shsmsx102.ccr.corp.intel.com (10.239.4.154) by fmsmsx109.amr.corp.intel.com (10.18.116.9) with Microsoft SMTP Server (TLS) id 14.3.123.3; Mon, 26 May 2014 19:25:20 -0700 Received: from shsmsx101.ccr.corp.intel.com ([169.254.1.7]) by shsmsx102.ccr.corp.intel.com ([169.254.2.190]) with mapi id 14.03.0123.003; Tue, 27 May 2014 10:25:18 +0800 From: "Xu, HuilongX" To: "dev@dpdk.org" , "Burakov, Anatoly" Thread-Topic: RE: [dpdk-dev] [PATCH v2 01/16] Separate igb_uio mapping into a separate file Thread-Index: Ac95UuV93c5XQBpySjWohQksuLlKgQ== Date: Tue, 27 May 2014 02:25:18 +0000 Message-ID: Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-cr-hashedpuzzle: AQVn BRGU Bkt5 CBrI C02v DKlR DTko FURO FVgX F1Pc GTNo G/mh HGf+ JJZD KrRH K7+2; 1; ZABlAHYAQABkAHAAZABrAC4AbwByAGcA; Sosha1_v1; 7; {CB850F0D-987F-4BCE-9EDC-9902820C30BD}; aAB1AGkAbABvAG4AZwB4AC4AeAB1AEAAaQBuAHQAZQBsAC4AYwBvAG0A; Tue, 27 May 2014 02:25:16 GMT; UgBFADoAIABbAGQAcABkAGsALQBkAGUAdgBdACAAWwBQAEEAVABDAEgAIAB2ADIAIAAwADEALwAxADYAXQAgAFMAZQBwAGEAcgBhAHQAZQAgAGkAZwBiAF8AdQBpAG8AIABtAGEAcABwAGkAbgBnACAAaQBuAHQAbwAgAGEAIABzAGUAcABhAHIAYQB0AGUAIABmAGkAbABlAA== x-cr-puzzleid: {CB850F0D-987F-4BCE-9EDC-9902820C30BD} x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable X-Content-Filtered-By: Mailman/MimeDel 2.1.15 Subject: Re: [dpdk-dev] [PATCH v2 01/16] Separate igb_uio mapping into a separate file X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 May 2014 02:25:24 -0000 In order to make the code a bit more clean while using multiple drivers, IGB_UIO mapping has been separated into its own file. Signed-off-by: Anatoly Burakov Test-by: HuilongX Xu > Compile pass >>Compile OS: FC20 x86_64 >>Kernel version: 3.13.6-200 >>GCC version: 4.8.2 >>Server: Crownpass --- lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/linuxapp/eal/eal_pci.c | 424 +----------------= --- lib/librte_eal/linuxapp/eal/eal_pci_uio.c | 403 +++++++++++++++++= ++ lib/librte_eal/linuxapp/eal/include/eal_pci_init.h | 65 +++ 4 files changed, 478 insertions(+), 415 deletions(-) create mode 100644 lib/librte_eal/linuxapp/eal/eal_pci_uio.c create mode 100644 lib/librte_eal/linuxapp/eal/include/eal_pci_init.h diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp= /eal/Makefile index b00e3ec..527fa2a 100644 --- a/lib/librte_eal/linuxapp/eal/Makefile +++ b/lib/librte_eal/linuxapp/eal/Makefile @@ -57,6 +57,7 @@ endif SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) +=3D eal_thread.c SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) +=3D eal_log.c SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) +=3D eal_pci.c +SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) +=3D eal_pci_uio.c SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) +=3D eal_debug.c SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) +=3D eal_lcore.c SRCS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) +=3D eal_timer.c diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxap= p/eal/eal_pci.c index ac2c1fe..cd5b797 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c @@ -31,82 +31,31 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #include -#include -#include #include #include -#include -#include -#include -#include #include -#include #include -#include -#include -#include -#include -#include #include #include "rte_pci_dev_ids.h" #include "eal_filesystem.h" #include "eal_private.h" +#include "eal_pci_init.h" /** * @file * PCI probing under linux * * This code is used to simulate a PCI probe by parsing information in - * sysfs. Moreover, when a registered driver matches a device, the - * kernel driver currently using it is unloaded and replaced by - * igb_uio module, which is a very minimal userland driver for Intel - * network card, only providing access to PCI BAR to applications, and - * enabling bus master. + * sysfs. When a registered device matches a driver, it is then initialize= d + * with either VFIO or IGB_UIO driver (or doesn't initialize), whichever + * driver the device is bound to. */ -struct uio_map { - void *addr; - uint64_t offset; - uint64_t size; - uint64_t phaddr; -}; - -/* - * For multi-process we need to reproduce all PCI mappings in secondary - * processes, so save them in a tailq. - */ -struct uio_resource { - TAILQ_ENTRY(uio_resource) next; - - struct rte_pci_addr pci_addr; - char path[PATH_MAX]; - size_t nb_maps; - struct uio_map maps[PCI_MAX_RESOURCE]; -}; - -TAILQ_HEAD(uio_res_list, uio_resource); - -static struct uio_res_list *uio_res_list =3D NULL; -static int pci_parse_sysfs_value(const char *filename, uint64_t *val); - /* unbind kernel driver for this device */ static int pci_unbind_kernel_driver(struct rte_pci_device *dev) @@ -147,31 +96,19 @@ error: } /* map a particular resource from a file */ -static void * -pci_map_resource(void *requested_addr, const char *devname, off_t offset, +void * +pci_map_resource(void *requested_addr, int fd, off_t offset, size_t size) { - int fd; void *mapaddr; - /* - * open devname, to mmap it - */ - fd =3D open(devname, O_RDWR); - if (fd < 0) { - RTE_LOG(ERR, EAL, "Cannot open %s: %s\n", - devname, strerror(errno)); - goto fail; - } - /* Map the PCI memory resource of device */ mapaddr =3D mmap(requested_addr, size, PROT_READ | PROT_WRIT= E, MAP_SHARED, fd, offset); - close(fd); if (mapaddr =3D=3D MAP_FAILED || (requested_addr !=3D NULL &&= mapaddr !=3D requested_addr)) { - RTE_LOG(ERR, EAL, "%s(): cannot mmap(%s(%d),= %p, 0x%lx, 0x%lx):" - " %s (%p)\n", __func__, devn= ame, fd, requested_addr, + RTE_LOG(ERR, EAL, "%s(): cannot mmap(%d, %p, = 0x%lx, 0x%lx):" + " %s (%p)\n", __func__, fd, r= equested_addr, (unsigned long)size, (unsign= ed long)offset, strerror(errno), mapaddr); goto fail; @@ -185,314 +122,6 @@ fail: return NULL; } -#define OFF_MAX ((uint64_t)(off_t)-1) -static ssize_t -pci_uio_get_mappings(const char *devname, struct uio_map maps[], size_t nb= _maps) -{ - size_t i; - char dirname[PATH_MAX]; - char filename[PATH_MAX]; - uint64_t offset, size; - - for (i =3D 0; i !=3D nb_maps; i++) { - - /* check if map directory exists */ - rte_snprintf(dirname, sizeof(dirname), - "%s/maps/map%u", devname, i)= ; - - if (access(dirname, F_OK) !=3D 0) - break; - - /* get mapping offset */ - rte_snprintf(filename, sizeof(filename), - "%s/offset", dirname); - if (pci_parse_sysfs_value(filename, &offset)= < 0) { - RTE_LOG(ERR, EAL, - "%s(): canno= t parse offset of %s\n", - __func__, di= rname); - return (-1); - } - - /* get mapping size */ - rte_snprintf(filename, sizeof(filename), - "%s/size", dirname); - if (pci_parse_sysfs_value(filename, &size) <= 0) { - RTE_LOG(ERR, EAL, - "%s(): canno= t parse size of %s\n", - __func__, di= rname); - return (-1); - } - - /* get mapping physical address */ - rte_snprintf(filename, sizeof(filename), - "%s/addr", dirname); - if (pci_parse_sysfs_value(filename, &maps[i]= .phaddr) < 0) { - RTE_LOG(ERR, EAL, - "%s(): canno= t parse addr of %s\n", - __func__, di= rname); - return (-1); - } - - if ((offset > OFF_MAX) || (size > SIZE_MAX))= { - RTE_LOG(ERR, EAL, - "%s(): offse= t/size exceed system max value\n", - __func__); - return (-1); - } - - maps[i].offset =3D offset; - maps[i].size =3D size; - } - return (i); -} - -static int -pci_uio_map_secondary(struct rte_pci_device *dev) -{ - size_t i; - struct uio_resource *uio_res; - - TAILQ_FOREACH(uio_res, uio_res_list, next) { - - /* skip this element if it doesn't match our= PCI address */ - if (memcmp(&uio_res->pci_addr, &dev->addr, s= izeof(dev->addr))) - continue; - - for (i =3D 0; i !=3D uio_res->nb_maps; i++) = { - if (pci_map_resource(uio_res= ->maps[i].addr, - = uio_res->path, - = (off_t)uio_res->maps[i].offset, - = (size_t)uio_res->maps[i].size) - !=3D uio_res->maps[i].ad= dr) { - RTE_LOG(ERR,= EAL, - = "Cannot mmap device resource\n"); - return (-1); - } - } - return (0); - } - - RTE_LOG(ERR, EAL, "Cannot find resource for device\n"); - return -1; -} - -static int pci_mknod_uio_dev(const char *sysfs_uio_path, unsigned uio_num) -{ - FILE *f; - char filename[PATH_MAX]; - int ret; - unsigned major, minor; - dev_t dev; - - /* get the name of the sysfs file that contains the major an= d minor - * of the uio device and read its content */ - rte_snprintf(filename, sizeof(filename), "%s/dev", sysfs_uio= _path); - - f =3D fopen(filename, "r"); - if (f =3D=3D NULL) { - RTE_LOG(ERR, EAL, "%s(): cannot open sysfs t= o get major:minor\n", - __func__); - return -1; - } - - ret =3D fscanf(f, "%d:%d", &major, &minor); - if (ret !=3D 2) { - RTE_LOG(ERR, EAL, "%s(): cannot parse sysfs = to get major:minor\n", - __func__); - fclose(f); - return -1; - } - fclose(f); - - /* create the char device "mknod /dev/uioX c major minor" */ - rte_snprintf(filename, sizeof(filename), "/dev/uio%u", uio_n= um); - dev =3D makedev(major, minor); - ret =3D mknod(filename, S_IFCHR | S_IRUSR | S_IWUSR, dev); - if (f =3D=3D NULL) { - RTE_LOG(ERR, EAL, "%s(): mknod() failed %s\n= ", - __func__, strerror(errno)); - return -1; - } - - return ret; -} - -/* - * Return the uioX char device used for a pci device. On success, return - * the UIO number and fill dstbuf string with the path of the device in - * sysfs. On error, return a negative value. In this case dstbuf is - * invalid. - */ -static int pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf, - unsigned int buflen) -{ - struct rte_pci_addr *loc =3D &dev->addr; - unsigned int uio_num; - struct dirent *e; - DIR *dir; - char dirname[PATH_MAX]; - - /* depending on kernel version, uio can be located in uio/ui= oX - * or uio:uioX */ - - rte_snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", - loc->domain, loc->bus, loc->devid, loc->function); - - dir =3D opendir(dirname); - if (dir =3D=3D NULL) { - /* retry with the parent directory */ - rte_snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, - loc->domain, loc->bus, loc->devid, = loc->function); - dir =3D opendir(dirname); - - if (dir =3D=3D NULL) { - RTE_LOG(ERR, EAL, "Cannot op= endir %s\n", dirname); - return -1; - } - } - - /* take the first file starting with "uio" */ - while ((e =3D readdir(dir)) !=3D NULL) { - /* format could be uio%d ...*/ - int shortprefix_len =3D sizeof("uio") - 1; - /* ... or uio:uio%d */ - int longprefix_len =3D sizeof("uio:uio") - 1= ; - char *endptr; - - if (strncmp(e->d_name, "uio", 3) !=3D 0) - continue; - - /* first try uio%d */ - errno =3D 0; - uio_num =3D strtoull(e->d_name + shortprefix= _len, &endptr, 10); - if (errno =3D=3D 0 && endptr !=3D (e->d_name= + shortprefix_len)) { - rte_snprintf(dstbuf, buflen,= "%s/uio%u", dirname, uio_num); - break; - } - - /* then try uio:uio%d */ - errno =3D 0; - uio_num =3D strtoull(e->d_name + longprefix_= len, &endptr, 10); - if (errno =3D=3D 0 && endptr !=3D (e->d_name= + longprefix_len)) { - rte_snprintf(dstbuf, buflen,= "%s/uio:uio%u", dirname, uio_num); - break; - } - } - closedir(dir); - - /* No uio resource found */ - if (e =3D=3D NULL) - return -1; - - /* create uio device if we've been asked to */ - if (internal_config.create_uio_dev && pci_mknod_uio_dev(dstb= uf, uio_num) < 0) - RTE_LOG(WARNING, EAL, "Cannot create /dev/ui= o%u\n", uio_num); - - return uio_num; -} - -/* map the PCI resource of a PCI device in virtual memory */ -static int -pci_uio_map_resource(struct rte_pci_device *dev) -{ - int i, j; - char dirname[PATH_MAX]; - char devname[PATH_MAX]; /* contains the /dev/uioX */ - void *mapaddr; - int uio_num; - uint64_t phaddr; - uint64_t offset; - uint64_t pagesz; - ssize_t nb_maps; - struct rte_pci_addr *loc =3D &dev->addr; - struct uio_resource *uio_res; - struct uio_map *maps; - - dev->intr_handle.fd =3D -1; - dev->intr_handle.type =3D RTE_INTR_HANDLE_UNKNOWN; - - /* secondary processes - use already recorded details */ - if (rte_eal_process_type() !=3D RTE_PROC_PRIMARY) - return (pci_uio_map_secondary(dev)); - - /* find uio resource */ - uio_num =3D pci_get_uio_dev(dev, dirname, sizeof(dirname)); - if (uio_num < 0) { - RTE_LOG(WARNING, EAL, " "PCI_PRI_FMT" not m= anaged by UIO driver, " - "skipping\n"= , loc->domain, loc->bus, loc->devid, loc->function); - return -1; - } - rte_snprintf(devname, sizeof(devname), "/dev/uio%u", uio_num= ); - - /* save fd if in primary process */ - dev->intr_handle.fd =3D open(devname, O_RDWR); - if (dev->intr_handle.fd < 0) { - RTE_LOG(ERR, EAL, "Cannot open %s: %s\n", - devname, strerror(errno)); - return -1; - } - dev->intr_handle.type =3D RTE_INTR_HANDLE_UIO; - - /* allocate the mapping details for secondary processes*/ - if ((uio_res =3D rte_zmalloc("UIO_RES", sizeof (*uio_res), 0= )) =3D=3D NULL) { - RTE_LOG(ERR, EAL, - "%s(): cannot store uio mmap= details\n", __func__); - return (-1); - } - - rte_snprintf(uio_res->path, sizeof(uio_res->path), "%s", dev= name); - memcpy(&uio_res->pci_addr, &dev->addr, sizeof(uio_res->pci_a= ddr)); - - /* collect info about device mappings */ - nb_maps =3D pci_uio_get_mappings(dirname, uio_res->maps, - RTE_D= IM(uio_res->maps)); - if (nb_maps < 0) { - rte_free(uio_res); - return (nb_maps); - } - - uio_res->nb_maps =3D nb_maps; - - /* Map all BARs */ - pagesz =3D sysconf(_SC_PAGESIZE); - - maps =3D uio_res->maps; - for (i =3D 0; i !=3D PCI_MAX_RESOURCE; i++) { - - /* skip empty BAR */ - if ((phaddr =3D dev->mem_resource[i].phys_ad= dr) =3D=3D 0) - continue; - - for (j =3D 0; j !=3D nb_maps && (phaddr !=3D= maps[j].phaddr || - dev->mem_res= ource[i].len !=3D maps[j].size); - j++) - ; - - /* if matching map is found, then use it */ - if (j !=3D nb_maps) { - offset =3D j * pagesz; - if (maps[j].addr !=3D NULL |= | - (mapaddr =3D pci_map_res= ource(NULL, devname, - = (off_t)offset, - = (size_t)maps[j].size) - ) =3D=3D NULL) { - rte_free(uio= _res); - return (-1); - } - - maps[j].addr =3D mapaddr; - maps[j].offset =3D offset; - dev->mem_resource[i].addr = =3D mapaddr; - } - } - - TAILQ_INSERT_TAIL(uio_res_list, uio_res, next); - - return (0); -} - /* parse the "resource" sysfs file */ #define IORESOURCE_MEM 0x00000200 @@ -556,41 +185,6 @@ error: return -1; } -/* - * parse a sysfs file containing one integer value - * different to the eal version, as it needs to work with 64-bit values - */ -static int -pci_parse_sysfs_value(const char *filename, uint64_t *val) -{ - FILE *f; - char buf[BUFSIZ]; - char *end =3D NULL; - - f =3D fopen(filename, "r"); - if (f =3D=3D NULL) { - RTE_LOG(ERR, EAL, "%s(): cannot open sysfs value %s\n", - __func__, filename); - return -1; - } - - if (fgets(buf, sizeof(buf), f) =3D=3D NULL) { - RTE_LOG(ERR, EAL, "%s(): cannot read sysfs value %s\n", - __func__, filename); - fclose(f); - return -1; - } - *val =3D strtoull(buf, &end, 0); - if ((buf[0] =3D=3D '\0') || (end =3D=3D NULL) || (*end !=3D '\n'))= { - RTE_LOG(ERR, EAL, "%s(): cannot parse sysfs value %s\n", - __func__, filename); - fclose(f); - return -1; - } - fclose(f); - return 0; -} - /* Compare two PCI device addresses. */ static int pci_addr_comparison(struct rte_pci_addr *addr, struct rte_pci_addr *addr2) @@ -866,7 +460,7 @@ rte_eal_pci_init(void) { TAILQ_INIT(&pci_driver_list); TAILQ_INIT(&pci_device_list); - uio_res_list =3D RTE_TAILQ_RESERVE_BY_IDX(RTE_TAILQ_PCI, uio= _res_list); + pci_res_list =3D RTE_TAILQ_RESERVE_BY_IDX(RTE_TAILQ_PCI, mapp= ed_pci_res_list); /* for debug purposes, PCI can be disabled */ if (internal_config.no_pci) diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/lin= uxapp/eal/eal_pci_uio.c new file mode 100644 index 0000000..f29fee5 --- /dev/null +++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c @@ -0,0 +1,403 @@ +/*- + * 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. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "rte_pci_dev_ids.h" +#include "eal_filesystem.h" +#include "eal_pci_init.h" + +static int pci_parse_sysfs_value(const char *filename, uint64_t *val); + +#define OFF_MAX ((uint64_t)(off_t)-1) +static ssize_t +pci_uio_get_mappings(const char *devname, struct pci_map maps[], size_t nb= _maps) { + size_t i; + char dirname[PATH_MAX]; + char filename[PATH_MAX]; + uint64_t offset, size; + + for (i =3D 0; i !=3D nb_maps; i++) { + + /* check if map directory exists */ + rte_snprintf(dirname, sizeof(dirname), "%s/ma= ps/map%u", devname, i); + + if (access(dirname, F_OK) !=3D 0) + break; + + /* get mapping offset */ + rte_snprintf(filename, sizeof(filename), "%s/= offset", dirname); + if (pci_parse_sysfs_value(filename, &offset) = < 0) { + RTE_LOG(ERR, EAL, + = "%s(): cannot parse offset of %s\n", __func__, dirname); + return (-1); + } + + /* get mapping size */ + rte_snprintf(filename, sizeof(filename), "%s/= size", dirname); + if (pci_parse_sysfs_value(filename, &size) < = 0) { + RTE_LOG(ERR, EAL, + = "%s(): cannot parse size of %s\n", __func__, dirname); + return (-1); + } + + /* get mapping physical address */ + rte_snprintf(filename, sizeof(filename), "%s/= addr", dirname); + if (pci_parse_sysfs_value(filename, &maps[i].= phaddr) < 0) { + RTE_LOG(ERR, EAL, + = "%s(): cannot parse addr of %s\n", __func__, dirname); + return (-1); + } + + if ((offset > OFF_MAX) || (size > SIZE_MAX)) = { + RTE_LOG(ERR, EAL, + = "%s(): offset/size exceed system max value\n", __func__); + return (-1); + } + + maps[i].offset =3D offset; + maps[i].size =3D size; + } + + return (i); +} + +static int +pci_uio_map_secondary(struct rte_pci_device *dev) { + int fd, i; + struct mapped_pci_resource *uio_res; + + TAILQ_FOREACH(uio_res, pci_res_list, next) { + + /* skip this element if it doesn't match our = PCI address */ + if (memcmp(&uio_res->pci_addr, &dev->addr, si= zeof(dev->addr))) + continue; + + for (i =3D 0; i !=3D uio_res->nb_maps; i++) { + /* + * open devname, to mmap it + */ + fd =3D open(uio_res->path, O_= RDWR); + if (fd < 0) { + RTE_LOG(ERR, = EAL, + = "Cannot open %s: %s\n", uio_res->path, strerror(errno)); + return -1; + } + + if (pci_map_resource(uio_res-= >maps[i].addr, fd, + = (off_t) uio_res->maps[i].offset, + = (size_t) uio_res->maps[i].size) !=3D uio_res->maps[i].addr) { + RTE_LOG(ERR, = EAL, "Cannot mmap device resource\n"); + close(fd); + return (-1); + } + /* fd is not needed in slave = process, close it */ + close(fd); + } + return (0); + } + + RTE_LOG(ERR, EAL, "Cannot find resource for device\n"); + return -1; +} + +static int +pci_mknod_uio_dev(const char *sysfs_uio_path, unsigned uio_num) { + FILE *f; + char filename[PATH_MAX]; + int ret; + unsigned major, minor; + dev_t dev; + + /* get the name of the sysfs file that contains the major and= minor + * of the uio device and read its content */ + rte_snprintf(filename, sizeof(filename), "%s/dev", sysfs_uio_= path); + + f =3D fopen(filename, "r"); + if (f =3D=3D NULL) { + RTE_LOG(ERR, EAL, + "%s(): cannot= open sysfs to get major:minor\n", __func__); + return -1; + } + + ret =3D fscanf(f, "%d:%d", &major, &minor); + if (ret !=3D 2) { + RTE_LOG(ERR, EAL, + "%s(): cannot= parse sysfs to get major:minor\n", __func__); + fclose(f); + return -1; + } + fclose(f); + + /* create the char device "mknod /dev/uioX c major minor" */ + rte_snprintf(filename, sizeof(filename), "/dev/uio%u", uio_nu= m); + dev =3D makedev(major, minor); + ret =3D mknod(filename, S_IFCHR | S_IRUSR | S_IWUSR, dev); + if (f =3D=3D NULL) { + RTE_LOG(ERR, EAL, + "%s(): mknod(= ) failed %s\n", __func__, strerror(errno)); + return -1; + } + + return ret; +} + +/* + * Return the uioX char device used for a pci device. On success, return + * the UIO number and fill dstbuf string with the path of the device in + * sysfs. On error, return a negative value. In this case dstbuf is + * invalid. + */ +static int +pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf, + unsigned int buflen) { + struct rte_pci_addr *loc =3D &dev->addr; + unsigned int uio_num; + struct dirent *e; + DIR *dir; + char dirname[PATH_MAX]; + + /* depending on kernel version, uio can be located in uio/uio= X + * or uio:uioX */ + + rte_snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI= _FMT "/uio", loc->domain, loc->bus, + loc->devid, loc->function); + + dir =3D opendir(dirname); + if (dir =3D=3D NULL) { + /* retry with the parent directory */ + rte_snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEV= ICES "/" PCI_PRI_FMT, loc->domain, loc->bus, + loc->devid, l= oc->function); + dir =3D opendir(dirname); + + if (dir =3D=3D NULL) { + RTE_LOG(ERR, EAL, "Cannot ope= ndir %s\n", dirname); + return -1; + } + } + + /* take the first file starting with "uio" */ + while ((e =3D readdir(dir)) !=3D NULL) { + /* format could be uio%d ...*/ + int shortprefix_len =3D sizeof("uio") - 1; + /* ... or uio:uio%d */ + int longprefix_len =3D sizeof("uio:uio") - 1; + char *endptr; + + if (strncmp(e->d_name, "uio", 3) !=3D 0) + continue; + + /* first try uio%d */errno =3D 0; + uio_num =3D strtoull(e->d_name + shortprefix_= len, &endptr, 10); + if (errno =3D=3D 0 && endptr !=3D (e->d_name = + shortprefix_len)) { + rte_snprintf(dstbuf, buflen, = "%s/uio%u", dirname, uio_num); + break; + } + + /* then try uio:uio%d */errno =3D 0; + uio_num =3D strtoull(e->d_name + longprefix_l= en, &endptr, 10); + if (errno =3D=3D 0 && endptr !=3D (e->d_name = + longprefix_len)) { + rte_snprintf(dstbuf, buflen, = "%s/uio:uio%u", dirname, uio_num); + break; + } + } + closedir(dir); + + /* No uio resource found */ + if (e =3D=3D NULL) + return -1; + + /* create uio device if we've been asked to */ + if (internal_config.create_uio_dev + && pci_mknod_uio_dev(dstbuf, = uio_num) < 0) + RTE_LOG(WARNING, EAL, "Cannot create /dev/uio= %u\n", uio_num); + + return uio_num; +} + +/* map the PCI resource of a PCI device in virtual memory */ +int +pci_uio_map_resource(struct rte_pci_device *dev) { + int i, j; + char dirname[PATH_MAX]; + char devname[PATH_MAX]; /* contains the /dev/uioX */ + void *mapaddr; + int uio_num; + uint64_t phaddr; + uint64_t offset; + uint64_t pagesz; + ssize_t nb_maps; + struct rte_pci_addr *loc =3D &dev->addr; + struct mapped_pci_resource *uio_res; + struct pci_map *maps; + + dev->intr_handle.fd =3D -1; + dev->intr_handle.type =3D RTE_INTR_HANDLE_UNKNOWN; + + /* secondary processes - use already recorded details */ + if (rte_eal_process_type() !=3D RTE_PROC_PRIMARY) + return (pci_uio_map_secondary(dev)); + + /* find uio resource */ + uio_num =3D pci_get_uio_dev(dev, dirname, sizeof(dirname)); + if (uio_num < 0) { + RTE_LOG(WARNING, EAL, " "PCI_PRI_FMT" not ma= naged by UIO driver, " + "skipping\n", loc->domain, loc->bus, loc->dev= id, loc->function); + return -1; + } + rte_snprintf(devname, sizeof(devname), "/dev/uio%u", uio_num)= ; + + /* save fd if in primary process */ + dev->intr_handle.fd =3D open(devname, O_RDWR); + if (dev->intr_handle.fd < 0) { + RTE_LOG(ERR, EAL, "Cannot open %s: %s\n", dev= name, strerror(errno)); + return -1; + } + dev->intr_handle.type =3D RTE_INTR_HANDLE_UIO; + + /* allocate the mapping details for secondary processes*/ + if ((uio_res =3D rte_zmalloc("UIO_RES", sizeof(*uio_res), 0))= =3D=3D NULL) { + RTE_LOG(ERR, EAL, "%s(): cannot store uio mma= p details\n", __func__); + return (-1); + } + + rte_snprintf(uio_res->path, sizeof(uio_res->path), "%s", devn= ame); + memcpy(&uio_res->pci_addr, &dev->addr, sizeof(uio_res->pci_ad= dr)); + + /* collect info about device mappings */ + nb_maps =3D pci_uio_get_mappings(dirname, uio_res->maps, + RTE_DIM(uio_res->maps)); + if (nb_maps < 0) { + rte_free(uio_res); + return (nb_maps); + } + + uio_res->nb_maps =3D nb_maps; + + /* Map all BARs */ + pagesz =3D sysconf(_SC_PAGESIZE); + + maps =3D uio_res->maps; + for (i =3D 0; i !=3D PCI_MAX_RESOURCE; i++) { + int fd; + + /* skip empty BAR */ + if ((phaddr =3D dev->mem_resource[i].phys_add= r) =3D=3D 0) + continue; + + for (j =3D 0; + j !=3D nb_map= s + = && (phaddr !=3D maps[j].phaddr + = || dev->mem_resource[i].= len !=3D maps[j].size); + j++) + ; + + /* if matching map is found, then use it */ + if (j !=3D nb_maps) { + offset =3D j * pagesz; + + /* + * open devname, to mmap it + */ + fd =3D open(uio_res->path, O_= RDWR); + if (fd < 0) { + RTE_LOG(ERR, = EAL, "Cannot open %s: %s\n", + = uio_res->path, strerror(errno)); + rte_free(uio_= res); + return -1; + } + + if (maps[j].addr !=3D NULL + = || (mapaddr =3D pci_map_resource(NULL, fd, + = (off_t) offset, (size_t) maps[j].size)) = =3D=3D NULL) { + rte_free(uio_= res); + close(fd); + return (-1); + } + close(fd); + + maps[j].addr =3D mapaddr; + maps[j].offset =3D offset; + dev->mem_resource[i].addr =3D= mapaddr; + } + } + + TAILQ_INSERT_TAIL(pci_res_list, uio_res, next); + + return (0); +} + +/* + * parse a sysfs file containing one integer value + * different to the eal version, as it needs to work with 64-bit values + */ +static int +pci_parse_sysfs_value(const char *filename, uint64_t *val) { + FILE *f; + char buf[BUFSIZ]; + char *end =3D NULL; + + f =3D fopen(filename, "r"); + if (f =3D=3D NULL) { + RTE_LOG(ERR, EAL, + "%s(): cannot= open sysfs value %s\n", __func__, filename); + return -1; + } + + if (fgets(buf, sizeof(buf), f) =3D=3D NULL) { + RTE_LOG(ERR, EAL, + "%s(): cannot= read sysfs value %s\n", __func__, filename); + fclose(f); + return -1; + } + *val =3D strtoull(buf, &end, 0); + if ((buf[0] =3D=3D '\0') || (end =3D=3D NULL) || (*end !=3D '= \n')) { + RTE_LOG(ERR, EAL, + "%s(): cannot= parse sysfs value %s\n", __func__, filename); + fclose(f); + return -1; + } + fclose(f); + return 0; +} diff --git a/lib/librte_eal/linuxapp/eal/include/eal_pci_init.h b/lib/librt= e_eal/linuxapp/eal/include/eal_pci_init.h new file mode 100644 index 0000000..699e80d --- /dev/null +++ b/lib/librte_eal/linuxapp/eal/include/eal_pci_init.h @@ -0,0 +1,65 @@ +/*- + * 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. + */ + +#ifndef EAL_PCI_INIT_H_ +#define EAL_PCI_INIT_H_ + +struct pci_map { + void *addr; + uint64_t offset; + uint64_t size; + uint64_t phaddr; +}; + +/* + * For multi-process we need to reproduce all PCI mappings in secondary + * processes, so save them in a tailq. + */ +struct mapped_pci_resource { + TAILQ_ENTRY(mapped_pci_resource) next; + + struct rte_pci_addr pci_addr; + char path[PATH_MAX]; + int nb_maps; + struct pci_map maps[PCI_MAX_RESOURCE]; +}; + +TAILQ_HEAD(mapped_pci_res_list, mapped_pci_resource); +struct mapped_pci_res_list *pci_res_list; + +void * pci_map_resource(void *requested_addr, int fd, off_t offset, size_t= size); + +/* map IGB_UIO resource prototype */ +int pci_uio_map_resource(struct rte_pci_device *dev); + +#endif /* EAL_PCI_INIT_H_ */ -- 1.7.0.7