From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <michael.qiu@intel.com>
Received: from mga09.intel.com (mga09.intel.com [134.134.136.24])
 by dpdk.org (Postfix) with ESMTP id AC52E58D2
 for <dev@dpdk.org>; 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" <michael.qiu@intel.com>
To: "Zhou, Danny" <danny.zhou@intel.com>, "dev@dpdk.org" <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 <dev.dpdk.org>
List-Unsubscribe: <http://dpdk.org/ml/options/dev>,
 <mailto:dev-request@dpdk.org?subject=unsubscribe>
List-Archive: <http://dpdk.org/ml/archives/dev/>
List-Post: <mailto:dev@dpdk.org>
List-Help: <mailto:dev-request@dpdk.org?subject=help>
List-Subscribe: <http://dpdk.org/ml/listinfo/dev>,
 <mailto:dev-request@dpdk.org?subject=subscribe>
X-List-Received-Date: Tue, 28 Oct 2014 02:50:04 -0000

Tested-by: Michael Qiu <michael.qiu@intel.com>=0A=
=0A=
=1B$B:_=1B(B 10/28/2014 1:49 AM, Danny Zhou =1B$B<LF;=1B(B:=0A=
> 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 <fcntl.h>=0A=
>  #include <dirent.h>=0A=
>  #include <sys/stat.h>=0A=
> +#include <linux/pci_regs.h>=0A=
>  =0A=
>  #include <rte_log.h>=0A=
>  #include <rte_pci.h>=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, &reg, 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, &reg, 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=