DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 0/4] rework ioport access for virtio
@ 2016-02-05 17:55 David Marchand
  2016-02-05 17:55 ` [dpdk-dev] [PATCH 1/4] virtio/bsd: fix typo David Marchand
                   ` (4 more replies)
  0 siblings, 5 replies; 29+ messages in thread
From: David Marchand @ 2016-02-05 17:55 UTC (permalink / raw)
  To: dev

Introduce a new ioport api in eal to mask all arch / kernel driver specifics.

- rte_eal_pci_ioport_map is responsible for initialising an rte_pci_ioport
  object that is used in subsequent calls, this function must be tweaked per
  architecture and per kernel driver, rte_ioport_t type is architecture
  specific and is used to hide those details to the application,
- rte_eal_pci_ioport_read / rte_eal_pci_ioport_write uses a rte_pci_ioport
  object to read / write those resources,
- rte_eal_pci_ioport_unmap releases resources used by a rte_pci_ioport
  object if necessary.

There is still some more work to ensure intr handle are properly initialized
and released when used in conjonction with rte_eal_map_device() api calls.

For now, only x86 uio / "none" is supported, rte_ioport x86 code has been
excessively simplified to only handle those cases at the moment.
Other archs might want to support both uio / vfio / xxx.

BSD code has been neither run nor compiled, please can someone confirm I did
not break too much stuff ?

virtio legacy code has been updated accordingly.
With this, virtio code should be ready for other archs now.

So in the end, all that is missing for ARM on linux is some vfio update and
implementation of rte_ioport stuff.


Regards, 
-- 
David Marchand

David Marchand (4):
  virtio/bsd: fix typo
  virtio: fix incorrect check when mapping pci resources
  eal: introduce ioport api
  virtio: use ioport api

 drivers/net/virtio/virtio_pci.c                    | 343 ++++-----------------
 drivers/net/virtio/virtio_pci.h                    |  38 +--
 lib/librte_eal/bsdapp/eal/eal_pci.c                |  76 +++++
 lib/librte_eal/bsdapp/eal/rte_eal_version.map      |   4 +
 .../common/include/arch/arm/rte_ioport.h           |  41 +++
 .../common/include/arch/ppc_64/rte_ioport.h        |  41 +++
 .../common/include/arch/tile/rte_ioport.h          |  41 +++
 .../common/include/arch/x86/rte_ioport.h           | 109 +++++++
 lib/librte_eal/common/include/rte_pci.h            |  68 ++++
 lib/librte_eal/linuxapp/eal/eal_pci.c              | 156 ++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci_init.h         |   6 +
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c          |  67 +++-
 lib/librte_eal/linuxapp/eal/eal_pci_vfio.c         |  17 +
 lib/librte_eal/linuxapp/eal/rte_eal_version.map    |   4 +
 14 files changed, 684 insertions(+), 327 deletions(-)
 create mode 100644 lib/librte_eal/common/include/arch/arm/rte_ioport.h
 create mode 100644 lib/librte_eal/common/include/arch/ppc_64/rte_ioport.h
 create mode 100644 lib/librte_eal/common/include/arch/tile/rte_ioport.h
 create mode 100644 lib/librte_eal/common/include/arch/x86/rte_ioport.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH 1/4] virtio/bsd: fix typo
  2016-02-05 17:55 [dpdk-dev] [PATCH 0/4] rework ioport access for virtio David Marchand
@ 2016-02-05 17:55 ` David Marchand
  2016-02-05 17:55 ` [dpdk-dev] [PATCH 2/4] virtio: fix incorrect check when mapping pci resources David Marchand
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 29+ messages in thread
From: David Marchand @ 2016-02-05 17:55 UTC (permalink / raw)
  To: dev

Fixes: c52afa68d763 ("virtio: move left PCI stuff in the right file")
Signed-off-by: David Marchand <david.marchand@6wind.com>
---
 drivers/net/virtio/virtio_pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 4e9928a..cd8b0ae 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -439,7 +439,7 @@ legacy_virtio_resource_init(struct rte_pci_device *pci_dev)
 
 #else
 static int
-legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
+legacy_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
 {
 	/* nic_uio does not enable interrupts, return 0 (false). */
 	return 0;
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH 2/4] virtio: fix incorrect check when mapping pci resources
  2016-02-05 17:55 [dpdk-dev] [PATCH 0/4] rework ioport access for virtio David Marchand
  2016-02-05 17:55 ` [dpdk-dev] [PATCH 1/4] virtio/bsd: fix typo David Marchand
@ 2016-02-05 17:55 ` David Marchand
  2016-02-05 17:55 ` [dpdk-dev] [PATCH 3/4] eal: introduce ioport api David Marchand
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 29+ messages in thread
From: David Marchand @ 2016-02-05 17:55 UTC (permalink / raw)
  To: dev

According to the api, rte_eal_pci_map_device is only successful when returning
0.

Fixes: 6ba1f63b5ab0 ("virtio: support specification 1.0")
Signed-off-by: David Marchand <david.marchand@6wind.com>
---
 drivers/net/virtio/virtio_pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index cd8b0ae..b1610dd 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -795,7 +795,7 @@ virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
 	struct virtio_pci_cap cap;
 	int ret;
 
-	if (rte_eal_pci_map_device(dev) < 0) {
+	if (rte_eal_pci_map_device(dev)) {
 		PMD_INIT_LOG(DEBUG, "failed to map pci device!");
 		return -1;
 	}
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH 3/4] eal: introduce ioport api
  2016-02-05 17:55 [dpdk-dev] [PATCH 0/4] rework ioport access for virtio David Marchand
  2016-02-05 17:55 ` [dpdk-dev] [PATCH 1/4] virtio/bsd: fix typo David Marchand
  2016-02-05 17:55 ` [dpdk-dev] [PATCH 2/4] virtio: fix incorrect check when mapping pci resources David Marchand
@ 2016-02-05 17:55 ` David Marchand
  2016-02-05 17:55 ` [dpdk-dev] [PATCH 4/4] virtio: use " David Marchand
  2016-02-07  7:48 ` [dpdk-dev] [PATCH v2 0/4] rework ioport access for virtio David Marchand
  4 siblings, 0 replies; 29+ messages in thread
From: David Marchand @ 2016-02-05 17:55 UTC (permalink / raw)
  To: dev

Most of the code is inspired on virtio driver.
rte_ioport_t is a arch-specific structure allocated at rte_pci_ioport_map and
release at rte_pci_ioport_unmap.
For x86, this is actually just a ioport number, handled by rte_ioport_xx api.

Signed-off-by: David Marchand <david.marchand@6wind.com>
---
 lib/librte_eal/bsdapp/eal/eal_pci.c                |  76 ++++++++++
 lib/librte_eal/bsdapp/eal/rte_eal_version.map      |   4 +
 .../common/include/arch/arm/rte_ioport.h           |  41 ++++++
 .../common/include/arch/ppc_64/rte_ioport.h        |  41 ++++++
 .../common/include/arch/tile/rte_ioport.h          |  41 ++++++
 .../common/include/arch/x86/rte_ioport.h           | 109 ++++++++++++++
 lib/librte_eal/common/include/rte_pci.h            |  68 +++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c              | 156 +++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci_init.h         |   6 +
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c          |  67 ++++++++-
 lib/librte_eal/linuxapp/eal/eal_pci_vfio.c         |  17 +++
 lib/librte_eal/linuxapp/eal/rte_eal_version.map    |   4 +
 12 files changed, 627 insertions(+), 3 deletions(-)
 create mode 100644 lib/librte_eal/common/include/arch/arm/rte_ioport.h
 create mode 100644 lib/librte_eal/common/include/arch/ppc_64/rte_ioport.h
 create mode 100644 lib/librte_eal/common/include/arch/tile/rte_ioport.h
 create mode 100644 lib/librte_eal/common/include/arch/x86/rte_ioport.h

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 95c32c1..29dd600 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -479,6 +479,82 @@ int rte_eal_pci_write_config(const struct rte_pci_device *dev,
 	return -1;
 }
 
+int
+rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
+		       struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (dev->kdrv) {
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	case RTE_KDRV_NIC_UIO:
+		p->ioport =
+			(rte_ioport_t)(uintptr_t)dev->mem_resource[bar].addr;
+		ret = 0;
+		break;
+#endif
+	default:
+		ret = -1;
+		break;
+	}
+
+	if (!ret)
+		p->dev = dev;
+
+	return ret;
+}
+
+int
+rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (p->dev->kdrv) {
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	case RTE_KDRV_NIC_UIO:
+		ret = 0;
+		break;
+#endif
+	default:
+		ret = -1;
+		break;
+	}
+
+	return ret;
+}
+
+void
+rte_eal_pci_ioport_read(struct rte_pci_ioport *p,
+			void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	/* for x86, as long as this api is called, we suppose that we have a
+	 * valid ioport, so no check and direct call to rte_ioport_xxx */
+	rte_ioport_read(p->ioport, data, len, offset);
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
+void
+rte_eal_pci_ioport_write(struct rte_pci_ioport *p,
+			 const void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	/* for x86, as long as this api is called, we suppose that we have a
+	 * valid ioport, so no check and direct call to rte_ioport_xxx */
+	rte_ioport_write(p->ioport, data, len, offset);
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
 /* Init the PCI EAL subsystem */
 int
 rte_eal_pci_init(void)
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index d8ac7f7..65da300 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -139,6 +139,10 @@ DPDK_2.2 {
 DPDK_2.3 {
 	global:
 
+	rte_eal_pci_ioport_map;
+	rte_eal_pci_ioport_read;
+	rte_eal_pci_ioport_unmap;
+	rte_eal_pci_ioport_write;
 	rte_eal_pci_map_device;
 	rte_eal_pci_unmap_device;
 	rte_cpu_feature_table;
diff --git a/lib/librte_eal/common/include/arch/arm/rte_ioport.h b/lib/librte_eal/common/include/arch/arm/rte_ioport.h
new file mode 100644
index 0000000..c6943fc
--- /dev/null
+++ b/lib/librte_eal/common/include/arch/arm/rte_ioport.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2016 6WIND S.A.
+ *
+ * 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 6WIND S.A. 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 __RTE_IOPORT_ARM_H__
+#define __RTE_IOPORT_ARM_H__
+
+/* FIXME: empty stub, not working on this arch */
+
+typedef unsigned short rte_ioport_t;
+
+#endif
diff --git a/lib/librte_eal/common/include/arch/ppc_64/rte_ioport.h b/lib/librte_eal/common/include/arch/ppc_64/rte_ioport.h
new file mode 100644
index 0000000..c6eb98a
--- /dev/null
+++ b/lib/librte_eal/common/include/arch/ppc_64/rte_ioport.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2016 6WIND S.A.
+ *
+ * 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 6WIND S.A. 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 __RTE_IOPORT_PPC_H__
+#define __RTE_IOPORT_PPC_H__
+
+/* FIXME: empty stub, not working on this arch */
+
+typedef unsigned short rte_ioport_t;
+
+#endif
diff --git a/lib/librte_eal/common/include/arch/tile/rte_ioport.h b/lib/librte_eal/common/include/arch/tile/rte_ioport.h
new file mode 100644
index 0000000..2028db8
--- /dev/null
+++ b/lib/librte_eal/common/include/arch/tile/rte_ioport.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2016 6WIND S.A.
+ *
+ * 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 6WIND S.A. 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 __RTE_IOPORT_TILE_H__
+#define __RTE_IOPORT_TILE_H__
+
+/* FIXME: empty stub, not working on this arch */
+
+typedef unsigned short rte_ioport_t;
+
+#endif
diff --git a/lib/librte_eal/common/include/arch/x86/rte_ioport.h b/lib/librte_eal/common/include/arch/x86/rte_ioport.h
new file mode 100644
index 0000000..1eb3cfc
--- /dev/null
+++ b/lib/librte_eal/common/include/arch/x86/rte_ioport.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2016 6WIND S.A.
+ *
+ * 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 6WIND S.A. 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 __RTE_IOPORT_X86_H__
+#define __RTE_IOPORT_X86_H__
+
+#ifndef __FreeBSD__
+#include <sys/io.h>
+#else
+
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+
+static inline void
+outb_p(unsigned char data, unsigned int port)
+{
+	outb(port, (u_char)data);
+}
+
+static inline void
+outw_p(unsigned short data, unsigned int port)
+{
+	outw(port, (u_short)data);
+}
+
+static inline void
+outl_p(unsigned int data, unsigned int port)
+{
+	outl(port, (u_int)data);
+}
+#endif
+
+typedef unsigned short rte_ioport_t;
+
+static inline void
+rte_ioport_read(const rte_ioport_t port, void *data, size_t len,
+		off_t offset)
+{
+	uint8_t *d;
+	int size;
+	unsigned short reg = port + offset;
+
+	for (d = data; len > 0; d += size, reg += size, len -= size) {
+		if (len >= 4) {
+			size = 4;
+			*(uint32_t *)d = inl(reg);
+		} else if (len >= 2) {
+			size = 2;
+			*(uint16_t *)d = inw(reg);
+		} else {
+			size = 1;
+			*d = inb(reg);
+		}
+	}
+}
+
+static inline void
+rte_ioport_write(rte_ioport_t port, const void *data, size_t len,
+		 off_t offset)
+{
+	const uint8_t *s;
+	int size;
+	unsigned short reg = port + offset;
+
+	for (s = data; len > 0; s += size, reg += size, len -= size) {
+		if (len >= 4) {
+			size = 4;
+			outl_p(*(const uint32_t *)s, reg);
+		} else if (len >= 2) {
+			size = 2;
+			outw_p(*(const uint16_t *)s, reg);
+		} else {
+			size = 1;
+			outb_p(*s, reg);
+		}
+	}
+}
+
+#endif
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 1508ea9..aedb06f 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -83,6 +83,7 @@ extern "C" {
 #include <inttypes.h>
 
 #include <rte_interrupts.h>
+#include <rte_ioport.h>
 
 TAILQ_HEAD(pci_device_list, rte_pci_device); /**< PCI devices in D-linked Q. */
 TAILQ_HEAD(pci_driver_list, rte_pci_driver); /**< PCI drivers in D-linked Q. */
@@ -512,6 +513,73 @@ int rte_eal_pci_read_config(const struct rte_pci_device *device,
 int rte_eal_pci_write_config(const struct rte_pci_device *device,
 			     const void *buf, size_t len, off_t offset);
 
+/**
+ * A structure used to access io resources for a pci device.
+ * rte_ioport_t is arch, os, driver specific, and should not be used outside
+ * of pci ioport api.
+ */
+struct rte_pci_ioport {
+	struct rte_pci_device *dev;
+	rte_ioport_t ioport;
+};
+
+/**
+ * Initialises a rte_pci_ioport object for a pci device io resource.
+ * This object is then used to gain access to those io resources (see below).
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device.
+ *   to use
+ * @param bar
+ *   Index of the io pci resource we want to access.
+ * @param p
+ *   The rte_pci_ioport object to be initialized.
+ * @return
+ *  0 on success, negative on error.
+ */
+int rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
+			   struct rte_pci_ioport *p);
+
+/**
+ * Release any resources used in a rte_pci_ioport object.
+ *
+ * @param p
+ *   The rte_pci_ioport object to be uninitialized.
+ */
+int rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p);
+
+/**
+ * Read from a io pci resource.
+ *
+ * @param p
+ *   The rte_pci_ioport object from which we want to read.
+ * @param data
+ *   A data buffer where the bytes should be read into
+ * @param len
+ *   The length of the data buffer.
+ * @param offset
+ *   The offset into the pci io resource.
+ * TODO: inline ?
+ */
+void rte_eal_pci_ioport_read(struct rte_pci_ioport *p,
+			     void *data, size_t len, off_t offset);
+
+/**
+ * Write to a io pci resource.
+ *
+ * @param p
+ *   The rte_pci_ioport object to which we want to write.
+ * @param data
+ *   A data buffer where the bytes should be read into
+ * @param len
+ *   The length of the data buffer.
+ * @param offset
+ *   The offset into the pci io resource.
+ * TODO: inline ?
+ */
+void rte_eal_pci_ioport_write(struct rte_pci_ioport *p,
+			      const void *data, size_t len, off_t offset);
+
 #ifdef RTE_PCI_CONFIG
 /**
  * Set special config space registers for performance purpose.
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index db947da..7a4d468 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -621,6 +621,162 @@ int rte_eal_pci_write_config(const struct rte_pci_device *device,
 	}
 }
 
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+static int
+pci_ioport_map(struct rte_pci_device *dev, int bar __rte_unused,
+	       rte_ioport_t *p)
+{
+	uint16_t start, end;
+	FILE *fp;
+	char *line = NULL;
+	char pci_id[16];
+	int found = 0;
+	size_t linesz;
+
+	snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT,
+		 dev->addr.domain, dev->addr.bus,
+		 dev->addr.devid, dev->addr.function);
+
+	fp = fopen("/proc/ioports", "r");
+	if (fp == NULL) {
+		RTE_LOG(ERR, EAL, "%s(): can't open ioports\n", __func__);
+		return -1;
+	}
+
+	while (getdelim(&line, &linesz, '\n', fp) > 0) {
+		char *ptr = line;
+		char *left;
+		int n;
+
+		n = strcspn(ptr, ":");
+		ptr[n] = 0;
+		left = &ptr[n + 1];
+
+		while (*left && isspace(*left))
+			left++;
+
+		if (!strncmp(left, pci_id, strlen(pci_id))) {
+			found = 1;
+
+			while (*ptr && isspace(*ptr))
+				ptr++;
+
+			sscanf(ptr, "%04hx-%04hx", &start, &end);
+
+			break;
+		}
+	}
+
+	free(line);
+	fclose(fp);
+
+	if (!found)
+		return -1;
+
+	dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
+	*p = start;
+	RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%x\n", start);
+
+	return 0;
+}
+#endif
+
+int
+rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
+		       struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (dev->kdrv) {
+	case RTE_KDRV_VFIO:
+		ret = -1;
+#ifdef VFIO_PRESENT
+		if (pci_vfio_is_enabled())
+			ret = pci_vfio_ioport_map(dev, bar, &p->ioport);
+#endif
+		break;
+	case RTE_KDRV_IGB_UIO:
+	case RTE_KDRV_UIO_GENERIC:
+		ret = pci_uio_ioport_map(dev, bar, &p->ioport);
+		break;
+	default:
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+		/* special case for x86 ... */
+		ret = pci_ioport_map(dev, bar, &p->ioport);
+#else
+		ret = -1;
+#endif
+		break;
+	}
+
+	if (!ret)
+		p->dev = dev;
+
+	return ret;
+}
+
+int
+rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (p->dev->kdrv) {
+	case RTE_KDRV_VFIO:
+		ret = -1;
+#ifdef VFIO_PRESENT
+		if (pci_vfio_is_enabled())
+			ret = pci_vfio_ioport_unmap(p->dev, &p->ioport);
+#endif
+		break;
+	case RTE_KDRV_IGB_UIO:
+	case RTE_KDRV_UIO_GENERIC:
+		ret = pci_uio_ioport_unmap(p->dev, &p->ioport);
+		break;
+	default:
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+		/* special case for x86 ... nothing to do */
+		ret = 0;
+#else
+		ret = -1;
+#endif
+		break;
+	}
+
+	return ret;
+}
+
+void
+rte_eal_pci_ioport_read(struct rte_pci_ioport *p,
+			void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	/* for x86, as long as this api is called, we suppose that we have a
+	 * valid ioport, so no check and direct call to rte_ioport_xxx */
+	rte_ioport_read(p->ioport, data, len, offset);
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
+void
+rte_eal_pci_ioport_write(struct rte_pci_ioport *p,
+			 const void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	/* for x86, as long as this api is called, we suppose that we have a
+	 * valid ioport, so no check and direct call to rte_ioport_xxx */
+	rte_ioport_write(p->ioport, data, len, offset);
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
 /* Init the PCI EAL subsystem */
 int
 rte_eal_pci_init(void)
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_init.h b/lib/librte_eal/linuxapp/eal/eal_pci_init.h
index a17c708..fdc8c99 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_init.h
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_init.h
@@ -54,6 +54,9 @@ int pci_uio_read_config(const struct rte_intr_handle *intr_handle,
 int pci_uio_write_config(const struct rte_intr_handle *intr_handle,
 			 const void *buf, size_t len, off_t offs);
 
+int pci_uio_ioport_map(struct rte_pci_device *dev, int bar, rte_ioport_t *p);
+int pci_uio_ioport_unmap(struct rte_pci_device *dev, rte_ioport_t *p);
+
 #ifdef VFIO_PRESENT
 
 #define VFIO_MAX_GROUPS 64
@@ -68,6 +71,9 @@ int pci_vfio_read_config(const struct rte_intr_handle *intr_handle,
 int pci_vfio_write_config(const struct rte_intr_handle *intr_handle,
 			  const void *buf, size_t len, off_t offs);
 
+int pci_vfio_ioport_map(struct rte_pci_device *dev, int bar, rte_ioport_t *p);
+int pci_vfio_ioport_unmap(struct rte_pci_device *dev, rte_ioport_t *p);
+
 /* map VFIO resource prototype */
 int pci_vfio_map_resource(struct rte_pci_device *dev);
 int pci_vfio_get_group_fd(int iommu_group_fd);
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index ac50e13..85ed411 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -145,7 +145,7 @@ pci_mknod_uio_dev(const char *sysfs_uio_path, unsigned uio_num)
  */
 static int
 pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
-			   unsigned int buflen)
+			   unsigned int buflen, int create)
 {
 	struct rte_pci_addr *loc = &dev->addr;
 	unsigned int uio_num;
@@ -208,7 +208,7 @@ pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
 		return -1;
 
 	/* create uio device if we've been asked to */
-	if (internal_config.create_uio_dev &&
+	if (internal_config.create_uio_dev && create &&
 			pci_mknod_uio_dev(dstbuf, uio_num) < 0)
 		RTE_LOG(WARNING, EAL, "Cannot create /dev/uio%u\n", uio_num);
 
@@ -245,7 +245,7 @@ pci_uio_alloc_resource(struct rte_pci_device *dev,
 	loc = &dev->addr;
 
 	/* find uio resource */
-	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname));
+	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 1);
 	if (uio_num < 0) {
 		RTE_LOG(WARNING, EAL, "  "PCI_PRI_FMT" not managed by UIO driver, "
 				"skipping\n", loc->domain, loc->bus, loc->devid, loc->function);
@@ -363,3 +363,64 @@ error:
 	rte_free(maps[map_idx].path);
 	return -1;
 }
+
+int
+pci_uio_ioport_map(struct rte_pci_device *dev, int bar, rte_ioport_t *p)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	char dirname[PATH_MAX];
+	char filename[PATH_MAX];
+	int uio_num;
+	unsigned long start;
+
+	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 0);
+	if (uio_num < 0)
+		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;
+	}
+
+	/* FIXME only for primary process ? */
+	if (dev->intr_handle.type == RTE_INTR_HANDLE_UNKNOWN) {
+
+		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;
+		}
+		dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
+	}
+
+	RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%lx\n", start);
+
+	*p = start;
+	return 0;
+#else
+	RTE_SET_USED(dev);
+	RTE_SET_USED(bar);
+	RTE_SET_USED(p);
+	return -1;
+#endif
+}
+
+int
+pci_uio_ioport_unmap(struct rte_pci_device *dev,
+		     rte_ioport_t *p)
+{
+	RTE_SET_USED(dev);
+	RTE_SET_USED(p);
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	/* FIXME close intr fd ? */
+	return 0;
+#else
+	return -1;
+#endif
+}
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c b/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
index a6c7e16..a8b74e1 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
@@ -976,6 +976,23 @@ pci_vfio_map_resource(struct rte_pci_device *dev)
 }
 
 int
