From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by dpdk.org (Postfix) with ESMTP id AC52E58D2 for ; Tue, 28 Oct 2014 03:50:01 +0100 (CET) Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga102.jf.intel.com with ESMTP; 27 Oct 2014 19:57:26 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.04,800,1406617200"; d="scan'208";a="597353466" Received: from pgsmsx103.gar.corp.intel.com ([10.221.44.82]) by orsmga001.jf.intel.com with ESMTP; 27 Oct 2014 19:58:45 -0700 Received: from pgsmsx108.gar.corp.intel.com (10.221.44.103) by PGSMSX103.gar.corp.intel.com (10.221.44.82) with Microsoft SMTP Server (TLS) id 14.3.195.1; Tue, 28 Oct 2014 10:57:03 +0800 Received: from shsmsx151.ccr.corp.intel.com (10.239.6.50) by PGSMSX108.gar.corp.intel.com (10.221.44.103) with Microsoft SMTP Server (TLS) id 14.3.195.1; Tue, 28 Oct 2014 10:57:02 +0800 Received: from shsmsx101.ccr.corp.intel.com ([169.254.1.202]) by SHSMSX151.ccr.corp.intel.com ([169.254.3.44]) with mapi id 14.03.0195.001; Tue, 28 Oct 2014 10:56:53 +0800 From: "Qiu, Michael" To: "Zhou, Danny" , "dev@dpdk.org" Thread-Topic: [dpdk-dev] [RFC PATCH] Enable uio_pci_generic support Thread-Index: AQHP8g5YXBZ4qI7WHU+1Cbd+ZLo1dA== Date: Tue, 28 Oct 2014 02:56:52 +0000 Message-ID: <533710CFB86FA344BFBF2D6802E60286C7C559@SHSMSX101.ccr.corp.intel.com> References: <1414432082-30428-1-git-send-email-danny.zhou@intel.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] Content-Type: text/plain; charset="iso-2022-jp" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Subject: Re: [dpdk-dev] [RFC PATCH] Enable uio_pci_generic support 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, 28 Oct 2014 02:50:04 -0000 Tested-by: Michael Qiu =0A= =0A= =1B$B:_=1B(B 10/28/2014 1:49 AM, Danny Zhou =1B$B Linux kernel provides UIO as well as VFIO mechanism to support writing us= er=0A= > space device driver. Comparing to UIO which is available since 2.6.32 ker= nel,=0A= > the VFIO is introduced into kernel since version 3.6.0 with better interr= upt=0A= > and memory protection (build on top of Intel VT-d technology) supports.= =0A= > Basically, UIO and VFIO do two common things below:=0A= > 1) Map PCIe device's I/O memory space to user space driver=0A= > 2) Support device interrupt notification mechanism allows user space=0A= > driver/application is notified when device interrupt triggers.=0A= >=0A= > To run an DPDK application and make use of VFIO, two in_kernel modules=0A= > vfio and vfio-pci module must be loaded. But to use UIO, a DPDK kernel=0A= > module igb_uio, which was there since DPDK is invented, must be loaded to= =0A= > attach to in_kernel uio module. As an possible solution to deprecate igb_= uio, =0A= > this RFC patch leverages uio_pci_generic this in_kernel module to support= =0A= > DPDK user space PMD in a generic fashion (like how VFIO works today), to= =0A= > partially (DPDK KNI module rte_kni still sits in kernel) remove DPDK depe= ndency=0A= > on GPL code igb_uio in kernel. Tests with uio_pci_generic shows performan= ce=0A= > remains same and LSC interrupts works as before.=0A= >=0A= > Example to bind Network Ports to uio_pci_generic:=0A= > modprobe uio=0A= > modprobe uio_pci_generic=0A= > /* to bind device 08:00.0, to the uio_pci_generic driver */=0A= > ./tools/dpdk_nic_bind.py -b uio_pci_generic 08:00.0=0A= >=0A= > Note: this RFC patch does not completely remove igb_uio support due to=0A= > igb_uio supports creating maximum number of SR-IOV VFs (Virtual Functions= )=0A= > by using max_vfs kernel parameter on older kernels (kernel 3.7.x and belo= w).=0A= > Specifically, igb_uio explicitly calls pci_enable_sriov() to create VFs, = while=0A= > it is not invoked in either uio or uio_pci_generic. On kernel 3.8.x=0A= > and above, user can use the standard sysfs to enable VFs. For examples:= =0A= >=0A= > #echo $num_vf_enabled > /sys/class/net/$dev/device/sriov_numvfs //enabl= e VFs=0A= > #echo 0 > /sys/class/net/$dev/device/sriov_numvfs //disab= le VFs=0A= >=0A= > ---=0A= > lib/librte_eal/common/include/rte_pci.h | 1 +=0A= > lib/librte_eal/linuxapp/eal/eal_interrupts.c | 67 +++++--=0A= > lib/librte_eal/linuxapp/eal/eal_pci.c | 2 +-=0A= > lib/librte_eal/linuxapp/eal/eal_pci_uio.c | 203 +++++++++++++++= +-----=0A= > .../linuxapp/eal/include/exec-env/rte_interrupts.h | 1 +=0A= > tools/dpdk_nic_bind.py | 2 +-=0A= > 6 files changed, 214 insertions(+), 62 deletions(-)=0A= >=0A= > diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/com= mon/include/rte_pci.h=0A= > index 66ed793..71ca882 100644=0A= > --- a/lib/librte_eal/common/include/rte_pci.h=0A= > +++ b/lib/librte_eal/common/include/rte_pci.h=0A= > @@ -148,6 +148,7 @@ struct rte_pci_device {=0A= > struct rte_pci_id id; /**< PCI ID. */=0A= > struct rte_pci_resource mem_resource[PCI_MAX_RESOURCE]; /**< PCI Memo= ry Resource */=0A= > struct rte_intr_handle intr_handle; /**< Interrupt handle */=0A= > + char driver_name[BUFSIZ]; /**< driver name */=0A= > const struct rte_pci_driver *driver; /**< Associated driver */=0A= > uint16_t max_vfs; /**< sriov enable if not zero *= /=0A= > int numa_node; /**< NUMA node connection */=0A= > diff --git a/lib/librte_eal/linuxapp/eal/eal_interrupts.c b/lib/librte_ea= l/linuxapp/eal/eal_interrupts.c=0A= > index dc2668a..f2da778 100644=0A= > --- a/lib/librte_eal/linuxapp/eal/eal_interrupts.c=0A= > +++ b/lib/librte_eal/linuxapp/eal/eal_interrupts.c=0A= > @@ -361,6 +361,53 @@ vfio_disable_msix(struct rte_intr_handle *intr_handl= e) {=0A= > }=0A= > #endif=0A= > =0A= > +static int=0A= > +uio_intr_enable(struct rte_intr_handle *intr_handle)=0A= > +{=0A= > + unsigned char command_high;=0A= > +=0A= > + /* use config file descriptor for uio_pci_generic */=0A= > + if (pread(intr_handle->uio_cfg_fd, &command_high, 1, 5) !=3D 1) {=0A= > + RTE_LOG(ERR, EAL,=0A= > + "Error reading interrupts status for fd %d\n",=0A= > + intr_handle->uio_cfg_fd);=0A= > + return -1;=0A= > + }=0A= > + /* disable interrupts */=0A= > + command_high |=3D 0x4;=0A= > + if (pwrite(intr_handle->uio_cfg_fd, &command_high, 1, 5) !=3D 1) {=0A= > + RTE_LOG(ERR, EAL,=0A= > + "Error disabling interrupts for fd %d\n",=0A= > + intr_handle->uio_cfg_fd);=0A= > + return -1;=0A= > + }=0A= > +=0A= > + return 0;=0A= > +}=0A= > +=0A= > +static int=0A= > +uio_intr_disable(struct rte_intr_handle *intr_handle)=0A= > +{=0A= > + unsigned char command_high;=0A= > +=0A= > + if (pread(intr_handle->uio_cfg_fd, &command_high, 1, 5) !=3D 1) {=0A= > + RTE_LOG(ERR, EAL,=0A= > + "Error reading interrupts status for fd %d\n",=0A= > + intr_handle->uio_cfg_fd);=0A= > + return -1;=0A= > + }=0A= > + /* enable interrupts */=0A= > + command_high &=3D ~0x4;=0A= > + if (pwrite(intr_handle->uio_cfg_fd, &command_high, 1, 5) !=3D 1) {=0A= > + RTE_LOG(ERR, EAL,=0A= > + "Error enabling interrupts for fd %d\n",=0A= > + intr_handle->uio_cfg_fd);=0A= > + return -1;=0A= > + }=0A= > +=0A= > + return 0;=0A= > +}=0A= > +=0A= > int=0A= > rte_intr_callback_register(struct rte_intr_handle *intr_handle,=0A= > rte_intr_callback_fn cb, void *cb_arg)=0A= > @@ -500,20 +547,14 @@ rte_intr_callback_unregister(struct rte_intr_handle= *intr_handle,=0A= > int=0A= > rte_intr_enable(struct rte_intr_handle *intr_handle)=0A= > {=0A= > - const int value =3D 1;=0A= > -=0A= > - if (!intr_handle || intr_handle->fd < 0)=0A= > + if (!intr_handle || intr_handle->fd < 0 || intr_handle->uio_cfg_fd)=0A= > return -1;=0A= > =0A= > switch (intr_handle->type){=0A= > /* write to the uio fd to enable the interrupt */=0A= > case RTE_INTR_HANDLE_UIO:=0A= > - if (write(intr_handle->fd, &value, sizeof(value)) < 0) {=0A= > - RTE_LOG(ERR, EAL,=0A= > - "Error enabling interrupts for fd %d\n",=0A= > - intr_handle->fd);=0A= > + if (uio_intr_enable(intr_handle))=0A= > return -1;=0A= > - }=0A= > break;=0A= > /* not used at this moment */=0A= > case RTE_INTR_HANDLE_ALARM:=0A= > @@ -546,20 +587,14 @@ rte_intr_enable(struct rte_intr_handle *intr_handle= )=0A= > int=0A= > rte_intr_disable(struct rte_intr_handle *intr_handle)=0A= > {=0A= > - const int value =3D 0;=0A= > -=0A= > - if (!intr_handle || intr_handle->fd < 0)=0A= > + if (!intr_handle || intr_handle->fd < 0 || intr_handle->uio_cfg_fd)=0A= > return -1;=0A= > =0A= > switch (intr_handle->type){=0A= > /* write to the uio fd to disable the interrupt */=0A= > case RTE_INTR_HANDLE_UIO:=0A= > - if (write(intr_handle->fd, &value, sizeof(value)) < 0){=0A= > - RTE_LOG(ERR, EAL,=0A= > - "Error disabling interrupts for fd %d\n",=0A= > - intr_handle->fd);=0A= > + if (uio_intr_disable(intr_handle))=0A= > return -1;=0A= > - }=0A= > break;=0A= > /* not used at this moment */=0A= > case RTE_INTR_HANDLE_ALARM:=0A= > diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linux= app/eal/eal_pci.c=0A= > index 5fe3961..5c73908 100644=0A= > --- a/lib/librte_eal/linuxapp/eal/eal_pci.c=0A= > +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c=0A= > @@ -498,7 +498,7 @@ pci_map_device(struct rte_pci_device *dev)=0A= > return ret;=0A= > }=0A= > #endif=0A= > - /* map resources for devices that use igb_uio */=0A= > + /* map resources for devices that use uio_pci_generic or igb_uio */=0A= > if (!mapped) {=0A= > ret =3D pci_uio_map_resource(dev);=0A= > if (ret !=3D 0)=0A= > diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/l= inuxapp/eal/eal_pci_uio.c=0A= > index 7e62266..4b159e2 100644=0A= > --- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c=0A= > +++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c=0A= > @@ -35,6 +35,7 @@=0A= > #include =0A= > #include =0A= > #include =0A= > +#include =0A= > =0A= > #include =0A= > #include =0A= > @@ -46,72 +47,130 @@=0A= > #include "eal_filesystem.h"=0A= > #include "eal_pci_init.h"=0A= > =0A= > +#define IORESOURCE_MEM 0x00000200=0A= > +#define UIO_PCI_GENERIC_NAME "uio_pci_generic"=0A= > +=0A= > static int pci_parse_sysfs_value(const char *filename, uint64_t *val);= =0A= > =0A= > =0A= > #define OFF_MAX ((uint64_t)(off_t)-1)=0A= > static int=0A= > -pci_uio_get_mappings(const char *devname, struct pci_map maps[], int nb_= maps)=0A= > +pci_uio_get_mappings(struct rte_pci_device *dev, const char *devname,=0A= > + struct pci_map maps[], int nb_maps)=0A= > {=0A= > - int i;=0A= > + struct rte_pci_addr *loc =3D &dev->addr;=0A= > + int i =3D 0;=0A= > char dirname[PATH_MAX];=0A= > char filename[PATH_MAX];=0A= > uint64_t offset, size;=0A= > + unsigned long long start_addr, end_addr, flags;=0A= > + FILE *f;=0A= > =0A= > - for (i =3D 0; i !=3D nb_maps; i++) {=0A= > -=0A= > - /* check if map directory exists */=0A= > - snprintf(dirname, sizeof(dirname),=0A= > - "%s/maps/map%u", devname, i);=0A= > -=0A= > - if (access(dirname, F_OK) !=3D 0)=0A= > - break;=0A= > -=0A= > - /* get mapping offset */=0A= > + if (strncmp(dev->driver_name, UIO_PCI_GENERIC_NAME,=0A= > + strlen(UIO_PCI_GENERIC_NAME)) =3D=3D 0) {=0A= > snprintf(filename, sizeof(filename),=0A= > - "%s/offset", dirname);=0A= > - if (pci_parse_sysfs_value(filename, &offset) < 0) {=0A= > - RTE_LOG(ERR, EAL,=0A= > - "%s(): cannot parse offset of %s\n",=0A= > - __func__, dirname);=0A= > - return -1;=0A= > - }=0A= > + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/resource",=0A= > + loc->domain, loc->bus, loc->devid, loc->function);=0A= > =0A= > - /* get mapping size */=0A= > - snprintf(filename, sizeof(filename),=0A= > - "%s/size", dirname);=0A= > - if (pci_parse_sysfs_value(filename, &size) < 0) {=0A= > + f =3D fopen(filename, "r");=0A= > + if (f =3D=3D NULL) {=0A= > RTE_LOG(ERR, EAL,=0A= > - "%s(): cannot parse size of %s\n",=0A= > - __func__, dirname);=0A= > + "%s(): cannot open sysfs %s\n",=0A= > + __func__, filename);=0A= > return -1;=0A= > }=0A= > =0A= > - /* get mapping physical address */=0A= > - snprintf(filename, sizeof(filename),=0A= > - "%s/addr", dirname);=0A= > - if (pci_parse_sysfs_value(filename, &maps[i].phaddr) < 0) {=0A= > - RTE_LOG(ERR, EAL,=0A= > - "%s(): cannot parse addr of %s\n",=0A= > - __func__, dirname);=0A= > - return -1;=0A= > + while (fscanf(f, "%llx %llx %llx", &start_addr,=0A= > + &end_addr, &flags) =3D=3D 3 && i < nb_maps) {=0A= > + if (flags & IORESOURCE_MEM) {=0A= > + maps[i].offset =3D 0x0;=0A= > + maps[i].size =3D end_addr - start_addr + 1;=0A= > + maps[i].phaddr =3D start_addr;=0A= > + i++;=0A= > + }=0A= > }=0A= > + fclose(f);=0A= > + } else {=0A= > + for (i =3D 0; i !=3D nb_maps; i++) {=0A= > + /* check if map directory exists */=0A= > + snprintf(dirname, sizeof(dirname),=0A= > + "%s/maps/map%u", devname, i);=0A= > +=0A= > + if (access(dirname, F_OK) !=3D 0)=0A= > + break;=0A= > +=0A= > + /* get mapping offset */=0A= > + snprintf(filename, sizeof(filename),=0A= > + "%s/offset", dirname);=0A= > + if (pci_parse_sysfs_value(filename, &offset) < 0) {=0A= > + RTE_LOG(ERR, EAL,=0A= > + "%s(): cannot parse offset of %s\n",=0A= > + __func__, dirname);=0A= > + return -1;=0A= > + }=0A= > =0A= > - if ((offset > OFF_MAX) || (size > SIZE_MAX)) {=0A= > - RTE_LOG(ERR, EAL,=0A= > - "%s(): offset/size exceed system max value\n",=0A= > - __func__);=0A= > - return -1;=0A= > - }=0A= > + /* get mapping size */=0A= > + snprintf(filename, sizeof(filename),=0A= > + "%s/size", dirname);=0A= > + if (pci_parse_sysfs_value(filename, &size) < 0) {=0A= > + RTE_LOG(ERR, EAL,=0A= > + "%s(): cannot parse size of %s\n",=0A= > + __func__, dirname);=0A= > + return -1;=0A= > + }=0A= > =0A= > - maps[i].offset =3D offset;=0A= > - maps[i].size =3D size;=0A= > + /* get mapping physical address */=0A= > + snprintf(filename, sizeof(filename),=0A= > + "%s/addr", dirname);=0A= > + if (pci_parse_sysfs_value(filename,=0A= > + &maps[i].phaddr) < 0) {=0A= > + RTE_LOG(ERR, EAL,=0A= > + "%s(): cannot parse addr of %s\n",=0A= > + __func__, dirname);=0A= > + return -1;=0A= > + }=0A= > +=0A= > + if ((offset > OFF_MAX) || (size > SIZE_MAX)) {=0A= > + RTE_LOG(ERR, EAL,=0A= > + "%s(): offset/size exceed system max value\n",=0A= > + __func__);=0A= > + return -1;=0A= > + }=0A= > +=0A= > + maps[i].offset =3D offset;=0A= > + maps[i].size =3D size;=0A= > + }=0A= > }=0A= > =0A= > return i;=0A= > }=0A= > =0A= > static int=0A= > +pci_uio_set_bus_master(int dev_fd)=0A= > +{=0A= > + uint16_t reg;=0A= > + int ret;=0A= > +=0A= > + ret =3D pread(dev_fd, ®, sizeof(reg), PCI_COMMAND);=0A= > + if (ret !=3D sizeof(reg)) {=0A= > + RTE_LOG(ERR, EAL,=0A= > + "Cannot read command from PCI config space!\n");=0A= > + return -1;=0A= > + }=0A= > +=0A= > + reg |=3D PCI_COMMAND_MASTER;=0A= > +=0A= > + ret =3D pwrite(dev_fd, ®, sizeof(reg), PCI_COMMAND);=0A= > + if (ret !=3D sizeof(reg)) {=0A= > + RTE_LOG(ERR, EAL,=0A= > + "Cannot write command to PCI config space!\n");=0A= > + return -1;=0A= > + }=0A= > +=0A= > + return 0;=0A= > +}=0A= > +=0A= > +static int=0A= > pci_uio_map_secondary(struct rte_pci_device *dev)=0A= > {=0A= > int fd, i;=0A= > @@ -210,6 +269,10 @@ pci_get_uio_dev(struct rte_pci_device *dev, char *ds= tbuf,=0A= > struct dirent *e;=0A= > DIR *dir;=0A= > char dirname[PATH_MAX];=0A= > + FILE *f;=0A= > + char fullpath[PATH_MAX];=0A= > + char buf[BUFSIZ];=0A= > + char *s;=0A= > =0A= > /* depending on kernel version, uio can be located in uio/uioX=0A= > * or uio:uioX */=0A= > @@ -265,6 +328,30 @@ pci_get_uio_dev(struct rte_pci_device *dev, char *ds= tbuf,=0A= > if (e =3D=3D NULL)=0A= > return -1;=0A= > =0A= > + /* remember driver name of uio device */=0A= > + snprintf(fullpath, sizeof(fullpath),=0A= > + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio/%s/name" ,=0A= > + loc->domain, loc->bus, loc->devid,=0A= > + loc->function, e->d_name);=0A= > +=0A= > + f =3D fopen(fullpath, "r");=0A= > + if (f =3D=3D NULL) {=0A= > + RTE_LOG(ERR, EAL,=0A= > + "%s(): cannot open sysfs to get driver name\n",=0A= > + __func__);=0A= > + return -1;=0A= > + }=0A= > + s =3D fgets(buf, sizeof(buf), f);=0A= > + if (s =3D=3D NULL) {=0A= > + RTE_LOG(ERR, EAL,=0A= > + "%s(): cannot read sysfs to get driver name\n",=0A= > + __func__);=0A= > + fclose(f);=0A= > + return -1;=0A= > + }=0A= > + strncpy(dev->driver_name, buf, sizeof(buf));=0A= > + fclose(f);=0A= > +=0A= > /* create uio device if we've been asked to */=0A= > if (internal_config.create_uio_dev &&=0A= > pci_mknod_uio_dev(dstbuf, uio_num) < 0)=0A= > @@ -279,6 +366,7 @@ pci_uio_map_resource(struct rte_pci_device *dev)=0A= > {=0A= > int i, j;=0A= > char dirname[PATH_MAX];=0A= > + char cfgname[PATH_MAX];=0A= > char devname[PATH_MAX]; /* contains the /dev/uioX */=0A= > void *mapaddr;=0A= > int uio_num;=0A= > @@ -291,6 +379,7 @@ pci_uio_map_resource(struct rte_pci_device *dev)=0A= > struct pci_map *maps;=0A= > =0A= > dev->intr_handle.fd =3D -1;=0A= > + dev->intr_handle.uio_cfg_fd =3D -1;=0A= > dev->intr_handle.type =3D RTE_INTR_HANDLE_UNKNOWN;=0A= > =0A= > /* secondary processes - use already recorded details */=0A= > @@ -315,6 +404,33 @@ pci_uio_map_resource(struct rte_pci_device *dev)=0A= > }=0A= > dev->intr_handle.type =3D RTE_INTR_HANDLE_UIO;=0A= > =0A= > + snprintf(cfgname, sizeof(cfgname),=0A= > + "/sys/class/uio/uio%u/device/config", uio_num);=0A= > + dev->intr_handle.uio_cfg_fd =3D open(cfgname, O_RDWR);=0A= > + if (dev->intr_handle.uio_cfg_fd < 0) {=0A= > + RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",=0A= > + cfgname, strerror(errno));=0A= > + return -1;=0A= > + }=0A= > +=0A= > + /* handle Misc. stuff for uio_pci_generic */=0A= > + if (strncmp(dev->driver_name, UIO_PCI_GENERIC_NAME,=0A= > + strlen(UIO_PCI_GENERIC_NAME)) =3D=3D 0) {=0A= > + /* update devname for uio_pci_generic */=0A= > + snprintf(devname, sizeof(devname),=0A= > + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/resource%d",=0A= > + loc->domain, loc->bus, loc->devid, loc->function, 0);=0A= > +=0A= > + /* set bus master that is not done by uio_pci_generic */=0A= > + if (rte_eal_process_type() =3D=3D RTE_PROC_PRIMARY) {=0A= > + if (pci_uio_set_bus_master(dev->intr_handle.uio_cfg_fd)) {=0A= > + RTE_LOG(ERR, EAL,=0A= > + "Cannot set up bus mastering!\n");=0A= > + return -1;=0A= > + }=0A= > + }=0A= > + }=0A= > +=0A= > /* allocate the mapping details for secondary processes*/=0A= > uio_res =3D rte_zmalloc("UIO_RES", sizeof(*uio_res), 0);=0A= > if (uio_res =3D=3D NULL) {=0A= > @@ -327,13 +443,12 @@ pci_uio_map_resource(struct rte_pci_device *dev)=0A= > memcpy(&uio_res->pci_addr, &dev->addr, sizeof(uio_res->pci_addr));=0A= > =0A= > /* collect info about device mappings */=0A= > - nb_maps =3D pci_uio_get_mappings(dirname, uio_res->maps,=0A= > - RTE_DIM(uio_res->maps));=0A= > + nb_maps =3D pci_uio_get_mappings(dev, dirname, uio_res->maps,=0A= > + RTE_DIM(uio_res->maps));=0A= > if (nb_maps < 0) {=0A= > rte_free(uio_res);=0A= > return nb_maps;=0A= > }=0A= > -=0A= > uio_res->nb_maps =3D nb_maps;=0A= > =0A= > /* Map all BARs */=0A= > diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.= h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h=0A= > index 23eafd9..151323d 100644=0A= > --- a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h=0A= > +++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_interrupts.h=0A= > @@ -51,6 +51,7 @@ enum rte_intr_handle_type {=0A= > /** Handle for interrupts. */=0A= > struct rte_intr_handle {=0A= > int vfio_dev_fd; /**< VFIO device file descriptor */=0A= > + int uio_cfg_fd; /**< UIO config file descriptor */=0A= > int fd; /**< file descriptor */=0A= > enum rte_intr_handle_type type; /**< handle type */=0A= > };=0A= > diff --git a/tools/dpdk_nic_bind.py b/tools/dpdk_nic_bind.py=0A= > index 812b6a1..2483056 100755=0A= > --- a/tools/dpdk_nic_bind.py=0A= > +++ b/tools/dpdk_nic_bind.py=0A= > @@ -43,7 +43,7 @@ ETHERNET_CLASS =3D "0200"=0A= > # Each device within this is itself a dictionary of device properties=0A= > devices =3D {}=0A= > # list of supported DPDK drivers=0A= > -dpdk_drivers =3D [ "igb_uio", "vfio-pci" ]=0A= > +dpdk_drivers =3D [ "igb_uio", "vfio-pci", "uio_pci_generic" ]=0A= > =0A= > # command-line arg flags=0A= > b_flag =3D None=0A= =0A=