+pci_vfio_ioport_map(struct rte_pci_device *dev, int bar, rte_ioport_t *p)
+{
+	RTE_SET_USED(dev);
+	RTE_SET_USED(bar);
+	RTE_SET_USED(p);
+	return -1;
+}
+
+int
+pci_vfio_ioport_unmap(struct rte_pci_device *dev, rte_ioport_t *p)
+{
+	RTE_SET_USED(dev);
+	RTE_SET_USED(p);
+	return -1;
+}
+
+int
 pci_vfio_enable(void)
 {
 	/* initialize group list */
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index 4c09c0b..dea260d 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -142,6 +142,10 @@ DPDK_2.2 {
 DPDK_2.3 {
 	global:
 
+	rte_eal_pci_ioport_map;
+	rte_eal_pci_ioport_read;
+	rte_eal_pci_ioport_unmap;
+	rte_eal_pci_ioport_write;
 	rte_eal_pci_map_device;
 	rte_eal_pci_unmap_device;
 	rte_cpu_feature_table;
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH 4/4] virtio: use ioport api
  2016-02-05 17:55 [dpdk-dev] [PATCH 0/4] rework ioport access for virtio David Marchand
                   ` (2 preceding siblings ...)
  2016-02-05 17:55 ` [dpdk-dev] [PATCH 3/4] eal: introduce ioport api David Marchand
@ 2016-02-05 17:55 ` David Marchand
  2016-02-07  7:48 ` [dpdk-dev] [PATCH v2 0/4] rework ioport access for virtio David Marchand
  4 siblings, 0 replies; 29+ messages in thread
From: David Marchand @ 2016-02-05 17:55 UTC (permalink / raw)
  To: dev

Signed-off-by: David Marchand <david.marchand@6wind.com>
---
 drivers/net/virtio/virtio_pci.c | 339 +++++++---------------------------------
 drivers/net/virtio/virtio_pci.h |  38 +----
 2 files changed, 55 insertions(+), 322 deletions(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index b1610dd..e04c0db 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -49,74 +49,35 @@
 #define PCI_CAPABILITY_LIST	0x34
 #define PCI_CAP_ID_VNDR		0x09
 
-#define VIRTIO_PCI_REG_ADDR(hw, reg) \
-	(unsigned short)((hw)->io_base + (reg))
-
-#define VIRTIO_READ_REG_1(hw, reg) \
-	inb((VIRTIO_PCI_REG_ADDR((hw), (reg))))
-#define VIRTIO_WRITE_REG_1(hw, reg, value) \
-	outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
-
-#define VIRTIO_READ_REG_2(hw, reg) \
-	inw((VIRTIO_PCI_REG_ADDR((hw), (reg))))
-#define VIRTIO_WRITE_REG_2(hw, reg, value) \
-	outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
-
-#define VIRTIO_READ_REG_4(hw, reg) \
-	inl((VIRTIO_PCI_REG_ADDR((hw), (reg))))
-#define VIRTIO_WRITE_REG_4(hw, reg, value) \
-	outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
+/*
+ * The remaining space is defined by each driver as the per-driver
+ * configuration space.
+ */
+#define VIRTIO_PCI_CONFIG(hw) (((hw)->use_msix) ? 24 : 20)
 
 static void
 legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
 		       void *dst, int length)
 {
-	uint64_t off;
-	uint8_t *d;
-	int size;
-
-	off = VIRTIO_PCI_CONFIG(hw) + offset;
-	for (d = dst; length > 0; d += size, off += size, length -= size) {
-		if (length >= 4) {
-			size = 4;
-			*(uint32_t *)d = VIRTIO_READ_REG_4(hw, off);
-		} else if (length >= 2) {
-			size = 2;
-			*(uint16_t *)d = VIRTIO_READ_REG_2(hw, off);
-		} else {
-			size = 1;
-			*d = VIRTIO_READ_REG_1(hw, off);
-		}
-	}
+	rte_eal_pci_ioport_read(&hw->io, dst, length,
+				VIRTIO_PCI_CONFIG(hw) + offset);
 }
 
 static void
 legacy_write_dev_config(struct virtio_hw *hw, size_t offset,
 			const void *src, int length)
 {
-	uint64_t off;
-	const uint8_t *s;
-	int size;
-
-	off = VIRTIO_PCI_CONFIG(hw) + offset;
-	for (s = src; length > 0; s += size, off += size, length -= size) {
-		if (length >= 4) {
-			size = 4;
-			VIRTIO_WRITE_REG_4(hw, off, *(const uint32_t *)s);
-		} else if (length >= 2) {
-			size = 2;
-			VIRTIO_WRITE_REG_2(hw, off, *(const uint16_t *)s);
-		} else {
-			size = 1;
-			VIRTIO_WRITE_REG_1(hw, off, *s);
-		}
-	}
+	rte_eal_pci_ioport_write(&hw->io, src, length,
+				 VIRTIO_PCI_CONFIG(hw) + offset);
 }
 
 static uint64_t
 legacy_get_features(struct virtio_hw *hw)
 {
-	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+	uint64_t dst;
+
+	rte_eal_pci_ioport_read(&hw->io, &dst, 4, VIRTIO_PCI_HOST_FEATURES);
+	return dst;
 }
 
 static void
@@ -127,19 +88,23 @@ legacy_set_features(struct virtio_hw *hw, uint64_t features)
 			"only 32 bit features are allowed for legacy virtio!");
 		return;
 	}
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
+	rte_eal_pci_ioport_write(&hw->io, &features, 4,
+				 VIRTIO_PCI_GUEST_FEATURES);
 }
 
 static uint8_t
 legacy_get_status(struct virtio_hw *hw)
 {
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
+	uint8_t dst;
+
+	rte_eal_pci_ioport_read(&hw->io, &dst, 1, VIRTIO_PCI_STATUS);
+	return dst;
 }
 
 static void
 legacy_set_status(struct virtio_hw *hw, uint8_t status)
 {
-	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+	rte_eal_pci_ioport_write(&hw->io, &status, 1, VIRTIO_PCI_STATUS);
 }
 
 static void
@@ -151,148 +116,63 @@ legacy_reset(struct virtio_hw *hw)
 static uint8_t
 legacy_get_isr(struct virtio_hw *hw)
 {
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+	uint8_t dst;
+
+	rte_eal_pci_ioport_read(&hw->io, &dst, 1, VIRTIO_PCI_ISR);
+	return dst;
 }
 
 /* Enable one vector (0) for Link State Intrerrupt */
 static uint16_t
 legacy_set_config_irq(struct virtio_hw *hw, uint16_t vec)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR, vec);
-	return VIRTIO_READ_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR);
+	uint16_t dst;
+
+	rte_eal_pci_ioport_write(&hw->io, &vec, 2, VIRTIO_MSI_CONFIG_VECTOR);
+	rte_eal_pci_ioport_read(&hw->io, &dst, 2, VIRTIO_MSI_CONFIG_VECTOR);
+	return dst;
 }
 
 static uint16_t
 legacy_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, queue_id);
-	return VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
+	uint16_t dst;
+
+	rte_eal_pci_ioport_write(&hw->io, &queue_id, 2, VIRTIO_PCI_QUEUE_SEL);
+	rte_eal_pci_ioport_read(&hw->io, &dst, 2, VIRTIO_PCI_QUEUE_NUM);
+	return dst;
 }
 
 static void
 legacy_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
+	uint32_t src;
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
-		vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+	rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2,
+			 VIRTIO_PCI_QUEUE_SEL);
+	src = vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
+	rte_eal_pci_ioport_write(&hw->io, &src, 4, VIRTIO_PCI_QUEUE_PFN);
 }
 
 static void
 legacy_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
+	uint32_t src = 0;
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+	rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2,
+			 VIRTIO_PCI_QUEUE_SEL);
+	rte_eal_pci_ioport_write(&hw->io, &src, 4, VIRTIO_PCI_QUEUE_PFN);
 }
 
 static void
 legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
+	rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2,
+			 VIRTIO_PCI_QUEUE_NOTIFY);
 }
 
 #ifdef RTE_EXEC_ENV_LINUXAPP
 static int
-parse_sysfs_value(const char *filename, unsigned long *val)
-{
-	FILE *f;
-	char buf[BUFSIZ];
-	char *end = NULL;
-
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s",
-			     __func__, filename);
-		return -1;
-	}
-
-	if (fgets(buf, sizeof(buf), f) == NULL) {
-		PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s",
-			     __func__, filename);
-		fclose(f);
-		return -1;
-	}
-	*val = strtoul(buf, &end, 0);
-	if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) {
-		PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s",
-			     __func__, filename);
-		fclose(f);
-		return -1;
-	}
-	fclose(f);
-	return 0;
-}
-
-static int
-get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen,
-			unsigned int *uio_num)
-{
-	struct dirent *e;
-	DIR *dir;
-	char dirname[PATH_MAX];
-
-	/*
-	 * depending on kernel version, uio can be located in uio/uioX
-	 * or uio:uioX
-	 */
-	snprintf(dirname, sizeof(dirname),
-		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio",
-		     loc->domain, loc->bus, loc->devid, loc->function);
-	dir = opendir(dirname);
-	if (dir == NULL) {
-		/* retry with the parent directory */
-		snprintf(dirname, sizeof(dirname),
-			     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT,
-			     loc->domain, loc->bus, loc->devid, loc->function);
-		dir = opendir(dirname);
-
-		if (dir == NULL) {
-			PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname);
-			return -1;
-		}
-	}
-
-	/* take the first file starting with "uio" */
-	while ((e = readdir(dir)) != NULL) {
-		/* format could be uio%d ...*/
-		int shortprefix_len = sizeof("uio") - 1;
-		/* ... or uio:uio%d */
-		int longprefix_len = sizeof("uio:uio") - 1;
-		char *endptr;
-
-		if (strncmp(e->d_name, "uio", 3) != 0)
-			continue;
-
-		/* first try uio%d */
-		errno = 0;
-		*uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10);
-		if (errno == 0 && endptr != (e->d_name + shortprefix_len)) {
-			snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num);
-			break;
-		}
-
-		/* then try uio:uio%d */
-		errno = 0;
-		*uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10);
-		if (errno == 0 && endptr != (e->d_name + longprefix_len)) {
-			snprintf(buf, buflen, "%s/uio:uio%u", dirname,
-				     *uio_num);
-			break;
-		}
-	}
-	closedir(dir);
-
-	/* No uio resource found */
-	if (e == NULL) {
-		PMD_INIT_LOG(ERR, "Could not find uio resource");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int
 legacy_virtio_has_msix(const struct rte_pci_addr *loc)
 {
 	DIR *d;
@@ -311,132 +191,20 @@ legacy_virtio_has_msix(const struct rte_pci_addr *loc)
 
 /* Extract I/O port numbers from sysfs */
 static int
-virtio_resource_init_by_uio(struct rte_pci_device *pci_dev)
+legacy_virtio_resource_init(struct rte_pci_device *pci_dev,
+			    struct virtio_hw *hw)
 {
-	char dirname[PATH_MAX];
-	char filename[PATH_MAX];
-	unsigned long start, size;
-	unsigned int uio_num;
-
-	if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0)
-		return -1;
-
-	/* get portio size */
-	snprintf(filename, sizeof(filename),
-		     "%s/portio/port0/size", dirname);
-	if (parse_sysfs_value(filename, &size) < 0) {
-		PMD_INIT_LOG(ERR, "%s(): cannot parse size",
-			     __func__);
-		return -1;
-	}
-
-	/* get portio start */
-	snprintf(filename, sizeof(filename),
-		 "%s/portio/port0/start", dirname);
-	if (parse_sysfs_value(filename, &start) < 0) {
-		PMD_INIT_LOG(ERR, "%s(): cannot parse portio start",
-			     __func__);
+	if (rte_eal_pci_ioport_map(pci_dev, 0, &hw->io) < 0)
 		return -1;
-	}
-	pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start;
-	pci_dev->mem_resource[0].len =  (uint64_t)size;
-	PMD_INIT_LOG(DEBUG,
-		     "PCI Port IO found start=0x%lx with size=0x%lx",
-		     start, size);
-
-	/* save fd */
-	memset(dirname, 0, sizeof(dirname));
-	snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num);
-	pci_dev->intr_handle.fd = open(dirname, O_RDWR);
-	if (pci_dev->intr_handle.fd < 0) {
-		PMD_INIT_LOG(ERR, "Cannot open %s: %s\n",
-			dirname, strerror(errno));
-		return -1;
-	}
-
-	pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
-	pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
-
-	return 0;
-}
-
-/* Extract port I/O numbers from proc/ioports */
-static int
-virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev)
-{
-	uint16_t start, end;
-	int size;
-	FILE *fp;
-	char *line = NULL;
-	char pci_id[16];
-	int found = 0;
-	size_t linesz;
-
-	snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT,
-		 pci_dev->addr.domain,
-		 pci_dev->addr.bus,
-		 pci_dev->addr.devid,
-		 pci_dev->addr.function);
-
-	fp = fopen("/proc/ioports", "r");
-	if (fp == NULL) {
-		PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__);
-		return -1;
-	}
 
-	while (getdelim(&line, &linesz, '\n', fp) > 0) {
-		char *ptr = line;
-		char *left;
-		int n;
-
-		n = strcspn(ptr, ":");
-		ptr[n] = 0;
-		left = &ptr[n + 1];
-
-		while (*left && isspace(*left))
-			left++;
-
-		if (!strncmp(left, pci_id, strlen(pci_id))) {
-			found = 1;
-
-			while (*ptr && isspace(*ptr))
-				ptr++;
-
-			sscanf(ptr, "%04hx-%04hx", &start, &end);
-			size = end - start + 1;
-
-			break;
-		}
-	}
-
-	free(line);
-	fclose(fp);
-
-	if (!found)
-		return -1;
-
-	pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start;
-	pci_dev->mem_resource[0].len =  (uint64_t)size;
-	PMD_INIT_LOG(DEBUG,
-		"PCI Port IO found start=0x%x with size=0x%x",
-		start, size);
-
-	/* can't support lsc interrupt without uio */
-	pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC;
+	if (pci_dev->intr_handle.type != RTE_INTR_HANDLE_UNKNOWN)
+		pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
+	else
+		pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC;
 
 	return 0;
 }
 
-/* Extract I/O port numbers from sysfs */
-static int
-legacy_virtio_resource_init(struct rte_pci_device *pci_dev)
-{
-	if (virtio_resource_init_by_uio(pci_dev) == 0)
-		return 0;
-	else
-		return virtio_resource_init_by_ioports(pci_dev);
-}
-
 #else
 static int
 legacy_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
@@ -882,12 +650,11 @@ vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 	}
 
 	PMD_INIT_LOG(INFO, "trying with legacy virtio pci.");
-	if (legacy_virtio_resource_init(dev) < 0)
+	if (legacy_virtio_resource_init(dev, hw) < 0)
 		return -1;
 
 	hw->vtpci_ops = &legacy_ops;
 	hw->use_msix = legacy_virtio_has_msix(&dev->addr);
-	hw->io_base  = (uint32_t)(uintptr_t)dev->mem_resource[0].addr;
 	hw->modern   = 0;
 
 	return 0;
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index 0544a07..b69785e 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -36,13 +36,7 @@
 
 #include <stdint.h>
 
-#ifdef __FreeBSD__
-#include <sys/types.h>
-#include <machine/cpufunc.h>
-#else
-#include <sys/io.h>
-#endif
-
+#include <rte_pci.h>
 #include <rte_ethdev.h>
 
 struct virtqueue;
@@ -249,7 +243,7 @@ struct virtio_net_config;
 
 struct virtio_hw {
 	struct virtqueue *cvq;
-	uint32_t    io_base;
+	struct rte_pci_ioport io;
 	uint64_t    guest_features;
 	uint32_t    max_tx_queues;
 	uint32_t    max_rx_queues;
@@ -282,12 +276,6 @@ struct virtio_net_config {
 } __attribute__((packed));
 
 /*
- * The remaining space is defined by each driver as the per-driver
- * configuration space.
- */
-#define VIRTIO_PCI_CONFIG(hw) (((hw)->use_msix) ? 24 : 20)
-
-/*
  * How many bits to shift physical queue address written to QUEUE_PFN.
  * 12 is historical, and due to x86 page size.
  */
@@ -296,28 +284,6 @@ struct virtio_net_config {
 /* The alignment to use between consumer and producer parts of vring. */
 #define VIRTIO_PCI_VRING_ALIGN 4096
 
-#ifdef __FreeBSD__
-
-static inline void
-outb_p(unsigned char data, unsigned int port)
-{
-
-	outb(port, (u_char)data);
-}
-
-static inline void
-outw_p(unsigned short data, unsigned int port)
-{
-	outw(port, (u_short)data);
-}
-
-static inline void
-outl_p(unsigned int data, unsigned int port)
-{
-	outl(port, (u_int)data);
-}
-#endif
-
 static inline int
 vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH v2 0/4] rework ioport access for virtio
  2016-02-05 17:55 [dpdk-dev] [PATCH 0/4] rework ioport access for virtio David Marchand
                   ` (3 preceding siblings ...)
  2016-02-05 17:55 ` [dpdk-dev] [PATCH 4/4] virtio: use " David Marchand
@ 2016-02-07  7:48 ` David Marchand
  2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 1/4] virtio/bsd: fix typo David Marchand
                     ` (4 more replies)
  4 siblings, 5 replies; 29+ messages in thread
From: David Marchand @ 2016-02-07  7:48 UTC (permalink / raw)
  To: dev

Introduce a new pci ioport api in eal to mask all arch / kernel driver
specifics.

- rte_eal_pci_ioport_map is responsible for initialising an rte_pci_ioport
  object that is used in subsequent calls, this function must be tweaked per
  architecture and per kernel driver,
- rte_eal_pci_ioport_read / rte_eal_pci_ioport_write uses a rte_pci_ioport
  object to read / write those resources,
- rte_eal_pci_ioport_unmap releases resources used by a rte_pci_ioport
  object if necessary.

There is still some more work to ensure intr handle are properly initialized
and released when used in conjonction with rte_eal_map_device() api calls.

BSD code has been neither run nor compiled, please can someone confirm I did
not break too much stuff ?

virtio legacy code has been updated accordingly.
With this, virtio code should be ready for other archs now.

So in the end, all that is missing on linux is some vfio update for support
of all architectures that have vfio.

Changes since v1:
- dropped rte_ioport and removed the arch headers, if performance is an
  issue, we will see how to enhance this in later patches


Regards, 
-- 
David Marchand

David Marchand (4):
  virtio/bsd: fix typo
  virtio: fix incorrect check when mapping pci resources
  eal: introduce pci ioport api
  virtio: use pci ioport api

 drivers/net/virtio/virtio_pci.c                 | 343 ++++--------------------
 drivers/net/virtio/virtio_pci.h                 |  38 +--
 lib/librte_eal/bsdapp/eal/eal_pci.c             | 135 ++++++++++
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   4 +
 lib/librte_eal/common/include/rte_pci.h         |  67 +++++
 lib/librte_eal/linuxapp/eal/eal_pci.c           | 170 ++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci_init.h      |  16 ++
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c       | 132 ++++++++-
 lib/librte_eal/linuxapp/eal/eal_pci_vfio.c      |  37 +++
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   4 +
 10 files changed, 619 insertions(+), 327 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH v2 1/4] virtio/bsd: fix typo
  2016-02-07  7:48 ` [dpdk-dev] [PATCH v2 0/4] rework ioport access for virtio David Marchand
@ 2016-02-07  7:48   ` David Marchand
  2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 2/4] virtio: fix incorrect check when mapping pci resources David Marchand
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 29+ messages in thread
From: David Marchand @ 2016-02-07  7:48 UTC (permalink / raw)
  To: dev

Fixes: c52afa68d763 ("virtio: move left PCI stuff in the right file")
Signed-off-by: David Marchand <david.marchand@6wind.com>
Acked-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 4e9928a..cd8b0ae 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -439,7 +439,7 @@ legacy_virtio_resource_init(struct rte_pci_device *pci_dev)
 
 #else
 static int
-legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
+legacy_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
 {
 	/* nic_uio does not enable interrupts, return 0 (false). */
 	return 0;
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH v2 2/4] virtio: fix incorrect check when mapping pci resources
  2016-02-07  7:48 ` [dpdk-dev] [PATCH v2 0/4] rework ioport access for virtio David Marchand
  2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 1/4] virtio/bsd: fix typo David Marchand
@ 2016-02-07  7:48   ` David Marchand
  2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 3/4] eal: introduce pci ioport api David Marchand
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 29+ messages in thread
From: David Marchand @ 2016-02-07  7:48 UTC (permalink / raw)
  To: dev

According to the api, rte_eal_pci_map_device is only successful when returning
0.

Fixes: 6ba1f63b5ab0 ("virtio: support specification 1.0")
Signed-off-by: David Marchand <david.marchand@6wind.com>
Acked-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index cd8b0ae..b1610dd 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -795,7 +795,7 @@ virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
 	struct virtio_pci_cap cap;
 	int ret;
 
-	if (rte_eal_pci_map_device(dev) < 0) {
+	if (rte_eal_pci_map_device(dev)) {
 		PMD_INIT_LOG(DEBUG, "failed to map pci device!");
 		return -1;
 	}
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH v2 3/4] eal: introduce pci ioport api
  2016-02-07  7:48 ` [dpdk-dev] [PATCH v2 0/4] rework ioport access for virtio David Marchand
  2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 1/4] virtio/bsd: fix typo David Marchand
  2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 2/4] virtio: fix incorrect check when mapping pci resources David Marchand
@ 2016-02-07  7:48   ` David Marchand
  2016-02-08  5:56     ` Santosh Shukla
  2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 4/4] virtio: use " David Marchand
  2016-02-15 13:24   ` [dpdk-dev] [PATCH v3 0/4] rework ioport access for virtio David Marchand
  4 siblings, 1 reply; 29+ messages in thread
From: David Marchand @ 2016-02-07  7:48 UTC (permalink / raw)
  To: dev

Most of the code is inspired on virtio driver.
rte_pci_ioport structure is filled at map time with anything needed for later
read / write calls.
At the moment, offset field is used to store a x86 ioport (uint16_t) and will
be reused for other arches.

TODO: check multi process, check intr_handle init/exit,

Signed-off-by: David Marchand <david.marchand@6wind.com>
---
Changes since v1:
- dropped rte_ioport and removed the arch headers, if performance is an
  issue, we will see how to enhance this in later patches
- rte_pci_ioport object now reaches driver implementation (uio / vfio)
- sanity checks are in uio map function, no reason to have those checks in
  read/write functions

---
 lib/librte_eal/bsdapp/eal/eal_pci.c             | 135 +++++++++++++++++++
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   4 +
 lib/librte_eal/common/include/rte_pci.h         |  67 ++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c           | 170 ++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci_init.h      |  16 +++
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c       | 132 +++++++++++++++++-
 lib/librte_eal/linuxapp/eal/eal_pci_vfio.c      |  37 ++++++
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   4 +
 8 files changed, 562 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 95c32c1..bda6d78 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -51,6 +51,11 @@
 #include <sys/pciio.h>
 #include <dev/pci/pcireg.h>
 
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+#endif
+
 #include <rte_interrupts.h>
 #include <rte_log.h>
 #include <rte_pci.h>
@@ -479,6 +484,136 @@ int rte_eal_pci_write_config(const struct rte_pci_device *dev,
 	return -1;
 }
 
+int
+rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
+		       struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (dev->kdrv) {
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	case RTE_KDRV_NIC_UIO:
+		if (dev->mem_resource[bar].addr <= UINT16_MAX) {
+			p->offset = dev->mem_resource[bar].addr;
+			ret = 0;
+		} else
+			ret = -1;
+		break;
+#endif
+	default:
+		ret = -1;
+		break;
+	}
+
+	if (!ret)
+		p->dev = dev;
+
+	return ret;
+}
+
+static void
+pci_uio_ioport_read(struct rte_pci_ioport *p,
+		    void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	uint8_t *d;
+	int size;
+	unsigned short reg = p->offset + offset;
+
+	for (d = data; len > 0; d += size, reg += size, len -= size) {
+		if (len >= 4) {
+			size = 4;
+			*(uint32_t *)d = inl(reg);
+		} else if (len >= 2) {
+			size = 2;
+			*(uint16_t *)d = inw(reg);
+		} else {
+			size = 1;
+			*d = inb(reg);
+		}
+	}
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
+void
+rte_eal_pci_ioport_read(struct rte_pci_ioport *p,
+			void *data, size_t len, off_t offset)
+{
+	switch (p->dev->kdrv) {
+	case RTE_KDRV_NIC_UIO:
+		pci_uio_ioport_read(p, data, len, offset);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+pci_uio_ioport_write(struct rte_pci_ioport *p,
+		     const void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	const uint8_t *s;
+	int size;
+	unsigned short reg = p->offset + offset;
+
+	for (s = data; len > 0; s += size, reg += size, len -= size) {
+		if (len >= 4) {
+			size = 4;
+			outl(*(const uint32_t *)s, reg);
+		} else if (len >= 2) {
+			size = 2;
+			outw(*(const uint16_t *)s, reg);
+		} else {
+			size = 1;
+			outb(*s, reg);
+		}
+	}
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
+void
+rte_eal_pci_ioport_write(struct rte_pci_ioport *p,
+			 const void *data, size_t len, off_t offset)
+{
+	switch (p->dev->kdrv) {
+	case RTE_KDRV_NIC_UIO:
+		pci_uio_ioport_write(p, data, len, offset);
+		break;
+	default:
+		break;
+	}
+}
+
+int
+rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (p->dev->kdrv) {
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	case RTE_KDRV_NIC_UIO:
+		ret = 0;
+		break;
+#endif
+	default:
+		ret = -1;
+		break;
+	}
+
+	return ret;
+}
+
 /* Init the PCI EAL subsystem */
 int
 rte_eal_pci_init(void)
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index d8ac7f7..65da300 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -139,6 +139,10 @@ DPDK_2.2 {
 DPDK_2.3 {
 	global:
 
+	rte_eal_pci_ioport_map;
+	rte_eal_pci_ioport_read;
+	rte_eal_pci_ioport_unmap;
+	rte_eal_pci_ioport_write;
 	rte_eal_pci_map_device;
 	rte_eal_pci_unmap_device;
 	rte_cpu_feature_table;
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 1508ea9..87d08b6 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -512,6 +512,73 @@ int rte_eal_pci_read_config(const struct rte_pci_device *device,
 int rte_eal_pci_write_config(const struct rte_pci_device *device,
 			     const void *buf, size_t len, off_t offset);
 
+/**
+ * A structure used to access io resources for a pci device.
+ * rte_ioport_t is arch, os, driver specific, and should not be used outside
+ * of pci ioport api.
+ */
+struct rte_pci_ioport {
+	struct rte_pci_device *dev;
+	uint64_t offset;
+};
+
+/**
+ * Initialises a rte_pci_ioport object for a pci device io resource.
+ * This object is then used to gain access to those io resources (see below).
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device.
+ *   to use
+ * @param bar
+ *   Index of the io pci resource we want to access.
+ * @param p
+ *   The rte_pci_ioport object to be initialized.
+ * @return
+ *  0 on success, negative on error.
+ */
+int rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
+			   struct rte_pci_ioport *p);
+
+/**
+ * Release any resources used in a rte_pci_ioport object.
+ *
+ * @param p
+ *   The rte_pci_ioport object to be uninitialized.
+ */
+int rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p);
+
+/**
+ * Read from a io pci resource.
+ *
+ * @param p
+ *   The rte_pci_ioport object from which we want to read.
+ * @param data
+ *   A data buffer where the bytes should be read into
+ * @param len
+ *   The length of the data buffer.
+ * @param offset
+ *   The offset into the pci io resource.
+ * TODO: inline ?
+ */
+void rte_eal_pci_ioport_read(struct rte_pci_ioport *p,
+			     void *data, size_t len, off_t offset);
+
+/**
+ * Write to a io pci resource.
+ *
+ * @param p
+ *   The rte_pci_ioport object to which we want to write.
+ * @param data
+ *   A data buffer where the bytes should be read into
+ * @param len
+ *   The length of the data buffer.
+ * @param offset
+ *   The offset into the pci io resource.
+ * TODO: inline ?
+ */
+void rte_eal_pci_ioport_write(struct rte_pci_ioport *p,
+			      const void *data, size_t len, off_t offset);
+
 #ifdef RTE_PCI_CONFIG
 /**
  * Set special config space registers for performance purpose.
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index db947da..1b9de1e 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -621,6 +621,176 @@ int rte_eal_pci_write_config(const struct rte_pci_device *device,
 	}
 }
 
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+static int
+pci_ioport_map(struct rte_pci_device *dev, int bar __rte_unused,
+	       struct rte_pci_ioport *p)
+{
+	uint16_t start, end;
+	FILE *fp;
+	char *line = NULL;
+	char pci_id[16];
+	int found = 0;
+	size_t linesz;
+
+	snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT,
+		 dev->addr.domain, dev->addr.bus,
+		 dev->addr.devid, dev->addr.function);
+
+	fp = fopen("/proc/ioports", "r");
+	if (fp == NULL) {
+		RTE_LOG(ERR, EAL, "%s(): can't open ioports\n", __func__);
+		return -1;
+	}
+
+	while (getdelim(&line, &linesz, '\n', fp) > 0) {
+		char *ptr = line;
+		char *left;
+		int n;
+
+		n = strcspn(ptr, ":");
+		ptr[n] = 0;
+		left = &ptr[n + 1];
+
+		while (*left && isspace(*left))
+			left++;
+
+		if (!strncmp(left, pci_id, strlen(pci_id))) {
+			found = 1;
+
+			while (*ptr && isspace(*ptr))
+				ptr++;
+
+			sscanf(ptr, "%04hx-%04hx", &start, &end);
+
+			break;
+		}
+	}
+
+	free(line);
+	fclose(fp);
+
+	if (!found)
+		return -1;
+
+	dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
+	p->offset = start;
+	RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%x\n", start);
+
+	return 0;
+}
+#endif
+
+int
+rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
+		       struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (dev->kdrv) {
+#ifdef VFIO_PRESENT
+	case RTE_KDRV_VFIO:
+		ret = -1;
+		if (pci_vfio_is_enabled())
+			ret = pci_vfio_ioport_map(dev, bar, p);
+		break;
+#endif
+	case RTE_KDRV_IGB_UIO:
+	case RTE_KDRV_UIO_GENERIC:
+		ret = pci_uio_ioport_map(dev, bar, p);
+		break;
+	default:
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+		/* special case for x86 ... */
+		ret = pci_ioport_map(dev, bar, p);
+#else
+		ret = -1;
+#endif
+		break;
+	}
+
+	if (!ret)
+		p->dev = dev;
+
+	return ret;
+}
+
+void
+rte_eal_pci_ioport_read(struct rte_pci_ioport *p,
+			void *data, size_t len, off_t offset)
+{
+	switch (p->dev->kdrv) {
+#ifdef VFIO_PRESENT
+	case RTE_KDRV_VFIO:
+		pci_vfio_ioport_read(p, data, len, offset);
+		break;
+#endif
+	case RTE_KDRV_IGB_UIO:
+	case RTE_KDRV_UIO_GENERIC:
+		pci_uio_ioport_read(p, data, len, offset);
+		break;
+	default:
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+		/* special case for x86 ... */
+		pci_uio_ioport_read(p, data, len, offset);
+#endif
+		break;
+	}
+}
+
+void
+rte_eal_pci_ioport_write(struct rte_pci_ioport *p,
+			 const void *data, size_t len, off_t offset)
+{
+	switch (p->dev->kdrv) {
+#ifdef VFIO_PRESENT
+	case RTE_KDRV_VFIO:
+		pci_vfio_ioport_write(p, data, len, offset);
+		break;
+#endif
+	case RTE_KDRV_IGB_UIO:
+	case RTE_KDRV_UIO_GENERIC:
+		pci_uio_ioport_write(p, data, len, offset);
+		break;
+	default:
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+		/* special case for x86 ... */
+		pci_uio_ioport_write(p, data, len, offset);
+#endif
+		break;
+	}
+}
+
+int
+rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (p->dev->kdrv) {
+#ifdef VFIO_PRESENT
+	case RTE_KDRV_VFIO:
+		ret = -1;
+		if (pci_vfio_is_enabled())
+			ret = pci_vfio_ioport_unmap(p);
+		break;
+#endif
+	case RTE_KDRV_IGB_UIO:
+	case RTE_KDRV_UIO_GENERIC:
+		ret = pci_uio_ioport_unmap(p);
+		break;
+	default:
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+		/* special case for x86 ... nothing to do */
+		ret = 0;
+#else
+		ret = -1;
+#endif
+		break;
+	}
+
+	return ret;
+}
+
 /* Init the PCI EAL subsystem */
 int
 rte_eal_pci_init(void)
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_init.h b/lib/librte_eal/linuxapp/eal/eal_pci_init.h
index a17c708..7011753 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_init.h
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_init.h
@@ -54,6 +54,14 @@ int pci_uio_read_config(const struct rte_intr_handle *intr_handle,
 int pci_uio_write_config(const struct rte_intr_handle *intr_handle,
 			 const void *buf, size_t len, off_t offs);
 
+int pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
+		       struct rte_pci_ioport *p);
+void pci_uio_ioport_read(struct rte_pci_ioport *p,
+			 void *data, size_t len, off_t offset);
+void pci_uio_ioport_write(struct rte_pci_ioport *p,
+			  const void *data, size_t len, off_t offset);
+int pci_uio_ioport_unmap(struct rte_pci_ioport *p);
+
 #ifdef VFIO_PRESENT
 
 #define VFIO_MAX_GROUPS 64
@@ -68,6 +76,14 @@ int pci_vfio_read_config(const struct rte_intr_handle *intr_handle,
 int pci_vfio_write_config(const struct rte_intr_handle *intr_handle,
 			  const void *buf, size_t len, off_t offs);
 
+int pci_vfio_ioport_map(struct rte_pci_device *dev, int bar,
+		        struct rte_pci_ioport *p);
+void pci_vfio_ioport_read(struct rte_pci_ioport *p,
+			  void *data, size_t len, off_t offset);
+void pci_vfio_ioport_write(struct rte_pci_ioport *p,
+			   const void *data, size_t len, off_t offset);
+int pci_vfio_ioport_unmap(struct rte_pci_ioport *p);
+
 /* map VFIO resource prototype */
 int pci_vfio_map_resource(struct rte_pci_device *dev);
 int pci_vfio_get_group_fd(int iommu_group_fd);
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index ac50e13..f891dda 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -39,6 +39,10 @@
 #include <sys/mman.h>
 #include <linux/pci_regs.h>
 
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+#include <sys/io.h>
+#endif
+
 #include <rte_log.h>
 #include <rte_pci.h>
 #include <rte_eal_memconfig.h>
@@ -145,7 +149,7 @@ pci_mknod_uio_dev(const char *sysfs_uio_path, unsigned uio_num)
  */
 static int
 pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
-			   unsigned int buflen)
+			   unsigned int buflen, int create)
 {
 	struct rte_pci_addr *loc = &dev->addr;
 	unsigned int uio_num;
@@ -208,7 +212,7 @@ pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
 		return -1;
 
 	/* create uio device if we've been asked to */
-	if (internal_config.create_uio_dev &&
+	if (internal_config.create_uio_dev && create &&
 			pci_mknod_uio_dev(dstbuf, uio_num) < 0)
 		RTE_LOG(WARNING, EAL, "Cannot create /dev/uio%u\n", uio_num);
 
@@ -245,7 +249,7 @@ pci_uio_alloc_resource(struct rte_pci_device *dev,
 	loc = &dev->addr;
 
 	/* find uio resource */
-	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname));
+	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 1);
 	if (uio_num < 0) {
 		RTE_LOG(WARNING, EAL, "  "PCI_PRI_FMT" not managed by UIO driver, "
 				"skipping\n", loc->domain, loc->bus, loc->devid, loc->function);
@@ -363,3 +367,125 @@ error:
 	rte_free(maps[map_idx].path);
 	return -1;
 }
+
+int
+pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
+		   struct rte_pci_ioport *p)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	char dirname[PATH_MAX];
+	char filename[PATH_MAX];
+	int uio_num;
+	unsigned long start;
+
+	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 0);
+	if (uio_num < 0)
+		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;
+	}
+	/* 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) {
+
+		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;
+		}
+		dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
+	}
+
+	RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%lx\n", start);
+
+	p->offset = start;
+	return 0;
+#else
+	RTE_SET_USED(dev);
+	RTE_SET_USED(bar);
+	RTE_SET_USED(p);
+	return -1;
+#endif
+}
+
+void
+pci_uio_ioport_read(struct rte_pci_ioport *p,
+		    void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	uint8_t *d;
+	int size;
+	unsigned short reg = p->offset + offset;
+
+	for (d = data; len > 0; d += size, reg += size, len -= size) {
+		if (len >= 4) {
+			size = 4;
+			*(uint32_t *)d = inl(reg);
+		} else if (len >= 2) {
+			size = 2;
+			*(uint16_t *)d = inw(reg);
+		} else {
+			size = 1;
+			*d = inb(reg);
+		}
+	}
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
+void
+pci_uio_ioport_write(struct rte_pci_ioport *p,
+		     const void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	const uint8_t *s;
+	int size;
+	unsigned short reg = p->offset + offset;
+
+	for (s = data; len > 0; s += size, reg += size, len -= size) {
+		if (len >= 4) {
+			size = 4;
+			outl_p(*(const uint32_t *)s, reg);
+		} else if (len >= 2) {
+			size = 2;
+			outw_p(*(const uint16_t *)s, reg);
+		} else {
+			size = 1;
+			outb_p(*s, reg);
+		}
+	}
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
+int
+pci_uio_ioport_unmap(struct rte_pci_ioport *p)
+{
+	RTE_SET_USED(p);
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	/* FIXME close intr fd ? */
+	return 0;
+#else
+	return -1;
+#endif
+}
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c b/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
index a6c7e16..ffa2dd0 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
@@ -976,6 +976,43 @@ pci_vfio_map_resource(struct rte_pci_device *dev)
 }
 
 int
+pci_vfio_ioport_map(struct rte_pci_device *dev, int bar,
+		    struct rte_pci_ioport *p)
+{
+	RTE_SET_USED(dev);
+	RTE_SET_USED(bar);
+	RTE_SET_USED(p);
+	return -1;
+}
+
+void
+pci_vfio_ioport_read(struct rte_pci_ioport *p,
+		     void *data, size_t len, off_t offset)
+{
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+}
+
+void
+pci_vfio_ioport_write(struct rte_pci_ioport *p,
+		      const void *data, size_t len, off_t offset)
+{
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+}
+
+int
+pci_vfio_ioport_unmap(struct rte_pci_ioport *p)
+{
+	RTE_SET_USED(p);
+	return -1;
+}
+
+int
 pci_vfio_enable(void)
 {
 	/* initialize group list */
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index 4c09c0b..dea260d 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -142,6 +142,10 @@ DPDK_2.2 {
 DPDK_2.3 {
 	global:
 
+	rte_eal_pci_ioport_map;
+	rte_eal_pci_ioport_read;
+	rte_eal_pci_ioport_unmap;
+	rte_eal_pci_ioport_write;
 	rte_eal_pci_map_device;
 	rte_eal_pci_unmap_device;
 	rte_cpu_feature_table;
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH v2 4/4] virtio: use pci ioport api
  2016-02-07  7:48 ` [dpdk-dev] [PATCH v2 0/4] rework ioport access for virtio David Marchand
                     ` (2 preceding siblings ...)
  2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 3/4] eal: introduce pci ioport api David Marchand
@ 2016-02-07  7:48   ` David Marchand
  2016-02-08  6:01     ` Santosh Shukla
  2016-02-09  3:52     ` Tetsuya Mukawa
  2016-02-15 13:24   ` [dpdk-dev] [PATCH v3 0/4] rework ioport access for virtio David Marchand
  4 siblings, 2 replies; 29+ messages in thread
From: David Marchand @ 2016-02-07  7:48 UTC (permalink / raw)
  To: dev

Move all os / arch specifics to eal.

Signed-off-by: David Marchand <david.marchand@6wind.com>
---
 drivers/net/virtio/virtio_pci.c | 339 +++++++---------------------------------
 drivers/net/virtio/virtio_pci.h |  38 +----
 2 files changed, 55 insertions(+), 322 deletions(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index b1610dd..e04c0db 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -49,74 +49,35 @@
 #define PCI_CAPABILITY_LIST	0x34
 #define PCI_CAP_ID_VNDR		0x09
 
-#define VIRTIO_PCI_REG_ADDR(hw, reg) \
-	(unsigned short)((hw)->io_base + (reg))
-
-#define VIRTIO_READ_REG_1(hw, reg) \
-	inb((VIRTIO_PCI_REG_ADDR((hw), (reg))))
-#define VIRTIO_WRITE_REG_1(hw, reg, value) \
-	outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
-
-#define VIRTIO_READ_REG_2(hw, reg) \
-	inw((VIRTIO_PCI_REG_ADDR((hw), (reg))))
-#define VIRTIO_WRITE_REG_2(hw, reg, value) \
-	outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
-
-#define VIRTIO_READ_REG_4(hw, reg) \
-	inl((VIRTIO_PCI_REG_ADDR((hw), (reg))))
-#define VIRTIO_WRITE_REG_4(hw, reg, value) \
-	outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
+/*
+ * The remaining space is defined by each driver as the per-driver
+ * configuration space.
+ */
+#define VIRTIO_PCI_CONFIG(hw) (((hw)->use_msix) ? 24 : 20)
 
 static void
 legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
 		       void *dst, int length)
 {
-	uint64_t off;
-	uint8_t *d;
-	int size;
-
-	off = VIRTIO_PCI_CONFIG(hw) + offset;
-	for (d = dst; length > 0; d += size, off += size, length -= size) {
-		if (length >= 4) {
-			size = 4;
-			*(uint32_t *)d = VIRTIO_READ_REG_4(hw, off);
-		} else if (length >= 2) {
-			size = 2;
-			*(uint16_t *)d = VIRTIO_READ_REG_2(hw, off);
-		} else {
-			size = 1;
-			*d = VIRTIO_READ_REG_1(hw, off);
-		}
-	}
+	rte_eal_pci_ioport_read(&hw->io, dst, length,
+				VIRTIO_PCI_CONFIG(hw) + offset);
 }
 
 static void
 legacy_write_dev_config(struct virtio_hw *hw, size_t offset,
 			const void *src, int length)
 {
-	uint64_t off;
-	const uint8_t *s;
-	int size;
-
-	off = VIRTIO_PCI_CONFIG(hw) + offset;
-	for (s = src; length > 0; s += size, off += size, length -= size) {
-		if (length >= 4) {
-			size = 4;
-			VIRTIO_WRITE_REG_4(hw, off, *(const uint32_t *)s);
-		} else if (length >= 2) {
-			size = 2;
-			VIRTIO_WRITE_REG_2(hw, off, *(const uint16_t *)s);
-		} else {
-			size = 1;
-			VIRTIO_WRITE_REG_1(hw, off, *s);
-		}
-	}
+	rte_eal_pci_ioport_write(&hw->io, src, length,
+				 VIRTIO_PCI_CONFIG(hw) + offset);
 }
 
 static uint64_t
 legacy_get_features(struct virtio_hw *hw)
 {
-	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+	uint64_t dst;
+
+	rte_eal_pci_ioport_read(&hw->io, &dst, 4, VIRTIO_PCI_HOST_FEATURES);
+	return dst;
 }
 
 static void
@@ -127,19 +88,23 @@ legacy_set_features(struct virtio_hw *hw, uint64_t features)
 			"only 32 bit features are allowed for legacy virtio!");
 		return;
 	}
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
+	rte_eal_pci_ioport_write(&hw->io, &features, 4,
+				 VIRTIO_PCI_GUEST_FEATURES);
 }
 
 static uint8_t
 legacy_get_status(struct virtio_hw *hw)
 {
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
+	uint8_t dst;
+
+	rte_eal_pci_ioport_read(&hw->io, &dst, 1, VIRTIO_PCI_STATUS);
+	return dst;
 }
 
 static void
 legacy_set_status(struct virtio_hw *hw, uint8_t status)
 {
-	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+	rte_eal_pci_ioport_write(&hw->io, &status, 1, VIRTIO_PCI_STATUS);
 }
 
 static void
@@ -151,148 +116,63 @@ legacy_reset(struct virtio_hw *hw)
 static uint8_t
 legacy_get_isr(struct virtio_hw *hw)
 {
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+	uint8_t dst;
+
+	rte_eal_pci_ioport_read(&hw->io, &dst, 1, VIRTIO_PCI_ISR);
+	return dst;
 }
 
 /* Enable one vector (0) for Link State Intrerrupt */
 static uint16_t
 legacy_set_config_irq(struct virtio_hw *hw, uint16_t vec)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR, vec);
-	return VIRTIO_READ_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR);
+	uint16_t dst;
+
+	rte_eal_pci_ioport_write(&hw->io, &vec, 2, VIRTIO_MSI_CONFIG_VECTOR);
+	rte_eal_pci_ioport_read(&hw->io, &dst, 2, VIRTIO_MSI_CONFIG_VECTOR);
+	return dst;
 }
 
 static uint16_t
 legacy_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, queue_id);
-	return VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
+	uint16_t dst;
+
+	rte_eal_pci_ioport_write(&hw->io, &queue_id, 2, VIRTIO_PCI_QUEUE_SEL);
+	rte_eal_pci_ioport_read(&hw->io, &dst, 2, VIRTIO_PCI_QUEUE_NUM);
+	return dst;
 }
 
 static void
 legacy_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
+	uint32_t src;
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
-		vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+	rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2,
+			 VIRTIO_PCI_QUEUE_SEL);
+	src = vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
+	rte_eal_pci_ioport_write(&hw->io, &src, 4, VIRTIO_PCI_QUEUE_PFN);
 }
 
 static void
 legacy_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
+	uint32_t src = 0;
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+	rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2,
+			 VIRTIO_PCI_QUEUE_SEL);
+	rte_eal_pci_ioport_write(&hw->io, &src, 4, VIRTIO_PCI_QUEUE_PFN);
 }
 
 static void
 legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
+	rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2,
+			 VIRTIO_PCI_QUEUE_NOTIFY);
 }
 
 #ifdef RTE_EXEC_ENV_LINUXAPP
 static int
-parse_sysfs_value(const char *filename, unsigned long *val)
-{
-	FILE *f;
-	char buf[BUFSIZ];
-	char *end = NULL;
-
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s",
-			     __func__, filename);
-		return -1;
-	}
-
-	if (fgets(buf, sizeof(buf), f) == NULL) {
-		PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s",
-			     __func__, filename);
-		fclose(f);
-		return -1;
-	}
-	*val = strtoul(buf, &end, 0);
-	if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) {
-		PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s",
-			     __func__, filename);
-		fclose(f);
-		return -1;
-	}
-	fclose(f);
-	return 0;
-}
-
-static int
-get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen,
-			unsigned int *uio_num)
-{
-	struct dirent *e;
-	DIR *dir;
-	char dirname[PATH_MAX];
-
-	/*
-	 * depending on kernel version, uio can be located in uio/uioX
-	 * or uio:uioX
-	 */
-	snprintf(dirname, sizeof(dirname),
-		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio",
-		     loc->domain, loc->bus, loc->devid, loc->function);
-	dir = opendir(dirname);
-	if (dir == NULL) {
-		/* retry with the parent directory */
-		snprintf(dirname, sizeof(dirname),
-			     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT,
-			     loc->domain, loc->bus, loc->devid, loc->function);
-		dir = opendir(dirname);
-
-		if (dir == NULL) {
-			PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname);
-			return -1;
-		}
-	}
-
-	/* take the first file starting with "uio" */
-	while ((e = readdir(dir)) != NULL) {
-		/* format could be uio%d ...*/
-		int shortprefix_len = sizeof("uio") - 1;
-		/* ... or uio:uio%d */
-		int longprefix_len = sizeof("uio:uio") - 1;
-		char *endptr;
-
-		if (strncmp(e->d_name, "uio", 3) != 0)
-			continue;
-
-		/* first try uio%d */
-		errno = 0;
-		*uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10);
-		if (errno == 0 && endptr != (e->d_name + shortprefix_len)) {
-			snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num);
-			break;
-		}
-
-		/* then try uio:uio%d */
-		errno = 0;
-		*uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10);
-		if (errno == 0 && endptr != (e->d_name + longprefix_len)) {
-			snprintf(buf, buflen, "%s/uio:uio%u", dirname,
-				     *uio_num);
-			break;
-		}
-	}
-	closedir(dir);
-
-	/* No uio resource found */
-	if (e == NULL) {
-		PMD_INIT_LOG(ERR, "Could not find uio resource");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int
 legacy_virtio_has_msix(const struct rte_pci_addr *loc)
 {
 	DIR *d;
@@ -311,132 +191,20 @@ legacy_virtio_has_msix(const struct rte_pci_addr *loc)
 
 /* Extract I/O port numbers from sysfs */
 static int
-virtio_resource_init_by_uio(struct rte_pci_device *pci_dev)
+legacy_virtio_resource_init(struct rte_pci_device *pci_dev,
+			    struct virtio_hw *hw)
 {
-	char dirname[PATH_MAX];
-	char filename[PATH_MAX];
-	unsigned long start, size;
-	unsigned int uio_num;
-
-	if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0)
-		return -1;
-
-	/* get portio size */
-	snprintf(filename, sizeof(filename),
-		     "%s/portio/port0/size", dirname);
-	if (parse_sysfs_value(filename, &size) < 0) {
-		PMD_INIT_LOG(ERR, "%s(): cannot parse size",
-			     __func__);
-		return -1;
-	}
-
-	/* get portio start */
-	snprintf(filename, sizeof(filename),
-		 "%s/portio/port0/start", dirname);
-	if (parse_sysfs_value(filename, &start) < 0) {
-		PMD_INIT_LOG(ERR, "%s(): cannot parse portio start",
-			     __func__);
+	if (rte_eal_pci_ioport_map(pci_dev, 0, &hw->io) < 0)
 		return -1;
-	}
-	pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start;
-	pci_dev->mem_resource[0].len =  (uint64_t)size;
-	PMD_INIT_LOG(DEBUG,
-		     "PCI Port IO found start=0x%lx with size=0x%lx",
-		     start, size);
-
-	/* save fd */
-	memset(dirname, 0, sizeof(dirname));
-	snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num);
-	pci_dev->intr_handle.fd = open(dirname, O_RDWR);
-	if (pci_dev->intr_handle.fd < 0) {
-		PMD_INIT_LOG(ERR, "Cannot open %s: %s\n",
-			dirname, strerror(errno));
-		return -1;
-	}
-
-	pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
-	pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
-
-	return 0;
-}
-
-/* Extract port I/O numbers from proc/ioports */
-static int
-virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev)
-{
-	uint16_t start, end;
-	int size;
-	FILE *fp;
-	char *line = NULL;
-	char pci_id[16];
-	int found = 0;
-	size_t linesz;
-
-	snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT,
-		 pci_dev->addr.domain,
-		 pci_dev->addr.bus,
-		 pci_dev->addr.devid,
-		 pci_dev->addr.function);
-
-	fp = fopen("/proc/ioports", "r");
-	if (fp == NULL) {
-		PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__);
-		return -1;
-	}
 
-	while (getdelim(&line, &linesz, '\n', fp) > 0) {
-		char *ptr = line;
-		char *left;
-		int n;
-
-		n = strcspn(ptr, ":");
-		ptr[n] = 0;
-		left = &ptr[n + 1];
-
-		while (*left && isspace(*left))
-			left++;
-
-		if (!strncmp(left, pci_id, strlen(pci_id))) {
-			found = 1;
-
-			while (*ptr && isspace(*ptr))
-				ptr++;
-
-			sscanf(ptr, "%04hx-%04hx", &start, &end);
-			size = end - start + 1;
-
-			break;
-		}
-	}
-
-	free(line);
-	fclose(fp);
-
-	if (!found)
-		return -1;
-
-	pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start;
-	pci_dev->mem_resource[0].len =  (uint64_t)size;
-	PMD_INIT_LOG(DEBUG,
-		"PCI Port IO found start=0x%x with size=0x%x",
-		start, size);
-
-	/* can't support lsc interrupt without uio */
-	pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC;
+	if (pci_dev->intr_handle.type != RTE_INTR_HANDLE_UNKNOWN)
+		pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
+	else
+		pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC;
 
 	return 0;
 }
 
-/* Extract I/O port numbers from sysfs */
-static int
-legacy_virtio_resource_init(struct rte_pci_device *pci_dev)
-{
-	if (virtio_resource_init_by_uio(pci_dev) == 0)
-		return 0;
-	else
-		return virtio_resource_init_by_ioports(pci_dev);
-}
-
 #else
 static int
 legacy_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
@@ -882,12 +650,11 @@ vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 	}
 
 	PMD_INIT_LOG(INFO, "trying with legacy virtio pci.");
-	if (legacy_virtio_resource_init(dev) < 0)
+	if (legacy_virtio_resource_init(dev, hw) < 0)
 		return -1;
 
 	hw->vtpci_ops = &legacy_ops;
 	hw->use_msix = legacy_virtio_has_msix(&dev->addr);
-	hw->io_base  = (uint32_t)(uintptr_t)dev->mem_resource[0].addr;
 	hw->modern   = 0;
 
 	return 0;
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index 0544a07..b69785e 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -36,13 +36,7 @@
 
 #include <stdint.h>
 
-#ifdef __FreeBSD__
-#include <sys/types.h>
-#include <machine/cpufunc.h>
-#else
-#include <sys/io.h>
-#endif
-
+#include <rte_pci.h>
 #include <rte_ethdev.h>
 
 struct virtqueue;
@@ -249,7 +243,7 @@ struct virtio_net_config;
 
 struct virtio_hw {
 	struct virtqueue *cvq;
-	uint32_t    io_base;
+	struct rte_pci_ioport io;
 	uint64_t    guest_features;
 	uint32_t    max_tx_queues;
 	uint32_t    max_rx_queues;
@@ -282,12 +276,6 @@ struct virtio_net_config {
 } __attribute__((packed));
 
 /*
- * The remaining space is defined by each driver as the per-driver
- * configuration space.
- */
-#define VIRTIO_PCI_CONFIG(hw) (((hw)->use_msix) ? 24 : 20)
-
-/*
  * How many bits to shift physical queue address written to QUEUE_PFN.
  * 12 is historical, and due to x86 page size.
  */
@@ -296,28 +284,6 @@ struct virtio_net_config {
 /* The alignment to use between consumer and producer parts of vring. */
 #define VIRTIO_PCI_VRING_ALIGN 4096
 
-#ifdef __FreeBSD__
-
-static inline void
-outb_p(unsigned char data, unsigned int port)
-{
-
-	outb(port, (u_char)data);
-}
-
-static inline void
-outw_p(unsigned short data, unsigned int port)
-{
-	outw(port, (u_short)data);
-}
-
-static inline void
-outl_p(unsigned int data, unsigned int port)
-{
-	outl(port, (u_int)data);
-}
-#endif
-
 static inline int
 vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [dpdk-dev] [PATCH v2 3/4] eal: introduce pci ioport api
  2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 3/4] eal: introduce pci ioport api David Marchand
@ 2016-02-08  5:56     ` Santosh Shukla
  0 siblings, 0 replies; 29+ messages in thread
From: Santosh Shukla @ 2016-02-08  5:56 UTC (permalink / raw)
  To: David Marchand; +Cc: dev

On Sun, Feb 7, 2016 at 1:18 PM, David Marchand <david.marchand@6wind.com> wrote:
> Most of the code is inspired on virtio driver.
> rte_pci_ioport structure is filled at map time with anything needed for later
> read / write calls.
> At the moment, offset field is used to store a x86 ioport (uint16_t) and will
> be reused for other arches.
>
> TODO: check multi process, check intr_handle init/exit,
>
> Signed-off-by: David Marchand <david.marchand@6wind.com>
> ---
> Changes since v1:
> - dropped rte_ioport and removed the arch headers, if performance is an
>   issue, we will see how to enhance this in later patches
> - rte_pci_ioport object now reaches driver implementation (uio / vfio)
> - sanity checks are in uio map function, no reason to have those checks in
>   read/write functions
>

Looks okay to me.

Reviewed-by: Santosh Shukla <sshukla@mvista.com>

Tested for arm64/x86_64 for vfio mode...so..
Tested-by: Santosh Shukla <sshukla@mvista.com>

> ---
>  lib/librte_eal/bsdapp/eal/eal_pci.c             | 135 +++++++++++++++++++
>  lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   4 +
>  lib/librte_eal/common/include/rte_pci.h         |  67 ++++++++++
>  lib/librte_eal/linuxapp/eal/eal_pci.c           | 170 ++++++++++++++++++++++++
>  lib/librte_eal/linuxapp/eal/eal_pci_init.h      |  16 +++
>  lib/librte_eal/linuxapp/eal/eal_pci_uio.c       | 132 +++++++++++++++++-
>  lib/librte_eal/linuxapp/eal/eal_pci_vfio.c      |  37 ++++++
>  lib/librte_eal/linuxapp/eal/rte_eal_version.map |   4 +
>  8 files changed, 562 insertions(+), 3 deletions(-)
>
> diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
> index 95c32c1..bda6d78 100644
> --- a/lib/librte_eal/bsdapp/eal/eal_pci.c
> +++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
> @@ -51,6 +51,11 @@
>  #include <sys/pciio.h>
>  #include <dev/pci/pcireg.h>
>
> +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
> +#include <sys/types.h>
> +#include <machine/cpufunc.h>
> +#endif
> +
>  #include <rte_interrupts.h>
>  #include <rte_log.h>
>  #include <rte_pci.h>
> @@ -479,6 +484,136 @@ int rte_eal_pci_write_config(const struct rte_pci_device *dev,
>         return -1;
>  }
>
> +int
> +rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
> +                      struct rte_pci_ioport *p)
> +{
> +       int ret;
> +
> +       switch (dev->kdrv) {
> +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
> +       case RTE_KDRV_NIC_UIO:
> +               if (dev->mem_resource[bar].addr <= UINT16_MAX) {
> +                       p->offset = dev->mem_resource[bar].addr;
> +                       ret = 0;
> +               } else
> +                       ret = -1;
> +               break;
> +#endif
> +       default:
> +               ret = -1;
> +               break;
> +       }
> +
> +       if (!ret)
> +               p->dev = dev;
> +
> +       return ret;
> +}
> +
> +static void
> +pci_uio_ioport_read(struct rte_pci_ioport *p,
> +                   void *data, size_t len, off_t offset)
> +{
> +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
> +       uint8_t *d;
> +       int size;
> +       unsigned short reg = p->offset + offset;
> +
> +       for (d = data; len > 0; d += size, reg += size, len -= size) {
> +               if (len >= 4) {
> +                       size = 4;
> +                       *(uint32_t *)d = inl(reg);
> +               } else if (len >= 2) {
> +                       size = 2;
> +                       *(uint16_t *)d = inw(reg);
> +               } else {
> +                       size = 1;
> +                       *d = inb(reg);
> +               }
> +       }
> +#else
> +       RTE_SET_USED(p);
> +       RTE_SET_USED(data);
> +       RTE_SET_USED(len);
> +       RTE_SET_USED(offset);
> +#endif
> +}
> +
> +void
> +rte_eal_pci_ioport_read(struct rte_pci_ioport *p,
> +                       void *data, size_t len, off_t offset)
> +{
> +       switch (p->dev->kdrv) {
> +       case RTE_KDRV_NIC_UIO:
> +               pci_uio_ioport_read(p, data, len, offset);
> +               break;
> +       default:
> +               break;
> +       }
> +}
> +
> +static void
> +pci_uio_ioport_write(struct rte_pci_ioport *p,
> +                    const void *data, size_t len, off_t offset)
> +{
> +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
> +       const uint8_t *s;
> +       int size;
> +       unsigned short reg = p->offset + offset;
> +
> +       for (s = data; len > 0; s += size, reg += size, len -= size) {
> +               if (len >= 4) {
> +                       size = 4;
> +                       outl(*(const uint32_t *)s, reg);
> +               } else if (len >= 2) {
> +                       size = 2;
> +                       outw(*(const uint16_t *)s, reg);
> +               } else {
> +                       size = 1;
> +                       outb(*s, reg);
> +               }
> +       }
> +#else
> +       RTE_SET_USED(p);
> +       RTE_SET_USED(data);
> +       RTE_SET_USED(len);
> +       RTE_SET_USED(offset);
> +#endif
> +}
> +
> +void
> +rte_eal_pci_ioport_write(struct rte_pci_ioport *p,
> +                        const void *data, size_t len, off_t offset)
> +{
> +       switch (p->dev->kdrv) {
> +       case RTE_KDRV_NIC_UIO:
> +               pci_uio_ioport_write(p, data, len, offset);
> +               break;
> +       default:
> +               break;
> +       }
> +}
> +
> +int
> +rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p)
> +{
> +       int ret;
> +
> +       switch (p->dev->kdrv) {
> +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
> +       case RTE_KDRV_NIC_UIO:
> +               ret = 0;
> +               break;
> +#endif
> +       default:
> +               ret = -1;
> +               break;
> +       }
> +
> +       return ret;
> +}
> +
>  /* Init the PCI EAL subsystem */
>  int
>  rte_eal_pci_init(void)
> diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
> index d8ac7f7..65da300 100644
> --- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
> +++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
> @@ -139,6 +139,10 @@ DPDK_2.2 {
>  DPDK_2.3 {
>         global:
>
> +       rte_eal_pci_ioport_map;
> +       rte_eal_pci_ioport_read;
> +       rte_eal_pci_ioport_unmap;
> +       rte_eal_pci_ioport_write;
>         rte_eal_pci_map_device;
>         rte_eal_pci_unmap_device;
>         rte_cpu_feature_table;
> diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
> index 1508ea9..87d08b6 100644
> --- a/lib/librte_eal/common/include/rte_pci.h
> +++ b/lib/librte_eal/common/include/rte_pci.h
> @@ -512,6 +512,73 @@ int rte_eal_pci_read_config(const struct rte_pci_device *device,
>  int rte_eal_pci_write_config(const struct rte_pci_device *device,
>                              const void *buf, size_t len, off_t offset);
>
> +/**
> + * A structure used to access io resources for a pci device.
> + * rte_ioport_t is arch, os, driver specific, and should not be used outside
> + * of pci ioport api.
> + */
> +struct rte_pci_ioport {
> +       struct rte_pci_device *dev;
> +       uint64_t offset;
> +};
> +
> +/**
> + * Initialises a rte_pci_ioport object for a pci device io resource.
> + * This object is then used to gain access to those io resources (see below).
> + *
> + * @param dev
> + *   A pointer to a rte_pci_device structure describing the device.
> + *   to use
> + * @param bar
> + *   Index of the io pci resource we want to access.
> + * @param p
> + *   The rte_pci_ioport object to be initialized.
> + * @return
> + *  0 on success, negative on error.
> + */
> +int rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
> +                          struct rte_pci_ioport *p);
> +
> +/**
> + * Release any resources used in a rte_pci_ioport object.
> + *
> + * @param p
> + *   The rte_pci_ioport object to be uninitialized.
> + */
> +int rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p);
> +
> +/**
> + * Read from a io pci resource.
> + *
> + * @param p
> + *   The rte_pci_ioport object from which we want to read.
> + * @param data
> + *   A data buffer where the bytes should be read into
> + * @param len
> + *   The length of the data buffer.
> + * @param offset
> + *   The offset into the pci io resource.
> + * TODO: inline ?
> + */
> +void rte_eal_pci_ioport_read(struct rte_pci_ioport *p,
> +                            void *data, size_t len, off_t offset);
> +
> +/**
> + * Write to a io pci resource.
> + *
> + * @param p
> + *   The rte_pci_ioport object to which we want to write.
> + * @param data
> + *   A data buffer where the bytes should be read into
> + * @param len
> + *   The length of the data buffer.
> + * @param offset
> + *   The offset into the pci io resource.
> + * TODO: inline ?
> + */
> +void rte_eal_pci_ioport_write(struct rte_pci_ioport *p,
> +                             const void *data, size_t len, off_t offset);
> +
>  #ifdef RTE_PCI_CONFIG
>  /**
>   * Set special config space registers for performance purpose.
> diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
> index db947da..1b9de1e 100644
> --- a/lib/librte_eal/linuxapp/eal/eal_pci.c
> +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
> @@ -621,6 +621,176 @@ int rte_eal_pci_write_config(const struct rte_pci_device *device,
>         }
>  }
>
> +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
> +static int
> +pci_ioport_map(struct rte_pci_device *dev, int bar __rte_unused,
> +              struct rte_pci_ioport *p)
> +{
> +       uint16_t start, end;
> +       FILE *fp;
> +       char *line = NULL;
> +       char pci_id[16];
> +       int found = 0;
> +       size_t linesz;
> +
> +       snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT,
> +                dev->addr.domain, dev->addr.bus,
> +                dev->addr.devid, dev->addr.function);
> +
> +       fp = fopen("/proc/ioports", "r");
> +       if (fp == NULL) {
> +               RTE_LOG(ERR, EAL, "%s(): can't open ioports\n", __func__);
> +               return -1;
> +       }
> +
> +       while (getdelim(&line, &linesz, '\n', fp) > 0) {
> +               char *ptr = line;
> +               char *left;
> +               int n;
> +
> +               n = strcspn(ptr, ":");
> +               ptr[n] = 0;
> +               left = &ptr[n + 1];
> +
> +               while (*left && isspace(*left))
> +                       left++;
> +
> +               if (!strncmp(left, pci_id, strlen(pci_id))) {
> +                       found = 1;
> +
> +                       while (*ptr && isspace(*ptr))
> +                               ptr++;
> +
> +                       sscanf(ptr, "%04hx-%04hx", &start, &end);
> +
> +                       break;
> +               }
> +       }
> +
> +       free(line);
> +       fclose(fp);
> +
> +       if (!found)
> +               return -1;
> +
> +       dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
> +       p->offset = start;
> +       RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%x\n", start);
> +
> +       return 0;
> +}
> +#endif
> +
> +int
> +rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
> +                      struct rte_pci_ioport *p)
> +{
> +       int ret;
> +
> +       switch (dev->kdrv) {
> +#ifdef VFIO_PRESENT
> +       case RTE_KDRV_VFIO:
> +               ret = -1;
> +               if (pci_vfio_is_enabled())
> +                       ret = pci_vfio_ioport_map(dev, bar, p);
> +               break;
> +#endif
> +       case RTE_KDRV_IGB_UIO:
> +       case RTE_KDRV_UIO_GENERIC:
> +               ret = pci_uio_ioport_map(dev, bar, p);
> +               break;
> +       default:
> +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
> +               /* special case for x86 ... */
> +               ret = pci_ioport_map(dev, bar, p);
> +#else
> +               ret = -1;
> +#endif
> +               break;
> +       }
> +
> +       if (!ret)
> +               p->dev = dev;
> +
> +       return ret;
> +}
> +
> +void
> +rte_eal_pci_ioport_read(struct rte_pci_ioport *p,
> +                       void *data, size_t len, off_t offset)
> +{
> +       switch (p->dev->kdrv) {
> +#ifdef VFIO_PRESENT
> +       case RTE_KDRV_VFIO:
> +               pci_vfio_ioport_read(p, data, len, offset);
> +               break;
> +#endif
> +       case RTE_KDRV_IGB_UIO:
> +       case RTE_KDRV_UIO_GENERIC:
> +               pci_uio_ioport_read(p, data, len, offset);
> +               break;
> +       default:
> +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
> +               /* special case for x86 ... */
> +               pci_uio_ioport_read(p, data, len, offset);
> +#endif
> +               break;
> +       }
> +}
> +
> +void
> +rte_eal_pci_ioport_write(struct rte_pci_ioport *p,
> +                        const void *data, size_t len, off_t offset)
> +{
> +       switch (p->dev->kdrv) {
> +#ifdef VFIO_PRESENT
> +       case RTE_KDRV_VFIO:
> +               pci_vfio_ioport_write(p, data, len, offset);
> +               break;
> +#endif
> +       case RTE_KDRV_IGB_UIO:
> +       case RTE_KDRV_UIO_GENERIC:
> +               pci_uio_ioport_write(p, data, len, offset);
> +               break;
> +       default:
> +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
> +               /* special case for x86 ... */
> +               pci_uio_ioport_write(p, data, len, offset);
> +#endif
> +               break;
> +       }
> +}
> +
> +int
> +rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p)
> +{
> +       int ret;
> +
> +       switch (p->dev->kdrv) {
> +#ifdef VFIO_PRESENT
> +       case RTE_KDRV_VFIO:
> +               ret = -1;
> +               if (pci_vfio_is_enabled())
> +                       ret = pci_vfio_ioport_unmap(p);
> +               break;
> +#endif
> +       case RTE_KDRV_IGB_UIO:
> +       case RTE_KDRV_UIO_GENERIC:
> +               ret = pci_uio_ioport_unmap(p);
> +               break;
> +       default:
> +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
> +               /* special case for x86 ... nothing to do */
> +               ret = 0;
> +#else
> +               ret = -1;
> +#endif
> +               break;
> +       }
> +
> +       return ret;
> +}
> +
>  /* Init the PCI EAL subsystem */
>  int
>  rte_eal_pci_init(void)
> diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_init.h b/lib/librte_eal/linuxapp/eal/eal_pci_init.h
> index a17c708..7011753 100644
> --- a/lib/librte_eal/linuxapp/eal/eal_pci_init.h
> +++ b/lib/librte_eal/linuxapp/eal/eal_pci_init.h
> @@ -54,6 +54,14 @@ int pci_uio_read_config(const struct rte_intr_handle *intr_handle,
>  int pci_uio_write_config(const struct rte_intr_handle *intr_handle,
>                          const void *buf, size_t len, off_t offs);
>
> +int pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
> +                      struct rte_pci_ioport *p);
> +void pci_uio_ioport_read(struct rte_pci_ioport *p,
> +                        void *data, size_t len, off_t offset);
> +void pci_uio_ioport_write(struct rte_pci_ioport *p,
> +                         const void *data, size_t len, off_t offset);
> +int pci_uio_ioport_unmap(struct rte_pci_ioport *p);
> +
>  #ifdef VFIO_PRESENT
>
>  #define VFIO_MAX_GROUPS 64
> @@ -68,6 +76,14 @@ int pci_vfio_read_config(const struct rte_intr_handle *intr_handle,
>  int pci_vfio_write_config(const struct rte_intr_handle *intr_handle,
>                           const void *buf, size_t len, off_t offs);
>
> +int pci_vfio_ioport_map(struct rte_pci_device *dev, int bar,
> +                       struct rte_pci_ioport *p);
> +void pci_vfio_ioport_read(struct rte_pci_ioport *p,
> +                         void *data, size_t len, off_t offset);
> +void pci_vfio_ioport_write(struct rte_pci_ioport *p,
> +                          const void *data, size_t len, off_t offset);
> +int pci_vfio_ioport_unmap(struct rte_pci_ioport *p);
> +
>  /* map VFIO resource prototype */
>  int pci_vfio_map_resource(struct rte_pci_device *dev);
>  int pci_vfio_get_group_fd(int iommu_group_fd);
> diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
> index ac50e13..f891dda 100644
> --- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
> +++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
> @@ -39,6 +39,10 @@
>  #include <sys/mman.h>
>  #include <linux/pci_regs.h>
>
> +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
> +#include <sys/io.h>
> +#endif
> +
>  #include <rte_log.h>
>  #include <rte_pci.h>
>  #include <rte_eal_memconfig.h>
> @@ -145,7 +149,7 @@ pci_mknod_uio_dev(const char *sysfs_uio_path, unsigned uio_num)
>   */
>  static int
>  pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
> -                          unsigned int buflen)
> +                          unsigned int buflen, int create)
>  {
>         struct rte_pci_addr *loc = &dev->addr;
>         unsigned int uio_num;
> @@ -208,7 +212,7 @@ pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
>                 return -1;
>
>         /* create uio device if we've been asked to */
> -       if (internal_config.create_uio_dev &&
> +       if (internal_config.create_uio_dev && create &&
>                         pci_mknod_uio_dev(dstbuf, uio_num) < 0)
>                 RTE_LOG(WARNING, EAL, "Cannot create /dev/uio%u\n", uio_num);
>
> @@ -245,7 +249,7 @@ pci_uio_alloc_resource(struct rte_pci_device *dev,
>         loc = &dev->addr;
>
>         /* find uio resource */
> -       uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname));
> +       uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 1);
>         if (uio_num < 0) {
>                 RTE_LOG(WARNING, EAL, "  "PCI_PRI_FMT" not managed by UIO driver, "
>                                 "skipping\n", loc->domain, loc->bus, loc->devid, loc->function);
> @@ -363,3 +367,125 @@ error:
>         rte_free(maps[map_idx].path);
>         return -1;
>  }
> +
> +int
> +pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
> +                  struct rte_pci_ioport *p)
> +{
> +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
> +       char dirname[PATH_MAX];
> +       char filename[PATH_MAX];
> +       int uio_num;
> +       unsigned long start;
> +
> +       uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 0);
> +       if (uio_num < 0)
> +               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;
> +       }
> +       /* 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) {
> +
> +               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;
> +               }
> +               dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
> +       }
> +
> +       RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%lx\n", start);
> +
> +       p->offset = start;
> +       return 0;
> +#else
> +       RTE_SET_USED(dev);
> +       RTE_SET_USED(bar);
> +       RTE_SET_USED(p);
> +       return -1;
> +#endif
> +}
> +
> +void
> +pci_uio_ioport_read(struct rte_pci_ioport *p,
> +                   void *data, size_t len, off_t offset)
> +{
> +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
> +       uint8_t *d;
> +       int size;
> +       unsigned short reg = p->offset + offset;
> +
> +       for (d = data; len > 0; d += size, reg += size, len -= size) {
> +               if (len >= 4) {
> +                       size = 4;
> +                       *(uint32_t *)d = inl(reg);
> +               } else if (len >= 2) {
> +                       size = 2;
> +                       *(uint16_t *)d = inw(reg);
> +               } else {
> +                       size = 1;
> +                       *d = inb(reg);
> +               }
> +       }
> +#else
> +       RTE_SET_USED(p);
> +       RTE_SET_USED(data);
> +       RTE_SET_USED(len);
> +       RTE_SET_USED(offset);
> +#endif
> +}
> +
> +void
> +pci_uio_ioport_write(struct rte_pci_ioport *p,
> +                    const void *data, size_t len, off_t offset)
> +{
> +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
> +       const uint8_t *s;
> +       int size;
> +       unsigned short reg = p->offset + offset;
> +
> +       for (s = data; len > 0; s += size, reg += size, len -= size) {
> +               if (len >= 4) {
> +                       size = 4;
> +                       outl_p(*(const uint32_t *)s, reg);
> +               } else if (len >= 2) {
> +                       size = 2;
> +                       outw_p(*(const uint16_t *)s, reg);
> +               } else {
> +                       size = 1;
> +                       outb_p(*s, reg);
> +               }
> +       }
> +#else
> +       RTE_SET_USED(p);
> +       RTE_SET_USED(data);
> +       RTE_SET_USED(len);
> +       RTE_SET_USED(offset);
> +#endif
> +}
> +
> +int
> +pci_uio_ioport_unmap(struct rte_pci_ioport *p)
> +{
> +       RTE_SET_USED(p);
> +#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
> +       /* FIXME close intr fd ? */
> +       return 0;
> +#else
> +       return -1;
> +#endif
> +}
> diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c b/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
> index a6c7e16..ffa2dd0 100644
> --- a/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
> +++ b/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
> @@ -976,6 +976,43 @@ pci_vfio_map_resource(struct rte_pci_device *dev)
>  }
>
>  int
> +pci_vfio_ioport_map(struct rte_pci_device *dev, int bar,
> +                   struct rte_pci_ioport *p)
> +{
> +       RTE_SET_USED(dev);
> +       RTE_SET_USED(bar);
> +       RTE_SET_USED(p);
> +       return -1;
> +}
> +
> +void
> +pci_vfio_ioport_read(struct rte_pci_ioport *p,
> +                    void *data, size_t len, off_t offset)
> +{
> +       RTE_SET_USED(p);
> +       RTE_SET_USED(data);
> +       RTE_SET_USED(len);
> +       RTE_SET_USED(offset);
> +}
> +
> +void
> +pci_vfio_ioport_write(struct rte_pci_ioport *p,
> +                     const void *data, size_t len, off_t offset)
> +{
> +       RTE_SET_USED(p);
> +       RTE_SET_USED(data);
> +       RTE_SET_USED(len);
> +       RTE_SET_USED(offset);
> +}
> +
> +int
> +pci_vfio_ioport_unmap(struct rte_pci_ioport *p)
> +{
> +       RTE_SET_USED(p);
> +       return -1;
> +}
> +
> +int
>  pci_vfio_enable(void)
>  {
>         /* initialize group list */
> diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
> index 4c09c0b..dea260d 100644
> --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
> +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
> @@ -142,6 +142,10 @@ DPDK_2.2 {
>  DPDK_2.3 {
>         global:
>
> +       rte_eal_pci_ioport_map;
> +       rte_eal_pci_ioport_read;
> +       rte_eal_pci_ioport_unmap;
> +       rte_eal_pci_ioport_write;
>         rte_eal_pci_map_device;
>         rte_eal_pci_unmap_device;
>         rte_cpu_feature_table;
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [dpdk-dev] [PATCH v2 4/4] virtio: use pci ioport api
  2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 4/4] virtio: use " David Marchand
@ 2016-02-08  6:01     ` Santosh Shukla
  2016-02-09  3:52     ` Tetsuya Mukawa
  1 sibling, 0 replies; 29+ messages in thread
From: Santosh Shukla @ 2016-02-08  6:01 UTC (permalink / raw)
  To: David Marchand; +Cc: dev

On Sun, Feb 7, 2016 at 1:18 PM, David Marchand <david.marchand@6wind.com> wrote:
> Move all os / arch specifics to eal.
>
> Signed-off-by: David Marchand <david.marchand@6wind.com>

Reviewed-by: Santosh Shukla <sshukla@mvista.com>
Tested-by: Santosh Shukla <sshukla@mvista.com>

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [dpdk-dev] [PATCH v2 4/4] virtio: use pci ioport api
  2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 4/4] virtio: use " David Marchand
  2016-02-08  6:01     ` Santosh Shukla
@ 2016-02-09  3:52     ` Tetsuya Mukawa
  2016-02-09  8:31       ` David Marchand
  1 sibling, 1 reply; 29+ messages in thread
From: Tetsuya Mukawa @ 2016-02-09  3:52 UTC (permalink / raw)
  To: David Marchand, dev

On 2016/02/07 16:48, David Marchand wrote:
> Move all os / arch specifics to eal.
>
> Signed-off-by: David Marchand <david.marchand@6wind.com>
> ---
>  drivers/net/virtio/virtio_pci.c | 339 +++++++---------------------------------
>  drivers/net/virtio/virtio_pci.h |  38 +----
>  2 files changed, 55 insertions(+), 322 deletions(-)
>
> diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
> index b1610dd..e04c0db 100644
> --- a/drivers/net/virtio/virtio_pci.c
> +++ b/drivers/net/virtio/virtio_pci.c
> @@ -49,74 +49,35 @@
>
> @@ -311,132 +191,20 @@ legacy_virtio_has_msix(const struct rte_pci_addr *loc)
>  
>  /* Extract I/O port numbers from sysfs */
>  static int
> -virtio_resource_init_by_uio(struct rte_pci_device *pci_dev)
> +legacy_virtio_resource_init(struct rte_pci_device *pci_dev,
> +			    struct virtio_hw *hw)

One more legacy_virtio_resource_init() is defined like below.

#ifdef RTE_EXEC_ENV_LINUXAPP
<snip>
#else
<snip>
static int
legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
{
        /* no setup required */
        return 0;
}
#endif

Should we change this also?

Thanks,
Tetsuya

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [dpdk-dev] [PATCH v2 4/4] virtio: use pci ioport api
  2016-02-09  3:52     ` Tetsuya Mukawa
@ 2016-02-09  8:31       ` David Marchand
  0 siblings, 0 replies; 29+ messages in thread
From: David Marchand @ 2016-02-09  8:31 UTC (permalink / raw)
  To: Tetsuya Mukawa; +Cc: dev

On Tue, Feb 9, 2016 at 4:52 AM, Tetsuya Mukawa <mukawa@igel.co.jp> wrote:
> On 2016/02/07 16:48, David Marchand wrote:
> One more legacy_virtio_resource_init() is defined like below.
>
> #ifdef RTE_EXEC_ENV_LINUXAPP
> <snip>
> #else
> <snip>
> static int
> legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
> {
>         /* no setup required */
>         return 0;
> }
> #endif
>
> Should we change this also?

Yes, I noticed this while doing the patches but forgot to update ...
Thanks.

In the end, I think that we end up with common code in this case for
both bsd and linux.

The only thing remaining in virtio that depends on "#ifdef os" is the
msix detection.
I do not have time to look at this, so I suppose this will have to wait.


-- 
David Marchand

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH v3 0/4] rework ioport access for virtio
  2016-02-07  7:48 ` [dpdk-dev] [PATCH v2 0/4] rework ioport access for virtio David Marchand
                     ` (3 preceding siblings ...)
  2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 4/4] virtio: use " David Marchand
@ 2016-02-15 13:24   ` David Marchand
  2016-02-15 13:24     ` [dpdk-dev] [PATCH v3 1/4] virtio/bsd: fix typo David Marchand
                       ` (4 more replies)
  4 siblings, 5 replies; 29+ messages in thread
From: David Marchand @ 2016-02-15 13:24 UTC (permalink / raw)
  To: dev

Introduce a new pci ioport api in eal to mask all arch / kernel driver
specifics.

- rte_eal_pci_ioport_map is responsible for initialising an rte_pci_ioport
  object that is used in subsequent calls, this function must be tweaked per
  architecture and per kernel driver,
- rte_eal_pci_ioport_read / rte_eal_pci_ioport_write uses a rte_pci_ioport
  object to read / write those resources,
- rte_eal_pci_ioport_unmap releases resources used by a rte_pci_ioport
  object if necessary.

There is still some more work to ensure intr handle are properly initialized
and released when used in conjonction with rte_eal_map_device() api calls.

BSD code has been neither run nor compiled, please can someone confirm I did
not break too much stuff ?

virtio legacy code has been updated accordingly.
With this, virtio code should be ready for other archs now.

So in the end, all that is missing on linux is some vfio update for support
of all architectures that have vfio.

Changes since v2:
- rebased on HEAD
- fixed a remaining reference to rte_ioport_t in comment
- fixed virtio driver for bsd

Changes since v1:
- dropped rte_ioport and removed the arch headers, if performance is an
  issue, we will see how to enhance this in later patches


Regards, 
-- 
David Marchand

David Marchand (4):
  virtio/bsd: fix typo
  virtio: fix incorrect check when mapping pci resources
  eal: introduce pci ioport api
  virtio: use pci ioport api

 drivers/net/virtio/virtio_pci.c                 | 358 ++++--------------------
 drivers/net/virtio/virtio_pci.h                 |  38 +--
 lib/librte_eal/bsdapp/eal/eal_pci.c             | 135 +++++++++
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   4 +
 lib/librte_eal/common/include/rte_pci.h         |  65 +++++
 lib/librte_eal/linuxapp/eal/eal_pci.c           | 170 +++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci_init.h      |  16 ++
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c       | 132 ++++++++-
 lib/librte_eal/linuxapp/eal/eal_pci_vfio.c      |  37 +++
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   4 +
 10 files changed, 620 insertions(+), 339 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH v3 1/4] virtio/bsd: fix typo
  2016-02-15 13:24   ` [dpdk-dev] [PATCH v3 0/4] rework ioport access for virtio David Marchand
@ 2016-02-15 13:24     ` David Marchand
  2016-02-15 13:24     ` [dpdk-dev] [PATCH v3 2/4] virtio: fix incorrect check when mapping pci resources David Marchand
                       ` (3 subsequent siblings)
  4 siblings, 0 replies; 29+ messages in thread
From: David Marchand @ 2016-02-15 13:24 UTC (permalink / raw)
  To: dev

Fixes: c52afa68d763 ("virtio: move left PCI stuff in the right file")
Signed-off-by: David Marchand <david.marchand@6wind.com>
Acked-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 455e40d..762e91c 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -439,7 +439,7 @@ legacy_virtio_resource_init(struct rte_pci_device *pci_dev)
 
 #else
 static int
-legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
+legacy_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
 {
 	/* nic_uio does not enable interrupts, return 0 (false). */
 	return 0;
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH v3 2/4] virtio: fix incorrect check when mapping pci resources
  2016-02-15 13:24   ` [dpdk-dev] [PATCH v3 0/4] rework ioport access for virtio David Marchand
  2016-02-15 13:24     ` [dpdk-dev] [PATCH v3 1/4] virtio/bsd: fix typo David Marchand
@ 2016-02-15 13:24     ` David Marchand
  2016-02-15 13:24     ` [dpdk-dev] [PATCH v3 3/4] eal: introduce pci ioport api David Marchand
                       ` (2 subsequent siblings)
  4 siblings, 0 replies; 29+ messages in thread
From: David Marchand @ 2016-02-15 13:24 UTC (permalink / raw)
  To: dev

According to the api, rte_eal_pci_map_device is only successful when returning
0.

Fixes: 6ba1f63b5ab0 ("virtio: support specification 1.0")
Signed-off-by: David Marchand <david.marchand@6wind.com>
Acked-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 762e91c..b4d4476 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -795,7 +795,7 @@ virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
 	struct virtio_pci_cap cap;
 	int ret;
 
-	if (rte_eal_pci_map_device(dev) < 0) {
+	if (rte_eal_pci_map_device(dev)) {
 		PMD_INIT_LOG(DEBUG, "failed to map pci device!");
 		return -1;
 	}
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH v3 3/4] eal: introduce pci ioport api
  2016-02-15 13:24   ` [dpdk-dev] [PATCH v3 0/4] rework ioport access for virtio David Marchand
  2016-02-15 13:24     ` [dpdk-dev] [PATCH v3 1/4] virtio/bsd: fix typo David Marchand
  2016-02-15 13:24     ` [dpdk-dev] [PATCH v3 2/4] virtio: fix incorrect check when mapping pci resources David Marchand
@ 2016-02-15 13:24     ` David Marchand
  2016-02-16  2:36       ` Yuanhan Liu
  2016-02-15 13:24     ` [dpdk-dev] [PATCH v3 4/4] virtio: use " David Marchand
  2016-02-16 20:37     ` [dpdk-dev] [PATCH v4 0/4] rework ioport access for virtio David Marchand
  4 siblings, 1 reply; 29+ messages in thread
From: David Marchand @ 2016-02-15 13:24 UTC (permalink / raw)
  To: dev

Most of the code is inspired on virtio driver.
rte_pci_ioport structure is filled at map time with anything needed for later
read / write calls.
At the moment, offset field is used to store a x86 ioport (uint16_t) and will
be reused for other arches.

TODO: check multi process, check intr_handle init/exit,

Signed-off-by: David Marchand <david.marchand@6wind.com>
Tested-by: Santosh Shukla <sshukla@mvista.com>
---
Changes since v2:
- removed remaining reference to rte_ioport_t

Changes since v1:
- dropped rte_ioport and removed the arch headers, if performance is an
  issue, we will see how to enhance this in later patches
- rte_pci_ioport object now reaches driver implementation (uio / vfio)
- sanity checks are in uio map function, no reason to have those checks in
  read/write functions

---
 lib/librte_eal/bsdapp/eal/eal_pci.c             | 135 +++++++++++++++++++
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   4 +
 lib/librte_eal/common/include/rte_pci.h         |  65 +++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c           | 170 ++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci_init.h      |  16 +++
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c       | 132 +++++++++++++++++-
 lib/librte_eal/linuxapp/eal/eal_pci_vfio.c      |  37 ++++++
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   4 +
 8 files changed, 560 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 95c32c1..58f2ec9 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -51,6 +51,11 @@
 #include <sys/pciio.h>
 #include <dev/pci/pcireg.h>
 
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+#endif
+
 #include <rte_interrupts.h>
 #include <rte_log.h>
 #include <rte_pci.h>
@@ -479,6 +484,136 @@ int rte_eal_pci_write_config(const struct rte_pci_device *dev,
 	return -1;
 }
 
+int
+rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
+		       struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (dev->kdrv) {
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	case RTE_KDRV_NIC_UIO:
+		if ((uintptr_t) dev->mem_resource[bar].addr <= UINT16_MAX) {
+			p->offset = (uintptr_t)dev->mem_resource[bar].addr;
+			ret = 0;
+		} else
+			ret = -1;
+		break;
+#endif
+	default:
+		ret = -1;
+		break;
+	}
+
+	if (!ret)
+		p->dev = dev;
+
+	return ret;
+}
+
+static void
+pci_uio_ioport_read(struct rte_pci_ioport *p,
+		    void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	uint8_t *d;
+	int size;
+	unsigned short reg = p->offset + offset;
+
+	for (d = data; len > 0; d += size, reg += size, len -= size) {
+		if (len >= 4) {
+			size = 4;
+			*(uint32_t *)d = inl(reg);
+		} else if (len >= 2) {
+			size = 2;
+			*(uint16_t *)d = inw(reg);
+		} else {
+			size = 1;
+			*d = inb(reg);
+		}
+	}
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
+void
+rte_eal_pci_ioport_read(struct rte_pci_ioport *p,
+			void *data, size_t len, off_t offset)
+{
+	switch (p->dev->kdrv) {
+	case RTE_KDRV_NIC_UIO:
+		pci_uio_ioport_read(p, data, len, offset);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+pci_uio_ioport_write(struct rte_pci_ioport *p,
+		     const void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	const uint8_t *s;
+	int size;
+	unsigned short reg = p->offset + offset;
+
+	for (s = data; len > 0; s += size, reg += size, len -= size) {
+		if (len >= 4) {
+			size = 4;
+			outl(*(const uint32_t *)s, reg);
+		} else if (len >= 2) {
+			size = 2;
+			outw(*(const uint16_t *)s, reg);
+		} else {
+			size = 1;
+			outb(*s, reg);
+		}
+	}
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
+void
+rte_eal_pci_ioport_write(struct rte_pci_ioport *p,
+			 const void *data, size_t len, off_t offset)
+{
+	switch (p->dev->kdrv) {
+	case RTE_KDRV_NIC_UIO:
+		pci_uio_ioport_write(p, data, len, offset);
+		break;
+	default:
+		break;
+	}
+}
+
+int
+rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (p->dev->kdrv) {
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	case RTE_KDRV_NIC_UIO:
+		ret = 0;
+		break;
+#endif
+	default:
+		ret = -1;
+		break;
+	}
+
+	return ret;
+}
+
 /* Init the PCI EAL subsystem */
 int
 rte_eal_pci_init(void)
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index d8ac7f7..65da300 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -139,6 +139,10 @@ DPDK_2.2 {
 DPDK_2.3 {
 	global:
 
+	rte_eal_pci_ioport_map;
+	rte_eal_pci_ioport_read;
+	rte_eal_pci_ioport_unmap;
+	rte_eal_pci_ioport_write;
 	rte_eal_pci_map_device;
 	rte_eal_pci_unmap_device;
 	rte_cpu_feature_table;
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 1508ea9..2d2a4dd 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -512,6 +512,71 @@ int rte_eal_pci_read_config(const struct rte_pci_device *device,
 int rte_eal_pci_write_config(const struct rte_pci_device *device,
 			     const void *buf, size_t len, off_t offset);
 
+/**
+ * A structure used to access io resources for a pci device.
+ * rte_pci_ioport is arch, os, driver specific, and should not be used outside
+ * of pci ioport api.
+ */
+struct rte_pci_ioport {
+	struct rte_pci_device *dev;
+	uint64_t offset;
+};
+
+/**
+ * Initialises a rte_pci_ioport object for a pci device io resource.
+ * This object is then used to gain access to those io resources (see below).
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device.
+ *   to use
+ * @param bar
+ *   Index of the io pci resource we want to access.
+ * @param p
+ *   The rte_pci_ioport object to be initialized.
+ * @return
+ *  0 on success, negative on error.
+ */
+int rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
+			   struct rte_pci_ioport *p);
+
+/**
+ * Release any resources used in a rte_pci_ioport object.
+ *
+ * @param p
+ *   The rte_pci_ioport object to be uninitialized.
+ */
+int rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p);
+
+/**
+ * Read from a io pci resource.
+ *
+ * @param p
+ *   The rte_pci_ioport object from which we want to read.
+ * @param data
+ *   A data buffer where the bytes should be read into
+ * @param len
+ *   The length of the data buffer.
+ * @param offset
+ *   The offset into the pci io resource.
+ */
+void rte_eal_pci_ioport_read(struct rte_pci_ioport *p,
+			     void *data, size_t len, off_t offset);
+
+/**
+ * Write to a io pci resource.
+ *
+ * @param p
+ *   The rte_pci_ioport object to which we want to write.
+ * @param data
+ *   A data buffer where the bytes should be read into
+ * @param len
+ *   The length of the data buffer.
+ * @param offset
+ *   The offset into the pci io resource.
+ */
+void rte_eal_pci_ioport_write(struct rte_pci_ioport *p,
+			      const void *data, size_t len, off_t offset);
+
 #ifdef RTE_PCI_CONFIG
 /**
  * Set special config space registers for performance purpose.
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index db947da..1b9de1e 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -621,6 +621,176 @@ int rte_eal_pci_write_config(const struct rte_pci_device *device,
 	}
 }
 
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+static int
+pci_ioport_map(struct rte_pci_device *dev, int bar __rte_unused,
+	       struct rte_pci_ioport *p)
+{
+	uint16_t start, end;
+	FILE *fp;
+	char *line = NULL;
+	char pci_id[16];
+	int found = 0;
+	size_t linesz;
+
+	snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT,
+		 dev->addr.domain, dev->addr.bus,
+		 dev->addr.devid, dev->addr.function);
+
+	fp = fopen("/proc/ioports", "r");
+	if (fp == NULL) {
+		RTE_LOG(ERR, EAL, "%s(): can't open ioports\n", __func__);
+		return -1;
+	}
+
+	while (getdelim(&line, &linesz, '\n', fp) > 0) {
+		char *ptr = line;
+		char *left;
+		int n;
+
+		n = strcspn(ptr, ":");
+		ptr[n] = 0;
+		left = &ptr[n + 1];
+
+		while (*left && isspace(*left))
+			left++;
+
+		if (!strncmp(left, pci_id, strlen(pci_id))) {
+			found = 1;
+
+			while (*ptr && isspace(*ptr))
+				ptr++;
+
+			sscanf(ptr, "%04hx-%04hx", &start, &end);
+
+			break;
+		}
+	}
+
+	free(line);
+	fclose(fp);
+
+	if (!found)
+		return -1;
+
+	dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
+	p->offset = start;
+	RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%x\n", start);
+
+	return 0;
+}
+#endif
+
+int
+rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
+		       struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (dev->kdrv) {
+#ifdef VFIO_PRESENT
+	case RTE_KDRV_VFIO:
+		ret = -1;
+		if (pci_vfio_is_enabled())
+			ret = pci_vfio_ioport_map(dev, bar, p);
+		break;
+#endif
+	case RTE_KDRV_IGB_UIO:
+	case RTE_KDRV_UIO_GENERIC:
+		ret = pci_uio_ioport_map(dev, bar, p);
+		break;
+	default:
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+		/* special case for x86 ... */
+		ret = pci_ioport_map(dev, bar, p);
+#else
+		ret = -1;
+#endif
+		break;
+	}
+
+	if (!ret)
+		p->dev = dev;
+
+	return ret;
+}
+
+void
+rte_eal_pci_ioport_read(struct rte_pci_ioport *p,
+			void *data, size_t len, off_t offset)
+{
+	switch (p->dev->kdrv) {
+#ifdef VFIO_PRESENT
+	case RTE_KDRV_VFIO:
+		pci_vfio_ioport_read(p, data, len, offset);
+		break;
+#endif
+	case RTE_KDRV_IGB_UIO:
+	case RTE_KDRV_UIO_GENERIC:
+		pci_uio_ioport_read(p, data, len, offset);
+		break;
+	default:
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+		/* special case for x86 ... */
+		pci_uio_ioport_read(p, data, len, offset);
+#endif
+		break;
+	}
+}
+
+void
+rte_eal_pci_ioport_write(struct rte_pci_ioport *p,
+			 const void *data, size_t len, off_t offset)
+{
+	switch (p->dev->kdrv) {
+#ifdef VFIO_PRESENT
+	case RTE_KDRV_VFIO:
+		pci_vfio_ioport_write(p, data, len, offset);
+		break;
+#endif
+	case RTE_KDRV_IGB_UIO:
+	case RTE_KDRV_UIO_GENERIC:
+		pci_uio_ioport_write(p, data, len, offset);
+		break;
+	default:
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+		/* special case for x86 ... */
+		pci_uio_ioport_write(p, data, len, offset);
+#endif
+		break;
+	}
+}
+
+int
+rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (p->dev->kdrv) {
+#ifdef VFIO_PRESENT
+	case RTE_KDRV_VFIO:
+		ret = -1;
+		if (pci_vfio_is_enabled())
+			ret = pci_vfio_ioport_unmap(p);
+		break;
+#endif
+	case RTE_KDRV_IGB_UIO:
+	case RTE_KDRV_UIO_GENERIC:
+		ret = pci_uio_ioport_unmap(p);
+		break;
+	default:
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+		/* special case for x86 ... nothing to do */
+		ret = 0;
+#else
+		ret = -1;
+#endif
+		break;
+	}
+
+	return ret;
+}
+
 /* Init the PCI EAL subsystem */
 int
 rte_eal_pci_init(void)
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_init.h b/lib/librte_eal/linuxapp/eal/eal_pci_init.h
index a17c708..7011753 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_init.h
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_init.h
@@ -54,6 +54,14 @@ int pci_uio_read_config(const struct rte_intr_handle *intr_handle,
 int pci_uio_write_config(const struct rte_intr_handle *intr_handle,
 			 const void *buf, size_t len, off_t offs);
 
+int pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
+		       struct rte_pci_ioport *p);
+void pci_uio_ioport_read(struct rte_pci_ioport *p,
+			 void *data, size_t len, off_t offset);
+void pci_uio_ioport_write(struct rte_pci_ioport *p,
+			  const void *data, size_t len, off_t offset);
+int pci_uio_ioport_unmap(struct rte_pci_ioport *p);
+
 #ifdef VFIO_PRESENT
 
 #define VFIO_MAX_GROUPS 64
@@ -68,6 +76,14 @@ int pci_vfio_read_config(const struct rte_intr_handle *intr_handle,
 int pci_vfio_write_config(const struct rte_intr_handle *intr_handle,
 			  const void *buf, size_t len, off_t offs);
 
+int pci_vfio_ioport_map(struct rte_pci_device *dev, int bar,
+		        struct rte_pci_ioport *p);
+void pci_vfio_ioport_read(struct rte_pci_ioport *p,
+			  void *data, size_t len, off_t offset);
+void pci_vfio_ioport_write(struct rte_pci_ioport *p,
+			   const void *data, size_t len, off_t offset);
+int pci_vfio_ioport_unmap(struct rte_pci_ioport *p);
+
 /* map VFIO resource prototype */
 int pci_vfio_map_resource(struct rte_pci_device *dev);
 int pci_vfio_get_group_fd(int iommu_group_fd);
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index ac50e13..f891dda 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -39,6 +39,10 @@
 #include <sys/mman.h>
 #include <linux/pci_regs.h>
 
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+#include <sys/io.h>
+#endif
+
 #include <rte_log.h>
 #include <rte_pci.h>
 #include <rte_eal_memconfig.h>
@@ -145,7 +149,7 @@ pci_mknod_uio_dev(const char *sysfs_uio_path, unsigned uio_num)
  */
 static int
 pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
-			   unsigned int buflen)
+			   unsigned int buflen, int create)
 {
 	struct rte_pci_addr *loc = &dev->addr;
 	unsigned int uio_num;
@@ -208,7 +212,7 @@ pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
 		return -1;
 
 	/* create uio device if we've been asked to */
-	if (internal_config.create_uio_dev &&
+	if (internal_config.create_uio_dev && create &&
 			pci_mknod_uio_dev(dstbuf, uio_num) < 0)
 		RTE_LOG(WARNING, EAL, "Cannot create /dev/uio%u\n", uio_num);
 
@@ -245,7 +249,7 @@ pci_uio_alloc_resource(struct rte_pci_device *dev,
 	loc = &dev->addr;
 
 	/* find uio resource */
-	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname));
+	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 1);
 	if (uio_num < 0) {
 		RTE_LOG(WARNING, EAL, "  "PCI_PRI_FMT" not managed by UIO driver, "
 				"skipping\n", loc->domain, loc->bus, loc->devid, loc->function);
@@ -363,3 +367,125 @@ error:
 	rte_free(maps[map_idx].path);
 	return -1;
 }
+
+int
+pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
+		   struct rte_pci_ioport *p)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	char dirname[PATH_MAX];
+	char filename[PATH_MAX];
+	int uio_num;
+	unsigned long start;
+
+	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 0);
+	if (uio_num < 0)
+		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;
+	}
+	/* 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) {
+
+		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;
+		}
+		dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
+	}
+
+	RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%lx\n", start);
+
+	p->offset = start;
+	return 0;
+#else
+	RTE_SET_USED(dev);
+	RTE_SET_USED(bar);
+	RTE_SET_USED(p);
+	return -1;
+#endif
+}
+
+void
+pci_uio_ioport_read(struct rte_pci_ioport *p,
+		    void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	uint8_t *d;
+	int size;
+	unsigned short reg = p->offset + offset;
+
+	for (d = data; len > 0; d += size, reg += size, len -= size) {
+		if (len >= 4) {
+			size = 4;
+			*(uint32_t *)d = inl(reg);
+		} else if (len >= 2) {
+			size = 2;
+			*(uint16_t *)d = inw(reg);
+		} else {
+			size = 1;
+			*d = inb(reg);
+		}
+	}
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
+void
+pci_uio_ioport_write(struct rte_pci_ioport *p,
+		     const void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	const uint8_t *s;
+	int size;
+	unsigned short reg = p->offset + offset;
+
+	for (s = data; len > 0; s += size, reg += size, len -= size) {
+		if (len >= 4) {
+			size = 4;
+			outl_p(*(const uint32_t *)s, reg);
+		} else if (len >= 2) {
+			size = 2;
+			outw_p(*(const uint16_t *)s, reg);
+		} else {
+			size = 1;
+			outb_p(*s, reg);
+		}
+	}
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
+int
+pci_uio_ioport_unmap(struct rte_pci_ioport *p)
+{
+	RTE_SET_USED(p);
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	/* FIXME close intr fd ? */
+	return 0;
+#else
+	return -1;
+#endif
+}
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c b/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
index a6c7e16..ffa2dd0 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
@@ -976,6 +976,43 @@ pci_vfio_map_resource(struct rte_pci_device *dev)
 }
 
 int
+pci_vfio_ioport_map(struct rte_pci_device *dev, int bar,
+		    struct rte_pci_ioport *p)
+{
+	RTE_SET_USED(dev);
+	RTE_SET_USED(bar);
+	RTE_SET_USED(p);
+	return -1;
+}
+
+void
+pci_vfio_ioport_read(struct rte_pci_ioport *p,
+		     void *data, size_t len, off_t offset)
+{
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+}
+
+void
+pci_vfio_ioport_write(struct rte_pci_ioport *p,
+		      const void *data, size_t len, off_t offset)
+{
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+}
+
+int
+pci_vfio_ioport_unmap(struct rte_pci_ioport *p)
+{
+	RTE_SET_USED(p);
+	return -1;
+}
+
+int
 pci_vfio_enable(void)
 {
 	/* initialize group list */
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index 4c09c0b..dea260d 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -142,6 +142,10 @@ DPDK_2.2 {
 DPDK_2.3 {
 	global:
 
+	rte_eal_pci_ioport_map;
+	rte_eal_pci_ioport_read;
+	rte_eal_pci_ioport_unmap;
+	rte_eal_pci_ioport_write;
 	rte_eal_pci_map_device;
 	rte_eal_pci_unmap_device;
 	rte_cpu_feature_table;
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH v3 4/4] virtio: use pci ioport api
  2016-02-15 13:24   ` [dpdk-dev] [PATCH v3 0/4] rework ioport access for virtio David Marchand
                       ` (2 preceding siblings ...)
  2016-02-15 13:24     ` [dpdk-dev] [PATCH v3 3/4] eal: introduce pci ioport api David Marchand
@ 2016-02-15 13:24     ` David Marchand
  2016-02-16  2:24       ` Yuanhan Liu
  2016-02-16 20:37     ` [dpdk-dev] [PATCH v4 0/4] rework ioport access for virtio David Marchand
  4 siblings, 1 reply; 29+ messages in thread
From: David Marchand @ 2016-02-15 13:24 UTC (permalink / raw)
  To: dev

Move all os / arch specifics to eal.

Signed-off-by: David Marchand <david.marchand@6wind.com>
Reviewed-by: Santosh Shukla <sshukla@mvista.com>
Tested-by: Santosh Shukla <sshukla@mvista.com>
---
Changes since v2:
- fixed bsd init issue (reported by Tetsuya M.)

---
 drivers/net/virtio/virtio_pci.c | 356 +++++++---------------------------------
 drivers/net/virtio/virtio_pci.h |  38 +----
 2 files changed, 59 insertions(+), 335 deletions(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index b4d4476..85fbe88 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -49,74 +49,35 @@
 #define PCI_CAPABILITY_LIST	0x34
 #define PCI_CAP_ID_VNDR		0x09
 
-#define VIRTIO_PCI_REG_ADDR(hw, reg) \
-	(unsigned short)((hw)->io_base + (reg))
-
-#define VIRTIO_READ_REG_1(hw, reg) \
-	inb((VIRTIO_PCI_REG_ADDR((hw), (reg))))
-#define VIRTIO_WRITE_REG_1(hw, reg, value) \
-	outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
-
-#define VIRTIO_READ_REG_2(hw, reg) \
-	inw((VIRTIO_PCI_REG_ADDR((hw), (reg))))
-#define VIRTIO_WRITE_REG_2(hw, reg, value) \
-	outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
-
-#define VIRTIO_READ_REG_4(hw, reg) \
-	inl((VIRTIO_PCI_REG_ADDR((hw), (reg))))
-#define VIRTIO_WRITE_REG_4(hw, reg, value) \
-	outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
+/*
+ * The remaining space is defined by each driver as the per-driver
+ * configuration space.
+ */
+#define VIRTIO_PCI_CONFIG(hw) (((hw)->use_msix) ? 24 : 20)
 
 static void
 legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
 		       void *dst, int length)
 {
-	uint64_t off;
-	uint8_t *d;
-	int size;
-
-	off = VIRTIO_PCI_CONFIG(hw) + offset;
-	for (d = dst; length > 0; d += size, off += size, length -= size) {
-		if (length >= 4) {
-			size = 4;
-			*(uint32_t *)d = VIRTIO_READ_REG_4(hw, off);
-		} else if (length >= 2) {
-			size = 2;
-			*(uint16_t *)d = VIRTIO_READ_REG_2(hw, off);
-		} else {
-			size = 1;
-			*d = VIRTIO_READ_REG_1(hw, off);
-		}
-	}
+	rte_eal_pci_ioport_read(&hw->io, dst, length,
+				VIRTIO_PCI_CONFIG(hw) + offset);
 }
 
 static void
 legacy_write_dev_config(struct virtio_hw *hw, size_t offset,
 			const void *src, int length)
 {
-	uint64_t off;
-	const uint8_t *s;
-	int size;
-
-	off = VIRTIO_PCI_CONFIG(hw) + offset;
-	for (s = src; length > 0; s += size, off += size, length -= size) {
-		if (length >= 4) {
-			size = 4;
-			VIRTIO_WRITE_REG_4(hw, off, *(const uint32_t *)s);
-		} else if (length >= 2) {
-			size = 2;
-			VIRTIO_WRITE_REG_2(hw, off, *(const uint16_t *)s);
-		} else {
-			size = 1;
-			VIRTIO_WRITE_REG_1(hw, off, *s);
-		}
-	}
+	rte_eal_pci_ioport_write(&hw->io, src, length,
+				 VIRTIO_PCI_CONFIG(hw) + offset);
 }
 
 static uint64_t
 legacy_get_features(struct virtio_hw *hw)
 {
-	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+	uint64_t dst;
+
+	rte_eal_pci_ioport_read(&hw->io, &dst, 4, VIRTIO_PCI_HOST_FEATURES);
+	return dst;
 }
 
 static void
@@ -127,19 +88,23 @@ legacy_set_features(struct virtio_hw *hw, uint64_t features)
 			"only 32 bit features are allowed for legacy virtio!");
 		return;
 	}
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
+	rte_eal_pci_ioport_write(&hw->io, &features, 4,
+				 VIRTIO_PCI_GUEST_FEATURES);
 }
 
 static uint8_t
 legacy_get_status(struct virtio_hw *hw)
 {
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
+	uint8_t dst;
+
+	rte_eal_pci_ioport_read(&hw->io, &dst, 1, VIRTIO_PCI_STATUS);
+	return dst;
 }
 
 static void
 legacy_set_status(struct virtio_hw *hw, uint8_t status)
 {
-	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+	rte_eal_pci_ioport_write(&hw->io, &status, 1, VIRTIO_PCI_STATUS);
 }
 
 static void
@@ -151,148 +116,63 @@ legacy_reset(struct virtio_hw *hw)
 static uint8_t
 legacy_get_isr(struct virtio_hw *hw)
 {
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+	uint8_t dst;
+
+	rte_eal_pci_ioport_read(&hw->io, &dst, 1, VIRTIO_PCI_ISR);
+	return dst;
 }
 
 /* Enable one vector (0) for Link State Intrerrupt */
 static uint16_t
 legacy_set_config_irq(struct virtio_hw *hw, uint16_t vec)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR, vec);
-	return VIRTIO_READ_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR);
+	uint16_t dst;
+
+	rte_eal_pci_ioport_write(&hw->io, &vec, 2, VIRTIO_MSI_CONFIG_VECTOR);
+	rte_eal_pci_ioport_read(&hw->io, &dst, 2, VIRTIO_MSI_CONFIG_VECTOR);
+	return dst;
 }
 
 static uint16_t
 legacy_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, queue_id);
-	return VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
+	uint16_t dst;
+
+	rte_eal_pci_ioport_write(&hw->io, &queue_id, 2, VIRTIO_PCI_QUEUE_SEL);
+	rte_eal_pci_ioport_read(&hw->io, &dst, 2, VIRTIO_PCI_QUEUE_NUM);
+	return dst;
 }
 
 static void
 legacy_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
+	uint32_t src;
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
-		vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+	rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2,
+			 VIRTIO_PCI_QUEUE_SEL);
+	src = vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
+	rte_eal_pci_ioport_write(&hw->io, &src, 4, VIRTIO_PCI_QUEUE_PFN);
 }
 
 static void
 legacy_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
+	uint32_t src = 0;
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+	rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2,
+			 VIRTIO_PCI_QUEUE_SEL);
+	rte_eal_pci_ioport_write(&hw->io, &src, 4, VIRTIO_PCI_QUEUE_PFN);
 }
 
 static void
 legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
+	rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2,
+			 VIRTIO_PCI_QUEUE_NOTIFY);
 }
 
 #ifdef RTE_EXEC_ENV_LINUXAPP
 static int
-parse_sysfs_value(const char *filename, unsigned long *val)
-{
-	FILE *f;
-	char buf[BUFSIZ];
-	char *end = NULL;
-
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s",
-			     __func__, filename);
-		return -1;
-	}
-
-	if (fgets(buf, sizeof(buf), f) == NULL) {
-		PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s",
-			     __func__, filename);
-		fclose(f);
-		return -1;
-	}
-	*val = strtoul(buf, &end, 0);
-	if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) {
-		PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s",
-			     __func__, filename);
-		fclose(f);
-		return -1;
-	}
-	fclose(f);
-	return 0;
-}
-
-static int
-get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen,
-			unsigned int *uio_num)
-{
-	struct dirent *e;
-	DIR *dir;
-	char dirname[PATH_MAX];
-
-	/*
-	 * depending on kernel version, uio can be located in uio/uioX
-	 * or uio:uioX
-	 */
-	snprintf(dirname, sizeof(dirname),
-		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio",
-		     loc->domain, loc->bus, loc->devid, loc->function);
-	dir = opendir(dirname);
-	if (dir == NULL) {
-		/* retry with the parent directory */
-		snprintf(dirname, sizeof(dirname),
-			     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT,
-			     loc->domain, loc->bus, loc->devid, loc->function);
-		dir = opendir(dirname);
-
-		if (dir == NULL) {
-			PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname);
-			return -1;
-		}
-	}
-
-	/* take the first file starting with "uio" */
-	while ((e = readdir(dir)) != NULL) {
-		/* format could be uio%d ...*/
-		int shortprefix_len = sizeof("uio") - 1;
-		/* ... or uio:uio%d */
-		int longprefix_len = sizeof("uio:uio") - 1;
-		char *endptr;
-
-		if (strncmp(e->d_name, "uio", 3) != 0)
-			continue;
-
-		/* first try uio%d */
-		errno = 0;
-		*uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10);
-		if (errno == 0 && endptr != (e->d_name + shortprefix_len)) {
-			snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num);
-			break;
-		}
-
-		/* then try uio:uio%d */
-		errno = 0;
-		*uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10);
-		if (errno == 0 && endptr != (e->d_name + longprefix_len)) {
-			snprintf(buf, buflen, "%s/uio:uio%u", dirname,
-				     *uio_num);
-			break;
-		}
-	}
-	closedir(dir);
-
-	/* No uio resource found */
-	if (e == NULL) {
-		PMD_INIT_LOG(ERR, "Could not find uio resource");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int
 legacy_virtio_has_msix(const struct rte_pci_addr *loc)
 {
 	DIR *d;
@@ -308,135 +188,6 @@ legacy_virtio_has_msix(const struct rte_pci_addr *loc)
 
 	return d != NULL;
 }
-
-/* Extract I/O port numbers from sysfs */
-static int
-virtio_resource_init_by_uio(struct rte_pci_device *pci_dev)
-{
-	char dirname[PATH_MAX];
-	char filename[PATH_MAX];
-	unsigned long start, size;
-	unsigned int uio_num;
-
-	if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0)
-		return -1;
-
-	/* get portio size */
-	snprintf(filename, sizeof(filename),
-		     "%s/portio/port0/size", dirname);
-	if (parse_sysfs_value(filename, &size) < 0) {
-		PMD_INIT_LOG(ERR, "%s(): cannot parse size",
-			     __func__);
-		return -1;
-	}
-
-	/* get portio start */
-	snprintf(filename, sizeof(filename),
-		 "%s/portio/port0/start", dirname);
-	if (parse_sysfs_value(filename, &start) < 0) {
-		PMD_INIT_LOG(ERR, "%s(): cannot parse portio start",
-			     __func__);
-		return -1;
-	}
-	pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start;
-	pci_dev->mem_resource[0].len =  (uint64_t)size;
-	PMD_INIT_LOG(DEBUG,
-		     "PCI Port IO found start=0x%lx with size=0x%lx",
-		     start, size);
-
-	/* save fd */
-	memset(dirname, 0, sizeof(dirname));
-	snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num);
-	pci_dev->intr_handle.fd = open(dirname, O_RDWR);
-	if (pci_dev->intr_handle.fd < 0) {
-		PMD_INIT_LOG(ERR, "Cannot open %s: %s\n",
-			dirname, strerror(errno));
-		return -1;
-	}
-
-	pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
-	pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
-
-	return 0;
-}
-
-/* Extract port I/O numbers from proc/ioports */
-static int
-virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev)
-{
-	uint16_t start, end;
-	int size;
-	FILE *fp;
-	char *line = NULL;
-	char pci_id[16];
-	int found = 0;
-	size_t linesz;
-
-	snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT,
-		 pci_dev->addr.domain,
-		 pci_dev->addr.bus,
-		 pci_dev->addr.devid,
-		 pci_dev->addr.function);
-
-	fp = fopen("/proc/ioports", "r");
-	if (fp == NULL) {
-		PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__);
-		return -1;
-	}
-
-	while (getdelim(&line, &linesz, '\n', fp) > 0) {
-		char *ptr = line;
-		char *left;
-		int n;
-
-		n = strcspn(ptr, ":");
-		ptr[n] = 0;
-		left = &ptr[n + 1];
-
-		while (*left && isspace(*left))
-			left++;
-
-		if (!strncmp(left, pci_id, strlen(pci_id))) {
-			found = 1;
-
-			while (*ptr && isspace(*ptr))
-				ptr++;
-
-			sscanf(ptr, "%04hx-%04hx", &start, &end);
-			size = end - start + 1;
-
-			break;
-		}
-	}
-
-	free(line);
-	fclose(fp);
-
-	if (!found)
-		return -1;
-
-	pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start;
-	pci_dev->mem_resource[0].len =  (uint64_t)size;
-	PMD_INIT_LOG(DEBUG,
-		"PCI Port IO found start=0x%x with size=0x%x",
-		start, size);
-
-	/* can't support lsc interrupt without uio */
-	pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC;
-
-	return 0;
-}
-
-/* Extract I/O port numbers from sysfs */
-static int
-legacy_virtio_resource_init(struct rte_pci_device *pci_dev)
-{
-	if (virtio_resource_init_by_uio(pci_dev) == 0)
-		return 0;
-	else
-		return virtio_resource_init_by_ioports(pci_dev);
-}
-
 #else
 static int
 legacy_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
@@ -444,14 +195,22 @@ legacy_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
 	/* nic_uio does not enable interrupts, return 0 (false). */
 	return 0;
 }
+#endif
 
 static int
-legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
+legacy_virtio_resource_init(struct rte_pci_device *pci_dev,
+			    struct virtio_hw *hw)
 {
-	/* no setup required */
+	if (rte_eal_pci_ioport_map(pci_dev, 0, &hw->io) < 0)
+		return -1;
+
+	if (pci_dev->intr_handle.type != RTE_INTR_HANDLE_UNKNOWN)
+		pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
+	else
+		pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC;
+
 	return 0;
 }
-#endif
 
 static const struct virtio_pci_ops legacy_ops = {
 	.read_dev_cfg	= legacy_read_dev_config,
@@ -882,12 +641,11 @@ vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 	}
 
 	PMD_INIT_LOG(INFO, "trying with legacy virtio pci.");
-	if (legacy_virtio_resource_init(dev) < 0)
+	if (legacy_virtio_resource_init(dev, hw) < 0)
 		return -1;
 
 	hw->vtpci_ops = &legacy_ops;
 	hw->use_msix = legacy_virtio_has_msix(&dev->addr);
-	hw->io_base  = (uint32_t)(uintptr_t)dev->mem_resource[0].addr;
 	hw->modern   = 0;
 
 	return 0;
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index 0544a07..b69785e 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -36,13 +36,7 @@
 
 #include <stdint.h>
 
-#ifdef __FreeBSD__
-#include <sys/types.h>
-#include <machine/cpufunc.h>
-#else
-#include <sys/io.h>
-#endif
-
+#include <rte_pci.h>
 #include <rte_ethdev.h>
 
 struct virtqueue;
@@ -249,7 +243,7 @@ struct virtio_net_config;
 
 struct virtio_hw {
 	struct virtqueue *cvq;
-	uint32_t    io_base;
+	struct rte_pci_ioport io;
 	uint64_t    guest_features;
 	uint32_t    max_tx_queues;
 	uint32_t    max_rx_queues;
@@ -282,12 +276,6 @@ struct virtio_net_config {
 } __attribute__((packed));
 
 /*
- * The remaining space is defined by each driver as the per-driver
- * configuration space.
- */
-#define VIRTIO_PCI_CONFIG(hw) (((hw)->use_msix) ? 24 : 20)
-
-/*
  * How many bits to shift physical queue address written to QUEUE_PFN.
  * 12 is historical, and due to x86 page size.
  */
@@ -296,28 +284,6 @@ struct virtio_net_config {
 /* The alignment to use between consumer and producer parts of vring. */
 #define VIRTIO_PCI_VRING_ALIGN 4096
 
-#ifdef __FreeBSD__
-
-static inline void
-outb_p(unsigned char data, unsigned int port)
-{
-
-	outb(port, (u_char)data);
-}
-
-static inline void
-outw_p(unsigned short data, unsigned int port)
-{
-	outw(port, (u_short)data);
-}
-
-static inline void
-outl_p(unsigned int data, unsigned int port)
-{
-	outl(port, (u_int)data);
-}
-#endif
-
 static inline int
 vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [dpdk-dev] [PATCH v3 4/4] virtio: use pci ioport api
  2016-02-15 13:24     ` [dpdk-dev] [PATCH v3 4/4] virtio: use " David Marchand
@ 2016-02-16  2:24       ` Yuanhan Liu
  0 siblings, 0 replies; 29+ messages in thread
From: Yuanhan Liu @ 2016-02-16  2:24 UTC (permalink / raw)
  To: David Marchand; +Cc: dev

On Mon, Feb 15, 2016 at 02:24:26PM +0100, David Marchand wrote:
> Move all os / arch specifics to eal.

Great stuff; something I want to do long time ago! So, thank you, and

Acked-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>

	--yliu

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [dpdk-dev] [PATCH v3 3/4] eal: introduce pci ioport api
  2016-02-15 13:24     ` [dpdk-dev] [PATCH v3 3/4] eal: introduce pci ioport api David Marchand
@ 2016-02-16  2:36       ` Yuanhan Liu
  2016-02-16  6:09         ` David Marchand
  0 siblings, 1 reply; 29+ messages in thread
From: Yuanhan Liu @ 2016-02-16  2:36 UTC (permalink / raw)
  To: David Marchand; +Cc: dev

On Mon, Feb 15, 2016 at 02:24:25PM +0100, David Marchand wrote:
> +/**
> + * A structure used to access io resources for a pci device.
> + * rte_pci_ioport is arch, os, driver specific, and should not be used outside
> + * of pci ioport api.
> + */
> +struct rte_pci_ioport {
> +	struct rte_pci_device *dev;
> +	uint64_t offset;
> +};

"offset" dosen't sound like a good name to me; espeicially when I found
code like below:

	reg = p->offset + offset;

Regarding that, maybe "base" is a better name? I don't like it too much,
though. Any better idea?

Otherwise, this patch looks good to me.

	--yliu

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [dpdk-dev] [PATCH v3 3/4] eal: introduce pci ioport api
  2016-02-16  2:36       ` Yuanhan Liu
@ 2016-02-16  6:09         ` David Marchand
  2016-02-16  6:12           ` Yuanhan Liu
  0 siblings, 1 reply; 29+ messages in thread
From: David Marchand @ 2016-02-16  6:09 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev

On Tue, Feb 16, 2016 at 3:36 AM, Yuanhan Liu
<yuanhan.liu@linux.intel.com> wrote:
> On Mon, Feb 15, 2016 at 02:24:25PM +0100, David Marchand wrote:
>> +/**
>> + * A structure used to access io resources for a pci device.
>> + * rte_pci_ioport is arch, os, driver specific, and should not be used outside
>> + * of pci ioport api.
>> + */
>> +struct rte_pci_ioport {
>> +     struct rte_pci_device *dev;
>> +     uint64_t offset;
>> +};
>
> "offset" dosen't sound like a good name to me; espeicially when I found
> code like below:
>
>         reg = p->offset + offset;
>
> Regarding that, maybe "base" is a better name? I don't like it too much,
> though. Any better idea?

Hum, yes, base sounds better, and I have no better idea, will go with
this unless someone else complains.

> Otherwise, this patch looks good to me.

Thanks.

I will respin this patchset and if nobody is against this, I think
this patchset should be pulled quickly because other patches depend on
it.


-- 
David Marchand

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [dpdk-dev] [PATCH v3 3/4] eal: introduce pci ioport api
  2016-02-16  6:09         ` David Marchand
@ 2016-02-16  6:12           ` Yuanhan Liu
  0 siblings, 0 replies; 29+ messages in thread
From: Yuanhan Liu @ 2016-02-16  6:12 UTC (permalink / raw)
  To: David Marchand; +Cc: dev

On Tue, Feb 16, 2016 at 07:09:49AM +0100, David Marchand wrote:
> On Tue, Feb 16, 2016 at 3:36 AM, Yuanhan Liu
> <yuanhan.liu@linux.intel.com> wrote:
> > On Mon, Feb 15, 2016 at 02:24:25PM +0100, David Marchand wrote:
> >> +/**
> >> + * A structure used to access io resources for a pci device.
> >> + * rte_pci_ioport is arch, os, driver specific, and should not be used outside
> >> + * of pci ioport api.
> >> + */
> >> +struct rte_pci_ioport {
> >> +     struct rte_pci_device *dev;
> >> +     uint64_t offset;
> >> +};
> >
> > "offset" dosen't sound like a good name to me; espeicially when I found
> > code like below:
> >
> >         reg = p->offset + offset;
> >
> > Regarding that, maybe "base" is a better name? I don't like it too much,
> > though. Any better idea?
> 
> Hum, yes, base sounds better, and I have no better idea, will go with
> this unless someone else complains.
> 
> > Otherwise, this patch looks good to me.
> 
> Thanks.
> 
> I will respin this patchset and if nobody is against this, I think

Feel free to add:

Reviewed-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>

	--yliu

> this patchset should be pulled quickly because other patches depend on
> it.
> 
> 
> -- 
> David Marchand

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH v4 0/4] rework ioport access for virtio
  2016-02-15 13:24   ` [dpdk-dev] [PATCH v3 0/4] rework ioport access for virtio David Marchand
                       ` (3 preceding siblings ...)
  2016-02-15 13:24     ` [dpdk-dev] [PATCH v3 4/4] virtio: use " David Marchand
@ 2016-02-16 20:37     ` David Marchand
  2016-02-16 20:37       ` [dpdk-dev] [PATCH v4 1/4] virtio/bsd: fix typo David Marchand
                         ` (4 more replies)
  4 siblings, 5 replies; 29+ messages in thread
From: David Marchand @ 2016-02-16 20:37 UTC (permalink / raw)
  To: dev

Introduce a new pci ioport api in eal to mask all arch / kernel driver
specifics.

- rte_eal_pci_ioport_map is responsible for initialising an rte_pci_ioport
  object that is used in subsequent calls, this function must be tweaked per
  architecture and per kernel driver,
- rte_eal_pci_ioport_read / rte_eal_pci_ioport_write uses a rte_pci_ioport
  object to read / write those resources,
- rte_eal_pci_ioport_unmap releases resources used by a rte_pci_ioport
  object if necessary.

There is still some more work to ensure intr handle are properly initialized
and released when used in conjonction with rte_eal_map_device() api calls.

BSD code has been neither run nor compiled, please can someone confirm I did
not break too much stuff ?

virtio legacy code has been updated accordingly.
With this, virtio code should be ready for other archs now.

So in the end, all that is missing on linux is some vfio update for support
of all architectures that have vfio.

Changes since v3:
- rebased on HEAD
- renamed "offset" field in rte_pci_ioport structure as "base"

Changes since v2:
- rebased on HEAD
- fixed a remaining reference to rte_ioport_t in comment
- fixed virtio driver for bsd

Changes since v1:
- dropped rte_ioport and removed the arch headers, if performance is an
  issue, we will see how to enhance this in later patches


Regards, 
-- 
David Marchand

David Marchand (4):
  virtio/bsd: fix typo
  virtio: fix incorrect check when mapping pci resources
  eal: introduce pci ioport api
  virtio: use pci ioport api

 drivers/net/virtio/virtio_pci.c                 | 358 ++++--------------------
 drivers/net/virtio/virtio_pci.h                 |  38 +--
 lib/librte_eal/bsdapp/eal/eal_pci.c             | 135 +++++++++
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   4 +
 lib/librte_eal/common/include/rte_pci.h         |  65 +++++
 lib/librte_eal/linuxapp/eal/eal_pci.c           | 170 +++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci_init.h      |  16 ++
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c       | 132 ++++++++-
 lib/librte_eal/linuxapp/eal/eal_pci_vfio.c      |  37 +++
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   4 +
 10 files changed, 620 insertions(+), 339 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH v4 1/4] virtio/bsd: fix typo
  2016-02-16 20:37     ` [dpdk-dev] [PATCH v4 0/4] rework ioport access for virtio David Marchand
@ 2016-02-16 20:37       ` David Marchand
  2016-02-16 20:37       ` [dpdk-dev] [PATCH v4 2/4] virtio: fix incorrect check when mapping pci resources David Marchand
                         ` (3 subsequent siblings)
  4 siblings, 0 replies; 29+ messages in thread
From: David Marchand @ 2016-02-16 20:37 UTC (permalink / raw)
  To: dev

Fixes: c52afa68d763 ("virtio: move left PCI stuff in the right file")
Signed-off-by: David Marchand <david.marchand@6wind.com>
Acked-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 455e40d..762e91c 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -439,7 +439,7 @@ legacy_virtio_resource_init(struct rte_pci_device *pci_dev)
 
 #else
 static int
-legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
+legacy_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
 {
 	/* nic_uio does not enable interrupts, return 0 (false). */
 	return 0;
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH v4 2/4] virtio: fix incorrect check when mapping pci resources
  2016-02-16 20:37     ` [dpdk-dev] [PATCH v4 0/4] rework ioport access for virtio David Marchand
  2016-02-16 20:37       ` [dpdk-dev] [PATCH v4 1/4] virtio/bsd: fix typo David Marchand
@ 2016-02-16 20:37       ` David Marchand
  2016-02-16 20:37       ` [dpdk-dev] [PATCH v4 3/4] eal: introduce pci ioport api David Marchand
                         ` (2 subsequent siblings)
  4 siblings, 0 replies; 29+ messages in thread
From: David Marchand @ 2016-02-16 20:37 UTC (permalink / raw)
  To: dev

According to the api, rte_eal_pci_map_device is only successful when returning
0.

Fixes: 6ba1f63b5ab0 ("virtio: support specification 1.0")
Signed-off-by: David Marchand <david.marchand@6wind.com>
Acked-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 762e91c..b4d4476 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -795,7 +795,7 @@ virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
 	struct virtio_pci_cap cap;
 	int ret;
 
-	if (rte_eal_pci_map_device(dev) < 0) {
+	if (rte_eal_pci_map_device(dev)) {
 		PMD_INIT_LOG(DEBUG, "failed to map pci device!");
 		return -1;
 	}
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH v4 3/4] eal: introduce pci ioport api
  2016-02-16 20:37     ` [dpdk-dev] [PATCH v4 0/4] rework ioport access for virtio David Marchand
  2016-02-16 20:37       ` [dpdk-dev] [PATCH v4 1/4] virtio/bsd: fix typo David Marchand
  2016-02-16 20:37       ` [dpdk-dev] [PATCH v4 2/4] virtio: fix incorrect check when mapping pci resources David Marchand
@ 2016-02-16 20:37       ` David Marchand
  2016-02-16 20:37       ` [dpdk-dev] [PATCH v4 4/4] virtio: use " David Marchand
  2016-02-16 21:59       ` [dpdk-dev] [PATCH v4 0/4] rework ioport access for virtio Thomas Monjalon
  4 siblings, 0 replies; 29+ messages in thread
From: David Marchand @ 2016-02-16 20:37 UTC (permalink / raw)
  To: dev

Most of the code is inspired on virtio driver.
rte_pci_ioport structure is filled at map time with anything needed for later
read / write calls.
At the moment, base field is used to store a x86 ioport (uint16_t) and will
be reused for other arches.

Signed-off-by: David Marchand <david.marchand@6wind.com>
Tested-by: Santosh Shukla <sshukla@mvista.com>
Reviewed-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
Changes since v3:
- renamed "offset" field in rte_pci_ioport structure as "base"

Changes since v2:
- removed remaining reference to rte_ioport_t

Changes since v1:
- dropped rte_ioport and removed the arch headers, if performance is an
  issue, we will see how to enhance this in later patches
- rte_pci_ioport object now reaches driver implementation (uio / vfio)
- sanity checks are in uio map function, no reason to have those checks in
  read/write functions

---
 lib/librte_eal/bsdapp/eal/eal_pci.c             | 135 +++++++++++++++++++
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   4 +
 lib/librte_eal/common/include/rte_pci.h         |  65 +++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c           | 170 ++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci_init.h      |  16 +++
 lib/librte_eal/linuxapp/eal/eal_pci_uio.c       | 132 +++++++++++++++++-
 lib/librte_eal/linuxapp/eal/eal_pci_vfio.c      |  37 ++++++
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   4 +
 8 files changed, 560 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 95c32c1..77e9cb3 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -51,6 +51,11 @@
 #include <sys/pciio.h>
 #include <dev/pci/pcireg.h>
 
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+#endif
+
 #include <rte_interrupts.h>
 #include <rte_log.h>
 #include <rte_pci.h>
@@ -479,6 +484,136 @@ int rte_eal_pci_write_config(const struct rte_pci_device *dev,
 	return -1;
 }
 
+int
+rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
+		       struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (dev->kdrv) {
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	case RTE_KDRV_NIC_UIO:
+		if ((uintptr_t) dev->mem_resource[bar].addr <= UINT16_MAX) {
+			p->base = (uintptr_t)dev->mem_resource[bar].addr;
+			ret = 0;
+		} else
+			ret = -1;
+		break;
+#endif
+	default:
+		ret = -1;
+		break;
+	}
+
+	if (!ret)
+		p->dev = dev;
+
+	return ret;
+}
+
+static void
+pci_uio_ioport_read(struct rte_pci_ioport *p,
+		    void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	uint8_t *d;
+	int size;
+	unsigned short reg = p->base + offset;
+
+	for (d = data; len > 0; d += size, reg += size, len -= size) {
+		if (len >= 4) {
+			size = 4;
+			*(uint32_t *)d = inl(reg);
+		} else if (len >= 2) {
+			size = 2;
+			*(uint16_t *)d = inw(reg);
+		} else {
+			size = 1;
+			*d = inb(reg);
+		}
+	}
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
+void
+rte_eal_pci_ioport_read(struct rte_pci_ioport *p,
+			void *data, size_t len, off_t offset)
+{
+	switch (p->dev->kdrv) {
+	case RTE_KDRV_NIC_UIO:
+		pci_uio_ioport_read(p, data, len, offset);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+pci_uio_ioport_write(struct rte_pci_ioport *p,
+		     const void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	const uint8_t *s;
+	int size;
+	unsigned short reg = p->base + offset;
+
+	for (s = data; len > 0; s += size, reg += size, len -= size) {
+		if (len >= 4) {
+			size = 4;
+			outl(*(const uint32_t *)s, reg);
+		} else if (len >= 2) {
+			size = 2;
+			outw(*(const uint16_t *)s, reg);
+		} else {
+			size = 1;
+			outb(*s, reg);
+		}
+	}
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
+void
+rte_eal_pci_ioport_write(struct rte_pci_ioport *p,
+			 const void *data, size_t len, off_t offset)
+{
+	switch (p->dev->kdrv) {
+	case RTE_KDRV_NIC_UIO:
+		pci_uio_ioport_write(p, data, len, offset);
+		break;
+	default:
+		break;
+	}
+}
+
+int
+rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (p->dev->kdrv) {
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	case RTE_KDRV_NIC_UIO:
+		ret = 0;
+		break;
+#endif
+	default:
+		ret = -1;
+		break;
+	}
+
+	return ret;
+}
+
 /* Init the PCI EAL subsystem */
 int
 rte_eal_pci_init(void)
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 1a96203..4f93ab7 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -140,6 +140,10 @@ DPDK_2.3 {
 	global:
 
 	rte_cpu_get_flag_name;
+	rte_eal_pci_ioport_map;
+	rte_eal_pci_ioport_read;
+	rte_eal_pci_ioport_unmap;
+	rte_eal_pci_ioport_write;
 	rte_eal_pci_map_device;
 	rte_eal_pci_unmap_device;
 
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 1508ea9..067e084 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -512,6 +512,71 @@ int rte_eal_pci_read_config(const struct rte_pci_device *device,
 int rte_eal_pci_write_config(const struct rte_pci_device *device,
 			     const void *buf, size_t len, off_t offset);
 
+/**
+ * A structure used to access io resources for a pci device.
+ * rte_pci_ioport is arch, os, driver specific, and should not be used outside
+ * of pci ioport api.
+ */
+struct rte_pci_ioport {
+	struct rte_pci_device *dev;
+	uint64_t base;
+};
+
+/**
+ * Initialises a rte_pci_ioport object for a pci device io resource.
+ * This object is then used to gain access to those io resources (see below).
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device.
+ *   to use
+ * @param bar
+ *   Index of the io pci resource we want to access.
+ * @param p
+ *   The rte_pci_ioport object to be initialized.
+ * @return
+ *  0 on success, negative on error.
+ */
+int rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
+			   struct rte_pci_ioport *p);
+
+/**
+ * Release any resources used in a rte_pci_ioport object.
+ *
+ * @param p
+ *   The rte_pci_ioport object to be uninitialized.
+ */
+int rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p);
+
+/**
+ * Read from a io pci resource.
+ *
+ * @param p
+ *   The rte_pci_ioport object from which we want to read.
+ * @param data
+ *   A data buffer where the bytes should be read into
+ * @param len
+ *   The length of the data buffer.
+ * @param offset
+ *   The offset into the pci io resource.
+ */
+void rte_eal_pci_ioport_read(struct rte_pci_ioport *p,
+			     void *data, size_t len, off_t offset);
+
+/**
+ * Write to a io pci resource.
+ *
+ * @param p
+ *   The rte_pci_ioport object to which we want to write.
+ * @param data
+ *   A data buffer where the bytes should be read into
+ * @param len
+ *   The length of the data buffer.
+ * @param offset
+ *   The offset into the pci io resource.
+ */
+void rte_eal_pci_ioport_write(struct rte_pci_ioport *p,
+			      const void *data, size_t len, off_t offset);
+
 #ifdef RTE_PCI_CONFIG
 /**
  * Set special config space registers for performance purpose.
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index db947da..4346973 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -621,6 +621,176 @@ int rte_eal_pci_write_config(const struct rte_pci_device *device,
 	}
 }
 
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+static int
+pci_ioport_map(struct rte_pci_device *dev, int bar __rte_unused,
+	       struct rte_pci_ioport *p)
+{
+	uint16_t start, end;
+	FILE *fp;
+	char *line = NULL;
+	char pci_id[16];
+	int found = 0;
+	size_t linesz;
+
+	snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT,
+		 dev->addr.domain, dev->addr.bus,
+		 dev->addr.devid, dev->addr.function);
+
+	fp = fopen("/proc/ioports", "r");
+	if (fp == NULL) {
+		RTE_LOG(ERR, EAL, "%s(): can't open ioports\n", __func__);
+		return -1;
+	}
+
+	while (getdelim(&line, &linesz, '\n', fp) > 0) {
+		char *ptr = line;
+		char *left;
+		int n;
+
+		n = strcspn(ptr, ":");
+		ptr[n] = 0;
+		left = &ptr[n + 1];
+
+		while (*left && isspace(*left))
+			left++;
+
+		if (!strncmp(left, pci_id, strlen(pci_id))) {
+			found = 1;
+
+			while (*ptr && isspace(*ptr))
+				ptr++;
+
+			sscanf(ptr, "%04hx-%04hx", &start, &end);
+
+			break;
+		}
+	}
+
+	free(line);
+	fclose(fp);
+
+	if (!found)
+		return -1;
+
+	dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
+	p->base = start;
+	RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%x\n", start);
+
+	return 0;
+}
+#endif
+
+int
+rte_eal_pci_ioport_map(struct rte_pci_device *dev, int bar,
+		       struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (dev->kdrv) {
+#ifdef VFIO_PRESENT
+	case RTE_KDRV_VFIO:
+		ret = -1;
+		if (pci_vfio_is_enabled())
+			ret = pci_vfio_ioport_map(dev, bar, p);
+		break;
+#endif
+	case RTE_KDRV_IGB_UIO:
+	case RTE_KDRV_UIO_GENERIC:
+		ret = pci_uio_ioport_map(dev, bar, p);
+		break;
+	default:
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+		/* special case for x86 ... */
+		ret = pci_ioport_map(dev, bar, p);
+#else
+		ret = -1;
+#endif
+		break;
+	}
+
+	if (!ret)
+		p->dev = dev;
+
+	return ret;
+}
+
+void
+rte_eal_pci_ioport_read(struct rte_pci_ioport *p,
+			void *data, size_t len, off_t offset)
+{
+	switch (p->dev->kdrv) {
+#ifdef VFIO_PRESENT
+	case RTE_KDRV_VFIO:
+		pci_vfio_ioport_read(p, data, len, offset);
+		break;
+#endif
+	case RTE_KDRV_IGB_UIO:
+	case RTE_KDRV_UIO_GENERIC:
+		pci_uio_ioport_read(p, data, len, offset);
+		break;
+	default:
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+		/* special case for x86 ... */
+		pci_uio_ioport_read(p, data, len, offset);
+#endif
+		break;
+	}
+}
+
+void
+rte_eal_pci_ioport_write(struct rte_pci_ioport *p,
+			 const void *data, size_t len, off_t offset)
+{
+	switch (p->dev->kdrv) {
+#ifdef VFIO_PRESENT
+	case RTE_KDRV_VFIO:
+		pci_vfio_ioport_write(p, data, len, offset);
+		break;
+#endif
+	case RTE_KDRV_IGB_UIO:
+	case RTE_KDRV_UIO_GENERIC:
+		pci_uio_ioport_write(p, data, len, offset);
+		break;
+	default:
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+		/* special case for x86 ... */
+		pci_uio_ioport_write(p, data, len, offset);
+#endif
+		break;
+	}
+}
+
+int
+rte_eal_pci_ioport_unmap(struct rte_pci_ioport *p)
+{
+	int ret;
+
+	switch (p->dev->kdrv) {
+#ifdef VFIO_PRESENT
+	case RTE_KDRV_VFIO:
+		ret = -1;
+		if (pci_vfio_is_enabled())
+			ret = pci_vfio_ioport_unmap(p);
+		break;
+#endif
+	case RTE_KDRV_IGB_UIO:
+	case RTE_KDRV_UIO_GENERIC:
+		ret = pci_uio_ioport_unmap(p);
+		break;
+	default:
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+		/* special case for x86 ... nothing to do */
+		ret = 0;
+#else
+		ret = -1;
+#endif
+		break;
+	}
+
+	return ret;
+}
+
 /* Init the PCI EAL subsystem */
 int
 rte_eal_pci_init(void)
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_init.h b/lib/librte_eal/linuxapp/eal/eal_pci_init.h
index a17c708..7011753 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_init.h
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_init.h
@@ -54,6 +54,14 @@ int pci_uio_read_config(const struct rte_intr_handle *intr_handle,
 int pci_uio_write_config(const struct rte_intr_handle *intr_handle,
 			 const void *buf, size_t len, off_t offs);
 
+int pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
+		       struct rte_pci_ioport *p);
+void pci_uio_ioport_read(struct rte_pci_ioport *p,
+			 void *data, size_t len, off_t offset);
+void pci_uio_ioport_write(struct rte_pci_ioport *p,
+			  const void *data, size_t len, off_t offset);
+int pci_uio_ioport_unmap(struct rte_pci_ioport *p);
+
 #ifdef VFIO_PRESENT
 
 #define VFIO_MAX_GROUPS 64
@@ -68,6 +76,14 @@ int pci_vfio_read_config(const struct rte_intr_handle *intr_handle,
 int pci_vfio_write_config(const struct rte_intr_handle *intr_handle,
 			  const void *buf, size_t len, off_t offs);
 
+int pci_vfio_ioport_map(struct rte_pci_device *dev, int bar,
+		        struct rte_pci_ioport *p);
+void pci_vfio_ioport_read(struct rte_pci_ioport *p,
+			  void *data, size_t len, off_t offset);
+void pci_vfio_ioport_write(struct rte_pci_ioport *p,
+			   const void *data, size_t len, off_t offset);
+int pci_vfio_ioport_unmap(struct rte_pci_ioport *p);
+
 /* map VFIO resource prototype */
 int pci_vfio_map_resource(struct rte_pci_device *dev);
 int pci_vfio_get_group_fd(int iommu_group_fd);
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
index ac50e13..db22d31 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_uio.c
@@ -39,6 +39,10 @@
 #include <sys/mman.h>
 #include <linux/pci_regs.h>
 
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+#include <sys/io.h>
+#endif
+
 #include <rte_log.h>
 #include <rte_pci.h>
 #include <rte_eal_memconfig.h>
@@ -145,7 +149,7 @@ pci_mknod_uio_dev(const char *sysfs_uio_path, unsigned uio_num)
  */
 static int
 pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
-			   unsigned int buflen)
+			   unsigned int buflen, int create)
 {
 	struct rte_pci_addr *loc = &dev->addr;
 	unsigned int uio_num;
@@ -208,7 +212,7 @@ pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
 		return -1;
 
 	/* create uio device if we've been asked to */
-	if (internal_config.create_uio_dev &&
+	if (internal_config.create_uio_dev && create &&
 			pci_mknod_uio_dev(dstbuf, uio_num) < 0)
 		RTE_LOG(WARNING, EAL, "Cannot create /dev/uio%u\n", uio_num);
 
@@ -245,7 +249,7 @@ pci_uio_alloc_resource(struct rte_pci_device *dev,
 	loc = &dev->addr;
 
 	/* find uio resource */
-	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname));
+	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 1);
 	if (uio_num < 0) {
 		RTE_LOG(WARNING, EAL, "  "PCI_PRI_FMT" not managed by UIO driver, "
 				"skipping\n", loc->domain, loc->bus, loc->devid, loc->function);
@@ -363,3 +367,125 @@ error:
 	rte_free(maps[map_idx].path);
 	return -1;
 }
+
+int
+pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
+		   struct rte_pci_ioport *p)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	char dirname[PATH_MAX];
+	char filename[PATH_MAX];
+	int uio_num;
+	unsigned long start;
+
+	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 0);
+	if (uio_num < 0)
+		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;
+	}
+	/* 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) {
+
+		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;
+		}
+		dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
+	}
+
+	RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%lx\n", start);
+
+	p->base = start;
+	return 0;
+#else
+	RTE_SET_USED(dev);
+	RTE_SET_USED(bar);
+	RTE_SET_USED(p);
+	return -1;
+#endif
+}
+
+void
+pci_uio_ioport_read(struct rte_pci_ioport *p,
+		    void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	uint8_t *d;
+	int size;
+	unsigned short reg = p->base + offset;
+
+	for (d = data; len > 0; d += size, reg += size, len -= size) {
+		if (len >= 4) {
+			size = 4;
+			*(uint32_t *)d = inl(reg);
+		} else if (len >= 2) {
+			size = 2;
+			*(uint16_t *)d = inw(reg);
+		} else {
+			size = 1;
+			*d = inb(reg);
+		}
+	}
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
+void
+pci_uio_ioport_write(struct rte_pci_ioport *p,
+		     const void *data, size_t len, off_t offset)
+{
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	const uint8_t *s;
+	int size;
+	unsigned short reg = p->base + offset;
+
+	for (s = data; len > 0; s += size, reg += size, len -= size) {
+		if (len >= 4) {
+			size = 4;
+			outl_p(*(const uint32_t *)s, reg);
+		} else if (len >= 2) {
+			size = 2;
+			outw_p(*(const uint16_t *)s, reg);
+		} else {
+			size = 1;
+			outb_p(*s, reg);
+		}
+	}
+#else
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+#endif
+}
+
+int
+pci_uio_ioport_unmap(struct rte_pci_ioport *p)
+{
+	RTE_SET_USED(p);
+#if defined(RTE_ARCH_X86_64) || defined(RTE_ARCH_I686)
+	/* FIXME close intr fd ? */
+	return 0;
+#else
+	return -1;
+#endif
+}
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c b/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
index a6c7e16..ffa2dd0 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci_vfio.c
@@ -976,6 +976,43 @@ pci_vfio_map_resource(struct rte_pci_device *dev)
 }
 
 int
+pci_vfio_ioport_map(struct rte_pci_device *dev, int bar,
+		    struct rte_pci_ioport *p)
+{
+	RTE_SET_USED(dev);
+	RTE_SET_USED(bar);
+	RTE_SET_USED(p);
+	return -1;
+}
+
+void
+pci_vfio_ioport_read(struct rte_pci_ioport *p,
+		     void *data, size_t len, off_t offset)
+{
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+}
+
+void
+pci_vfio_ioport_write(struct rte_pci_ioport *p,
+		      const void *data, size_t len, off_t offset)
+{
+	RTE_SET_USED(p);
+	RTE_SET_USED(data);
+	RTE_SET_USED(len);
+	RTE_SET_USED(offset);
+}
+
+int
+pci_vfio_ioport_unmap(struct rte_pci_ioport *p)
+{
+	RTE_SET_USED(p);
+	return -1;
+}
+
+int
 pci_vfio_enable(void)
 {
 	/* initialize group list */
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index 440fac2..e8d8660 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -143,6 +143,10 @@ DPDK_2.3 {
 	global:
 
 	rte_cpu_get_flag_name;
+	rte_eal_pci_ioport_map;
+	rte_eal_pci_ioport_read;
+	rte_eal_pci_ioport_unmap;
+	rte_eal_pci_ioport_write;
 	rte_eal_pci_map_device;
 	rte_eal_pci_unmap_device;
 
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [dpdk-dev] [PATCH v4 4/4] virtio: use pci ioport api
  2016-02-16 20:37     ` [dpdk-dev] [PATCH v4 0/4] rework ioport access for virtio David Marchand
                         ` (2 preceding siblings ...)
  2016-02-16 20:37       ` [dpdk-dev] [PATCH v4 3/4] eal: introduce pci ioport api David Marchand
@ 2016-02-16 20:37       ` David Marchand
  2016-02-16 21:59       ` [dpdk-dev] [PATCH v4 0/4] rework ioport access for virtio Thomas Monjalon
  4 siblings, 0 replies; 29+ messages in thread
From: David Marchand @ 2016-02-16 20:37 UTC (permalink / raw)
  To: dev

Move all os / arch specifics to eal.

Signed-off-by: David Marchand <david.marchand@6wind.com>
Reviewed-by: Santosh Shukla <sshukla@mvista.com>
Tested-by: Santosh Shukla <sshukla@mvista.com>
Acked-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
Changes since v2:
- fixed bsd init issue (reported by Tetsuya M.)

---
 drivers/net/virtio/virtio_pci.c | 356 +++++++---------------------------------
 drivers/net/virtio/virtio_pci.h |  38 +----
 2 files changed, 59 insertions(+), 335 deletions(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index b4d4476..85fbe88 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -49,74 +49,35 @@
 #define PCI_CAPABILITY_LIST	0x34
 #define PCI_CAP_ID_VNDR		0x09
 
-#define VIRTIO_PCI_REG_ADDR(hw, reg) \
-	(unsigned short)((hw)->io_base + (reg))
-
-#define VIRTIO_READ_REG_1(hw, reg) \
-	inb((VIRTIO_PCI_REG_ADDR((hw), (reg))))
-#define VIRTIO_WRITE_REG_1(hw, reg, value) \
-	outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
-
-#define VIRTIO_READ_REG_2(hw, reg) \
-	inw((VIRTIO_PCI_REG_ADDR((hw), (reg))))
-#define VIRTIO_WRITE_REG_2(hw, reg, value) \
-	outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
-
-#define VIRTIO_READ_REG_4(hw, reg) \
-	inl((VIRTIO_PCI_REG_ADDR((hw), (reg))))
-#define VIRTIO_WRITE_REG_4(hw, reg, value) \
-	outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
+/*
+ * The remaining space is defined by each driver as the per-driver
+ * configuration space.
+ */
+#define VIRTIO_PCI_CONFIG(hw) (((hw)->use_msix) ? 24 : 20)
 
 static void
 legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
 		       void *dst, int length)
 {
-	uint64_t off;
-	uint8_t *d;
-	int size;
-
-	off = VIRTIO_PCI_CONFIG(hw) + offset;
-	for (d = dst; length > 0; d += size, off += size, length -= size) {
-		if (length >= 4) {
-			size = 4;
-			*(uint32_t *)d = VIRTIO_READ_REG_4(hw, off);
-		} else if (length >= 2) {
-			size = 2;
-			*(uint16_t *)d = VIRTIO_READ_REG_2(hw, off);
-		} else {
-			size = 1;
-			*d = VIRTIO_READ_REG_1(hw, off);
-		}
-	}
+	rte_eal_pci_ioport_read(&hw->io, dst, length,
+				VIRTIO_PCI_CONFIG(hw) + offset);
 }
 
 static void
 legacy_write_dev_config(struct virtio_hw *hw, size_t offset,
 			const void *src, int length)
 {
-	uint64_t off;
-	const uint8_t *s;
-	int size;
-
-	off = VIRTIO_PCI_CONFIG(hw) + offset;
-	for (s = src; length > 0; s += size, off += size, length -= size) {
-		if (length >= 4) {
-			size = 4;
-			VIRTIO_WRITE_REG_4(hw, off, *(const uint32_t *)s);
-		} else if (length >= 2) {
-			size = 2;
-			VIRTIO_WRITE_REG_2(hw, off, *(const uint16_t *)s);
-		} else {
-			size = 1;
-			VIRTIO_WRITE_REG_1(hw, off, *s);
-		}
-	}
+	rte_eal_pci_ioport_write(&hw->io, src, length,
+				 VIRTIO_PCI_CONFIG(hw) + offset);
 }
 
 static uint64_t
 legacy_get_features(struct virtio_hw *hw)
 {
-	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+	uint64_t dst;
+
+	rte_eal_pci_ioport_read(&hw->io, &dst, 4, VIRTIO_PCI_HOST_FEATURES);
+	return dst;
 }
 
 static void
@@ -127,19 +88,23 @@ legacy_set_features(struct virtio_hw *hw, uint64_t features)
 			"only 32 bit features are allowed for legacy virtio!");
 		return;
 	}
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
+	rte_eal_pci_ioport_write(&hw->io, &features, 4,
+				 VIRTIO_PCI_GUEST_FEATURES);
 }
 
 static uint8_t
 legacy_get_status(struct virtio_hw *hw)
 {
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
+	uint8_t dst;
+
+	rte_eal_pci_ioport_read(&hw->io, &dst, 1, VIRTIO_PCI_STATUS);
+	return dst;
 }
 
 static void
 legacy_set_status(struct virtio_hw *hw, uint8_t status)
 {
-	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+	rte_eal_pci_ioport_write(&hw->io, &status, 1, VIRTIO_PCI_STATUS);
 }
 
 static void
@@ -151,148 +116,63 @@ legacy_reset(struct virtio_hw *hw)
 static uint8_t
 legacy_get_isr(struct virtio_hw *hw)
 {
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+	uint8_t dst;
+
+	rte_eal_pci_ioport_read(&hw->io, &dst, 1, VIRTIO_PCI_ISR);
+	return dst;
 }
 
 /* Enable one vector (0) for Link State Intrerrupt */
 static uint16_t
 legacy_set_config_irq(struct virtio_hw *hw, uint16_t vec)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR, vec);
-	return VIRTIO_READ_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR);
+	uint16_t dst;
+
+	rte_eal_pci_ioport_write(&hw->io, &vec, 2, VIRTIO_MSI_CONFIG_VECTOR);
+	rte_eal_pci_ioport_read(&hw->io, &dst, 2, VIRTIO_MSI_CONFIG_VECTOR);
+	return dst;
 }
 
 static uint16_t
 legacy_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, queue_id);
-	return VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
+	uint16_t dst;
+
+	rte_eal_pci_ioport_write(&hw->io, &queue_id, 2, VIRTIO_PCI_QUEUE_SEL);
+	rte_eal_pci_ioport_read(&hw->io, &dst, 2, VIRTIO_PCI_QUEUE_NUM);
+	return dst;
 }
 
 static void
 legacy_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
+	uint32_t src;
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
-		vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+	rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2,
+			 VIRTIO_PCI_QUEUE_SEL);
+	src = vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
+	rte_eal_pci_ioport_write(&hw->io, &src, 4, VIRTIO_PCI_QUEUE_PFN);
 }
 
 static void
 legacy_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
+	uint32_t src = 0;
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+	rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2,
+			 VIRTIO_PCI_QUEUE_SEL);
+	rte_eal_pci_ioport_write(&hw->io, &src, 4, VIRTIO_PCI_QUEUE_PFN);
 }
 
 static void
 legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
+	rte_eal_pci_ioport_write(&hw->io, &vq->vq_queue_index, 2,
+			 VIRTIO_PCI_QUEUE_NOTIFY);
 }
 
 #ifdef RTE_EXEC_ENV_LINUXAPP
 static int
-parse_sysfs_value(const char *filename, unsigned long *val)
-{
-	FILE *f;
-	char buf[BUFSIZ];
-	char *end = NULL;
-
-	f = fopen(filename, "r");
-	if (f == NULL) {
-		PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s",
-			     __func__, filename);
-		return -1;
-	}
-
-	if (fgets(buf, sizeof(buf), f) == NULL) {
-		PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s",
-			     __func__, filename);
-		fclose(f);
-		return -1;
-	}
-	*val = strtoul(buf, &end, 0);
-	if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) {
-		PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s",
-			     __func__, filename);
-		fclose(f);
-		return -1;
-	}
-	fclose(f);
-	return 0;
-}
-
-static int
-get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen,
-			unsigned int *uio_num)
-{
-	struct dirent *e;
-	DIR *dir;
-	char dirname[PATH_MAX];
-
-	/*
-	 * depending on kernel version, uio can be located in uio/uioX
-	 * or uio:uioX
-	 */
-	snprintf(dirname, sizeof(dirname),
-		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio",
-		     loc->domain, loc->bus, loc->devid, loc->function);
-	dir = opendir(dirname);
-	if (dir == NULL) {
-		/* retry with the parent directory */
-		snprintf(dirname, sizeof(dirname),
-			     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT,
-			     loc->domain, loc->bus, loc->devid, loc->function);
-		dir = opendir(dirname);
-
-		if (dir == NULL) {
-			PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname);
-			return -1;
-		}
-	}
-
-	/* take the first file starting with "uio" */
-	while ((e = readdir(dir)) != NULL) {
-		/* format could be uio%d ...*/
-		int shortprefix_len = sizeof("uio") - 1;
-		/* ... or uio:uio%d */
-		int longprefix_len = sizeof("uio:uio") - 1;
-		char *endptr;
-
-		if (strncmp(e->d_name, "uio", 3) != 0)
-			continue;
-
-		/* first try uio%d */
-		errno = 0;
-		*uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10);
-		if (errno == 0 && endptr != (e->d_name + shortprefix_len)) {
-			snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num);
-			break;
-		}
-
-		/* then try uio:uio%d */
-		errno = 0;
-		*uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10);
-		if (errno == 0 && endptr != (e->d_name + longprefix_len)) {
-			snprintf(buf, buflen, "%s/uio:uio%u", dirname,
-				     *uio_num);
-			break;
-		}
-	}
-	closedir(dir);
-
-	/* No uio resource found */
-	if (e == NULL) {
-		PMD_INIT_LOG(ERR, "Could not find uio resource");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int
 legacy_virtio_has_msix(const struct rte_pci_addr *loc)
 {
 	DIR *d;
@@ -308,135 +188,6 @@ legacy_virtio_has_msix(const struct rte_pci_addr *loc)
 
 	return d != NULL;
 }
-
-/* Extract I/O port numbers from sysfs */
-static int
-virtio_resource_init_by_uio(struct rte_pci_device *pci_dev)
-{
-	char dirname[PATH_MAX];
-	char filename[PATH_MAX];
-	unsigned long start, size;
-	unsigned int uio_num;
-
-	if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0)
-		return -1;
-
-	/* get portio size */
-	snprintf(filename, sizeof(filename),
-		     "%s/portio/port0/size", dirname);
-	if (parse_sysfs_value(filename, &size) < 0) {
-		PMD_INIT_LOG(ERR, "%s(): cannot parse size",
-			     __func__);
-		return -1;
-	}
-
-	/* get portio start */
-	snprintf(filename, sizeof(filename),
-		 "%s/portio/port0/start", dirname);
-	if (parse_sysfs_value(filename, &start) < 0) {
-		PMD_INIT_LOG(ERR, "%s(): cannot parse portio start",
-			     __func__);
-		return -1;
-	}
-	pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start;
-	pci_dev->mem_resource[0].len =  (uint64_t)size;
-	PMD_INIT_LOG(DEBUG,
-		     "PCI Port IO found start=0x%lx with size=0x%lx",
-		     start, size);
-
-	/* save fd */
-	memset(dirname, 0, sizeof(dirname));
-	snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num);
-	pci_dev->intr_handle.fd = open(dirname, O_RDWR);
-	if (pci_dev->intr_handle.fd < 0) {
-		PMD_INIT_LOG(ERR, "Cannot open %s: %s\n",
-			dirname, strerror(errno));
-		return -1;
-	}
-
-	pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
-	pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
-
-	return 0;
-}
-
-/* Extract port I/O numbers from proc/ioports */
-static int
-virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev)
-{
-	uint16_t start, end;
-	int size;
-	FILE *fp;
-	char *line = NULL;
-	char pci_id[16];
-	int found = 0;
-	size_t linesz;
-
-	snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT,
-		 pci_dev->addr.domain,
-		 pci_dev->addr.bus,
-		 pci_dev->addr.devid,
-		 pci_dev->addr.function);
-
-	fp = fopen("/proc/ioports", "r");
-	if (fp == NULL) {
-		PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__);
-		return -1;
-	}
-
-	while (getdelim(&line, &linesz, '\n', fp) > 0) {
-		char *ptr = line;
-		char *left;
-		int n;
-
-		n = strcspn(ptr, ":");
-		ptr[n] = 0;
-		left = &ptr[n + 1];
-
-		while (*left && isspace(*left))
-			left++;
-
-		if (!strncmp(left, pci_id, strlen(pci_id))) {
-			found = 1;
-
-			while (*ptr && isspace(*ptr))
-				ptr++;
-
-			sscanf(ptr, "%04hx-%04hx", &start, &end);
-			size = end - start + 1;
-
-			break;
-		}
-	}
-
-	free(line);
-	fclose(fp);
-
-	if (!found)
-		return -1;
-
-	pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start;
-	pci_dev->mem_resource[0].len =  (uint64_t)size;
-	PMD_INIT_LOG(DEBUG,
-		"PCI Port IO found start=0x%x with size=0x%x",
-		start, size);
-
-	/* can't support lsc interrupt without uio */
-	pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC;
-
-	return 0;
-}
-
-/* Extract I/O port numbers from sysfs */
-static int
-legacy_virtio_resource_init(struct rte_pci_device *pci_dev)
-{
-	if (virtio_resource_init_by_uio(pci_dev) == 0)
-		return 0;
-	else
-		return virtio_resource_init_by_ioports(pci_dev);
-}
-
 #else
 static int
 legacy_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
@@ -444,14 +195,22 @@ legacy_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
 	/* nic_uio does not enable interrupts, return 0 (false). */
 	return 0;
 }
+#endif
 
 static int
-legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
+legacy_virtio_resource_init(struct rte_pci_device *pci_dev,
+			    struct virtio_hw *hw)
 {
-	/* no setup required */
+	if (rte_eal_pci_ioport_map(pci_dev, 0, &hw->io) < 0)
+		return -1;
+
+	if (pci_dev->intr_handle.type != RTE_INTR_HANDLE_UNKNOWN)
+		pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
+	else
+		pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC;
+
 	return 0;
 }
-#endif
 
 static const struct virtio_pci_ops legacy_ops = {
 	.read_dev_cfg	= legacy_read_dev_config,
@@ -882,12 +641,11 @@ vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 	}
 
 	PMD_INIT_LOG(INFO, "trying with legacy virtio pci.");
-	if (legacy_virtio_resource_init(dev) < 0)
+	if (legacy_virtio_resource_init(dev, hw) < 0)
 		return -1;
 
 	hw->vtpci_ops = &legacy_ops;
 	hw->use_msix = legacy_virtio_has_msix(&dev->addr);
-	hw->io_base  = (uint32_t)(uintptr_t)dev->mem_resource[0].addr;
 	hw->modern   = 0;
 
 	return 0;
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index 0544a07..b69785e 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -36,13 +36,7 @@
 
 #include <stdint.h>
 
-#ifdef __FreeBSD__
-#include <sys/types.h>
-#include <machine/cpufunc.h>
-#else
-#include <sys/io.h>
-#endif
-
+#include <rte_pci.h>
 #include <rte_ethdev.h>
 
 struct virtqueue;
@@ -249,7 +243,7 @@ struct virtio_net_config;
 
 struct virtio_hw {
 	struct virtqueue *cvq;
-	uint32_t    io_base;
+	struct rte_pci_ioport io;
 	uint64_t    guest_features;
 	uint32_t    max_tx_queues;
 	uint32_t    max_rx_queues;
@@ -282,12 +276,6 @@ struct virtio_net_config {
 } __attribute__((packed));
 
 /*
- * The remaining space is defined by each driver as the per-driver
- * configuration space.
- */
-#define VIRTIO_PCI_CONFIG(hw) (((hw)->use_msix) ? 24 : 20)
-
-/*
  * How many bits to shift physical queue address written to QUEUE_PFN.
  * 12 is historical, and due to x86 page size.
  */
@@ -296,28 +284,6 @@ struct virtio_net_config {
 /* The alignment to use between consumer and producer parts of vring. */
 #define VIRTIO_PCI_VRING_ALIGN 4096
 
-#ifdef __FreeBSD__
-
-static inline void
-outb_p(unsigned char data, unsigned int port)
-{
-
-	outb(port, (u_char)data);
-}
-
-static inline void
-outw_p(unsigned short data, unsigned int port)
-{
-	outw(port, (u_short)data);
-}
-
-static inline void
-outl_p(unsigned int data, unsigned int port)
-{
-	outl(port, (u_int)data);
-}
-#endif
-
 static inline int
 vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-- 
1.9.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [dpdk-dev] [PATCH v4 0/4] rework ioport access for virtio
  2016-02-16 20:37     ` [dpdk-dev] [PATCH v4 0/4] rework ioport access for virtio David Marchand
                         ` (3 preceding siblings ...)
  2016-02-16 20:37       ` [dpdk-dev] [PATCH v4 4/4] virtio: use " David Marchand
@ 2016-02-16 21:59       ` Thomas Monjalon
  4 siblings, 0 replies; 29+ messages in thread
From: Thomas Monjalon @ 2016-02-16 21:59 UTC (permalink / raw)
  To: David Marchand; +Cc: dev

2016-02-16 21:37, David Marchand:
> Introduce a new pci ioport api in eal to mask all arch / kernel driver
> specifics.
> 
> - rte_eal_pci_ioport_map is responsible for initialising an rte_pci_ioport
>   object that is used in subsequent calls, this function must be tweaked per
>   architecture and per kernel driver,
> - rte_eal_pci_ioport_read / rte_eal_pci_ioport_write uses a rte_pci_ioport
>   object to read / write those resources,
> - rte_eal_pci_ioport_unmap releases resources used by a rte_pci_ioport
>   object if necessary.

Applied, thanks

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2016-02-16 22:01 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-05 17:55 [dpdk-dev] [PATCH 0/4] rework ioport access for virtio David Marchand
2016-02-05 17:55 ` [dpdk-dev] [PATCH 1/4] virtio/bsd: fix typo David Marchand
2016-02-05 17:55 ` [dpdk-dev] [PATCH 2/4] virtio: fix incorrect check when mapping pci resources David Marchand
2016-02-05 17:55 ` [dpdk-dev] [PATCH 3/4] eal: introduce ioport api David Marchand
2016-02-05 17:55 ` [dpdk-dev] [PATCH 4/4] virtio: use " David Marchand
2016-02-07  7:48 ` [dpdk-dev] [PATCH v2 0/4] rework ioport access for virtio David Marchand
2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 1/4] virtio/bsd: fix typo David Marchand
2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 2/4] virtio: fix incorrect check when mapping pci resources David Marchand
2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 3/4] eal: introduce pci ioport api David Marchand
2016-02-08  5:56     ` Santosh Shukla
2016-02-07  7:48   ` [dpdk-dev] [PATCH v2 4/4] virtio: use " David Marchand
2016-02-08  6:01     ` Santosh Shukla
2016-02-09  3:52     ` Tetsuya Mukawa
2016-02-09  8:31       ` David Marchand
2016-02-15 13:24   ` [dpdk-dev] [PATCH v3 0/4] rework ioport access for virtio David Marchand
2016-02-15 13:24     ` [dpdk-dev] [PATCH v3 1/4] virtio/bsd: fix typo David Marchand
2016-02-15 13:24     ` [dpdk-dev] [PATCH v3 2/4] virtio: fix incorrect check when mapping pci resources David Marchand
2016-02-15 13:24     ` [dpdk-dev] [PATCH v3 3/4] eal: introduce pci ioport api David Marchand
2016-02-16  2:36       ` Yuanhan Liu
2016-02-16  6:09         ` David Marchand
2016-02-16  6:12           ` Yuanhan Liu
2016-02-15 13:24     ` [dpdk-dev] [PATCH v3 4/4] virtio: use " David Marchand
2016-02-16  2:24       ` Yuanhan Liu
2016-02-16 20:37     ` [dpdk-dev] [PATCH v4 0/4] rework ioport access for virtio David Marchand
2016-02-16 20:37       ` [dpdk-dev] [PATCH v4 1/4] virtio/bsd: fix typo David Marchand
2016-02-16 20:37       ` [dpdk-dev] [PATCH v4 2/4] virtio: fix incorrect check when mapping pci resources David Marchand
2016-02-16 20:37       ` [dpdk-dev] [PATCH v4 3/4] eal: introduce pci ioport api David Marchand
2016-02-16 20:37       ` [dpdk-dev] [PATCH v4 4/4] virtio: use " David Marchand
2016-02-16 21:59       ` [dpdk-dev] [PATCH v4 0/4] rework ioport access for virtio Thomas Monjalon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).