DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling
@ 2015-12-10  3:54 Yuanhan Liu
  2015-12-10  3:54 ` [dpdk-dev] [PATCH 1/6] virtio: don't set vring address again at queue startup Yuanhan Liu
                   ` (8 more replies)
  0 siblings, 9 replies; 122+ messages in thread
From: Yuanhan Liu @ 2015-12-10  3:54 UTC (permalink / raw)
  To: dev

Hi,

Here is an initial virtio 1.0 pmd driver enabling.

Almost all difference comes from virtio 1.0 are the PCI layout change:
the major configuration structures are stored at bar space, and their
location is stored at corresponding pci cap structure. Reading/parsing
them is one of the major work of patch 6.

To make handling virtio v1.0 and v0.95 co-exist well, this patch set
introduces a virtio_pci_ops structure, to add another layer so that
we could keep those vtpci_foo_bar "APIs". With that, we could do the
minimum change to add virtio 1.0 support.

Note that the enabling is still in rough state, and it's likely I may
miss something. So, comments are huge welcome!

	--yliu

---
Yuanhan Liu (6):
  virtio: don't set vring address again at queue startup
  virtio: introduce struct virtio_pci_ops
  virtio: move left pci stuff to virtio_pci.c
  viritio: switch to 64 bit features
  virtio: set RTE_PCI_DRV_NEED_MAPPING flag
  virtio: add virtio v1.0 support

 drivers/net/virtio/virtio_ethdev.c | 297 +--------------
 drivers/net/virtio/virtio_ethdev.h |   3 +-
 drivers/net/virtio/virtio_pci.c    | 752 +++++++++++++++++++++++++++++++++++--
 drivers/net/virtio/virtio_pci.h    | 100 ++++-
 drivers/net/virtio/virtio_rxtx.c   |  15 -
 drivers/net/virtio/virtqueue.h     |   4 +-
 6 files changed, 843 insertions(+), 328 deletions(-)

-- 
1.9.0

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

* [dpdk-dev] [PATCH 1/6] virtio: don't set vring address again at queue startup
  2015-12-10  3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu
@ 2015-12-10  3:54 ` Yuanhan Liu
  2015-12-10  3:54 ` [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops Yuanhan Liu
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2015-12-10  3:54 UTC (permalink / raw)
  To: dev

As we have already set up it at virtio_dev_queue_setup(), and a vq
restart will not reset the settings.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_rxtx.c | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index 74b39ef..b7267c0 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -339,11 +339,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type)
 		vq_update_avail_idx(vq);
 
 		PMD_INIT_LOG(DEBUG, "Allocated %d bufs", nbufs);
-
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 	} else if (queue_type == VTNET_TQ) {
 		if (use_simple_rxtx) {
 			int mid_idx  = vq->vq_nentries >> 1;
@@ -362,16 +357,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type)
 			for (i = mid_idx; i < vq->vq_nentries; i++)
 				vq->vq_ring.avail->ring[i] = i;
 		}
-
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
-	} else {
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 	}
 }
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops
  2015-12-10  3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu
  2015-12-10  3:54 ` [dpdk-dev] [PATCH 1/6] virtio: don't set vring address again at queue startup Yuanhan Liu
@ 2015-12-10  3:54 ` Yuanhan Liu
  2015-12-29 11:31   ` Tan, Jianfeng
  2015-12-10  3:54 ` [dpdk-dev] [PATCH 3/6] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2015-12-10  3:54 UTC (permalink / raw)
  To: dev

Introduce struct virtio_pci_ops, to let legacy virtio (v0.95) and
modern virtio (1.0) have different implementation regarding to a
specific pci action, such as read host status.

With that, this patch reimplements all exported pci functions, in
a way like:

	vtpci_foo_bar(struct virtio_hw *hw)
	{
		hw->vtpci_ops->foo_bar(hw);
	}

So that we need pay attention to those pci related functions only
while adding virtio 1.0 support.

This patch introduced a new vtpci function, vtpci_init(), to do
proper virtio pci settings. It's pretty simple so far: just sets
hw->vtpci_ops to legacy_ops as we don't support 1.0 yet.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_ethdev.c |  22 ++---
 drivers/net/virtio/virtio_pci.c    | 162 ++++++++++++++++++++++++++++++-------
 drivers/net/virtio/virtio_pci.h    |  27 +++++++
 drivers/net/virtio/virtqueue.h     |   2 +-
 4 files changed, 171 insertions(+), 42 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index d928339..6c1d3a0 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -272,9 +272,7 @@ virtio_dev_queue_release(struct virtqueue *vq) {
 
 	if (vq) {
 		hw = vq->hw;
-		/* Select and deactivate the queue */
-		VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+		hw->vtpci_ops->del_queue(hw, vq);
 
 		rte_free(vq->sw_ring);
 		rte_free(vq);
@@ -295,15 +293,13 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
 	struct virtio_hw *hw = dev->data->dev_private;
 	struct virtqueue *vq = NULL;
 
-	/* Write the virtqueue index to the Queue Select Field */
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vtpci_queue_idx);
-	PMD_INIT_LOG(DEBUG, "selecting queue: %u", vtpci_queue_idx);
+	PMD_INIT_LOG(DEBUG, "setting up queue: %u", vtpci_queue_idx);
 
 	/*
 	 * Read the virtqueue size from the Queue Size field
 	 * Always power of 2 and if 0 virtqueue does not exist
 	 */
-	vq_size = VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
+	vq_size = hw->vtpci_ops->get_queue_num(hw, vtpci_queue_idx);
 	PMD_INIT_LOG(DEBUG, "vq_size: %u nb_desc:%u", vq_size, nb_desc);
 	if (vq_size == 0) {
 		PMD_INIT_LOG(ERR, "%s: virtqueue does not exist", __func__);
@@ -436,12 +432,8 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
 		memset(vq->virtio_net_hdr_mz->addr, 0, PAGE_SIZE);
 	}
 
-	/*
-	 * Set guest physical address of the virtqueue
-	 * in VIRTIO_PCI_QUEUE_PFN config register of device
-	 */
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
-			mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+	hw->vtpci_ops->setup_queue(hw, vq);
+
 	*pvq = vq;
 	return 0;
 }
@@ -950,7 +942,7 @@ virtio_negotiate_features(struct virtio_hw *hw)
 		hw->guest_features);
 
 	/* Read device(host) feature bits */
-	host_features = VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+	host_features = hw->vtpci_ops->get_features(hw);
 	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x",
 		host_features);
 
@@ -1287,6 +1279,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 
+	vtpci_init(pci_dev, hw);
+
 	if (virtio_resource_init(pci_dev) < 0)
 		return -1;
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 2245bec..9bcaa07 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -34,12 +34,11 @@
 
 #include "virtio_pci.h"
 #include "virtio_logs.h"
+#include "virtqueue.h"
 
-static uint8_t vtpci_get_status(struct virtio_hw *);
-
-void
-vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
-		void *dst, int length)
+static void
+legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset,
+		       void *dst, int length)
 {
 	uint64_t off;
 	uint8_t *d;
@@ -60,9 +59,9 @@ vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 	}
 }
 
-void
-vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
-		void *src, int length)
+static void
+legacy_write_dev_config(struct virtio_hw *hw, uint64_t offset,
+			void *src, int length)
 {
 	uint64_t off;
 	uint8_t *s;
@@ -83,17 +82,130 @@ vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
 	}
 }
 
+static uint32_t
+legacy_get_features(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+}
+
+static void
+legacy_set_features(struct virtio_hw *hw, uint32_t features)
+{
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
+}
+
+static uint8_t
+legacy_get_status(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
+}
+
+static void
+legacy_set_status(struct virtio_hw *hw, uint8_t status)
+{
+	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+}
+
+static void
+legacy_reset(struct virtio_hw *hw)
+{
+	/*
+	 * Setting the status to RESET sets the host device to
+	 * the original, uninitialized state.
+	 */
+	legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+	legacy_get_status(hw);
+}
+
+static uint8_t
+legacy_get_isr(struct virtio_hw *hw)
+{
+
+	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+}
+
+/* Enable one vector (0) for Link State Intrerrupt */
+static uint16_t
+legacy_set_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);
+}
+
+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);
+}
+
+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);
+
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
+		vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+}
+
+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);
+
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+}
+
+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);
+}
+
+
+static const struct virtio_pci_ops legacy_ops = {
+	.read_dev_cfg	= legacy_read_dev_config,
+	.write_dev_cfg	= legacy_write_dev_config,
+	.reset		= legacy_reset,
+	.get_status	= legacy_get_status,
+	.set_status	= legacy_set_status,
+	.get_features	= legacy_get_features,
+	.set_features	= legacy_set_features,
+	.get_isr	= legacy_get_isr,
+	.set_irq	= legacy_set_irq,
+	.get_queue_num	= legacy_get_queue_num,
+	.setup_queue	= legacy_setup_queue,
+	.del_queue	= legacy_del_queue,
+	.notify_queue	= legacy_notify_queue,
+};
+
+
+void
+vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
+		      void *dst, int length)
+{
+	hw->vtpci_ops->read_dev_cfg(hw, offset, dst, length);
+}
+
+void
+vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
+		void *src, int length)
+{
+	hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
+}
+
 uint32_t
 vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
 {
 	uint32_t features;
+
 	/*
 	 * Limit negotiated features to what the driver, virtqueue, and
 	 * host all support.
 	 */
 	features = host_features & hw->guest_features;
+	hw->vtpci_ops->set_features(hw, features);
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
 	return features;
 }
 
@@ -101,12 +213,8 @@ vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
 void
 vtpci_reset(struct virtio_hw *hw)
 {
-	/*
-	 * Setting the status to RESET sets the host device to
-	 * the original, uninitialized state.
-	 */
-	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
-	vtpci_get_status(hw);
+	hw->vtpci_ops->set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+	hw->vtpci_ops->get_status(hw);
 }
 
 void
@@ -115,26 +223,19 @@ vtpci_reinit_complete(struct virtio_hw *hw)
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK);
 }
 
-static uint8_t
-vtpci_get_status(struct virtio_hw *hw)
-{
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
-}
-
 void
 vtpci_set_status(struct virtio_hw *hw, uint8_t status)
 {
 	if (status != VIRTIO_CONFIG_STATUS_RESET)
-		status = (uint8_t)(status | vtpci_get_status(hw));
+		status |= hw->vtpci_ops->get_status(hw);
 
-	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+	hw->vtpci_ops->set_status(hw, status);
 }
 
 uint8_t
 vtpci_isr(struct virtio_hw *hw)
 {
-
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+	return hw->vtpci_ops->get_isr(hw);
 }
 
 
@@ -142,6 +243,13 @@ vtpci_isr(struct virtio_hw *hw)
 uint16_t
 vtpci_irq_config(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);
+	return hw->vtpci_ops->set_irq(hw, vec);
+}
+
+int
+vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw)
+{
+	hw->vtpci_ops = &legacy_ops;
+
+	return 0;
 }
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index 47f722a..a11a4f6 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -163,6 +163,31 @@ struct virtqueue;
  */
 #define VIRTIO_MAX_VIRTQUEUES 8
 
+struct virtio_hw;
+
+struct virtio_pci_ops {
+	void (*read_dev_cfg)(struct virtio_hw *hw, uint64_t offset,
+			     void *dst, int len);
+	void (*write_dev_cfg)(struct virtio_hw *hw, uint64_t offset,
+			      void *src, int len);
+	void (*reset)(struct virtio_hw *hw);
+
+	uint8_t (*get_status)(struct virtio_hw *hw);
+	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
+
+	uint32_t (*get_features)(struct virtio_hw *hw);
+	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
+
+	uint8_t (*get_isr)(struct virtio_hw *hw);
+
+	uint16_t (*set_irq)(struct virtio_hw *hw, uint16_t vec);
+
+	uint16_t (*get_queue_num)(struct virtio_hw *hw, uint16_t queue_id);
+	void (*setup_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+	void (*del_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+	void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+};
+
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
@@ -174,6 +199,7 @@ struct virtio_hw {
 	uint8_t	    use_msix;
 	uint8_t     started;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
+	const struct virtio_pci_ops *vtpci_ops;
 };
 
 /*
@@ -253,6 +279,7 @@ vtpci_with_feature(struct virtio_hw *hw, uint32_t bit)
 /*
  * Function declaration from virtio_pci.c
  */
+int vtpci_init(struct rte_pci_device *, struct virtio_hw *);
 void vtpci_reset(struct virtio_hw *);
 
 void vtpci_reinit_complete(struct virtio_hw *);
diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h
index 61b3137..d7fb450 100644
--- a/drivers/net/virtio/virtqueue.h
+++ b/drivers/net/virtio/virtqueue.h
@@ -302,7 +302,7 @@ virtqueue_notify(struct virtqueue *vq)
 	 * For virtio on IA, the notificaiton is through io port operation
 	 * which is a serialization instruction itself.
 	 */
-	VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
+	vq->hw->vtpci_ops->notify_queue(vq->hw, vq);
 }
 
 #ifdef RTE_LIBRTE_VIRTIO_DEBUG_DUMP
-- 
1.9.0

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

* [dpdk-dev] [PATCH 3/6] virtio: move left pci stuff to virtio_pci.c
  2015-12-10  3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu
  2015-12-10  3:54 ` [dpdk-dev] [PATCH 1/6] virtio: don't set vring address again at queue startup Yuanhan Liu
  2015-12-10  3:54 ` [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops Yuanhan Liu
@ 2015-12-10  3:54 ` Yuanhan Liu
  2015-12-10  3:54 ` [dpdk-dev] [PATCH 4/6] viritio: switch to 64 bit features Yuanhan Liu
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2015-12-10  3:54 UTC (permalink / raw)
  To: dev

virtio_pci.c is a more proper place for pci stuff; virtio_ethdev is not.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_ethdev.c | 265 +-----------------------------------
 drivers/net/virtio/virtio_pci.c    | 270 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 270 insertions(+), 265 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 6c1d3a0..b57224d 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -36,10 +36,6 @@
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
-#ifdef RTE_EXEC_ENV_LINUXAPP
-#include <dirent.h>
-#include <fcntl.h>
-#endif
 
 #include <rte_ethdev.h>
 #include <rte_memcpy.h>
@@ -955,260 +951,6 @@ virtio_negotiate_features(struct virtio_hw *hw)
 		hw->guest_features);
 }
 
-#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
-virtio_has_msix(const struct rte_pci_addr *loc)
-{
-	DIR *d;
-	char dirname[PATH_MAX];
-
-	snprintf(dirname, sizeof(dirname),
-		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
-		     loc->domain, loc->bus, loc->devid, loc->function);
-
-	d = opendir(dirname);
-	if (d)
-		closedir(d);
-
-	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 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
-virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
-{
-	/* nic_uio does not enable interrupts, return 0 (false). */
-	return 0;
-}
-
-static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
-{
-	/* no setup required */
-	return 0;
-}
-#endif
-
 /*
  * Process Virtio Config changed interrupt and call the callback
  * if link state changed.
@@ -1279,14 +1021,9 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 
-	vtpci_init(pci_dev, hw);
-
-	if (virtio_resource_init(pci_dev) < 0)
+	if (vtpci_init(pci_dev, hw) < 0)
 		return -1;
 
-	hw->use_msix = virtio_has_msix(&pci_dev->addr);
-	hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr;
-
 	/* Reset the device although not necessary at startup */
 	vtpci_reset(hw);
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 9bcaa07..0094d5f 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -32,6 +32,11 @@
  */
 #include <stdint.h>
 
+#ifdef RTE_EXEC_ENV_LINUXAPP
+ #include <dirent.h>
+ #include <fcntl.h>
+#endif
+
 #include "virtio_pci.h"
 #include "virtio_logs.h"
 #include "virtqueue.h"
@@ -162,6 +167,264 @@ legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
 	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
 }
 
+#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;
+	char dirname[PATH_MAX];
+
+	snprintf(dirname, sizeof(dirname),
+		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
+		     loc->domain, loc->bus, loc->devid, loc->function);
+
+	d = opendir(dirname);
+	if (d)
+		closedir(d);
+
+	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
+legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
+{
+	/* nic_uio does not enable interrupts, return 0 (false). */
+	return 0;
+}
+
+static int
+legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
+{
+	/* no setup required */
+	return 0;
+}
+#endif
 
 static const struct virtio_pci_ops legacy_ops = {
 	.read_dev_cfg	= legacy_read_dev_config,
@@ -247,9 +510,14 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
 }
 
 int
-vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw)
+vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 {
 	hw->vtpci_ops = &legacy_ops;
 
+	if (legacy_virtio_resource_init(dev) < 0)
+		return -1;
+	hw->use_msix = legacy_virtio_has_msix(&dev->addr);
+	hw->io_base  = (uint32_t)(uintptr_t)dev->mem_resource[0].addr;
+
 	return 0;
 }
-- 
1.9.0

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

* [dpdk-dev] [PATCH 4/6] viritio: switch to 64 bit features
  2015-12-10  3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu
                   ` (2 preceding siblings ...)
  2015-12-10  3:54 ` [dpdk-dev] [PATCH 3/6] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
@ 2015-12-10  3:54 ` Yuanhan Liu
  2015-12-10  3:54 ` [dpdk-dev] [PATCH 5/6] virtio: set RTE_PCI_DRV_NEED_MAPPING flag Yuanhan Liu
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2015-12-10  3:54 UTC (permalink / raw)
  To: dev

Switch to 64 bit features, which virtio 1.0 supports.

While legacy virtio only supports 32 bit features, it complains aloud
and quit when trying to setting > 32 bit features.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_ethdev.c |  8 ++++----
 drivers/net/virtio/virtio_pci.c    | 15 ++++++++++-----
 drivers/net/virtio/virtio_pci.h    | 12 ++++++------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index b57224d..94e0c4a 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -930,16 +930,16 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 static void
 virtio_negotiate_features(struct virtio_hw *hw)
 {
-	uint32_t host_features;
+	uint64_t host_features;
 
 	/* Prepare guest_features: feature that driver wants to support */
 	hw->guest_features = VIRTIO_PMD_GUEST_FEATURES;
-	PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %"PRIx64,
 		hw->guest_features);
 
 	/* Read device(host) feature bits */
 	host_features = hw->vtpci_ops->get_features(hw);
-	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %"PRIx64,
 		host_features);
 
 	/*
@@ -947,7 +947,7 @@ virtio_negotiate_features(struct virtio_hw *hw)
 	 * guest feature bits.
 	 */
 	hw->guest_features = vtpci_negotiate_features(hw, host_features);
-	PMD_INIT_LOG(DEBUG, "features after negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,
 		hw->guest_features);
 }
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 0094d5f..26b0a0c 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -87,15 +87,20 @@ legacy_write_dev_config(struct virtio_hw *hw, uint64_t offset,
 	}
 }
 
-static uint32_t
+static uint64_t
 legacy_get_features(struct virtio_hw *hw)
 {
 	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
 }
 
 static void
-legacy_set_features(struct virtio_hw *hw, uint32_t features)
+legacy_set_features(struct virtio_hw *hw, uint64_t features)
 {
+	if ((features >> 32) != 0) {
+		PMD_DRV_LOG(ERR,
+			"only 32 bit features are allowed for legacy virtio!");
+		return;
+	}
 	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
 }
 
@@ -457,10 +462,10 @@ vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
 	hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
 }
 
-uint32_t
-vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
+uint64_t
+vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features)
 {
-	uint32_t features;
+	uint64_t features;
 
 	/*
 	 * Limit negotiated features to what the driver, virtqueue, and
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index a11a4f6..0900cd0 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -175,8 +175,8 @@ struct virtio_pci_ops {
 	uint8_t (*get_status)(struct virtio_hw *hw);
 	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
 
-	uint32_t (*get_features)(struct virtio_hw *hw);
-	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
+	uint64_t (*get_features)(struct virtio_hw *hw);
+	void     (*set_features)(struct virtio_hw *hw, uint64_t features);
 
 	uint8_t (*get_isr)(struct virtio_hw *hw);
 
@@ -191,7 +191,7 @@ struct virtio_pci_ops {
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
-	uint32_t    guest_features;
+	uint64_t    guest_features;
 	uint32_t    max_tx_queues;
 	uint32_t    max_rx_queues;
 	uint16_t    vtnet_hdr_size;
@@ -271,9 +271,9 @@ outl_p(unsigned int data, unsigned int port)
 	outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
 
 static inline int
-vtpci_with_feature(struct virtio_hw *hw, uint32_t bit)
+vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-	return (hw->guest_features & (1u << bit)) != 0;
+	return (hw->guest_features & (1ULL << bit)) != 0;
 }
 
 /*
@@ -286,7 +286,7 @@ void vtpci_reinit_complete(struct virtio_hw *);
 
 void vtpci_set_status(struct virtio_hw *, uint8_t);
 
-uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t);
+uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t);
 
 void vtpci_write_dev_config(struct virtio_hw *, uint64_t, void *, int);
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH 5/6] virtio: set RTE_PCI_DRV_NEED_MAPPING flag
  2015-12-10  3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu
                   ` (3 preceding siblings ...)
  2015-12-10  3:54 ` [dpdk-dev] [PATCH 4/6] viritio: switch to 64 bit features Yuanhan Liu
@ 2015-12-10  3:54 ` Yuanhan Liu
  2015-12-10  3:54 ` [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support Yuanhan Liu
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2015-12-10  3:54 UTC (permalink / raw)
  To: dev

We need to to map pci bar space for enabling modern virtio pci device,
as all modern configs are stored at pci bar space.

Setting RTE_PCI_DRV_NEED_MAPPING flag will let eal do that for us.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_ethdev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 94e0c4a..9847ed8 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -1169,7 +1169,7 @@ static struct eth_driver rte_virtio_pmd = {
 	.pci_drv = {
 		.name = "rte_virtio_pmd",
 		.id_table = pci_id_virtio_map,
-		.drv_flags = RTE_PCI_DRV_DETACHABLE,
+		.drv_flags = RTE_PCI_DRV_DETACHABLE | RTE_PCI_DRV_NEED_MAPPING,
 	},
 	.eth_dev_init = eth_virtio_dev_init,
 	.eth_dev_uninit = eth_virtio_dev_uninit,
-- 
1.9.0

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

* [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support
  2015-12-10  3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu
                   ` (4 preceding siblings ...)
  2015-12-10  3:54 ` [dpdk-dev] [PATCH 5/6] virtio: set RTE_PCI_DRV_NEED_MAPPING flag Yuanhan Liu
@ 2015-12-10  3:54 ` Yuanhan Liu
  2015-12-29 11:39   ` Tan, Jianfeng
  2015-12-10  3:58 ` [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2015-12-10  3:54 UTC (permalink / raw)
  To: dev

Modern (v1.0) virtio pci device defines several pci capabilities.
Each cap has a configure structure corresponding to it, and the
cap.bar and cap.offset fields tell us where to find it.

And thanks to the RTE_PCI_DRV_NEED_MAPPING, which already maps all
the bar space for us, we could easily locate to a cfg structure by:

    cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset;

Therefore, the entrance of enabling modern (v1.0) pci device support
is to iterate the pci capability lists, and to locate some configs
we care; and they are:

- common cfg

  For generic virtio and virtuqueu configuration, such as setting/getting
  features, enabling a specific queue, and so on.

- nofity cfg

  Combining with `queue_notify_off' from common cfg, we could use it to
  notify a specific virt queue.

- device cfg

  Where virtio_net_config structure locates.

If any of above cap is not found, we fallback to the legacy virtio
handling.

If succeed, hw->vtpci_ops is assigned to modern_ops, where all
operations are implemented by reading/writing a (or few) specific
configuration space from above 3 cfg structures. And that's basically
how this patch works.

Besides those changes, virtio 1.0 introduces a new status field:
FEATURES_OK, which is set after features negotiation is done.

Last, set the VIRTIO_F_VERSION_1 feature flag.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_ethdev.c |  16 +-
 drivers/net/virtio/virtio_ethdev.h |   3 +-
 drivers/net/virtio/virtio_pci.c    | 313 ++++++++++++++++++++++++++++++++++++-
 drivers/net/virtio/virtio_pci.h    |  65 ++++++++
 drivers/net/virtio/virtqueue.h     |   2 +
 5 files changed, 395 insertions(+), 4 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 9847ed8..1f9de01 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return virtio_send_command(hw->cvq, &ctrl, &len, 1);
 }
 
-static void
+static int
 virtio_negotiate_features(struct virtio_hw *hw)
 {
 	uint64_t host_features;
@@ -949,6 +949,17 @@ virtio_negotiate_features(struct virtio_hw *hw)
 	hw->guest_features = vtpci_negotiate_features(hw, host_features);
 	PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,
 		hw->guest_features);
+
+	if (hw->modern) {
+		if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) {
+			PMD_INIT_LOG(ERR,
+				"VIRTIO_F_VERSION_1 features is not enabled");
+			return -1;
+		}
+		vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK);
+	}
+
+	return 0;
 }
 
 /*
@@ -1032,7 +1043,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	/* Tell the host we've known how to drive the device. */
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
-	virtio_negotiate_features(hw);
+	if (virtio_negotiate_features(hw) < 0)
+		return -1;
 
 	/* If host does not support status then disable LSC */
 	if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS))
diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h
index ae2d47d..fed9571 100644
--- a/drivers/net/virtio/virtio_ethdev.h
+++ b/drivers/net/virtio/virtio_ethdev.h
@@ -64,7 +64,8 @@
 	 1u << VIRTIO_NET_F_CTRL_VQ	  |	\
 	 1u << VIRTIO_NET_F_CTRL_RX	  |	\
 	 1u << VIRTIO_NET_F_CTRL_VLAN	  |	\
-	 1u << VIRTIO_NET_F_MRG_RXBUF)
+	 1u << VIRTIO_NET_F_MRG_RXBUF	  |	\
+	 1ULL << VIRTIO_F_VERSION_1)
 
 /*
  * CQ function prototype
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 26b0a0c..7862d7f 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -31,6 +31,7 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include <stdint.h>
+#include <linux/pci_regs.h>
 
 #ifdef RTE_EXEC_ENV_LINUXAPP
  #include <dirent.h>
@@ -448,6 +449,205 @@ static const struct virtio_pci_ops legacy_ops = {
 };
 
 
+#define MODERN_READ_DEF(nr_bits, type)		\
+static inline type				\
+modern_read##nr_bits(type *addr)		\
+{						\
+	return *(volatile type *)addr;		\
+}
+
+#define MODERN_WRITE_DEF(nr_bits, type)		\
+static inline void				\
+modern_write##nr_bits(type val, type *addr)	\
+{						\
+	*(volatile type *)addr = val;		\
+}
+
+MODERN_READ_DEF (8, uint8_t)
+MODERN_WRITE_DEF(8, uint8_t)
+
+MODERN_READ_DEF (16, uint16_t)
+MODERN_WRITE_DEF(16, uint16_t)
+
+MODERN_READ_DEF (32, uint32_t)
+MODERN_WRITE_DEF(32, uint32_t)
+
+static inline void
+modern_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
+{
+	modern_write32((uint32_t)val, lo);
+	modern_write32(val >> 32,     hi);
+}
+
+static void
+modern_read_dev_config(struct virtio_hw *hw, uint64_t offset,
+		       void *dst, int length)
+{
+	int i;
+	uint8_t *p;
+	uint8_t old_gen, new_gen;
+
+	do {
+		old_gen = modern_read8(&hw->common_cfg->config_generation);
+
+		p = dst;
+		for (i = 0;  i < length; i++)
+			*p++ = modern_read8((uint8_t *)hw->dev_cfg + offset + i);
+
+		new_gen = modern_read8(&hw->common_cfg->config_generation);
+	} while (old_gen != new_gen);
+}
+
+static void
+modern_write_dev_config(struct virtio_hw *hw, uint64_t offset,
+		        void *src, int length)
+{
+	int i;
+	uint8_t *p = src;
+
+	for (i = 0;  i < length; i++)
+		modern_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i);
+}
+
+static uint64_t
+modern_get_features(struct virtio_hw *hw)
+{
+	uint32_t features_lo, features_hi;
+
+	modern_write32(0, &hw->common_cfg->device_feature_select);
+	features_lo = modern_read32(&hw->common_cfg->device_feature);
+
+	modern_write32(1, &hw->common_cfg->device_feature_select);
+	features_hi = modern_read32(&hw->common_cfg->device_feature);
+
+	return ((uint64_t)(features_hi) << 32) | features_lo;
+}
+
+static void
+modern_set_features(struct virtio_hw *hw, uint64_t features)
+{
+	modern_write32(0, &hw->common_cfg->guest_feature_select);
+	modern_write32(features & ((1ULL<<32) - 1),
+		&hw->common_cfg->guest_feature);
+
+	modern_write32(1, &hw->common_cfg->guest_feature_select);
+	modern_write32(features >> 32,
+		&hw->common_cfg->guest_feature);
+}
+
+static uint8_t
+modern_get_status(struct virtio_hw *hw)
+{
+	return modern_read8(&hw->common_cfg->device_status);
+}
+
+static void
+modern_set_status(struct virtio_hw *hw, uint8_t status)
+{
+	modern_write8(status, &hw->common_cfg->device_status);
+}
+
+static void
+modern_reset(struct virtio_hw *hw)
+{
+	modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+	modern_get_status(hw);
+}
+
+static uint8_t
+modern_get_isr(struct virtio_hw *hw __rte_unused)
+{
+	/* FIXME: xxx */
+	return 0;
+}
+
+static uint16_t
+modern_set_irq(struct virtio_hw *hw __rte_unused, uint16_t vec __rte_unused)
+{
+	/* FIXME: xxx */
+	return 0;
+}
+
+static uint16_t
+modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
+{
+	modern_write16(queue_id, &hw->common_cfg->queue_select);
+	return modern_read16(&hw->common_cfg->queue_size);
+}
+
+static void
+modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
+{
+	uint64_t desc_addr, avail_addr, used_addr;
+	uint16_t notify_off;
+
+	desc_addr = vq->mz->phys_addr;
+	avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
+	used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail,
+							 ring[vq->vq_nentries]),
+				   VIRTIO_PCI_VRING_ALIGN);
+
+	modern_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
+
+	modern_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo,
+					  &hw->common_cfg->queue_desc_hi);
+	modern_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo,
+					   &hw->common_cfg->queue_avail_hi);
+	modern_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo,
+					  &hw->common_cfg->queue_used_hi);
+
+	notify_off = modern_read16(&hw->common_cfg->queue_notify_off);
+	vq->notify_addr = (void *)((uint8_t *)hw->notify_base +
+				notify_off * hw->notify_off_multiplier);
+
+	modern_write16(1, &hw->common_cfg->queue_enable);
+
+	PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index);
+	PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr);
+	PMD_INIT_LOG(DEBUG, "\t aval_addr: %"PRIx64, avail_addr);
+	PMD_INIT_LOG(DEBUG, "\t used_addr: %"PRIx64, used_addr);
+	PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)",
+		vq->notify_addr, notify_off);
+}
+
+static void
+modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
+{
+	modern_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
+
+	modern_write64_twopart(0, &hw->common_cfg->queue_desc_lo,
+				  &hw->common_cfg->queue_desc_hi);
+	modern_write64_twopart(0, &hw->common_cfg->queue_avail_lo,
+				  &hw->common_cfg->queue_avail_hi);
+	modern_write64_twopart(0, &hw->common_cfg->queue_used_lo,
+				  &hw->common_cfg->queue_used_hi);
+
+	modern_write16(0, &hw->common_cfg->queue_enable);
+}
+
+static void
+modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
+{
+	modern_write16(1, vq->notify_addr);
+}
+
+static const struct virtio_pci_ops modern_ops = {
+	.read_dev_cfg	= modern_read_dev_config,
+	.write_dev_cfg	= modern_write_dev_config,
+	.reset		= modern_reset,
+	.get_status	= modern_get_status,
+	.set_status	= modern_set_status,
+	.get_features	= modern_get_features,
+	.set_features	= modern_set_features,
+	.get_isr	= modern_get_isr,
+	.set_irq	= modern_set_irq,
+	.get_queue_num	= modern_get_queue_num,
+	.setup_queue	= modern_setup_queue,
+	.del_queue	= modern_del_queue,
+	.notify_queue	= modern_notify_queue,
+};
+
+
 void
 vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 		      void *dst, int length)
@@ -514,15 +714,126 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
 	return hw->vtpci_ops->set_irq(hw, vec);
 }
 
+static inline void *
+get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)
+{
+	uint8_t  bar    = cap->bar;
+	uint32_t length = cap->length;
+	uint32_t offset = cap->offset;
+	uint8_t *base;
+
+	if (unlikely(bar > 5)) {
+		PMD_INIT_LOG(ERR, "invalid bar: %u", bar);
+		return NULL;
+	}
+
+	if (unlikely(offset + length > dev->mem_resource[bar].len)) {
+		PMD_INIT_LOG(ERR,
+			"invalid cap: overflows bar space: %u > %"PRIu64,
+			offset + length, dev->mem_resource[bar].len);
+		return NULL;
+	}
+
+	base = dev->mem_resource[bar].addr;
+	if (unlikely(base == NULL)) {
+		PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar);
+		return NULL;
+	}
+
+	return base + offset;
+}
+
+static int
+virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
+{
+	uint8_t pos;
+	struct virtio_pci_cap cap;
+	int ret;
+
+	ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST);
+	if (ret < 0) {
+		PMD_INIT_LOG(DEBUG, "failed to read pci capability list");
+		return -1;
+	}
+
+	while (pos) {
+		ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos);
+		if (ret < 0) {
+			PMD_INIT_LOG(ERR,
+				"failed to read pci cap at pos: %x", pos);
+			break;
+		}
+
+		if (cap.cap_vndr != PCI_CAP_ID_VNDR) {
+			PMD_INIT_LOG(DEBUG,
+				"[%2x] skipping non VNDR cap id: %02x",
+				pos, cap.cap_vndr);
+			goto next;
+		}
+
+		PMD_INIT_LOG(DEBUG,
+			"[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u",
+			pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
+
+		switch (cap.cfg_type) {
+		case VIRTIO_PCI_CAP_COMMON_CFG:
+			hw->common_cfg = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_NOTIFY_CFG:
+			rte_eal_pci_read_config(dev, &hw->notify_off_multiplier,
+						4, pos + sizeof(cap));
+			hw->notify_base = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_DEVICE_CFG:
+			hw->dev_cfg = get_cfg_addr(dev, &cap);
+			break;
+		}
+
+	next:
+		pos = cap.cap_next;
+	}
+
+	if (hw->common_cfg == NULL || hw->notify_base == NULL ||
+	    hw->dev_cfg == NULL) {
+		PMD_INIT_LOG(INFO, "no modern virtio pci device found.");
+		return -1;
+	}
+
+	PMD_INIT_LOG(INFO, "found modern virtio pci device.");
+
+	PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg);
+	PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg);
+	PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u",
+		hw->notify_base, hw->notify_off_multiplier);
+
+	return 0;
+}
+
 int
 vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 {
-	hw->vtpci_ops = &legacy_ops;
+	hw->dev = dev;
 
+	/*
+	 * Try if we can succeed reading virtio pci caps, which exists
+	 * only on modern pci device. If failed, we fallback to legacy
+	 * virtio hanlding.
+	 */
+	if (virtio_read_caps(dev, hw) == 0) {
+		PMD_INIT_LOG(INFO, "moderen virtio pci detected.");
+		hw->vtpci_ops = &modern_ops;
+		hw->modern    = 1;
+		return 0;
+	}
+
+	PMD_INIT_LOG(INFO, "trying with legacy virtio pci.");
 	if (legacy_virtio_resource_init(dev) < 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 0900cd0..8ff51d2 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -93,6 +93,7 @@ struct virtqueue;
 #define VIRTIO_CONFIG_STATUS_ACK       0x01
 #define VIRTIO_CONFIG_STATUS_DRIVER    0x02
 #define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04
+#define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08
 #define VIRTIO_CONFIG_STATUS_FAILED    0x80
 
 /*
@@ -141,6 +142,8 @@ struct virtqueue;
 /* We support indirect buffer descriptors */
 #define VIRTIO_RING_F_INDIRECT_DESC	28
 
+#define VIRTIO_F_VERSION_1		32
+
 /*
  * Some VirtIO feature bits (currently bits 28 through 31) are
  * reserved for the transport being used (eg. virtio_ring), the
@@ -163,6 +166,60 @@ struct virtqueue;
  */
 #define VIRTIO_MAX_VIRTQUEUES 8
 
+/* Common configuration */
+#define VIRTIO_PCI_CAP_COMMON_CFG	1
+/* Notifications */
+#define VIRTIO_PCI_CAP_NOTIFY_CFG	2
+/* ISR Status */
+#define VIRTIO_PCI_CAP_ISR_CFG		3
+/* Device specific configuration */
+#define VIRTIO_PCI_CAP_DEVICE_CFG	4
+/* PCI configuration access */
+#define VIRTIO_PCI_CAP_PCI_CFG		5
+
+/* This is the PCI capability header: */
+struct virtio_pci_cap {
+	uint8_t cap_vndr;		/* Generic PCI field: PCI_CAP_ID_VNDR */
+	uint8_t cap_next;		/* Generic PCI field: next ptr. */
+	uint8_t cap_len;		/* Generic PCI field: capability length */
+	uint8_t cfg_type;		/* Identifies the structure. */
+	uint8_t bar;			/* Where to find it. */
+	uint8_t padding[3];		/* Pad to full dword. */
+	uint32_t offset;		/* Offset within bar. */
+	uint32_t length;		/* Length of the structure, in bytes. */
+};
+
+struct virtio_pci_notify_cap {
+	struct virtio_pci_cap cap;
+	uint32_t notify_off_multiplier;	/* Multiplier for queue_notify_off. */
+};
+
+/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */
+struct virtio_pci_common_cfg {
+	/* About the whole device. */
+	uint32_t device_feature_select;	/* read-write */
+	uint32_t device_feature;	/* read-only */
+	uint32_t guest_feature_select;	/* read-write */
+	uint32_t guest_feature;		/* read-write */
+	uint16_t msix_config;		/* read-write */
+	uint16_t num_queues;		/* read-only */
+	uint8_t device_status;		/* read-write */
+	uint8_t config_generation;	/* read-only */
+
+	/* About a specific virtqueue. */
+	uint16_t queue_select;		/* read-write */
+	uint16_t queue_size;		/* read-write, power of 2. */
+	uint16_t queue_msix_vector;	/* read-write */
+	uint16_t queue_enable;		/* read-write */
+	uint16_t queue_notify_off;	/* read-only */
+	uint32_t queue_desc_lo;		/* read-write */
+	uint32_t queue_desc_hi;		/* read-write */
+	uint32_t queue_avail_lo;	/* read-write */
+	uint32_t queue_avail_hi;	/* read-write */
+	uint32_t queue_used_lo;		/* read-write */
+	uint32_t queue_used_hi;		/* read-write */
+};
+
 struct virtio_hw;
 
 struct virtio_pci_ops {
@@ -188,6 +245,8 @@ struct virtio_pci_ops {
 	void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq);
 };
 
+struct virtio_net_config;
+
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
@@ -198,7 +257,13 @@ struct virtio_hw {
 	uint8_t	    vlan_strip;
 	uint8_t	    use_msix;
 	uint8_t     started;
+	uint8_t     modern;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
+	uint32_t    notify_off_multiplier;
+	uint16_t    *notify_base;
+	struct rte_pci_device *dev;
+	struct virtio_pci_common_cfg *common_cfg;
+	struct virtio_net_config *dev_cfg;
 	const struct virtio_pci_ops *vtpci_ops;
 };
 
diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h
index d7fb450..99d4fa9 100644
--- a/drivers/net/virtio/virtqueue.h
+++ b/drivers/net/virtio/virtqueue.h
@@ -202,6 +202,8 @@ struct virtqueue {
 	/* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */
 	uint64_t	size_bins[8];
 
+	uint16_t	*notify_addr;
+
 	struct vq_desc_extra {
 		void              *cookie;
 		uint16_t          ndescs;
-- 
1.9.0

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

* Re: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling
  2015-12-10  3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu
                   ` (5 preceding siblings ...)
  2015-12-10  3:54 ` [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support Yuanhan Liu
@ 2015-12-10  3:58 ` Yuanhan Liu
  2015-12-29 11:19 ` Tan, Jianfeng
  2016-01-12  6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
  8 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2015-12-10  3:58 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: dev

Michael,

Sorry that I forgot to CC you. (In fact, I intended to, but there is
a tiny bug at my send-email script :(

It'd be great if you could take some time to review it.

Thanks.

	--yliu


On Thu, Dec 10, 2015 at 11:54:04AM +0800, Yuanhan Liu wrote:
> Hi,
> 
> Here is an initial virtio 1.0 pmd driver enabling.
> 
> Almost all difference comes from virtio 1.0 are the PCI layout change:
> the major configuration structures are stored at bar space, and their
> location is stored at corresponding pci cap structure. Reading/parsing
> them is one of the major work of patch 6.
> 
> To make handling virtio v1.0 and v0.95 co-exist well, this patch set
> introduces a virtio_pci_ops structure, to add another layer so that
> we could keep those vtpci_foo_bar "APIs". With that, we could do the
> minimum change to add virtio 1.0 support.
> 
> Note that the enabling is still in rough state, and it's likely I may
> miss something. So, comments are huge welcome!
> 
> 	--yliu
> 
> ---
> Yuanhan Liu (6):
>   virtio: don't set vring address again at queue startup
>   virtio: introduce struct virtio_pci_ops
>   virtio: move left pci stuff to virtio_pci.c
>   viritio: switch to 64 bit features
>   virtio: set RTE_PCI_DRV_NEED_MAPPING flag
>   virtio: add virtio v1.0 support
> 
>  drivers/net/virtio/virtio_ethdev.c | 297 +--------------
>  drivers/net/virtio/virtio_ethdev.h |   3 +-
>  drivers/net/virtio/virtio_pci.c    | 752 +++++++++++++++++++++++++++++++++++--
>  drivers/net/virtio/virtio_pci.h    | 100 ++++-
>  drivers/net/virtio/virtio_rxtx.c   |  15 -
>  drivers/net/virtio/virtqueue.h     |   4 +-
>  6 files changed, 843 insertions(+), 328 deletions(-)
> 
> -- 
> 1.9.0

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

* Re: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling
  2015-12-10  3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu
                   ` (6 preceding siblings ...)
  2015-12-10  3:58 ` [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu
@ 2015-12-29 11:19 ` Tan, Jianfeng
  2015-12-30  3:53   ` Yuanhan Liu
  2016-01-04  3:55   ` Xu, Qian Q
  2016-01-12  6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
  8 siblings, 2 replies; 122+ messages in thread
From: Tan, Jianfeng @ 2015-12-29 11:19 UTC (permalink / raw)
  To: Yuanhan Liu, dev



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu
> Sent: Thursday, December 10, 2015 11:54 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling
> 
> Hi,
> 
> Here is an initial virtio 1.0 pmd driver enabling.
> 
> Almost all difference comes from virtio 1.0 are the PCI layout change:
> the major configuration structures are stored at bar space, and their
> location is stored at corresponding pci cap structure. Reading/parsing
> them is one of the major work of patch 6.
> 
> To make handling virtio v1.0 and v0.95 co-exist well, this patch set
> introduces a virtio_pci_ops structure, to add another layer so that
> we could keep those vtpci_foo_bar "APIs". With that, we could do the
> minimum change to add virtio 1.0 support.


Please point out from which version, qemu starts to support virtio 1.0 net devices.

Thanks,
Jianfeng

> 
> Note that the enabling is still in rough state, and it's likely I may
> miss something. So, comments are huge welcome!
> 
> 	--yliu
> 
> ---
> Yuanhan Liu (6):
>   virtio: don't set vring address again at queue startup
>   virtio: introduce struct virtio_pci_ops
>   virtio: move left pci stuff to virtio_pci.c
>   viritio: switch to 64 bit features
>   virtio: set RTE_PCI_DRV_NEED_MAPPING flag
>   virtio: add virtio v1.0 support
> 
>  drivers/net/virtio/virtio_ethdev.c | 297 +--------------
>  drivers/net/virtio/virtio_ethdev.h |   3 +-
>  drivers/net/virtio/virtio_pci.c    | 752
> +++++++++++++++++++++++++++++++++++--
>  drivers/net/virtio/virtio_pci.h    | 100 ++++-
>  drivers/net/virtio/virtio_rxtx.c   |  15 -
>  drivers/net/virtio/virtqueue.h     |   4 +-
>  6 files changed, 843 insertions(+), 328 deletions(-)
> 
> --
> 1.9.0

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

* Re: [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops
  2015-12-10  3:54 ` [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops Yuanhan Liu
@ 2015-12-29 11:31   ` Tan, Jianfeng
  2015-12-30  3:45     ` Yuanhan Liu
  0 siblings, 1 reply; 122+ messages in thread
From: Tan, Jianfeng @ 2015-12-29 11:31 UTC (permalink / raw)
  To: Yuanhan Liu, dev



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu
> Sent: Thursday, December 10, 2015 11:54 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops
> 
> Introduce struct virtio_pci_ops, to let legacy virtio (v0.95) and
> modern virtio (1.0) have different implementation regarding to a
> specific pci action, such as read host status.
> 
...
> +static void
> +legacy_reset(struct virtio_hw *hw)
> +{
> +	/*
> +	 * Setting the status to RESET sets the host device to
> +	 * the original, uninitialized state.
> +	 */
> +	legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
> +	legacy_get_status(hw);


May need a comment to explain why here we need to get_status().


> +}
> +
> +static uint8_t
> +legacy_get_isr(struct virtio_hw *hw)
> +{

Please delete the following blank line.

> +
> +	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
> +}
> +
> +/* Enable one vector (0) for Link State Intrerrupt */
> +static uint16_t
> +legacy_set_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);
> +}
> +
...
> +
> +struct virtio_pci_ops {
> +	void (*read_dev_cfg)(struct virtio_hw *hw, uint64_t offset,
> +			     void *dst, int len);
> +	void (*write_dev_cfg)(struct virtio_hw *hw, uint64_t offset,
> +			      void *src, int len);
> +	void (*reset)(struct virtio_hw *hw);
> +
> +	uint8_t (*get_status)(struct virtio_hw *hw);
> +	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
> +
> +	uint32_t (*get_features)(struct virtio_hw *hw);
> +	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
> +
> +	uint8_t (*get_isr)(struct virtio_hw *hw);
> +
> +	uint16_t (*set_irq)(struct virtio_hw *hw, uint16_t vec);
> +
> +	uint16_t (*get_queue_num)(struct virtio_hw *hw, uint16_t
> queue_id);

How about changing the name into get_queue_size? From my side, queue_num is very confusing.

Thanks,
Jianfeng

> +	void (*setup_queue)(struct virtio_hw *hw, struct virtqueue *vq);
> +	void (*del_queue)(struct virtio_hw *hw, struct virtqueue *vq);
> +	void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq);
> +};
> +
...
>  #ifdef RTE_LIBRTE_VIRTIO_DEBUG_DUMP
> --
> 1.9.0

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

* Re: [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support
  2015-12-10  3:54 ` [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support Yuanhan Liu
@ 2015-12-29 11:39   ` Tan, Jianfeng
  2015-12-30  3:40     ` Yuanhan Liu
  0 siblings, 1 reply; 122+ messages in thread
From: Tan, Jianfeng @ 2015-12-29 11:39 UTC (permalink / raw)
  To: Yuanhan Liu, dev



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu
> Sent: Thursday, December 10, 2015 11:54 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support
> 
...
> Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
> ---
>  drivers/net/virtio/virtio_ethdev.c |  16 +-
>  drivers/net/virtio/virtio_ethdev.h |   3 +-
>  drivers/net/virtio/virtio_pci.c    | 313
> ++++++++++++++++++++++++++++++++++++-
>  drivers/net/virtio/virtio_pci.h    |  65 ++++++++
>  drivers/net/virtio/virtqueue.h     |   2 +
>  5 files changed, 395 insertions(+), 4 deletions(-)
> 

As legacy VIRTIO_WRITE_REG_XXXs are only used in virtio_pci.c, move these definitions into virtio_pci.c?

> diff --git a/drivers/net/virtio/virtio_ethdev.c
> b/drivers/net/virtio/virtio_ethdev.c
> index 9847ed8..1f9de01 100644
> --- a/drivers/net/virtio/virtio_ethdev.c
> +++ b/drivers/net/virtio/virtio_ethdev.c
> @@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev,
> uint16_t vlan_id, int on)
>  	return virtio_send_command(hw->cvq, &ctrl, &len, 1);
>  }
> 
> -static void
> +static int
>  virtio_negotiate_features(struct virtio_hw *hw)
>  {
>  	uint64_t host_features;
> @@ -949,6 +949,17 @@ virtio_negotiate_features(struct virtio_hw *hw)
>  	hw->guest_features = vtpci_negotiate_features(hw, host_features);
>  	PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,
>  		hw->guest_features);
> +
> +	if (hw->modern) {
> +		if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) {
> +			PMD_INIT_LOG(ERR,
> +				"VIRTIO_F_VERSION_1 features is not
> enabled");
> +			return -1;
> +		}
> +		vtpci_set_status(hw,
> VIRTIO_CONFIG_STATUS_FEATURES_OK);


As per Linux code drivers/virtio/virtio.c:virtio_finalize_features(), vtpci_set_status() may fail, and there's a double check.
Is it necessary here?


> +	}
> +
> +	return 0;
>  }
> 
>  /*
> @@ -1032,7 +1043,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
> 
>  	/* Tell the host we've known how to drive the device. */
>  	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
> -	virtio_negotiate_features(hw);
> +	if (virtio_negotiate_features(hw) < 0)
> +		return -1;
> 
>  	/* If host does not support status then disable LSC */
>  	if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS))
> diff --git a/drivers/net/virtio/virtio_ethdev.h
> b/drivers/net/virtio/virtio_ethdev.h
> index ae2d47d..fed9571 100644
> --- a/drivers/net/virtio/virtio_ethdev.h
> +++ b/drivers/net/virtio/virtio_ethdev.h
> @@ -64,7 +64,8 @@
>  	 1u << VIRTIO_NET_F_CTRL_VQ	  |	\
>  	 1u << VIRTIO_NET_F_CTRL_RX	  |	\
>  	 1u << VIRTIO_NET_F_CTRL_VLAN	  |	\
> -	 1u << VIRTIO_NET_F_MRG_RXBUF)
> +	 1u << VIRTIO_NET_F_MRG_RXBUF	  |	\
> +	 1ULL << VIRTIO_F_VERSION_1)
> 
>  /*
>   * CQ function prototype
> diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
> index 26b0a0c..7862d7f 100644
> --- a/drivers/net/virtio/virtio_pci.c
> +++ b/drivers/net/virtio/virtio_pci.c
> @@ -31,6 +31,7 @@
>   *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
>   */
>  #include <stdint.h>
> +#include <linux/pci_regs.h>

Put this "include" into macro RTE_EXEC_ENV_LINUXAPP followed?

> 
>  #ifdef RTE_EXEC_ENV_LINUXAPP
>   #include <dirent.h>
> @@ -448,6 +449,205 @@ static const struct virtio_pci_ops legacy_ops = {
>  };
> 
> 
...
> +
> +static uint16_t
> +modern_set_irq(struct virtio_hw *hw __rte_unused, uint16_t vec
> __rte_unused)
> +{
> +	/* FIXME: xxx */
> +	return 0;
> +}

If not going to support LSC, please give clear indication at related doc. My concern is: this will affect
some users, who are using LSC in legacy virtio. (If LSC works well on legacy virtio?).

> +
> +static uint16_t
> +modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
> +{
> +	modern_write16(queue_id, &hw->common_cfg->queue_select);
> +	return modern_read16(&hw->common_cfg->queue_size);
> +}
> +
...
> 
> +static inline void *
> +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)
> +{
> +	uint8_t  bar    = cap->bar;
> +	uint32_t length = cap->length;
> +	uint32_t offset = cap->offset;
> +	uint8_t *base;
> +

Use a macro to substitute hardcoded "5"?

> +	if (unlikely(bar > 5)) {
> +		PMD_INIT_LOG(ERR, "invalid bar: %u", bar);
> +		return NULL;
> +	}
> +
...
>  int
>  vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
>  {
> -	hw->vtpci_ops = &legacy_ops;
> +	hw->dev = dev;
> 
> +	/*
> +	 * Try if we can succeed reading virtio pci caps, which exists
> +	 * only on modern pci device. If failed, we fallback to legacy
> +	 * virtio hanlding.

hanlding -> handling

Thanks,
Jianfeng

> +	 */
...
> +
>  	struct vq_desc_extra {
>  		void              *cookie;
>  		uint16_t          ndescs;
> --
> 1.9.0

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

* Re: [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support
  2015-12-29 11:39   ` Tan, Jianfeng
@ 2015-12-30  3:40     ` Yuanhan Liu
  0 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2015-12-30  3:40 UTC (permalink / raw)
  To: Tan, Jianfeng; +Cc: dev

On Tue, Dec 29, 2015 at 11:39:47AM +0000, Tan, Jianfeng wrote:
> 
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu
> > Sent: Thursday, December 10, 2015 11:54 AM
> > To: dev@dpdk.org
> > Subject: [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support
> > 
> ...
> > Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
> > ---
> >  drivers/net/virtio/virtio_ethdev.c |  16 +-
> >  drivers/net/virtio/virtio_ethdev.h |   3 +-
> >  drivers/net/virtio/virtio_pci.c    | 313
> > ++++++++++++++++++++++++++++++++++++-
> >  drivers/net/virtio/virtio_pci.h    |  65 ++++++++
> >  drivers/net/virtio/virtqueue.h     |   2 +
> >  5 files changed, 395 insertions(+), 4 deletions(-)
> > 
> 
> As legacy VIRTIO_WRITE_REG_XXXs are only used in virtio_pci.c, move these definitions into virtio_pci.c?

Yes, and I planned to do it in another series, where I will do more virtio
cleanups. (hmm..., maybe I could stack them on top of this series).

> 
> > diff --git a/drivers/net/virtio/virtio_ethdev.c
> > b/drivers/net/virtio/virtio_ethdev.c
> > index 9847ed8..1f9de01 100644
> > --- a/drivers/net/virtio/virtio_ethdev.c
> > +++ b/drivers/net/virtio/virtio_ethdev.c
> > @@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev,
> > uint16_t vlan_id, int on)
> >  	return virtio_send_command(hw->cvq, &ctrl, &len, 1);
> >  }
> > 
> > -static void
> > +static int
> >  virtio_negotiate_features(struct virtio_hw *hw)
> >  {
> >  	uint64_t host_features;
> > @@ -949,6 +949,17 @@ virtio_negotiate_features(struct virtio_hw *hw)
> >  	hw->guest_features = vtpci_negotiate_features(hw, host_features);
> >  	PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,
> >  		hw->guest_features);
> > +
> > +	if (hw->modern) {
> > +		if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) {
> > +			PMD_INIT_LOG(ERR,
> > +				"VIRTIO_F_VERSION_1 features is not
> > enabled");
> > +			return -1;
> > +		}
> > +		vtpci_set_status(hw,
> > VIRTIO_CONFIG_STATUS_FEATURES_OK);
> 
> 
> As per Linux code drivers/virtio/virtio.c:virtio_finalize_features(), vtpci_set_status() may fail, and there's a double check.
> Is it necessary here?

Yes, it's necessary: see the spec (3.1.1 Driver Requirements: Device
Initialization):

    5. Set the FEATURES_OK status bit. The driver MUST NOT accept new
       feature bits after this step.

    6. Re-read device status to ensure the FEATURES_OK bit is still set:
       otherwise, the device does not support our subset of features and
       the device is unusable.
> 
> 
> > +	}
> > +
> > +	return 0;
> >  }
> > 
> >  /*
> > @@ -1032,7 +1043,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
> > 
> >  	/* Tell the host we've known how to drive the device. */
> >  	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
> > -	virtio_negotiate_features(hw);
> > +	if (virtio_negotiate_features(hw) < 0)
> > +		return -1;
> > 
> >  	/* If host does not support status then disable LSC */
> >  	if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS))
> > diff --git a/drivers/net/virtio/virtio_ethdev.h
> > b/drivers/net/virtio/virtio_ethdev.h
> > index ae2d47d..fed9571 100644
> > --- a/drivers/net/virtio/virtio_ethdev.h
> > +++ b/drivers/net/virtio/virtio_ethdev.h
> > @@ -64,7 +64,8 @@
> >  	 1u << VIRTIO_NET_F_CTRL_VQ	  |	\
> >  	 1u << VIRTIO_NET_F_CTRL_RX	  |	\
> >  	 1u << VIRTIO_NET_F_CTRL_VLAN	  |	\
> > -	 1u << VIRTIO_NET_F_MRG_RXBUF)
> > +	 1u << VIRTIO_NET_F_MRG_RXBUF	  |	\
> > +	 1ULL << VIRTIO_F_VERSION_1)
> > 
> >  /*
> >   * CQ function prototype
> > diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
> > index 26b0a0c..7862d7f 100644
> > --- a/drivers/net/virtio/virtio_pci.c
> > +++ b/drivers/net/virtio/virtio_pci.c
> > @@ -31,6 +31,7 @@
> >   *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> > DAMAGE.
> >   */
> >  #include <stdint.h>
> > +#include <linux/pci_regs.h>
> 
> Put this "include" into macro RTE_EXEC_ENV_LINUXAPP followed?

We can't simply do that, as we need reference some macros from it
in common code path, virtio_read_caps(). But yes, you just remind
me that there should be no such header in non-linux platform. We
can't include it blindly here. Good catch, btw!

What's lucky here is that we just need reference quite few macros,
maybe we could just define them by ourself, to get rid of the
depency.

> 
> > 
> >  #ifdef RTE_EXEC_ENV_LINUXAPP
> >   #include <dirent.h>
> > @@ -448,6 +449,205 @@ static const struct virtio_pci_ops legacy_ops = {
> >  };
> > 
> > 
> ...
> > +
> > +static uint16_t
> > +modern_set_irq(struct virtio_hw *hw __rte_unused, uint16_t vec
> > __rte_unused)
> > +{
> > +	/* FIXME: xxx */
> > +	return 0;
> > +}
> 
> If not going to support LSC, please give clear indication at related doc. My concern is: this will affect
> some users, who are using LSC in legacy virtio. (If LSC works well on legacy virtio?).

TBH, I don't spent too much time on that, therefore, I marked it as
FIXME here, with the hope that I will revisit it with more cares in
future version.

> > +
> > +static uint16_t
> > +modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
> > +{
> > +	modern_write16(queue_id, &hw->common_cfg->queue_select);
> > +	return modern_read16(&hw->common_cfg->queue_size);
> > +}
> > +
> ...
> > 
> > +static inline void *
> > +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)
> > +{
> > +	uint8_t  bar    = cap->bar;
> > +	uint32_t length = cap->length;
> > +	uint32_t offset = cap->offset;
> > +	uint8_t *base;
> > +
> 
> Use a macro to substitute hardcoded "5"?

The fact that 5 is the max bar number is so well known, that I don't
think it's necessary to add a macro here.

> > +	if (unlikely(bar > 5)) {
> > +		PMD_INIT_LOG(ERR, "invalid bar: %u", bar);
> > +		return NULL;
> > +	}
> > +
> ...
> >  int
> >  vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
> >  {
> > -	hw->vtpci_ops = &legacy_ops;
> > +	hw->dev = dev;
> > 
> > +	/*
> > +	 * Try if we can succeed reading virtio pci caps, which exists
> > +	 * only on modern pci device. If failed, we fallback to legacy
> > +	 * virtio hanlding.
> 
> hanlding -> handling

Oops, and thanks.

	--yliu

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

* Re: [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops
  2015-12-29 11:31   ` Tan, Jianfeng
@ 2015-12-30  3:45     ` Yuanhan Liu
  0 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2015-12-30  3:45 UTC (permalink / raw)
  To: Tan, Jianfeng; +Cc: dev

On Tue, Dec 29, 2015 at 11:31:35AM +0000, Tan, Jianfeng wrote:
> 
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu
> > Sent: Thursday, December 10, 2015 11:54 AM
> > To: dev@dpdk.org
> > Subject: [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops
> > 
> > Introduce struct virtio_pci_ops, to let legacy virtio (v0.95) and
> > modern virtio (1.0) have different implementation regarding to a
> > specific pci action, such as read host status.
> > 
> ...
> > +static void
> > +legacy_reset(struct virtio_hw *hw)
> > +{
> > +	/*
> > +	 * Setting the status to RESET sets the host device to
> > +	 * the original, uninitialized state.
> > +	 */
> > +	legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
> > +	legacy_get_status(hw);
> 
> 
> May need a comment to explain why here we need to get_status().

I don't know, those are old code; I just moved them into a new
function. Maybe I need look into the spec for answer.
> 
> 
> > +}
> > +
> > +static uint8_t
> > +legacy_get_isr(struct virtio_hw *hw)
> > +{
> 
> Please delete the following blank line.

oops ...

> > +
> > +	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
> > +}
> > +
> > +/* Enable one vector (0) for Link State Intrerrupt */
> > +static uint16_t
> > +legacy_set_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);
> > +}
> > +
> ...
> > +
> > +struct virtio_pci_ops {
> > +	void (*read_dev_cfg)(struct virtio_hw *hw, uint64_t offset,
> > +			     void *dst, int len);
> > +	void (*write_dev_cfg)(struct virtio_hw *hw, uint64_t offset,
> > +			      void *src, int len);
> > +	void (*reset)(struct virtio_hw *hw);
> > +
> > +	uint8_t (*get_status)(struct virtio_hw *hw);
> > +	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
> > +
> > +	uint32_t (*get_features)(struct virtio_hw *hw);
> > +	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
> > +
> > +	uint8_t (*get_isr)(struct virtio_hw *hw);
> > +
> > +	uint16_t (*set_irq)(struct virtio_hw *hw, uint16_t vec);
> > +
> > +	uint16_t (*get_queue_num)(struct virtio_hw *hw, uint16_t
> > queue_id);
> 
> How about changing the name into get_queue_size? From my side, queue_num is very confusing.

I agree with you that queue_size is better here, however, queue_num is
taken for being consistent with the virtio spec naming:

    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);
    }


	--yliu

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

* Re: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling
  2015-12-29 11:19 ` Tan, Jianfeng
@ 2015-12-30  3:53   ` Yuanhan Liu
  2016-01-04  3:55   ` Xu, Qian Q
  1 sibling, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2015-12-30  3:53 UTC (permalink / raw)
  To: Tan, Jianfeng; +Cc: dev

On Tue, Dec 29, 2015 at 11:19:20AM +0000, Tan, Jianfeng wrote:
> 
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu
> > Sent: Thursday, December 10, 2015 11:54 AM
> > To: dev@dpdk.org
> > Subject: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling
> > 
> > Hi,
> > 
> > Here is an initial virtio 1.0 pmd driver enabling.
> > 
> > Almost all difference comes from virtio 1.0 are the PCI layout change:
> > the major configuration structures are stored at bar space, and their
> > location is stored at corresponding pci cap structure. Reading/parsing
> > them is one of the major work of patch 6.
> > 
> > To make handling virtio v1.0 and v0.95 co-exist well, this patch set
> > introduces a virtio_pci_ops structure, to add another layer so that
> > we could keep those vtpci_foo_bar "APIs". With that, we could do the
> > minimum change to add virtio 1.0 support.
> 
> 
> Please point out from which version, qemu starts to support virtio 1.0 net devices.

I didn't bother to check: I always use the latest qemu, the one build
from git.

To test it, you need to add 'disable-modern=false' option to the
virtio-net-pci device. I have added a simple test guide on internal
jira. And I should have done so here; will add the test guide in
next version.

	--yliu

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

* Re: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling
  2015-12-29 11:19 ` Tan, Jianfeng
  2015-12-30  3:53   ` Yuanhan Liu
@ 2016-01-04  3:55   ` Xu, Qian Q
  2016-01-04  4:16     ` Yuanhan Liu
  1 sibling, 1 reply; 122+ messages in thread
From: Xu, Qian Q @ 2016-01-04  3:55 UTC (permalink / raw)
  To: Tan, Jianfeng, Yuanhan Liu, dev

Does dpdk vhost-switch sample support virtio1.0? I tried it but seems not working. 

Thanks
Qian


-----Original Message-----
From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tan, Jianfeng
Sent: Tuesday, December 29, 2015 7:19 PM
To: Yuanhan Liu; dev@dpdk.org
Subject: Re: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu
> Sent: Thursday, December 10, 2015 11:54 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling
> 
> Hi,
> 
> Here is an initial virtio 1.0 pmd driver enabling.
> 
> Almost all difference comes from virtio 1.0 are the PCI layout change:
> the major configuration structures are stored at bar space, and their 
> location is stored at corresponding pci cap structure. Reading/parsing 
> them is one of the major work of patch 6.
> 
> To make handling virtio v1.0 and v0.95 co-exist well, this patch set 
> introduces a virtio_pci_ops structure, to add another layer so that we 
> could keep those vtpci_foo_bar "APIs". With that, we could do the 
> minimum change to add virtio 1.0 support.


Please point out from which version, qemu starts to support virtio 1.0 net devices.

Thanks,
Jianfeng

> 
> Note that the enabling is still in rough state, and it's likely I may 
> miss something. So, comments are huge welcome!
> 
> 	--yliu
> 
> ---
> Yuanhan Liu (6):
>   virtio: don't set vring address again at queue startup
>   virtio: introduce struct virtio_pci_ops
>   virtio: move left pci stuff to virtio_pci.c
>   viritio: switch to 64 bit features
>   virtio: set RTE_PCI_DRV_NEED_MAPPING flag
>   virtio: add virtio v1.0 support
> 
>  drivers/net/virtio/virtio_ethdev.c | 297 +--------------
>  drivers/net/virtio/virtio_ethdev.h |   3 +-
>  drivers/net/virtio/virtio_pci.c    | 752
> +++++++++++++++++++++++++++++++++++--
>  drivers/net/virtio/virtio_pci.h    | 100 ++++-
>  drivers/net/virtio/virtio_rxtx.c   |  15 -
>  drivers/net/virtio/virtqueue.h     |   4 +-
>  6 files changed, 843 insertions(+), 328 deletions(-)
> 
> --
> 1.9.0

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

* Re: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling
  2016-01-04  3:55   ` Xu, Qian Q
@ 2016-01-04  4:16     ` Yuanhan Liu
  0 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-04  4:16 UTC (permalink / raw)
  To: Xu, Qian Q; +Cc: dev

On Mon, Jan 04, 2016 at 03:55:14AM +0000, Xu, Qian Q wrote:
> Does dpdk vhost-switch sample support virtio1.0? I tried it but seems not working. 

It has nothing to do with vhost-switch sample. It worked from my
test; you may come to find me offline to see what might be wrong
on your side.

	--yliu
> 
> Thanks
> Qian
> 
> 
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tan, Jianfeng
> Sent: Tuesday, December 29, 2015 7:19 PM
> To: Yuanhan Liu; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling
> 
> 
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu
> > Sent: Thursday, December 10, 2015 11:54 AM
> > To: dev@dpdk.org
> > Subject: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling
> > 
> > Hi,
> > 
> > Here is an initial virtio 1.0 pmd driver enabling.
> > 
> > Almost all difference comes from virtio 1.0 are the PCI layout change:
> > the major configuration structures are stored at bar space, and their 
> > location is stored at corresponding pci cap structure. Reading/parsing 
> > them is one of the major work of patch 6.
> > 
> > To make handling virtio v1.0 and v0.95 co-exist well, this patch set 
> > introduces a virtio_pci_ops structure, to add another layer so that we 
> > could keep those vtpci_foo_bar "APIs". With that, we could do the 
> > minimum change to add virtio 1.0 support.
> 
> 
> Please point out from which version, qemu starts to support virtio 1.0 net devices.
> 
> Thanks,
> Jianfeng
> 
> > 
> > Note that the enabling is still in rough state, and it's likely I may 
> > miss something. So, comments are huge welcome!
> > 
> > 	--yliu
> > 
> > ---
> > Yuanhan Liu (6):
> >   virtio: don't set vring address again at queue startup
> >   virtio: introduce struct virtio_pci_ops
> >   virtio: move left pci stuff to virtio_pci.c
> >   viritio: switch to 64 bit features
> >   virtio: set RTE_PCI_DRV_NEED_MAPPING flag
> >   virtio: add virtio v1.0 support
> > 
> >  drivers/net/virtio/virtio_ethdev.c | 297 +--------------
> >  drivers/net/virtio/virtio_ethdev.h |   3 +-
> >  drivers/net/virtio/virtio_pci.c    | 752
> > +++++++++++++++++++++++++++++++++++--
> >  drivers/net/virtio/virtio_pci.h    | 100 ++++-
> >  drivers/net/virtio/virtio_rxtx.c   |  15 -
> >  drivers/net/virtio/virtqueue.h     |   4 +-
> >  6 files changed, 843 insertions(+), 328 deletions(-)
> > 
> > --
> > 1.9.0

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

* [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver
  2015-12-10  3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu
                   ` (7 preceding siblings ...)
  2015-12-29 11:19 ` Tan, Jianfeng
@ 2016-01-12  6:58 ` Yuanhan Liu
  2016-01-12  6:58   ` [dpdk-dev] [PATCH v2 1/7] virtio: don't set vring address again at queue startup Yuanhan Liu
                     ` (10 more replies)
  8 siblings, 11 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-12  6:58 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

v2: - fix a data corruption reported by Qian, due to hdr size mismatch.
      check detailes at ptach 5.

    - Add missing config_irq and isr reading support from v1.

    - fix comments from v1.

Almost all difference comes from virtio 1.0 are the PCI layout change:
the major configuration structures are stored at bar space, and their
location is stored at corresponding pci cap structure. Reading/parsing
them is one of the major work of patch 7.

To make handling virtio v1.0 and v0.95 co-exist well, this patch set
introduces a virtio_pci_ops structure, to add another layer so that
we could keep those vtpci_foo_bar "APIs". With that, we could do the
minimum change to add virtio 1.0 support.


---
Yuanhan Liu (7):
  virtio: don't set vring address again at queue startup
  virtio: introduce struct virtio_pci_ops
  virtio: move left pci stuff to virtio_pci.c
  viritio: switch to 64 bit features
  virtio: retrieve hdr_size from hw->vtnet_hdr_size
  eal: pci: export pci_map_device
  virtio: add 1.0 support

 doc/guides/rel_notes/release_2_3.rst            |   3 +
 drivers/net/virtio/virtio_ethdev.c              | 301 +---------
 drivers/net/virtio/virtio_ethdev.h              |   3 +-
 drivers/net/virtio/virtio_pci.c                 | 768 +++++++++++++++++++++++-
 drivers/net/virtio/virtio_pci.h                 | 102 +++-
 drivers/net/virtio/virtio_rxtx.c                |  21 +-
 drivers/net/virtio/virtqueue.h                  |   4 +-
 lib/librte_eal/bsdapp/eal/eal_pci.c             |   2 +-
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   6 +
 lib/librte_eal/common/eal_common_pci.c          |   2 +-
 lib/librte_eal/common/eal_private.h             |  11 -
 lib/librte_eal/common/include/rte_pci.h         |  11 +
 lib/librte_eal/linuxapp/eal/eal_pci.c           |   2 +-
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   6 +
 14 files changed, 899 insertions(+), 343 deletions(-)

-- 
1.9.0

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

* [dpdk-dev] [PATCH v2 1/7] virtio: don't set vring address again at queue startup
  2016-01-12  6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
@ 2016-01-12  6:58   ` Yuanhan Liu
  2016-01-12  6:58   ` [dpdk-dev] [PATCH v2 2/7] virtio: introduce struct virtio_pci_ops Yuanhan Liu
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-12  6:58 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

As we have already set up it at virtio_dev_queue_setup(), and a vq
restart will not reset the settings.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_rxtx.c | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index 74b39ef..b7267c0 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -339,11 +339,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type)
 		vq_update_avail_idx(vq);
 
 		PMD_INIT_LOG(DEBUG, "Allocated %d bufs", nbufs);
-
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 	} else if (queue_type == VTNET_TQ) {
 		if (use_simple_rxtx) {
 			int mid_idx  = vq->vq_nentries >> 1;
@@ -362,16 +357,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type)
 			for (i = mid_idx; i < vq->vq_nentries; i++)
 				vq->vq_ring.avail->ring[i] = i;
 		}
-
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
-	} else {
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 	}
 }
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH v2 2/7] virtio: introduce struct virtio_pci_ops
  2016-01-12  6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
  2016-01-12  6:58   ` [dpdk-dev] [PATCH v2 1/7] virtio: don't set vring address again at queue startup Yuanhan Liu
@ 2016-01-12  6:58   ` Yuanhan Liu
  2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 3/7] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
                     ` (8 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-12  6:58 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

Introduce struct virtio_pci_ops, to let legacy virtio (v0.95) and
modern virtio (1.0) have different implementation regarding to a
specific pci action, such as read host status.

With that, this patch reimplements all exported pci functions, in
a way like:

	vtpci_foo_bar(struct virtio_hw *hw)
	{
		hw->vtpci_ops->foo_bar(hw);
	}

So that we need pay attention to those pci related functions only
while adding virtio 1.0 support.

This patch introduced a new vtpci function, vtpci_init(), to do
proper virtio pci settings. It's pretty simple so far: just sets
hw->vtpci_ops to legacy_ops as we don't support 1.0 yet.

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

v2: extra whitespace line removing, and comment on "reading status
    after reset".

    rename the badly taken op name "set_irq" to "set_config_irq".
---
 drivers/net/virtio/virtio_ethdev.c |  22 ++----
 drivers/net/virtio/virtio_pci.c    | 158 ++++++++++++++++++++++++++++++-------
 drivers/net/virtio/virtio_pci.h    |  27 +++++++
 drivers/net/virtio/virtqueue.h     |   2 +-
 4 files changed, 166 insertions(+), 43 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index d928339..6c1d3a0 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -272,9 +272,7 @@ virtio_dev_queue_release(struct virtqueue *vq) {
 
 	if (vq) {
 		hw = vq->hw;
-		/* Select and deactivate the queue */
-		VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+		hw->vtpci_ops->del_queue(hw, vq);
 
 		rte_free(vq->sw_ring);
 		rte_free(vq);
@@ -295,15 +293,13 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
 	struct virtio_hw *hw = dev->data->dev_private;
 	struct virtqueue *vq = NULL;
 
-	/* Write the virtqueue index to the Queue Select Field */
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vtpci_queue_idx);
-	PMD_INIT_LOG(DEBUG, "selecting queue: %u", vtpci_queue_idx);
+	PMD_INIT_LOG(DEBUG, "setting up queue: %u", vtpci_queue_idx);
 
 	/*
 	 * Read the virtqueue size from the Queue Size field
 	 * Always power of 2 and if 0 virtqueue does not exist
 	 */
-	vq_size = VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
+	vq_size = hw->vtpci_ops->get_queue_num(hw, vtpci_queue_idx);
 	PMD_INIT_LOG(DEBUG, "vq_size: %u nb_desc:%u", vq_size, nb_desc);
 	if (vq_size == 0) {
 		PMD_INIT_LOG(ERR, "%s: virtqueue does not exist", __func__);
@@ -436,12 +432,8 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
 		memset(vq->virtio_net_hdr_mz->addr, 0, PAGE_SIZE);
 	}
 
-	/*
-	 * Set guest physical address of the virtqueue
-	 * in VIRTIO_PCI_QUEUE_PFN config register of device
-	 */
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
-			mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+	hw->vtpci_ops->setup_queue(hw, vq);
+
 	*pvq = vq;
 	return 0;
 }
@@ -950,7 +942,7 @@ virtio_negotiate_features(struct virtio_hw *hw)
 		hw->guest_features);
 
 	/* Read device(host) feature bits */
-	host_features = VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+	host_features = hw->vtpci_ops->get_features(hw);
 	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x",
 		host_features);
 
@@ -1287,6 +1279,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 
+	vtpci_init(pci_dev, hw);
+
 	if (virtio_resource_init(pci_dev) < 0)
 		return -1;
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 2245bec..9930efa 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -34,12 +34,11 @@
 
 #include "virtio_pci.h"
 #include "virtio_logs.h"
+#include "virtqueue.h"
 
-static uint8_t vtpci_get_status(struct virtio_hw *);
-
-void
-vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
-		void *dst, int length)
+static void
+legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset,
+		       void *dst, int length)
 {
 	uint64_t off;
 	uint8_t *d;
@@ -60,9 +59,9 @@ vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 	}
 }
 
-void
-vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
-		void *src, int length)
+static void
+legacy_write_dev_config(struct virtio_hw *hw, uint64_t offset,
+			void *src, int length)
 {
 	uint64_t off;
 	uint8_t *s;
@@ -83,30 +82,133 @@ vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
 	}
 }
 
+static uint32_t
+legacy_get_features(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+}
+
+static void
+legacy_set_features(struct virtio_hw *hw, uint32_t features)
+{
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
+}
+
+static uint8_t
+legacy_get_status(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
+}
+
+static void
+legacy_set_status(struct virtio_hw *hw, uint8_t status)
+{
+	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+}
+
+static void
+legacy_reset(struct virtio_hw *hw)
+{
+	legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+}
+
+static uint8_t
+legacy_get_isr(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+}
+
+/* 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);
+}
+
+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);
+}
+
+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);
+
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
+		vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+}
+
+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);
+
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+}
+
+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);
+}
+
+
+static const struct virtio_pci_ops legacy_ops = {
+	.read_dev_cfg	= legacy_read_dev_config,
+	.write_dev_cfg	= legacy_write_dev_config,
+	.reset		= legacy_reset,
+	.get_status	= legacy_get_status,
+	.set_status	= legacy_set_status,
+	.get_features	= legacy_get_features,
+	.set_features	= legacy_set_features,
+	.get_isr	= legacy_get_isr,
+	.set_config_irq	= legacy_set_config_irq,
+	.get_queue_num	= legacy_get_queue_num,
+	.setup_queue	= legacy_setup_queue,
+	.del_queue	= legacy_del_queue,
+	.notify_queue	= legacy_notify_queue,
+};
+
+
+void
+vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
+		      void *dst, int length)
+{
+	hw->vtpci_ops->read_dev_cfg(hw, offset, dst, length);
+}
+
+void
+vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
+		void *src, int length)
+{
+	hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
+}
+
 uint32_t
 vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
 {
 	uint32_t features;
+
 	/*
 	 * Limit negotiated features to what the driver, virtqueue, and
 	 * host all support.
 	 */
 	features = host_features & hw->guest_features;
+	hw->vtpci_ops->set_features(hw, features);
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
 	return features;
 }
 
-
 void
 vtpci_reset(struct virtio_hw *hw)
 {
-	/*
-	 * Setting the status to RESET sets the host device to
-	 * the original, uninitialized state.
-	 */
-	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
-	vtpci_get_status(hw);
+	hw->vtpci_ops->set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+	/* flush status write */
+	hw->vtpci_ops->get_status(hw);
 }
 
 void
@@ -115,26 +217,19 @@ vtpci_reinit_complete(struct virtio_hw *hw)
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK);
 }
 
-static uint8_t
-vtpci_get_status(struct virtio_hw *hw)
-{
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
-}
-
 void
 vtpci_set_status(struct virtio_hw *hw, uint8_t status)
 {
 	if (status != VIRTIO_CONFIG_STATUS_RESET)
-		status = (uint8_t)(status | vtpci_get_status(hw));
+		status |= hw->vtpci_ops->get_status(hw);
 
-	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+	hw->vtpci_ops->set_status(hw, status);
 }
 
 uint8_t
 vtpci_isr(struct virtio_hw *hw)
 {
-
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+	return hw->vtpci_ops->get_isr(hw);
 }
 
 
@@ -142,6 +237,13 @@ vtpci_isr(struct virtio_hw *hw)
 uint16_t
 vtpci_irq_config(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);
+	return hw->vtpci_ops->set_config_irq(hw, vec);
+}
+
+int
+vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw)
+{
+	hw->vtpci_ops = &legacy_ops;
+
+	return 0;
 }
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index 47f722a..ee7d265 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -163,6 +163,31 @@ struct virtqueue;
  */
 #define VIRTIO_MAX_VIRTQUEUES 8
 
+struct virtio_hw;
+
+struct virtio_pci_ops {
+	void (*read_dev_cfg)(struct virtio_hw *hw, uint64_t offset,
+			     void *dst, int len);
+	void (*write_dev_cfg)(struct virtio_hw *hw, uint64_t offset,
+			      void *src, int len);
+	void (*reset)(struct virtio_hw *hw);
+
+	uint8_t (*get_status)(struct virtio_hw *hw);
+	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
+
+	uint32_t (*get_features)(struct virtio_hw *hw);
+	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
+
+	uint8_t (*get_isr)(struct virtio_hw *hw);
+
+	uint16_t (*set_config_irq)(struct virtio_hw *hw, uint16_t vec);
+
+	uint16_t (*get_queue_num)(struct virtio_hw *hw, uint16_t queue_id);
+	void (*setup_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+	void (*del_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+	void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+};
+
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
@@ -174,6 +199,7 @@ struct virtio_hw {
 	uint8_t	    use_msix;
 	uint8_t     started;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
+	const struct virtio_pci_ops *vtpci_ops;
 };
 
 /*
@@ -253,6 +279,7 @@ vtpci_with_feature(struct virtio_hw *hw, uint32_t bit)
 /*
  * Function declaration from virtio_pci.c
  */
+int vtpci_init(struct rte_pci_device *, struct virtio_hw *);
 void vtpci_reset(struct virtio_hw *);
 
 void vtpci_reinit_complete(struct virtio_hw *);
diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h
index 61b3137..d7fb450 100644
--- a/drivers/net/virtio/virtqueue.h
+++ b/drivers/net/virtio/virtqueue.h
@@ -302,7 +302,7 @@ virtqueue_notify(struct virtqueue *vq)
 	 * For virtio on IA, the notificaiton is through io port operation
 	 * which is a serialization instruction itself.
 	 */
-	VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
+	vq->hw->vtpci_ops->notify_queue(vq->hw, vq);
 }
 
 #ifdef RTE_LIBRTE_VIRTIO_DEBUG_DUMP
-- 
1.9.0

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

* [dpdk-dev] [PATCH v2 3/7] virtio: move left pci stuff to virtio_pci.c
  2016-01-12  6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
  2016-01-12  6:58   ` [dpdk-dev] [PATCH v2 1/7] virtio: don't set vring address again at queue startup Yuanhan Liu
  2016-01-12  6:58   ` [dpdk-dev] [PATCH v2 2/7] virtio: introduce struct virtio_pci_ops Yuanhan Liu
@ 2016-01-12  6:59   ` Yuanhan Liu
  2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 4/7] viritio: switch to 64 bit features Yuanhan Liu
                     ` (7 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-12  6:59 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

virtio_pci.c is a more proper place for pci stuff; virtio_ethdev is not.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_ethdev.c | 265 +-----------------------------------
 drivers/net/virtio/virtio_pci.c    | 270 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 270 insertions(+), 265 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 6c1d3a0..b57224d 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -36,10 +36,6 @@
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
-#ifdef RTE_EXEC_ENV_LINUXAPP
-#include <dirent.h>
-#include <fcntl.h>
-#endif
 
 #include <rte_ethdev.h>
 #include <rte_memcpy.h>
@@ -955,260 +951,6 @@ virtio_negotiate_features(struct virtio_hw *hw)
 		hw->guest_features);
 }
 
-#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
-virtio_has_msix(const struct rte_pci_addr *loc)
-{
-	DIR *d;
-	char dirname[PATH_MAX];
-
-	snprintf(dirname, sizeof(dirname),
-		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
-		     loc->domain, loc->bus, loc->devid, loc->function);
-
-	d = opendir(dirname);
-	if (d)
-		closedir(d);
-
-	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 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
-virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
-{
-	/* nic_uio does not enable interrupts, return 0 (false). */
-	return 0;
-}
-
-static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
-{
-	/* no setup required */
-	return 0;
-}
-#endif
-
 /*
  * Process Virtio Config changed interrupt and call the callback
  * if link state changed.
@@ -1279,14 +1021,9 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 
-	vtpci_init(pci_dev, hw);
-
-	if (virtio_resource_init(pci_dev) < 0)
+	if (vtpci_init(pci_dev, hw) < 0)
 		return -1;
 
-	hw->use_msix = virtio_has_msix(&pci_dev->addr);
-	hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr;
-
 	/* Reset the device although not necessary at startup */
 	vtpci_reset(hw);
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 9930efa..03d623b 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -32,6 +32,11 @@
  */
 #include <stdint.h>
 
+#ifdef RTE_EXEC_ENV_LINUXAPP
+ #include <dirent.h>
+ #include <fcntl.h>
+#endif
+
 #include "virtio_pci.h"
 #include "virtio_logs.h"
 #include "virtqueue.h"
@@ -156,6 +161,264 @@ legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
 	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
 }
 
+#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;
+	char dirname[PATH_MAX];
+
+	snprintf(dirname, sizeof(dirname),
+		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
+		     loc->domain, loc->bus, loc->devid, loc->function);
+
+	d = opendir(dirname);
+	if (d)
+		closedir(d);
+
+	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
+legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
+{
+	/* nic_uio does not enable interrupts, return 0 (false). */
+	return 0;
+}
+
+static int
+legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
+{
+	/* no setup required */
+	return 0;
+}
+#endif
 
 static const struct virtio_pci_ops legacy_ops = {
 	.read_dev_cfg	= legacy_read_dev_config,
@@ -241,9 +504,14 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
 }
 
 int
-vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw)
+vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 {
 	hw->vtpci_ops = &legacy_ops;
 
+	if (legacy_virtio_resource_init(dev) < 0)
+		return -1;
+	hw->use_msix = legacy_virtio_has_msix(&dev->addr);
+	hw->io_base  = (uint32_t)(uintptr_t)dev->mem_resource[0].addr;
+
 	return 0;
 }
-- 
1.9.0

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

* [dpdk-dev] [PATCH v2 4/7] viritio: switch to 64 bit features
  2016-01-12  6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                     ` (2 preceding siblings ...)
  2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 3/7] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
@ 2016-01-12  6:59   ` Yuanhan Liu
  2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 5/7] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
                     ` (6 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-12  6:59 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

Switch to 64 bit features, which virtio 1.0 supports.

While legacy virtio only supports 32 bit features, it complains aloud
and quit when trying to setting > 32 bit features.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_ethdev.c |  8 ++++----
 drivers/net/virtio/virtio_pci.c    | 15 ++++++++++-----
 drivers/net/virtio/virtio_pci.h    | 12 ++++++------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index b57224d..94e0c4a 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -930,16 +930,16 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 static void
 virtio_negotiate_features(struct virtio_hw *hw)
 {
-	uint32_t host_features;
+	uint64_t host_features;
 
 	/* Prepare guest_features: feature that driver wants to support */
 	hw->guest_features = VIRTIO_PMD_GUEST_FEATURES;
-	PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %"PRIx64,
 		hw->guest_features);
 
 	/* Read device(host) feature bits */
 	host_features = hw->vtpci_ops->get_features(hw);
-	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %"PRIx64,
 		host_features);
 
 	/*
@@ -947,7 +947,7 @@ virtio_negotiate_features(struct virtio_hw *hw)
 	 * guest feature bits.
 	 */
 	hw->guest_features = vtpci_negotiate_features(hw, host_features);
-	PMD_INIT_LOG(DEBUG, "features after negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,
 		hw->guest_features);
 }
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 03d623b..5eed57e 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -87,15 +87,20 @@ legacy_write_dev_config(struct virtio_hw *hw, uint64_t offset,
 	}
 }
 
-static uint32_t
+static uint64_t
 legacy_get_features(struct virtio_hw *hw)
 {
 	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
 }
 
 static void
-legacy_set_features(struct virtio_hw *hw, uint32_t features)
+legacy_set_features(struct virtio_hw *hw, uint64_t features)
 {
+	if ((features >> 32) != 0) {
+		PMD_DRV_LOG(ERR,
+			"only 32 bit features are allowed for legacy virtio!");
+		return;
+	}
 	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
 }
 
@@ -451,10 +456,10 @@ vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
 	hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
 }
 
-uint32_t
-vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
+uint64_t
+vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features)
 {
-	uint32_t features;
+	uint64_t features;
 
 	/*
 	 * Limit negotiated features to what the driver, virtqueue, and
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index ee7d265..3fd86f6 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -175,8 +175,8 @@ struct virtio_pci_ops {
 	uint8_t (*get_status)(struct virtio_hw *hw);
 	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
 
-	uint32_t (*get_features)(struct virtio_hw *hw);
-	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
+	uint64_t (*get_features)(struct virtio_hw *hw);
+	void     (*set_features)(struct virtio_hw *hw, uint64_t features);
 
 	uint8_t (*get_isr)(struct virtio_hw *hw);
 
@@ -191,7 +191,7 @@ struct virtio_pci_ops {
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
-	uint32_t    guest_features;
+	uint64_t    guest_features;
 	uint32_t    max_tx_queues;
 	uint32_t    max_rx_queues;
 	uint16_t    vtnet_hdr_size;
@@ -271,9 +271,9 @@ outl_p(unsigned int data, unsigned int port)
 	outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
 
 static inline int
-vtpci_with_feature(struct virtio_hw *hw, uint32_t bit)
+vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-	return (hw->guest_features & (1u << bit)) != 0;
+	return (hw->guest_features & (1ULL << bit)) != 0;
 }
 
 /*
@@ -286,7 +286,7 @@ void vtpci_reinit_complete(struct virtio_hw *);
 
 void vtpci_set_status(struct virtio_hw *, uint8_t);
 
-uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t);
+uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t);
 
 void vtpci_write_dev_config(struct virtio_hw *, uint64_t, void *, int);
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH v2 5/7] virtio: retrieve hdr_size from hw->vtnet_hdr_size
  2016-01-12  6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                     ` (3 preceding siblings ...)
  2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 4/7] viritio: switch to 64 bit features Yuanhan Liu
@ 2016-01-12  6:59   ` Yuanhan Liu
  2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device Yuanhan Liu
                     ` (5 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-12  6:59 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

The mergeable virtio net hdr format has been the standard and the
only virtio net hdr format since virtio 1.0. Therefore, we could
not hardcode hdr_size to "sizeof(struct virtio_net_hdr)" any more
at virtio_recv_pkts(), otherwise, there would be a mismatch of
hdr size from rte_vhost_enqueue_burst() and virtio_recv_pkts(),
leading a packet corruption.

Instead, we should retrieve it from hw->vtnet_hdr_size; we will
do proper settings at eth_virtio_dev_init().

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_rxtx.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index b7267c0..41a1366 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -560,7 +560,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 	struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
 	int error;
 	uint32_t i, nb_enqueued;
-	const uint32_t hdr_size = sizeof(struct virtio_net_hdr);
+	uint32_t hdr_size;
 
 	nb_used = VIRTQUEUE_NUSED(rxvq);
 
@@ -580,6 +580,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 	hw = rxvq->hw;
 	nb_rx = 0;
 	nb_enqueued = 0;
+	hdr_size = hw->vtnet_hdr_size;
 
 	for (i = 0; i < num ; i++) {
 		rxm = rcv_pkts[i];
@@ -664,7 +665,7 @@ virtio_recv_mergeable_pkts(void *rx_queue,
 	uint32_t seg_num;
 	uint16_t extra_idx;
 	uint32_t seg_res;
-	const uint32_t hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+	uint32_t hdr_size;
 
 	nb_used = VIRTQUEUE_NUSED(rxvq);
 
@@ -682,6 +683,7 @@ virtio_recv_mergeable_pkts(void *rx_queue,
 	seg_num = 0;
 	extra_idx = 0;
 	seg_res = 0;
+	hdr_size = hw->vtnet_hdr_size;
 
 	while (i < nb_used) {
 		struct virtio_net_hdr_mrg_rxbuf *header;
-- 
1.9.0

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

* [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device
  2016-01-12  6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                     ` (4 preceding siblings ...)
  2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 5/7] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
@ 2016-01-12  6:59   ` Yuanhan Liu
  2016-01-12  8:31     ` David Marchand
  2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support Yuanhan Liu
                     ` (4 subsequent siblings)
  10 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-12  6:59 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will
invoke pci_map_device internally for us. From that point view, there
is no need to export pci_map_device.

However, for virtio pmd driver, which is designed to work without
binding UIO (or something similar first), pci_map_device() will fail,
which ends up with virtio pmd driver being skipped. Therefore, we can
not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver.

Therefore, this patch exports pci_map_device, and let virtio pmd
call it when necessary.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 lib/librte_eal/bsdapp/eal/eal_pci.c             |  2 +-
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |  6 ++++++
 lib/librte_eal/common/eal_common_pci.c          |  2 +-
 lib/librte_eal/common/eal_private.h             | 11 -----------
 lib/librte_eal/common/include/rte_pci.h         | 11 +++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c           |  2 +-
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |  6 ++++++
 7 files changed, 26 insertions(+), 14 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 6c21fbd..adb0915 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -93,7 +93,7 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused)
 
 /* Map pci device */
 int
-pci_map_device(struct rte_pci_device *dev)
+rte_eal_pci_map_device(struct rte_pci_device *dev)
 {
 	int ret = -1;
 
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 9d7adf1..b166c3c 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -135,3 +135,9 @@ DPDK_2.2 {
 	rte_xen_dom0_supported;
 
 } DPDK_2.1;
+
+DPDK_2.3 {
+	global:
+
+	rte_eal_pci_map_device;
+} DPDK_2.2;
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index dcfe947..486d921 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -188,7 +188,7 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 			pci_config_space_set(dev);
 #endif
 			/* map resources for devices that use igb_uio */
-			ret = pci_map_device(dev);
+			ret = rte_eal_pci_map_device(dev);
 			if (ret != 0)
 				return ret;
 		} else if (dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND &&
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index 072e672..ae710b7 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -165,17 +165,6 @@ struct rte_pci_device;
 int pci_unbind_kernel_driver(struct rte_pci_device *dev);
 
 /**
- * Map this device
- *
- * This function is private to EAL.
- *
- * @return
- *   0 on success, negative on error and positive if no driver
- *   is found for the device.
- */
-int pci_map_device(struct rte_pci_device *dev);
-
-/**
  * Unmap this device
  *
  * This function is private to EAL.
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 334c12e..e9e1725 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -485,6 +485,17 @@ 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);
+/**
+ * Map this device
+ *
+ * This function is private to EAL.
+ *
+ * @return
+ *   0 on success, negative on error and positive if no driver
+ *   is found for the device.
+ */
+int rte_eal_pci_map_device(struct rte_pci_device *dev);
+
 
 #ifdef RTE_PCI_CONFIG
 /**
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index bc5b5be..a8cef37 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -124,7 +124,7 @@ pci_get_kernel_driver_by_path(const char *filename, char *dri_name)
 
 /* Map pci device */
 int
-pci_map_device(struct rte_pci_device *dev)
+rte_eal_pci_map_device(struct rte_pci_device *dev)
 {
 	int ret = -1;
 
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index cbe175f..7b12282 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -138,3 +138,9 @@ DPDK_2.2 {
 	rte_xen_dom0_supported;
 
 } DPDK_2.1;
+
+DPDK_2.3 {
+	global:
+
+	rte_eal_pci_map_device;
+} DPDK_2.2;
-- 
1.9.0

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

* [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support
  2016-01-12  6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                     ` (5 preceding siblings ...)
  2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device Yuanhan Liu
@ 2016-01-12  6:59   ` Yuanhan Liu
  2016-01-13  3:31     ` Tetsuya Mukawa
                       ` (2 more replies)
  2016-01-12  7:07   ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                     ` (3 subsequent siblings)
  10 siblings, 3 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-12  6:59 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

Modern (v1.0) virtio pci device defines several pci capabilities.
Each cap has a configure structure corresponding to it, and the
cap.bar and cap.offset fields tell us where to find it.

Firstly, we map the pci resources by rte_eal_pci_map_device().
We then could easily locate to a cfg structure by:

    cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset;

Therefore, the entrance of enabling modern (v1.0) pci device support
is to iterate the pci capability lists, and to locate some configs
we care; and they are:

- common cfg

  For generic virtio and virtuqueu configuration, such as setting/getting
  features, enabling a specific queue, and so on.

- nofity cfg

  Combining with `queue_notify_off' from common cfg, we could use it to
  notify a specific virt queue.

- device cfg

  Where virtio_net_config structure locates.

- isr cfg

  Where to read isr (interrupt status).

If any of above cap is not found, we fallback to the legacy virtio
handling.

If succeed, hw->vtpci_ops is assigned to modern_ops, where all
operations are implemented by reading/writing a (or few) specific
configuration space from above 4 cfg structures. And that's basically
how this patch works.

Besides those changes, virtio 1.0 introduces a new status field:
FEATURES_OK, which is set after features negotiation is done.

Last, set the VIRTIO_F_VERSION_1 feature flag.

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

v2: - re-read status after setting FEATURES_OK to make sure status is
      set correctly.

    - Add isr reading and config irq setting support.

    - Define some pci macro on our own to not get the dependency of
      linux/pci_regs.h, as there should be no such file at non-Linux
      platform
---
 doc/guides/rel_notes/release_2_3.rst |   3 +
 drivers/net/virtio/virtio_ethdev.c   |  24 ++-
 drivers/net/virtio/virtio_ethdev.h   |   3 +-
 drivers/net/virtio/virtio_pci.c      | 335 ++++++++++++++++++++++++++++++++++-
 drivers/net/virtio/virtio_pci.h      |  67 +++++++
 drivers/net/virtio/virtqueue.h       |   2 +
 6 files changed, 429 insertions(+), 5 deletions(-)

diff --git a/doc/guides/rel_notes/release_2_3.rst b/doc/guides/rel_notes/release_2_3.rst
index 99de186..c390d97 100644
--- a/doc/guides/rel_notes/release_2_3.rst
+++ b/doc/guides/rel_notes/release_2_3.rst
@@ -4,6 +4,9 @@ DPDK Release 2.3
 New Features
 ------------
 
+* **Virtio 1.0 support.**
+
+  Enabled virtio 1.0 support for virtio pmd driver.
 
 Resolved Issues
 ---------------
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 94e0c4a..1afaba4 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return virtio_send_command(hw->cvq, &ctrl, &len, 1);
 }
 
-static void
+static int
 virtio_negotiate_features(struct virtio_hw *hw)
 {
 	uint64_t host_features;
@@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw)
 	hw->guest_features = vtpci_negotiate_features(hw, host_features);
 	PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,
 		hw->guest_features);
+
+	if (hw->modern) {
+		if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) {
+			PMD_INIT_LOG(ERR,
+				"VIRTIO_F_VERSION_1 features is not enabled.");
+			return -1;
+		}
+		vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK);
+		if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) {
+			PMD_INIT_LOG(ERR,
+				"failed to set FEATURES_OK status!");
+			return -1;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -1032,7 +1048,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	/* Tell the host we've known how to drive the device. */
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
-	virtio_negotiate_features(hw);
+	if (virtio_negotiate_features(hw) < 0)
+		return -1;
 
 	/* If host does not support status then disable LSC */
 	if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS))
@@ -1043,7 +1060,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 	rx_func_get(eth_dev);
 
 	/* Setting up rx_header size for the device */
-	if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF))
+	if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) ||
+	    vtpci_with_feature(hw, VIRTIO_F_VERSION_1))
 		hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
 	else
 		hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr);
diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h
index ae2d47d..fed9571 100644
--- a/drivers/net/virtio/virtio_ethdev.h
+++ b/drivers/net/virtio/virtio_ethdev.h
@@ -64,7 +64,8 @@
 	 1u << VIRTIO_NET_F_CTRL_VQ	  |	\
 	 1u << VIRTIO_NET_F_CTRL_RX	  |	\
 	 1u << VIRTIO_NET_F_CTRL_VLAN	  |	\
-	 1u << VIRTIO_NET_F_MRG_RXBUF)
+	 1u << VIRTIO_NET_F_MRG_RXBUF	  |	\
+	 1ULL << VIRTIO_F_VERSION_1)
 
 /*
  * CQ function prototype
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 5eed57e..9b62013 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -41,6 +41,14 @@
 #include "virtio_logs.h"
 #include "virtqueue.h"
 
+/*
+ * Following macros are derieved from linux/pci_regs.h, however,
+ * we can't simply include that header here, as there is no such
+ * file for non-Linux platform.
+ */
+#define PCI_CAPABILITY_LIST	0x34
+#define PCI_CAP_ID_VNDR		0x09
+
 static void
 legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 		       void *dst, int length)
@@ -442,6 +450,204 @@ static const struct virtio_pci_ops legacy_ops = {
 };
 
 
+#define MODERN_READ_DEF(nr_bits, type)		\
+static inline type				\
+modern_read##nr_bits(type *addr)		\
+{						\
+	return *(volatile type *)addr;		\
+}
+
+#define MODERN_WRITE_DEF(nr_bits, type)		\
+static inline void				\
+modern_write##nr_bits(type val, type *addr)	\
+{						\
+	*(volatile type *)addr = val;		\
+}
+
+MODERN_READ_DEF (8, uint8_t)
+MODERN_WRITE_DEF(8, uint8_t)
+
+MODERN_READ_DEF (16, uint16_t)
+MODERN_WRITE_DEF(16, uint16_t)
+
+MODERN_READ_DEF (32, uint32_t)
+MODERN_WRITE_DEF(32, uint32_t)
+
+static inline void
+modern_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
+{
+	modern_write32((uint32_t)val, lo);
+	modern_write32(val >> 32,     hi);
+}
+
+static void
+modern_read_dev_config(struct virtio_hw *hw, uint64_t offset,
+		       void *dst, int length)
+{
+	int i;
+	uint8_t *p;
+	uint8_t old_gen, new_gen;
+
+	do {
+		old_gen = modern_read8(&hw->common_cfg->config_generation);
+
+		p = dst;
+		for (i = 0;  i < length; i++)
+			*p++ = modern_read8((uint8_t *)hw->dev_cfg + offset + i);
+
+		new_gen = modern_read8(&hw->common_cfg->config_generation);
+	} while (old_gen != new_gen);
+}
+
+static void
+modern_write_dev_config(struct virtio_hw *hw, uint64_t offset,
+			void *src, int length)
+{
+	int i;
+	uint8_t *p = src;
+
+	for (i = 0;  i < length; i++)
+		modern_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i);
+}
+
+static uint64_t
+modern_get_features(struct virtio_hw *hw)
+{
+	uint32_t features_lo, features_hi;
+
+	modern_write32(0, &hw->common_cfg->device_feature_select);
+	features_lo = modern_read32(&hw->common_cfg->device_feature);
+
+	modern_write32(1, &hw->common_cfg->device_feature_select);
+	features_hi = modern_read32(&hw->common_cfg->device_feature);
+
+	return ((uint64_t)(features_hi) << 32) | features_lo;
+}
+
+static void
+modern_set_features(struct virtio_hw *hw, uint64_t features)
+{
+	modern_write32(0, &hw->common_cfg->guest_feature_select);
+	modern_write32(features & ((1ULL << 32) - 1),
+		&hw->common_cfg->guest_feature);
+
+	modern_write32(1, &hw->common_cfg->guest_feature_select);
+	modern_write32(features >> 32,
+		&hw->common_cfg->guest_feature);
+}
+
+static uint8_t
+modern_get_status(struct virtio_hw *hw)
+{
+	return modern_read8(&hw->common_cfg->device_status);
+}
+
+static void
+modern_set_status(struct virtio_hw *hw, uint8_t status)
+{
+	modern_write8(status, &hw->common_cfg->device_status);
+}
+
+static void
+modern_reset(struct virtio_hw *hw)
+{
+	modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+	modern_get_status(hw);
+}
+
+static uint8_t
+modern_get_isr(struct virtio_hw *hw)
+{
+	return modern_read8(hw->isr);
+}
+
+static uint16_t
+modern_set_config_irq(struct virtio_hw *hw, uint16_t vec)
+{
+	modern_write16(vec, &hw->common_cfg->msix_config);
+	return modern_read16(&hw->common_cfg->msix_config);
+}
+
+static uint16_t
+modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
+{
+	modern_write16(queue_id, &hw->common_cfg->queue_select);
+	return modern_read16(&hw->common_cfg->queue_size);
+}
+
+static void
+modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
+{
+	uint64_t desc_addr, avail_addr, used_addr;
+	uint16_t notify_off;
+
+	desc_addr = vq->mz->phys_addr;
+	avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
+	used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail,
+							 ring[vq->vq_nentries]),
+				   VIRTIO_PCI_VRING_ALIGN);
+
+	modern_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
+
+	modern_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo,
+					  &hw->common_cfg->queue_desc_hi);
+	modern_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo,
+					   &hw->common_cfg->queue_avail_hi);
+	modern_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo,
+					  &hw->common_cfg->queue_used_hi);
+
+	notify_off = modern_read16(&hw->common_cfg->queue_notify_off);
+	vq->notify_addr = (void *)((uint8_t *)hw->notify_base +
+				notify_off * hw->notify_off_multiplier);
+
+	modern_write16(1, &hw->common_cfg->queue_enable);
+
+	PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index);
+	PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr);
+	PMD_INIT_LOG(DEBUG, "\t aval_addr: %"PRIx64, avail_addr);
+	PMD_INIT_LOG(DEBUG, "\t used_addr: %"PRIx64, used_addr);
+	PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)",
+		vq->notify_addr, notify_off);
+}
+
+static void
+modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
+{
+	modern_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
+
+	modern_write64_twopart(0, &hw->common_cfg->queue_desc_lo,
+				  &hw->common_cfg->queue_desc_hi);
+	modern_write64_twopart(0, &hw->common_cfg->queue_avail_lo,
+				  &hw->common_cfg->queue_avail_hi);
+	modern_write64_twopart(0, &hw->common_cfg->queue_used_lo,
+				  &hw->common_cfg->queue_used_hi);
+
+	modern_write16(0, &hw->common_cfg->queue_enable);
+}
+
+static void
+modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
+{
+	modern_write16(1, vq->notify_addr);
+}
+
+static const struct virtio_pci_ops modern_ops = {
+	.read_dev_cfg	= modern_read_dev_config,
+	.write_dev_cfg	= modern_write_dev_config,
+	.reset		= modern_reset,
+	.get_status	= modern_get_status,
+	.set_status	= modern_set_status,
+	.get_features	= modern_get_features,
+	.set_features	= modern_set_features,
+	.get_isr	= modern_get_isr,
+	.set_config_irq	= modern_set_config_irq,
+	.get_queue_num	= modern_get_queue_num,
+	.setup_queue	= modern_setup_queue,
+	.del_queue	= modern_del_queue,
+	.notify_queue	= modern_notify_queue,
+};
+
+
 void
 vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 		      void *dst, int length)
@@ -495,6 +701,12 @@ vtpci_set_status(struct virtio_hw *hw, uint8_t status)
 }
 
 uint8_t
+vtpci_get_status(struct virtio_hw *hw)
+{
+	return hw->vtpci_ops->get_status(hw);
+}
+
+uint8_t
 vtpci_isr(struct virtio_hw *hw)
 {
 	return hw->vtpci_ops->get_isr(hw);
@@ -508,15 +720,136 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
 	return hw->vtpci_ops->set_config_irq(hw, vec);
 }
 
+static inline void *
+get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)
+{
+	uint8_t  bar    = cap->bar;
+	uint32_t length = cap->length;
+	uint32_t offset = cap->offset;
+	uint8_t *base;
+
+	if (unlikely(bar > 5)) {
+		PMD_INIT_LOG(ERR, "invalid bar: %u", bar);
+		return NULL;
+	}
+
+	if (unlikely(offset + length > dev->mem_resource[bar].len)) {
+		PMD_INIT_LOG(ERR,
+			"invalid cap: overflows bar space: %u > %"PRIu64,
+			offset + length, dev->mem_resource[bar].len);
+		return NULL;
+	}
+
+	base = dev->mem_resource[bar].addr;
+	if (unlikely(base == NULL)) {
+		PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar);
+		return NULL;
+	}
+
+	return base + offset;
+}
+
+static int
+virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
+{
+	uint8_t pos;
+	struct virtio_pci_cap cap;
+	int ret;
+
+	if (rte_eal_pci_map_device(dev) < 0) {
+		PMD_INIT_LOG(DEBUG, "failed to map pci device!");
+		return -1;
+	}
+
+	ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST);
+	if (ret < 0) {
+		PMD_INIT_LOG(DEBUG, "failed to read pci capability list");
+		return -1;
+	}
+
+	while (pos) {
+		ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos);
+		if (ret < 0) {
+			PMD_INIT_LOG(ERR,
+				"failed to read pci cap at pos: %x", pos);
+			break;
+		}
+
+		if (cap.cap_vndr != PCI_CAP_ID_VNDR) {
+			PMD_INIT_LOG(DEBUG,
+				"[%2x] skipping non VNDR cap id: %02x",
+				pos, cap.cap_vndr);
+			goto next;
+		}
+
+		PMD_INIT_LOG(DEBUG,
+			"[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u",
+			pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
+
+		switch (cap.cfg_type) {
+		case VIRTIO_PCI_CAP_COMMON_CFG:
+			hw->common_cfg = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_NOTIFY_CFG:
+			rte_eal_pci_read_config(dev, &hw->notify_off_multiplier,
+						4, pos + sizeof(cap));
+			hw->notify_base = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_DEVICE_CFG:
+			hw->dev_cfg = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_ISR_CFG:
+			hw->isr = get_cfg_addr(dev, &cap);
+			break;
+		}
+
+	next:
+		pos = cap.cap_next;
+	}
+
+	if (hw->common_cfg == NULL || hw->notify_base == NULL ||
+	    hw->dev_cfg == NULL    || hw->isr == NULL) {
+		PMD_INIT_LOG(INFO, "no modern virtio pci device found.");
+		return -1;
+	}
+
+	PMD_INIT_LOG(INFO, "found modern virtio pci device.");
+
+	PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg);
+	PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg);
+	PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr);
+	PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u",
+		hw->notify_base, hw->notify_off_multiplier);
+
+	return 0;
+}
+
 int
 vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 {
-	hw->vtpci_ops = &legacy_ops;
+	hw->dev = dev;
+
+	/*
+	 * Try if we can succeed reading virtio pci caps, which exists
+	 * only on modern pci device. If failed, we fallback to legacy
+	 * virtio handling.
+	 */
+	if (virtio_read_caps(dev, hw) == 0) {
+		PMD_INIT_LOG(INFO, "modern virtio pci detected.");
+		hw->vtpci_ops = &modern_ops;
+		hw->modern    = 1;
+		dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
+		return 0;
+	}
 
+	PMD_INIT_LOG(INFO, "trying with legacy virtio pci.");
 	if (legacy_virtio_resource_init(dev) < 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 3fd86f6..6ade642 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -93,6 +93,7 @@ struct virtqueue;
 #define VIRTIO_CONFIG_STATUS_ACK       0x01
 #define VIRTIO_CONFIG_STATUS_DRIVER    0x02
 #define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04
+#define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08
 #define VIRTIO_CONFIG_STATUS_FAILED    0x80
 
 /*
@@ -141,6 +142,8 @@ struct virtqueue;
 /* We support indirect buffer descriptors */
 #define VIRTIO_RING_F_INDIRECT_DESC	28
 
+#define VIRTIO_F_VERSION_1		32
+
 /*
  * Some VirtIO feature bits (currently bits 28 through 31) are
  * reserved for the transport being used (eg. virtio_ring), the
@@ -163,6 +166,60 @@ struct virtqueue;
  */
 #define VIRTIO_MAX_VIRTQUEUES 8
 
+/* Common configuration */
+#define VIRTIO_PCI_CAP_COMMON_CFG	1
+/* Notifications */
+#define VIRTIO_PCI_CAP_NOTIFY_CFG	2
+/* ISR Status */
+#define VIRTIO_PCI_CAP_ISR_CFG		3
+/* Device specific configuration */
+#define VIRTIO_PCI_CAP_DEVICE_CFG	4
+/* PCI configuration access */
+#define VIRTIO_PCI_CAP_PCI_CFG		5
+
+/* This is the PCI capability header: */
+struct virtio_pci_cap {
+	uint8_t cap_vndr;		/* Generic PCI field: PCI_CAP_ID_VNDR */
+	uint8_t cap_next;		/* Generic PCI field: next ptr. */
+	uint8_t cap_len;		/* Generic PCI field: capability length */
+	uint8_t cfg_type;		/* Identifies the structure. */
+	uint8_t bar;			/* Where to find it. */
+	uint8_t padding[3];		/* Pad to full dword. */
+	uint32_t offset;		/* Offset within bar. */
+	uint32_t length;		/* Length of the structure, in bytes. */
+};
+
+struct virtio_pci_notify_cap {
+	struct virtio_pci_cap cap;
+	uint32_t notify_off_multiplier;	/* Multiplier for queue_notify_off. */
+};
+
+/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */
+struct virtio_pci_common_cfg {
+	/* About the whole device. */
+	uint32_t device_feature_select;	/* read-write */
+	uint32_t device_feature;	/* read-only */
+	uint32_t guest_feature_select;	/* read-write */
+	uint32_t guest_feature;		/* read-write */
+	uint16_t msix_config;		/* read-write */
+	uint16_t num_queues;		/* read-only */
+	uint8_t device_status;		/* read-write */
+	uint8_t config_generation;	/* read-only */
+
+	/* About a specific virtqueue. */
+	uint16_t queue_select;		/* read-write */
+	uint16_t queue_size;		/* read-write, power of 2. */
+	uint16_t queue_msix_vector;	/* read-write */
+	uint16_t queue_enable;		/* read-write */
+	uint16_t queue_notify_off;	/* read-only */
+	uint32_t queue_desc_lo;		/* read-write */
+	uint32_t queue_desc_hi;		/* read-write */
+	uint32_t queue_avail_lo;	/* read-write */
+	uint32_t queue_avail_hi;	/* read-write */
+	uint32_t queue_used_lo;		/* read-write */
+	uint32_t queue_used_hi;		/* read-write */
+};
+
 struct virtio_hw;
 
 struct virtio_pci_ops {
@@ -188,6 +245,8 @@ struct virtio_pci_ops {
 	void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq);
 };
 
+struct virtio_net_config;
+
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
@@ -198,7 +257,14 @@ struct virtio_hw {
 	uint8_t	    vlan_strip;
 	uint8_t	    use_msix;
 	uint8_t     started;
+	uint8_t     modern;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
+	uint32_t    notify_off_multiplier;
+	uint8_t     *isr;
+	uint16_t    *notify_base;
+	struct rte_pci_device *dev;
+	struct virtio_pci_common_cfg *common_cfg;
+	struct virtio_net_config *dev_cfg;
 	const struct virtio_pci_ops *vtpci_ops;
 };
 
@@ -284,6 +350,7 @@ void vtpci_reset(struct virtio_hw *);
 
 void vtpci_reinit_complete(struct virtio_hw *);
 
+uint8_t vtpci_get_status(struct virtio_hw *);
 void vtpci_set_status(struct virtio_hw *, uint8_t);
 
 uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t);
diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h
index d7fb450..99d4fa9 100644
--- a/drivers/net/virtio/virtqueue.h
+++ b/drivers/net/virtio/virtqueue.h
@@ -202,6 +202,8 @@ struct virtqueue {
 	/* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */
 	uint64_t	size_bins[8];
 
+	uint16_t	*notify_addr;
+
 	struct vq_desc_extra {
 		void              *cookie;
 		uint16_t          ndescs;
-- 
1.9.0

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

* Re: [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver
  2016-01-12  6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                     ` (6 preceding siblings ...)
  2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support Yuanhan Liu
@ 2016-01-12  7:07   ` Yuanhan Liu
  2016-01-14  4:27   ` Tetsuya Mukawa
                     ` (2 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-12  7:07 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

On Tue, Jan 12, 2016 at 02:58:57PM +0800, Yuanhan Liu wrote:
> v2: - fix a data corruption reported by Qian, due to hdr size mismatch.
>       check detailes at ptach 5.
> 
>     - Add missing config_irq and isr reading support from v1.
> 
>     - fix comments from v1.
> 
> Almost all difference comes from virtio 1.0 are the PCI layout change:
> the major configuration structures are stored at bar space, and their
> location is stored at corresponding pci cap structure. Reading/parsing
> them is one of the major work of patch 7.
> 
> To make handling virtio v1.0 and v0.95 co-exist well, this patch set
> introduces a virtio_pci_ops structure, to add another layer so that
> we could keep those vtpci_foo_bar "APIs". With that, we could do the
> minimum change to add virtio 1.0 support.

Oops, I just found that I missed a simple test guide here, as promised
before. And here it is:

Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add
option "disable-modern=false" to qemu virtio-net-pci device to enable
virtio 1.0 (which is disabled by default).

And if you see something like following from 'lspci -v', it means virtio
1.0 is indeed enabled:

    00:04.0 Ethernet controller: Red Hat, Inc Virtio network device
    Subsystem: Red Hat, Inc Device 0001 
    Physical Slot: 4 
    Flags: bus master, fast devsel, latency 0, IRQ 11 
    I/O ports at c040 [size=64] 
    Memory at febf1000 (32-bit, non-prefetchable) [size=4K] 
    Memory at fe000000 (64-bit, prefetchable) [size=8M] 
    Expansion ROM at feb80000 [disabled] [size=256K] 
    Capabilities: [98] MSI-X: Enable+ Count=6 Masked- 
==> Capabilities: [84] Vendor Specific Information: Len=14 <?> 
==> Capabilities: [70] Vendor Specific Information: Len=14 <?> 
==> Capabilities: [60] Vendor Specific Information: Len=10 <?> 
==> Capabilities: [50] Vendor Specific Information: Len=10 <?> 
==> Capabilities: [40] Vendor Specific Information: Len=10 <?> 
    Kernel driver in use: virtio-pci 
    Kernel modules: virtio_pci

After that, there wasn't anything speical comparing to the old virtio
0.95 pmd driver.

	--yliu
> 
> ---
> Yuanhan Liu (7):
>   virtio: don't set vring address again at queue startup
>   virtio: introduce struct virtio_pci_ops
>   virtio: move left pci stuff to virtio_pci.c
>   viritio: switch to 64 bit features
>   virtio: retrieve hdr_size from hw->vtnet_hdr_size
>   eal: pci: export pci_map_device
>   virtio: add 1.0 support
> 
>  doc/guides/rel_notes/release_2_3.rst            |   3 +
>  drivers/net/virtio/virtio_ethdev.c              | 301 +---------
>  drivers/net/virtio/virtio_ethdev.h              |   3 +-
>  drivers/net/virtio/virtio_pci.c                 | 768 +++++++++++++++++++++++-
>  drivers/net/virtio/virtio_pci.h                 | 102 +++-
>  drivers/net/virtio/virtio_rxtx.c                |  21 +-
>  drivers/net/virtio/virtqueue.h                  |   4 +-
>  lib/librte_eal/bsdapp/eal/eal_pci.c             |   2 +-
>  lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   6 +
>  lib/librte_eal/common/eal_common_pci.c          |   2 +-
>  lib/librte_eal/common/eal_private.h             |  11 -
>  lib/librte_eal/common/include/rte_pci.h         |  11 +
>  lib/librte_eal/linuxapp/eal/eal_pci.c           |   2 +-
>  lib/librte_eal/linuxapp/eal/rte_eal_version.map |   6 +
>  14 files changed, 899 insertions(+), 343 deletions(-)
> 
> -- 
> 1.9.0

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

* Re: [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device
  2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device Yuanhan Liu
@ 2016-01-12  8:31     ` David Marchand
  2016-01-12  8:40       ` Yuanhan Liu
  0 siblings, 1 reply; 122+ messages in thread
From: David Marchand @ 2016-01-12  8:31 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev, Michael S. Tsirkin

On Tue, Jan 12, 2016 at 7:59 AM, Yuanhan Liu <yuanhan.liu@linux.intel.com>
wrote:

> Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will
> invoke pci_map_device internally for us. From that point view, there
> is no need to export pci_map_device.
>
> However, for virtio pmd driver, which is designed to work without
> binding UIO (or something similar first), pci_map_device() will fail,
> which ends up with virtio pmd driver being skipped. Therefore, we can
> not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver.
>
> Therefore, this patch exports pci_map_device, and let virtio pmd
> call it when necessary.
>

Well, if you introduce map function, I suppose, for hotplug, you would need
unmap.

[snip]

diff --git a/lib/librte_eal/common/include/rte_pci.h
> b/lib/librte_eal/common/include/rte_pci.h
> index 334c12e..e9e1725 100644
> --- a/lib/librte_eal/common/include/rte_pci.h
> +++ b/lib/librte_eal/common/include/rte_pci.h
> @@ -485,6 +485,17 @@ 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);
> +/**
> + * Map this device
> + *
> + * This function is private to EAL.
> + *
> + * @return
> + *   0 on success, negative on error and positive if no driver
> + *   is found for the device.
> + */
> +int rte_eal_pci_map_device(struct rte_pci_device *dev);
> +
>

If you export it, then this can not be marked as private anymore.
Description could be better (I agree it was not that great before).
And a little comment on when to call: driver should not set
RTE_PCI_DRV_NEED_MAPPING flag if it wants to use it.

The rest looks good to me.

-- 
David Marchand

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

* Re: [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device
  2016-01-12  8:31     ` David Marchand
@ 2016-01-12  8:40       ` Yuanhan Liu
  2016-01-12  9:05         ` Yuanhan Liu
  0 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-12  8:40 UTC (permalink / raw)
  To: David Marchand; +Cc: dev

On Tue, Jan 12, 2016 at 09:31:05AM +0100, David Marchand wrote:
> On Tue, Jan 12, 2016 at 7:59 AM, Yuanhan Liu <yuanhan.liu@linux.intel.com>
> wrote:
> 
>     Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will
>     invoke pci_map_device internally for us. From that point view, there
>     is no need to export pci_map_device.
> 
>     However, for virtio pmd driver, which is designed to work without
>     binding UIO (or something similar first), pci_map_device() will fail,
>     which ends up with virtio pmd driver being skipped. Therefore, we can
>     not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver.
> 
>     Therefore, this patch exports pci_map_device, and let virtio pmd
>     call it when necessary.
> 
> 
> Well, if you introduce map function, I suppose, for hotplug, you would need
> unmap.

Good remind. Thanks. I will export pci_unmap_device as well.

> [snip]
> 
> 
>     diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/
>     common/include/rte_pci.h
>     index 334c12e..e9e1725 100644
>     --- a/lib/librte_eal/common/include/rte_pci.h
>     +++ b/lib/librte_eal/common/include/rte_pci.h
>     @@ -485,6 +485,17 @@ 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);
>     +/**
>     + * Map this device
>     + *
>     + * This function is private to EAL.
>     + *
>     + * @return
>     + *   0 on success, negative on error and positive if no driver
>     + *   is found for the device.
>     + */
>     +int rte_eal_pci_map_device(struct rte_pci_device *dev);
>     +
> 
> 
> If you export it, then this can not be marked as private anymore.

Oops, a silly C&P error. Will fix it.

> Description could be better (I agree it was not that great before).
> And a little comment on when to call: driver should not set
> RTE_PCI_DRV_NEED_MAPPING flag if it wants to use it.

Good suggestion.

> The rest looks good to me.

Thanks.

	--yliu

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

* Re: [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device
  2016-01-12  8:40       ` Yuanhan Liu
@ 2016-01-12  9:05         ` Yuanhan Liu
  2016-01-13 14:44           ` Santosh Shukla
  0 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-12  9:05 UTC (permalink / raw)
  To: David Marchand; +Cc: dev

On Tue, Jan 12, 2016 at 04:40:43PM +0800, Yuanhan Liu wrote:
> On Tue, Jan 12, 2016 at 09:31:05AM +0100, David Marchand wrote:
> > On Tue, Jan 12, 2016 at 7:59 AM, Yuanhan Liu <yuanhan.liu@linux.intel.com>
> > wrote:
> > 
> >     Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will
> >     invoke pci_map_device internally for us. From that point view, there
> >     is no need to export pci_map_device.
> > 
> >     However, for virtio pmd driver, which is designed to work without
> >     binding UIO (or something similar first), pci_map_device() will fail,
> >     which ends up with virtio pmd driver being skipped. Therefore, we can
> >     not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver.
> > 
> >     Therefore, this patch exports pci_map_device, and let virtio pmd
> >     call it when necessary.
> > 
> > 
> > Well, if you introduce map function, I suppose, for hotplug, you would need
> > unmap.
> 
> Good remind. Thanks. I will export pci_unmap_device as well.

And here you go.

	--yliu

-- >8 --
>From aa3d9d0fa827781d1563fd4c06ba04a8fafdc41c Mon Sep 17 00:00:00 2001
From: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Date: Mon, 11 Jan 2016 16:51:35 +0800
Subject: [PATCH] eal: pci: export pci_[un]map_device

Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will
invoke pci_map_device internally for us. From that point view, there
is no need to export pci_map_device.

However, for virtio pmd driver, which is designed to work without
binding UIO (or something similar first), pci_map_device() will fail,
which ends up with virtio pmd driver being skipped. Therefore, we can
not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver.

Therefore, this patch exports pci_map_device, and let virtio pmd
call it when necessary.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
v2: - export pci_unmap_device as well

    - Add few more comments about rte_eal_pci_map_device().
---
 lib/librte_eal/bsdapp/eal/eal_pci.c             |  4 ++--
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |  7 +++++++
 lib/librte_eal/common/eal_common_pci.c          |  4 ++--
 lib/librte_eal/common/eal_private.h             | 18 -----------------
 lib/librte_eal/common/include/rte_pci.h         | 27 +++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c           |  4 ++--
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |  7 +++++++
 7 files changed, 47 insertions(+), 24 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 6c21fbd..95c32c1 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -93,7 +93,7 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused)
 
 /* Map pci device */
 int
-pci_map_device(struct rte_pci_device *dev)
+rte_eal_pci_map_device(struct rte_pci_device *dev)
 {
 	int ret = -1;
 
@@ -115,7 +115,7 @@ pci_map_device(struct rte_pci_device *dev)
 
 /* Unmap pci device */
 void
-pci_unmap_device(struct rte_pci_device *dev)
+rte_eal_pci_unmap_device(struct rte_pci_device *dev)
 {
 	/* try unmapping the NIC resources */
 	switch (dev->kdrv) {
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 9d7adf1..1b28170 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -135,3 +135,10 @@ DPDK_2.2 {
 	rte_xen_dom0_supported;
 
 } DPDK_2.1;
+
+DPDK_2.3 {
+	global:
+
+	rte_eal_pci_map_device;
+	rte_eal_pci_unmap_device;
+} DPDK_2.2;
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index dcfe947..96d5113 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -188,7 +188,7 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 			pci_config_space_set(dev);
 #endif
 			/* map resources for devices that use igb_uio */
-			ret = pci_map_device(dev);
+			ret = rte_eal_pci_map_device(dev);
 			if (ret != 0)
 				return ret;
 		} else if (dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND &&
@@ -254,7 +254,7 @@ rte_eal_pci_detach_dev(struct rte_pci_driver *dr,
 
 		if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
 			/* unmap resources for devices that use igb_uio */
-			pci_unmap_device(dev);
+			rte_eal_pci_unmap_device(dev);
 
 		return 0;
 	}
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index 072e672..2342fa1 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -165,24 +165,6 @@ struct rte_pci_device;
 int pci_unbind_kernel_driver(struct rte_pci_device *dev);
 
 /**
- * Map this device
- *
- * This function is private to EAL.
- *
- * @return
- *   0 on success, negative on error and positive if no driver
- *   is found for the device.
- */
-int pci_map_device(struct rte_pci_device *dev);
-
-/**
- * Unmap this device
- *
- * This function is private to EAL.
- */
-void pci_unmap_device(struct rte_pci_device *dev);
-
-/**
  * Map the PCI resource of a PCI device in virtual memory
  *
  * This function is private to EAL.
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 334c12e..2224109 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -485,6 +485,33 @@ 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);
+/**
+ * Map the PCI device resources in user space virtual memory address
+ *
+ * Note that driver should not call this function when flag
+ * RTE_PCI_DRV_NEED_MAPPING is set, as EAL will do that for
+ * you when it's on.
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device
+ *   to use
+ *
+ * @return
+ *   0 on success, negative on error and positive if no driver
+ *   is found for the device.
+ */
+int rte_eal_pci_map_device(struct rte_pci_device *dev);
+
+/**
+ * Unmap this device
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device
+ *   to use
+ */
+void rte_eal_pci_unmap_device(struct rte_pci_device *dev);
+
+
 
 #ifdef RTE_PCI_CONFIG
 /**
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index bc5b5be..db947da 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -124,7 +124,7 @@ pci_get_kernel_driver_by_path(const char *filename, char *dri_name)
 
 /* Map pci device */
 int
-pci_map_device(struct rte_pci_device *dev)
+rte_eal_pci_map_device(struct rte_pci_device *dev)
 {
 	int ret = -1;
 
@@ -153,7 +153,7 @@ pci_map_device(struct rte_pci_device *dev)
 
 /* Unmap pci device */
 void
-pci_unmap_device(struct rte_pci_device *dev)
+rte_eal_pci_unmap_device(struct rte_pci_device *dev)
 {
 	/* try unmapping the NIC resources using VFIO if it exists */
 	switch (dev->kdrv) {
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index cbe175f..b9937c4 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -138,3 +138,10 @@ DPDK_2.2 {
 	rte_xen_dom0_supported;
 
 } DPDK_2.1;
+
+DPDK_2.3 {
+	global:
+
+	rte_eal_pci_map_device;
+	rte_eal_pci_unmap_device;
+} DPDK_2.2;
-- 
1.9.0

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

* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support
  2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support Yuanhan Liu
@ 2016-01-13  3:31     ` Tetsuya Mukawa
  2016-01-13  9:38       ` Yuanhan Liu
  2016-01-14  7:47     ` Xie, Huawei
  2016-01-14  7:50     ` Xie, Huawei
  2 siblings, 1 reply; 122+ messages in thread
From: Tetsuya Mukawa @ 2016-01-13  3:31 UTC (permalink / raw)
  To: Yuanhan Liu, dev; +Cc: Michael S. Tsirkin

On 2016/01/12 15:59, Yuanhan Liu wrote:
> +static int
> +virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
> +{
> +	uint8_t pos;
> +	struct virtio_pci_cap cap;
> +	int ret;
> +
> +	if (rte_eal_pci_map_device(dev) < 0) {
> +		PMD_INIT_LOG(DEBUG, "failed to map pci device!");
> +		return -1;
> +	}
> +

Do you need to call rte_eal_pci_unmap_device() in somewhere in this file?

Anyway, I've reviewed and tested your all patches.
And it seems except for it, I guess your patches are good.

Thanks,
Tetsuya

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

* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support
  2016-01-13  3:31     ` Tetsuya Mukawa
@ 2016-01-13  9:38       ` Yuanhan Liu
  0 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-13  9:38 UTC (permalink / raw)
  To: Tetsuya Mukawa; +Cc: dev, Michael S. Tsirkin

On Wed, Jan 13, 2016 at 12:31:43PM +0900, Tetsuya Mukawa wrote:
> On 2016/01/12 15:59, Yuanhan Liu wrote:
> > +static int
> > +virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
> > +{
> > +	uint8_t pos;
> > +	struct virtio_pci_cap cap;
> > +	int ret;
> > +
> > +	if (rte_eal_pci_map_device(dev) < 0) {
> > +		PMD_INIT_LOG(DEBUG, "failed to map pci device!");
> > +		return -1;
> > +	}
> > +
> 
> Do you need to call rte_eal_pci_unmap_device() in somewhere in this file?

Yes, we should. I will see where I can find a proper place for it in
next version; eth_virtio_dev_uninit sounds like a good option.

> Anyway, I've reviewed and tested your all patches.
> And it seems except for it, I guess your patches are good.

Thank you for reviewing and testing it!

	--yliu

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

* Re: [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device
  2016-01-12  9:05         ` Yuanhan Liu
@ 2016-01-13 14:44           ` Santosh Shukla
  0 siblings, 0 replies; 122+ messages in thread
From: Santosh Shukla @ 2016-01-13 14:44 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev

On Tue, Jan 12, 2016 at 2:35 PM, Yuanhan Liu
<yuanhan.liu@linux.intel.com> wrote:
> On Tue, Jan 12, 2016 at 04:40:43PM +0800, Yuanhan Liu wrote:
>> On Tue, Jan 12, 2016 at 09:31:05AM +0100, David Marchand wrote:
>> > On Tue, Jan 12, 2016 at 7:59 AM, Yuanhan Liu <yuanhan.liu@linux.intel.com>
>> > wrote:
>> >
>> >     Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will
>> >     invoke pci_map_device internally for us. From that point view, there
>> >     is no need to export pci_map_device.
>> >
>> >     However, for virtio pmd driver, which is designed to work without
>> >     binding UIO (or something similar first), pci_map_device() will fail,
>> >     which ends up with virtio pmd driver being skipped. Therefore, we can
>> >     not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver.
>> >
>> >     Therefore, this patch exports pci_map_device, and let virtio pmd
>> >     call it when necessary.
>> >
>> >
>> > Well, if you introduce map function, I suppose, for hotplug, you would need
>> > unmap.
>>
>> Good remind. Thanks. I will export pci_unmap_device as well.
>
> And here you go.
>
>         --yliu
>
> -- >8 --
> From aa3d9d0fa827781d1563fd4c06ba04a8fafdc41c Mon Sep 17 00:00:00 2001
> From: Yuanhan Liu <yuanhan.liu@linux.intel.com>
> Date: Mon, 11 Jan 2016 16:51:35 +0800
> Subject: [PATCH] eal: pci: export pci_[un]map_device
>
> Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will
> invoke pci_map_device internally for us. From that point view, there
> is no need to export pci_map_device.
>
> However, for virtio pmd driver, which is designed to work without
> binding UIO (or something similar first), pci_map_device() will fail,
> which ends up with virtio pmd driver being skipped. Therefore, we can
> not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver.
>
> Therefore, this patch exports pci_map_device, and let virtio pmd
> call it when necessary.
>
> Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
> ---
> v2: - export pci_unmap_device as well
>
>     - Add few more comments about rte_eal_pci_map_device().

This patch tested for vfio-noIOMMU mode for arm64 platform.
Tested-By: Santosh Shukla <sshukla@mvista.com>

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

* Re: [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver
  2016-01-12  6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                     ` (7 preceding siblings ...)
  2016-01-12  7:07   ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
@ 2016-01-14  4:27   ` Tetsuya Mukawa
  2016-01-14  5:59     ` Yuanhan Liu
  2016-01-14  6:09     ` Tan, Jianfeng
  2016-01-14  7:42   ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu
  2016-01-15  4:36   ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
  10 siblings, 2 replies; 122+ messages in thread
From: Tetsuya Mukawa @ 2016-01-14  4:27 UTC (permalink / raw)
  To: Yuanhan Liu, dev, Tan Jianfeng; +Cc: Michael S. Tsirkin

On 2016/01/12 15:58, Yuanhan Liu wrote:
> v2: - fix a data corruption reported by Qian, due to hdr size mismatch.
>       check detailes at ptach 5.
>
>     - Add missing config_irq and isr reading support from v1.
>
>     - fix comments from v1.
>
> Almost all difference comes from virtio 1.0 are the PCI layout change:
> the major configuration structures are stored at bar space, and their
> location is stored at corresponding pci cap structure. Reading/parsing
> them is one of the major work of patch 7.
>
> To make handling virtio v1.0 and v0.95 co-exist well, this patch set
> introduces a virtio_pci_ops structure, to add another layer so that
> we could keep those vtpci_foo_bar "APIs". With that, we could do the
> minimum change to add virtio 1.0 support.
>
>
> ---
> Yuanhan Liu (7):
>   virtio: don't set vring address again at queue startup
>   virtio: introduce struct virtio_pci_ops
>   virtio: move left pci stuff to virtio_pci.c
>   viritio: switch to 64 bit features
>   virtio: retrieve hdr_size from hw->vtnet_hdr_size
>   eal: pci: export pci_map_device
>   virtio: add 1.0 support
>
>  doc/guides/rel_notes/release_2_3.rst            |   3 +
>  drivers/net/virtio/virtio_ethdev.c              | 301 +---------
>  drivers/net/virtio/virtio_ethdev.h              |   3 +-
>  drivers/net/virtio/virtio_pci.c                 | 768 +++++++++++++++++++++++-
>  drivers/net/virtio/virtio_pci.h                 | 102 +++-
>  drivers/net/virtio/virtio_rxtx.c                |  21 +-
>  drivers/net/virtio/virtqueue.h                  |   4 +-
>  lib/librte_eal/bsdapp/eal/eal_pci.c             |   2 +-
>  lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   6 +
>  lib/librte_eal/common/eal_common_pci.c          |   2 +-
>  lib/librte_eal/common/eal_private.h             |  11 -
>  lib/librte_eal/common/include/rte_pci.h         |  11 +
>  lib/librte_eal/linuxapp/eal/eal_pci.c           |   2 +-
>  lib/librte_eal/linuxapp/eal/rte_eal_version.map |   6 +
>  14 files changed, 899 insertions(+), 343 deletions(-)
>

Hi Yuanhan and Jianfeng,

Thanks for great patches.
I want to use VIRTIO-1.0 feature for my virtio container patch, because
it will solve 44 bit memory address limitation.
(So far, legacy virtio-net device only receives queue address under (1
<< (32 + 12)).)

I have a few comments to rebase virtio container patches on this patches.

1. VIRTIO_READ_REG_X

So far, VIRTIO_READ_REG_1/2/4 are defined in virtio_pci.h.
But these macros are only referred by virtio_pci.c.
How about moving the macros to virtio_pci.c?

2. Abstraction of read/write accesses.

It may be difficult to cleanly rebase my patches on this patches,
because virtio_read_caps() is not abstracted.
Let me describe it more.
So far, we need to handle below 3 virtio-net devices..
 - physical virtio-net device.
 - virtual virtio-net device in virtio-net PMD. (Jianfeng's patch)
 - virtual virtio-net device in QEMU. (my patch)

Almost all code of the virtio-net PMD can be shared between above
different cases.
Probably big difference is how to access to configuration space.

Yuanhan's patch introduces an abstraction layer to hide configuration
space layout and how to access it.
Is it possible to separate?
I guess "access method" will be nice to be abstracted separately from
"configuration space layout".
Probably access method will be defined by "eth_dev->dev_type" and the
PMD name like "eth_cvio".
And "configuration space layout" will be defined by capability list of
PCI configuration layout.

For example, if access method like below are abstracted separately and
current "virtio_pci.c" is implemented on this abstraction, we can easily
re-use virtio_read_caps().
 - how to read/write virtio configuration space.
 - how to mmap PCI configuration space.
 - how to read/(write) PCI configuration space.

Thanks,
Tetsuya

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

* Re: [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver
  2016-01-14  4:27   ` Tetsuya Mukawa
@ 2016-01-14  5:59     ` Yuanhan Liu
  2016-01-14  6:09     ` Tan, Jianfeng
  1 sibling, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  5:59 UTC (permalink / raw)
  To: Tetsuya Mukawa; +Cc: dev, Michael S. Tsirkin

On Thu, Jan 14, 2016 at 01:27:37PM +0900, Tetsuya Mukawa wrote:
> On 2016/01/12 15:58, Yuanhan Liu wrote:
> > v2: - fix a data corruption reported by Qian, due to hdr size mismatch.
> >       check detailes at ptach 5.
> >
> >     - Add missing config_irq and isr reading support from v1.
> >
> >     - fix comments from v1.
> >
> > Almost all difference comes from virtio 1.0 are the PCI layout change:
> > the major configuration structures are stored at bar space, and their
> > location is stored at corresponding pci cap structure. Reading/parsing
> > them is one of the major work of patch 7.
> >
> > To make handling virtio v1.0 and v0.95 co-exist well, this patch set
> > introduces a virtio_pci_ops structure, to add another layer so that
> > we could keep those vtpci_foo_bar "APIs". With that, we could do the
> > minimum change to add virtio 1.0 support.
> >
> >
> 
> Hi Yuanhan and Jianfeng,
> 
> Thanks for great patches.
> I want to use VIRTIO-1.0 feature for my virtio container patch, because
> it will solve 44 bit memory address limitation.
> (So far, legacy virtio-net device only receives queue address under (1
> << (32 + 12)).)
> 
> I have a few comments to rebase virtio container patches on this patches.
> 
> 1. VIRTIO_READ_REG_X
> 
> So far, VIRTIO_READ_REG_1/2/4 are defined in virtio_pci.h.
> But these macros are only referred by virtio_pci.c.
> How about moving the macros to virtio_pci.c?

Jianfeng had same suggestion. I could do that in next version then.

> 2. Abstraction of read/write accesses.
> 
> It may be difficult to cleanly rebase my patches on this patches,
> because virtio_read_caps() is not abstracted.

I don't think we can/need abstract virtio_read_caps() here. As that
detects wheter it is a legacy or modern (virtio 1.0) virtio device
or not.

If virtio_read_caps failes, which could either due to pci map failed,
or because malformed pci layout, we fallback to legacy virtio 1.0
handling, using io port read/write to do configuration.

> Let me describe it more.
> So far, we need to handle below 3 virtio-net devices..
>  - physical virtio-net device.
>  - virtual virtio-net device in virtio-net PMD. (Jianfeng's patch)
>  - virtual virtio-net device in QEMU. (my patch)
> 
> Almost all code of the virtio-net PMD can be shared between above
> different cases.
> Probably big difference is how to access to configuration space.
> 
> Yuanhan's patch introduces an abstraction layer to hide configuration
> space layout and how to access it.

Actually, I didn't introduce the abstraction for pci device access. It's
just a simple "if ... else ..." case here: use io port read/write, the
VIRTIO_READ/WRITE_REG_X macros, to do access for legacy virtio,
otherwise for modern virtio, use direct mapped memory read/write access:
modern_read/writex.

> Is it possible to separate?

As stated, there is no mix, therefore no need for seperation. But
you could add another access abstraction layer, and assign it properly
later, say, by checking eth_dev->dev_type as you suggested below.

> I guess "access method" will be nice to be abstracted separately from
> "configuration space layout".
> Probably access method will be defined by "eth_dev->dev_type" and the
> PMD name like "eth_cvio".
> And "configuration space layout" will be defined by capability list of
> PCI configuration layout.
> 
> For example, if access method like below are abstracted separately and
> current "virtio_pci.c" is implemented on this abstraction, we can easily
> re-use virtio_read_caps().
>  - how to read/write virtio configuration space.

It's abstracted by virtio_pci_ops.

>  - how to mmap PCI configuration space.
>  - how to read/(write) PCI configuration space.

For now, it's actually done by EAL, or by functions provided by EAL.
I haven't read your (as well Jianfeng's) code yet, but seems that
you need implement another set of functions for above needes for
your virtio device.

If so, I'd suggest you (or Jianfeng) to do the abstraction based on
my patchset: what I am kind of sure is that I should not add those
abstraction here, simply for it has nothing to do with virtio 1.0
enabling.

	--yliu

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

* Re: [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver
  2016-01-14  4:27   ` Tetsuya Mukawa
  2016-01-14  5:59     ` Yuanhan Liu
@ 2016-01-14  6:09     ` Tan, Jianfeng
  2016-01-14  6:41       ` Tetsuya Mukawa
  2016-01-14  6:45       ` Yuanhan Liu
  1 sibling, 2 replies; 122+ messages in thread
From: Tan, Jianfeng @ 2016-01-14  6:09 UTC (permalink / raw)
  To: Tetsuya Mukawa, Yuanhan Liu, dev; +Cc: Michael S. Tsirkin


Hi Tetsuya,

On 1/14/2016 12:27 PM, Tetsuya Mukawa wrote:
> On 2016/01/12 15:58, Yuanhan Liu wrote:
> Hi Yuanhan and Jianfeng,
>
> Thanks for great patches.
> I want to use VIRTIO-1.0 feature for my virtio container patch, because
> it will solve 44 bit memory address limitation.
> (So far, legacy virtio-net device only receives queue address under (1
> << (32 + 12)).)

I suppose you are specifying the code below:
         /*
          * Virtio PCI device VIRTIO_PCI_QUEUE_PF register is 32bit,
          * and only accepts 32 bit page frame number.
          * Check if the allocated physical memory exceeds 16TB.
          */
         if ((mz->phys_addr + vq->vq_ring_size - 1) >> 
(VIRTIO_PCI_QUEUE_ADDR_SHIFT + 32)) {
                 PMD_INIT_LOG(ERR, "vring address shouldn't be above 
16TB!");
                 rte_free(vq);
                 return -ENOMEM;
         }

So you don't need to add extra cmd option, right?

>
> I have a few comments to rebase virtio container patches on this patches.
>
> 1. VIRTIO_READ_REG_X
>
> So far, VIRTIO_READ_REG_1/2/4 are defined in virtio_pci.h.
> But these macros are only referred by virtio_pci.c.
> How about moving the macros to virtio_pci.c?

+1 for this.

>
> 2. Abstraction of read/write accesses.
>
> It may be difficult to cleanly rebase my patches on this patches,
> because virtio_read_caps() is not abstracted.
> Let me describe it more.
> So far, we need to handle below 3 virtio-net devices..
>   - physical virtio-net device.
>   - virtual virtio-net device in virtio-net PMD. (Jianfeng's patch)
>   - virtual virtio-net device in QEMU. (my patch)
>
> Almost all code of the virtio-net PMD can be shared between above
> different cases.
> Probably big difference is how to access to configuration space.
>
> Yuanhan's patch introduces an abstraction layer to hide configuration
> space layout and how to access it.
> Is it possible to separate?
> I guess "access method" will be nice to be abstracted separately from
> "configuration space layout".
> Probably access method will be defined by "eth_dev->dev_type" and the
> PMD name like "eth_cvio".
> And "configuration space layout" will be defined by capability list of
> PCI configuration layout.
>
> For example, if access method like below are abstracted separately and
> current "virtio_pci.c" is implemented on this abstraction, we can easily
> re-use virtio_read_caps().
>   - how to read/write virtio configuration space.
>   - how to mmap PCI configuration space.
>   - how to read/(write) PCI configuration space.


I basically agree with you. We have two dimensions here:

legacy             modern
physical virtio device:                     Use virtio_read_caps_phys() 
to distinguish
virtual virtio device (Tetsuya):       Use virtio_read_caps_virt() to 
distinguish
virtual virtio device (Jianfeng):    does not need a "configuration 
space layout", no need to distinguish

So in vtpci_init(), we needs to test "eth_dev->dev_type" firstly

vtpci_init() {
     if (eth_dev->dev_type == RTE_ETH_DEV_PCI) {
         if (virtio_read_caps_phys()) {
             // modern
         } else {
             // legacy
         }
     } else {
         if (Tetsuya's way) {
             if (virtio_read_caps_virt()) {
                 // modern
             } else {
                 // legacy
             }
         } else {
             // Jianfeng's way
         }
     }
}

And from Yuanhan's angle, I think he does not need to address this 
problem. How do you think?

Thanks,
Jianfeng


>
> Thanks,
> Tetsuya

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

* Re: [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver
  2016-01-14  6:09     ` Tan, Jianfeng
@ 2016-01-14  6:41       ` Tetsuya Mukawa
  2016-01-18  9:04         ` Tetsuya Mukawa
  2016-01-14  6:45       ` Yuanhan Liu
  1 sibling, 1 reply; 122+ messages in thread
From: Tetsuya Mukawa @ 2016-01-14  6:41 UTC (permalink / raw)
  To: Tan, Jianfeng, Yuanhan Liu, dev; +Cc: Michael S. Tsirkin

On 2016/01/14 15:09, Tan, Jianfeng wrote:
>
> Hi Tetsuya,
>
> On 1/14/2016 12:27 PM, Tetsuya Mukawa wrote:
>> On 2016/01/12 15:58, Yuanhan Liu wrote:
>> Hi Yuanhan and Jianfeng,
>>
>> Thanks for great patches.
>> I want to use VIRTIO-1.0 feature for my virtio container patch, because
>> it will solve 44 bit memory address limitation.
>> (So far, legacy virtio-net device only receives queue address under (1
>> << (32 + 12)).)
>
> I suppose you are specifying the code below:
>         /*
>          * Virtio PCI device VIRTIO_PCI_QUEUE_PF register is 32bit,
>          * and only accepts 32 bit page frame number.
>          * Check if the allocated physical memory exceeds 16TB.
>          */
>         if ((mz->phys_addr + vq->vq_ring_size - 1) >>
> (VIRTIO_PCI_QUEUE_ADDR_SHIFT + 32)) {
>                 PMD_INIT_LOG(ERR, "vring address shouldn't be above
> 16TB!");
>                 rte_free(vq);
>                 return -ENOMEM;
>         }
>
> So you don't need to add extra cmd option, right?

Yes, this is the code.
In our case, instead of using physical address, virtual address will be
used, right?
Problem is that virtual address will be over (1 << 44) without
specifying some mmap options.
Probably we need to specify "MAP_FIXED" option while mmapping EAL memory
to get lower address.

But if we can use VIRTIO-1.0, we can specify 64bit address, then we
don't need to do something tricky mmaping.

>
>>
>> I have a few comments to rebase virtio container patches on this
>> patches.
>>
>> 1. VIRTIO_READ_REG_X
>>
>> So far, VIRTIO_READ_REG_1/2/4 are defined in virtio_pci.h.
>> But these macros are only referred by virtio_pci.c.
>> How about moving the macros to virtio_pci.c?
>
> +1 for this.
>
>>
>> 2. Abstraction of read/write accesses.
>>
>> It may be difficult to cleanly rebase my patches on this patches,
>> because virtio_read_caps() is not abstracted.
>> Let me describe it more.
>> So far, we need to handle below 3 virtio-net devices..
>>   - physical virtio-net device.
>>   - virtual virtio-net device in virtio-net PMD. (Jianfeng's patch)
>>   - virtual virtio-net device in QEMU. (my patch)
>>
>> Almost all code of the virtio-net PMD can be shared between above
>> different cases.
>> Probably big difference is how to access to configuration space.
>>
>> Yuanhan's patch introduces an abstraction layer to hide configuration
>> space layout and how to access it.
>> Is it possible to separate?
>> I guess "access method" will be nice to be abstracted separately from
>> "configuration space layout".
>> Probably access method will be defined by "eth_dev->dev_type" and the
>> PMD name like "eth_cvio".
>> And "configuration space layout" will be defined by capability list of
>> PCI configuration layout.
>>
>> For example, if access method like below are abstracted separately and
>> current "virtio_pci.c" is implemented on this abstraction, we can easily
>> re-use virtio_read_caps().
>>   - how to read/write virtio configuration space.
>>   - how to mmap PCI configuration space.
>>   - how to read/(write) PCI configuration space.
>
>
> I basically agree with you. We have two dimensions here:
>
> legacy             modern
> physical virtio device:                     Use
> virtio_read_caps_phys() to distinguish
> virtual virtio device (Tetsuya):       Use virtio_read_caps_virt() to
> distinguish
> virtual virtio device (Jianfeng):    does not need a "configuration
> space layout", no need to distinguish
>
> So in vtpci_init(), we needs to test "eth_dev->dev_type" firstly
>
> vtpci_init() {
>     if (eth_dev->dev_type == RTE_ETH_DEV_PCI) {
>         if (virtio_read_caps_phys()) {
>             // modern
>         } else {
>             // legacy
>         }
>     } else {
>         if (Tetsuya's way) {
>             if (virtio_read_caps_virt()) {
>                 // modern
>             } else {
>                 // legacy
>             }
>         } else {
>             // Jianfeng's way
>         }
>     }
> }
>
> And from Yuanhan's angle, I think he does not need to address this
> problem. How do you think?

Yes, I agree he doesn't need.

Firstly, I have implemented like above, then I noticed that
virtio_read_caps_phy() and virtio_read_caps_virt() are same except for
access method.
Anyway, I guess abstracting access method is not so difficult.
If you are OK, I want to send RFC on Yuanhan's patch. Is it OK?

Thanks,
Tetsuya

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

* Re: [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver
  2016-01-14  6:09     ` Tan, Jianfeng
  2016-01-14  6:41       ` Tetsuya Mukawa
@ 2016-01-14  6:45       ` Yuanhan Liu
  1 sibling, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  6:45 UTC (permalink / raw)
  To: Tan, Jianfeng; +Cc: dev, Michael S. Tsirkin

On Thu, Jan 14, 2016 at 02:09:18PM +0800, Tan, Jianfeng wrote:
...
> I basically agree with you. We have two dimensions here:
> 
> legacy             modern
> physical virtio device:                     Use virtio_read_caps_phys() to
> distinguish
> virtual virtio device (Tetsuya):       Use virtio_read_caps_virt() to
> distinguish
> virtual virtio device (Jianfeng):    does not need a "configuration space
> layout", no need to distinguish

I guess you meant to build a form or something, but seems you failed :)

> 
> So in vtpci_init(), we needs to test "eth_dev->dev_type" firstly
> 
> vtpci_init() {
>     if (eth_dev->dev_type == RTE_ETH_DEV_PCI) {
>         if (virtio_read_caps_phys()) {
>             // modern
>         } else {
>             // legacy
>         }
>     } else {
>         if (Tetsuya's way) {
>             if (virtio_read_caps_virt()) {
>                 // modern
>             } else {
>                 // legacy
>             }
>         } else {
>             // Jianfeng's way
>         }
>     }
> }

Normally, I'd like to hide the details inside virtio_read_caps(): I don't
want similar codes to be appeared twice. And if it can be simply done
by "if (eth_dev->dev_type == ...)", I'd like to do it in this way. If not,
introducing another set of operation abstractions as suggested in my
another email might be a better option.

> And from Yuanhan's angle, I think he does not need to address this problem.

Yep; it just has nothing to do with this patch set.

	--yliu

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

* [dpdk-dev] [PATCH v3 0/8] virtio 1.0 enabling for virtio pmd driver
  2016-01-12  6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                     ` (8 preceding siblings ...)
  2016-01-14  4:27   ` Tetsuya Mukawa
@ 2016-01-14  7:42   ` Yuanhan Liu
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu
                       ` (7 more replies)
  2016-01-15  4:36   ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
  10 siblings, 8 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  7:42 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

v3: - export pci_unmap_device as well; and invoke it at virtio
      uninit stage.

    - fixed same data corruption bug reported by Qian in simple
      rxtx code path.

    - move VIRTIO_READ/WRITE_REG_X to virtio_pci.c

v2: - fix a data corruption reported by Qian, due to hdr size mismatch.
      check detailes at ptach 5.

    - Add missing config_irq and isr reading support from v1.

    - fix comments from v1.

Almost all difference comes from virtio 1.0 are the PCI layout change:
the major configuration structures are stored at bar space, and their
location is stored at corresponding pci cap structure. Reading/parsing
them is one of the major work of patch 7.

To make handling virtio v1.0 and v0.95 co-exist well, this patch set
introduces a virtio_pci_ops structure, to add another layer so that
we could keep those vtpci_foo_bar "APIs". With that, we could do the
minimum change to add virtio 1.0 support.


Rough test guide
================

Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add
option "disable-modern=false" to qemu virtio-net-pci device to enable
virtio 1.0 (which is disabled by default).

And if you see something like following from 'lspci -v', it means virtio
1.0 is indeed enabled:

    00:04.0 Ethernet controller: Red Hat, Inc Virtio network device
    Subsystem: Red Hat, Inc Device 0001
    Physical Slot: 4
    Flags: bus master, fast devsel, latency 0, IRQ 11
    I/O ports at c040 [size=64]
    Memory at febf1000 (32-bit, non-prefetchable) [size=4K]
    Memory at fe000000 (64-bit, prefetchable) [size=8M]
    Expansion ROM at feb80000 [disabled] [size=256K]
    Capabilities: [98] MSI-X: Enable+ Count=6 Masked-
==> Capabilities: [84] Vendor Specific Information: Len=14 <?>
==> Capabilities: [70] Vendor Specific Information: Len=14 <?>
==> Capabilities: [60] Vendor Specific Information: Len=10 <?>
==> Capabilities: [50] Vendor Specific Information: Len=10 <?>
==> Capabilities: [40] Vendor Specific Information: Len=10 <?>
    Kernel driver in use: virtio-pci
    Kernel modules: virtio_pci

After that, there wasn't anything speical comparing to the old virtio
0.95 pmd driver.


---
Yuanhan Liu (8):
  virtio: don't set vring address again at queue startup
  virtio: introduce struct virtio_pci_ops
  virtio: move left pci stuff to virtio_pci.c
  viritio: switch to 64 bit features
  virtio: retrieve hdr_size from hw->vtnet_hdr_size
  eal: pci: export pci_[un]map_device
  virtio: add 1.0 support
  virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c

 doc/guides/rel_notes/release_2_3.rst            |   3 +
 drivers/net/virtio/virtio_ethdev.c              | 302 +--------
 drivers/net/virtio/virtio_ethdev.h              |   3 +-
 drivers/net/virtio/virtio_pci.c                 | 787 +++++++++++++++++++++++-
 drivers/net/virtio/virtio_pci.h                 | 120 +++-
 drivers/net/virtio/virtio_rxtx.c                |  21 +-
 drivers/net/virtio/virtio_rxtx_simple.c         |  12 +-
 drivers/net/virtio/virtqueue.h                  |   4 +-
 lib/librte_eal/bsdapp/eal/eal_pci.c             |   4 +-
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   7 +
 lib/librte_eal/common/eal_common_pci.c          |   4 +-
 lib/librte_eal/common/eal_private.h             |  18 -
 lib/librte_eal/common/include/rte_pci.h         |  27 +
 lib/librte_eal/linuxapp/eal/eal_pci.c           |   4 +-
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   7 +
 15 files changed, 946 insertions(+), 377 deletions(-)

-- 
1.9.0

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

* [dpdk-dev] [PATCH v3 1/8] virtio: don't set vring address again at queue startup
  2016-01-14  7:42   ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu
@ 2016-01-14  7:42     ` Yuanhan Liu
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 2/8] virtio: introduce struct virtio_pci_ops Yuanhan Liu
                       ` (6 subsequent siblings)
  7 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  7:42 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

As we have already set up it at virtio_dev_queue_setup(), and a vq
restart will not reset the settings.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_rxtx.c | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index 74b39ef..b7267c0 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -339,11 +339,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type)
 		vq_update_avail_idx(vq);
 
 		PMD_INIT_LOG(DEBUG, "Allocated %d bufs", nbufs);
-
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 	} else if (queue_type == VTNET_TQ) {
 		if (use_simple_rxtx) {
 			int mid_idx  = vq->vq_nentries >> 1;
@@ -362,16 +357,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type)
 			for (i = mid_idx; i < vq->vq_nentries; i++)
 				vq->vq_ring.avail->ring[i] = i;
 		}
-
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
-	} else {
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 	}
 }
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH v3 2/8] virtio: introduce struct virtio_pci_ops
  2016-01-14  7:42   ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu
@ 2016-01-14  7:42     ` Yuanhan Liu
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 3/8] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
                       ` (5 subsequent siblings)
  7 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  7:42 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

Introduce struct virtio_pci_ops, to let legacy virtio (v0.95) and
modern virtio (1.0) have different implementation regarding to a
specific pci action, such as read host status.

With that, this patch reimplements all exported pci functions, in
a way like:

	vtpci_foo_bar(struct virtio_hw *hw)
	{
		hw->vtpci_ops->foo_bar(hw);
	}

So that we need pay attention to those pci related functions only
while adding virtio 1.0 support.

This patch introduced a new vtpci function, vtpci_init(), to do
proper virtio pci settings. It's pretty simple so far: just sets
hw->vtpci_ops to legacy_ops as we don't support 1.0 yet.

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

v2: extra whitespace line removing, and comment on "reading status
    after reset".

    rename the badly taken op name "set_irq" to "set_config_irq".
---
 drivers/net/virtio/virtio_ethdev.c |  22 ++----
 drivers/net/virtio/virtio_pci.c    | 158 ++++++++++++++++++++++++++++++-------
 drivers/net/virtio/virtio_pci.h    |  27 +++++++
 drivers/net/virtio/virtqueue.h     |   2 +-
 4 files changed, 166 insertions(+), 43 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index d928339..6c1d3a0 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -272,9 +272,7 @@ virtio_dev_queue_release(struct virtqueue *vq) {
 
 	if (vq) {
 		hw = vq->hw;
-		/* Select and deactivate the queue */
-		VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+		hw->vtpci_ops->del_queue(hw, vq);
 
 		rte_free(vq->sw_ring);
 		rte_free(vq);
@@ -295,15 +293,13 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
 	struct virtio_hw *hw = dev->data->dev_private;
 	struct virtqueue *vq = NULL;
 
-	/* Write the virtqueue index to the Queue Select Field */
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vtpci_queue_idx);
-	PMD_INIT_LOG(DEBUG, "selecting queue: %u", vtpci_queue_idx);
+	PMD_INIT_LOG(DEBUG, "setting up queue: %u", vtpci_queue_idx);
 
 	/*
 	 * Read the virtqueue size from the Queue Size field
 	 * Always power of 2 and if 0 virtqueue does not exist
 	 */
-	vq_size = VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
+	vq_size = hw->vtpci_ops->get_queue_num(hw, vtpci_queue_idx);
 	PMD_INIT_LOG(DEBUG, "vq_size: %u nb_desc:%u", vq_size, nb_desc);
 	if (vq_size == 0) {
 		PMD_INIT_LOG(ERR, "%s: virtqueue does not exist", __func__);
@@ -436,12 +432,8 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
 		memset(vq->virtio_net_hdr_mz->addr, 0, PAGE_SIZE);
 	}
 
-	/*
-	 * Set guest physical address of the virtqueue
-	 * in VIRTIO_PCI_QUEUE_PFN config register of device
-	 */
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
-			mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+	hw->vtpci_ops->setup_queue(hw, vq);
+
 	*pvq = vq;
 	return 0;
 }
@@ -950,7 +942,7 @@ virtio_negotiate_features(struct virtio_hw *hw)
 		hw->guest_features);
 
 	/* Read device(host) feature bits */
-	host_features = VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+	host_features = hw->vtpci_ops->get_features(hw);
 	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x",
 		host_features);
 
@@ -1287,6 +1279,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 
+	vtpci_init(pci_dev, hw);
+
 	if (virtio_resource_init(pci_dev) < 0)
 		return -1;
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 2245bec..9930efa 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -34,12 +34,11 @@
 
 #include "virtio_pci.h"
 #include "virtio_logs.h"
+#include "virtqueue.h"
 
-static uint8_t vtpci_get_status(struct virtio_hw *);
-
-void
-vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
-		void *dst, int length)
+static void
+legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset,
+		       void *dst, int length)
 {
 	uint64_t off;
 	uint8_t *d;
@@ -60,9 +59,9 @@ vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 	}
 }
 
-void
-vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
-		void *src, int length)
+static void
+legacy_write_dev_config(struct virtio_hw *hw, uint64_t offset,
+			void *src, int length)
 {
 	uint64_t off;
 	uint8_t *s;
@@ -83,30 +82,133 @@ vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
 	}
 }
 
+static uint32_t
+legacy_get_features(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+}
+
+static void
+legacy_set_features(struct virtio_hw *hw, uint32_t features)
+{
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
+}
+
+static uint8_t
+legacy_get_status(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
+}
+
+static void
+legacy_set_status(struct virtio_hw *hw, uint8_t status)
+{
+	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+}
+
+static void
+legacy_reset(struct virtio_hw *hw)
+{
+	legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+}
+
+static uint8_t
+legacy_get_isr(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+}
+
+/* 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);
+}
+
+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);
+}
+
+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);
+
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
+		vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+}
+
+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);
+
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+}
+
+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);
+}
+
+
+static const struct virtio_pci_ops legacy_ops = {
+	.read_dev_cfg	= legacy_read_dev_config,
+	.write_dev_cfg	= legacy_write_dev_config,
+	.reset		= legacy_reset,
+	.get_status	= legacy_get_status,
+	.set_status	= legacy_set_status,
+	.get_features	= legacy_get_features,
+	.set_features	= legacy_set_features,
+	.get_isr	= legacy_get_isr,
+	.set_config_irq	= legacy_set_config_irq,
+	.get_queue_num	= legacy_get_queue_num,
+	.setup_queue	= legacy_setup_queue,
+	.del_queue	= legacy_del_queue,
+	.notify_queue	= legacy_notify_queue,
+};
+
+
+void
+vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
+		      void *dst, int length)
+{
+	hw->vtpci_ops->read_dev_cfg(hw, offset, dst, length);
+}
+
+void
+vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
+		void *src, int length)
+{
+	hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
+}
+
 uint32_t
 vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
 {
 	uint32_t features;
+
 	/*
 	 * Limit negotiated features to what the driver, virtqueue, and
 	 * host all support.
 	 */
 	features = host_features & hw->guest_features;
+	hw->vtpci_ops->set_features(hw, features);
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
 	return features;
 }
 
-
 void
 vtpci_reset(struct virtio_hw *hw)
 {
-	/*
-	 * Setting the status to RESET sets the host device to
-	 * the original, uninitialized state.
-	 */
-	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
-	vtpci_get_status(hw);
+	hw->vtpci_ops->set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+	/* flush status write */
+	hw->vtpci_ops->get_status(hw);
 }
 
 void
@@ -115,26 +217,19 @@ vtpci_reinit_complete(struct virtio_hw *hw)
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK);
 }
 
-static uint8_t
-vtpci_get_status(struct virtio_hw *hw)
-{
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
-}
-
 void
 vtpci_set_status(struct virtio_hw *hw, uint8_t status)
 {
 	if (status != VIRTIO_CONFIG_STATUS_RESET)
-		status = (uint8_t)(status | vtpci_get_status(hw));
+		status |= hw->vtpci_ops->get_status(hw);
 
-	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+	hw->vtpci_ops->set_status(hw, status);
 }
 
 uint8_t
 vtpci_isr(struct virtio_hw *hw)
 {
-
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+	return hw->vtpci_ops->get_isr(hw);
 }
 
 
@@ -142,6 +237,13 @@ vtpci_isr(struct virtio_hw *hw)
 uint16_t
 vtpci_irq_config(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);
+	return hw->vtpci_ops->set_config_irq(hw, vec);
+}
+
+int
+vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw)
+{
+	hw->vtpci_ops = &legacy_ops;
+
+	return 0;
 }
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index 47f722a..ee7d265 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -163,6 +163,31 @@ struct virtqueue;
  */
 #define VIRTIO_MAX_VIRTQUEUES 8
 
+struct virtio_hw;
+
+struct virtio_pci_ops {
+	void (*read_dev_cfg)(struct virtio_hw *hw, uint64_t offset,
+			     void *dst, int len);
+	void (*write_dev_cfg)(struct virtio_hw *hw, uint64_t offset,
+			      void *src, int len);
+	void (*reset)(struct virtio_hw *hw);
+
+	uint8_t (*get_status)(struct virtio_hw *hw);
+	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
+
+	uint32_t (*get_features)(struct virtio_hw *hw);
+	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
+
+	uint8_t (*get_isr)(struct virtio_hw *hw);
+
+	uint16_t (*set_config_irq)(struct virtio_hw *hw, uint16_t vec);
+
+	uint16_t (*get_queue_num)(struct virtio_hw *hw, uint16_t queue_id);
+	void (*setup_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+	void (*del_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+	void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+};
+
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
@@ -174,6 +199,7 @@ struct virtio_hw {
 	uint8_t	    use_msix;
 	uint8_t     started;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
+	const struct virtio_pci_ops *vtpci_ops;
 };
 
 /*
@@ -253,6 +279,7 @@ vtpci_with_feature(struct virtio_hw *hw, uint32_t bit)
 /*
  * Function declaration from virtio_pci.c
  */
+int vtpci_init(struct rte_pci_device *, struct virtio_hw *);
 void vtpci_reset(struct virtio_hw *);
 
 void vtpci_reinit_complete(struct virtio_hw *);
diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h
index 61b3137..d7fb450 100644
--- a/drivers/net/virtio/virtqueue.h
+++ b/drivers/net/virtio/virtqueue.h
@@ -302,7 +302,7 @@ virtqueue_notify(struct virtqueue *vq)
 	 * For virtio on IA, the notificaiton is through io port operation
 	 * which is a serialization instruction itself.
 	 */
-	VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
+	vq->hw->vtpci_ops->notify_queue(vq->hw, vq);
 }
 
 #ifdef RTE_LIBRTE_VIRTIO_DEBUG_DUMP
-- 
1.9.0

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

* [dpdk-dev] [PATCH v3 3/8] virtio: move left pci stuff to virtio_pci.c
  2016-01-14  7:42   ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 2/8] virtio: introduce struct virtio_pci_ops Yuanhan Liu
@ 2016-01-14  7:42     ` Yuanhan Liu
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 4/8] viritio: switch to 64 bit features Yuanhan Liu
                       ` (4 subsequent siblings)
  7 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  7:42 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

virtio_pci.c is a more proper place for pci stuff; virtio_ethdev.c is not.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_ethdev.c | 265 +-----------------------------------
 drivers/net/virtio/virtio_pci.c    | 270 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 270 insertions(+), 265 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 6c1d3a0..b57224d 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -36,10 +36,6 @@
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
-#ifdef RTE_EXEC_ENV_LINUXAPP
-#include <dirent.h>
-#include <fcntl.h>
-#endif
 
 #include <rte_ethdev.h>
 #include <rte_memcpy.h>
@@ -955,260 +951,6 @@ virtio_negotiate_features(struct virtio_hw *hw)
 		hw->guest_features);
 }
 
-#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
-virtio_has_msix(const struct rte_pci_addr *loc)
-{
-	DIR *d;
-	char dirname[PATH_MAX];
-
-	snprintf(dirname, sizeof(dirname),
-		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
-		     loc->domain, loc->bus, loc->devid, loc->function);
-
-	d = opendir(dirname);
-	if (d)
-		closedir(d);
-
-	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 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
-virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
-{
-	/* nic_uio does not enable interrupts, return 0 (false). */
-	return 0;
-}
-
-static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
-{
-	/* no setup required */
-	return 0;
-}
-#endif
-
 /*
  * Process Virtio Config changed interrupt and call the callback
  * if link state changed.
@@ -1279,14 +1021,9 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 
-	vtpci_init(pci_dev, hw);
-
-	if (virtio_resource_init(pci_dev) < 0)
+	if (vtpci_init(pci_dev, hw) < 0)
 		return -1;
 
-	hw->use_msix = virtio_has_msix(&pci_dev->addr);
-	hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr;
-
 	/* Reset the device although not necessary at startup */
 	vtpci_reset(hw);
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 9930efa..03d623b 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -32,6 +32,11 @@
  */
 #include <stdint.h>
 
+#ifdef RTE_EXEC_ENV_LINUXAPP
+ #include <dirent.h>
+ #include <fcntl.h>
+#endif
+
 #include "virtio_pci.h"
 #include "virtio_logs.h"
 #include "virtqueue.h"
@@ -156,6 +161,264 @@ legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
 	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
 }
 
+#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;
+	char dirname[PATH_MAX];
+
+	snprintf(dirname, sizeof(dirname),
+		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
+		     loc->domain, loc->bus, loc->devid, loc->function);
+
+	d = opendir(dirname);
+	if (d)
+		closedir(d);
+
+	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
+legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
+{
+	/* nic_uio does not enable interrupts, return 0 (false). */
+	return 0;
+}
+
+static int
+legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
+{
+	/* no setup required */
+	return 0;
+}
+#endif
 
 static const struct virtio_pci_ops legacy_ops = {
 	.read_dev_cfg	= legacy_read_dev_config,
@@ -241,9 +504,14 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
 }
 
 int
-vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw)
+vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 {
 	hw->vtpci_ops = &legacy_ops;
 
+	if (legacy_virtio_resource_init(dev) < 0)
+		return -1;
+	hw->use_msix = legacy_virtio_has_msix(&dev->addr);
+	hw->io_base  = (uint32_t)(uintptr_t)dev->mem_resource[0].addr;
+
 	return 0;
 }
-- 
1.9.0

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

* [dpdk-dev] [PATCH v3 4/8] viritio: switch to 64 bit features
  2016-01-14  7:42   ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu
                       ` (2 preceding siblings ...)
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 3/8] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
@ 2016-01-14  7:42     ` Yuanhan Liu
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
                       ` (3 subsequent siblings)
  7 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  7:42 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

Switch to 64 bit features, that virtio 1.0 supports.

While legacy virtio only supports 32 bit features, here we complain
aloud and quit when trying to setting > 32 bit features for legacy
device.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_ethdev.c |  8 ++++----
 drivers/net/virtio/virtio_pci.c    | 15 ++++++++++-----
 drivers/net/virtio/virtio_pci.h    | 12 ++++++------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index b57224d..94e0c4a 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -930,16 +930,16 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 static void
 virtio_negotiate_features(struct virtio_hw *hw)
 {
-	uint32_t host_features;
+	uint64_t host_features;
 
 	/* Prepare guest_features: feature that driver wants to support */
 	hw->guest_features = VIRTIO_PMD_GUEST_FEATURES;
-	PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %"PRIx64,
 		hw->guest_features);
 
 	/* Read device(host) feature bits */
 	host_features = hw->vtpci_ops->get_features(hw);
-	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %"PRIx64,
 		host_features);
 
 	/*
@@ -947,7 +947,7 @@ virtio_negotiate_features(struct virtio_hw *hw)
 	 * guest feature bits.
 	 */
 	hw->guest_features = vtpci_negotiate_features(hw, host_features);
-	PMD_INIT_LOG(DEBUG, "features after negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,
 		hw->guest_features);
 }
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 03d623b..5eed57e 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -87,15 +87,20 @@ legacy_write_dev_config(struct virtio_hw *hw, uint64_t offset,
 	}
 }
 
-static uint32_t
+static uint64_t
 legacy_get_features(struct virtio_hw *hw)
 {
 	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
 }
 
 static void
-legacy_set_features(struct virtio_hw *hw, uint32_t features)
+legacy_set_features(struct virtio_hw *hw, uint64_t features)
 {
+	if ((features >> 32) != 0) {
+		PMD_DRV_LOG(ERR,
+			"only 32 bit features are allowed for legacy virtio!");
+		return;
+	}
 	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
 }
 
@@ -451,10 +456,10 @@ vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
 	hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
 }
 
-uint32_t
-vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
+uint64_t
+vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features)
 {
-	uint32_t features;
+	uint64_t features;
 
 	/*
 	 * Limit negotiated features to what the driver, virtqueue, and
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index ee7d265..3fd86f6 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -175,8 +175,8 @@ struct virtio_pci_ops {
 	uint8_t (*get_status)(struct virtio_hw *hw);
 	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
 
-	uint32_t (*get_features)(struct virtio_hw *hw);
-	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
+	uint64_t (*get_features)(struct virtio_hw *hw);
+	void     (*set_features)(struct virtio_hw *hw, uint64_t features);
 
 	uint8_t (*get_isr)(struct virtio_hw *hw);
 
@@ -191,7 +191,7 @@ struct virtio_pci_ops {
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
-	uint32_t    guest_features;
+	uint64_t    guest_features;
 	uint32_t    max_tx_queues;
 	uint32_t    max_rx_queues;
 	uint16_t    vtnet_hdr_size;
@@ -271,9 +271,9 @@ outl_p(unsigned int data, unsigned int port)
 	outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
 
 static inline int
-vtpci_with_feature(struct virtio_hw *hw, uint32_t bit)
+vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-	return (hw->guest_features & (1u << bit)) != 0;
+	return (hw->guest_features & (1ULL << bit)) != 0;
 }
 
 /*
@@ -286,7 +286,7 @@ void vtpci_reinit_complete(struct virtio_hw *);
 
 void vtpci_set_status(struct virtio_hw *, uint8_t);
 
-uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t);
+uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t);
 
 void vtpci_write_dev_config(struct virtio_hw *, uint64_t, void *, int);
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH v3 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size
  2016-01-14  7:42   ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu
                       ` (3 preceding siblings ...)
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 4/8] viritio: switch to 64 bit features Yuanhan Liu
@ 2016-01-14  7:42     ` Yuanhan Liu
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 6/8] eal: pci: export pci_[un]map_device Yuanhan Liu
                       ` (2 subsequent siblings)
  7 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  7:42 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

The mergeable virtio net hdr format has been the standard and the
only virtio net hdr format since virtio 1.0. Therefore, we can
not hardcode hdr_size to "sizeof(struct virtio_net_hdr)" any more
at virtio_recv_pkts(), otherwise, there would be a mismatch of
hdr size from rte_vhost_enqueue_burst() and virtio_recv_pkts(),
leading a packet corruption.

Instead, we should retrieve it from hw->vtnet_hdr_size; we will
do proper settings at eth_virtio_dev_init() in later patches.

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

v3: retrieve hdr_size from hw->vtnet_hdr_size for simple rxtx
    code path as well: it should not break anything, as simple
    rx and mergeable rx still will not co-exist.
---
 drivers/net/virtio/virtio_rxtx.c        |  6 ++++--
 drivers/net/virtio/virtio_rxtx_simple.c | 12 ++++++------
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index b7267c0..41a1366 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -560,7 +560,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 	struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
 	int error;
 	uint32_t i, nb_enqueued;
-	const uint32_t hdr_size = sizeof(struct virtio_net_hdr);
+	uint32_t hdr_size;
 
 	nb_used = VIRTQUEUE_NUSED(rxvq);
 
@@ -580,6 +580,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 	hw = rxvq->hw;
 	nb_rx = 0;
 	nb_enqueued = 0;
+	hdr_size = hw->vtnet_hdr_size;
 
 	for (i = 0; i < num ; i++) {
 		rxm = rcv_pkts[i];
@@ -664,7 +665,7 @@ virtio_recv_mergeable_pkts(void *rx_queue,
 	uint32_t seg_num;
 	uint16_t extra_idx;
 	uint32_t seg_res;
-	const uint32_t hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+	uint32_t hdr_size;
 
 	nb_used = VIRTQUEUE_NUSED(rxvq);
 
@@ -682,6 +683,7 @@ virtio_recv_mergeable_pkts(void *rx_queue,
 	seg_num = 0;
 	extra_idx = 0;
 	seg_res = 0;
+	hdr_size = hw->vtnet_hdr_size;
 
 	while (i < nb_used) {
 		struct virtio_net_hdr_mrg_rxbuf *header;
diff --git a/drivers/net/virtio/virtio_rxtx_simple.c b/drivers/net/virtio/virtio_rxtx_simple.c
index ff3c11a..3e66e8b 100644
--- a/drivers/net/virtio/virtio_rxtx_simple.c
+++ b/drivers/net/virtio/virtio_rxtx_simple.c
@@ -81,9 +81,9 @@ virtqueue_enqueue_recv_refill_simple(struct virtqueue *vq,
 
 	start_dp = vq->vq_ring.desc;
 	start_dp[desc_idx].addr = (uint64_t)((uintptr_t)cookie->buf_physaddr +
-		RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr));
+		RTE_PKTMBUF_HEADROOM - vq->hw->vtnet_hdr_size);
 	start_dp[desc_idx].len = cookie->buf_len -
-		RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr);
+		RTE_PKTMBUF_HEADROOM + vq->hw->vtnet_hdr_size;
 
 	vq->vq_free_cnt--;
 	vq->vq_avail_idx++;
@@ -120,9 +120,9 @@ virtio_rxq_rearm_vec(struct virtqueue *rxvq)
 
 		start_dp[i].addr =
 			(uint64_t)((uintptr_t)sw_ring[i]->buf_physaddr +
-			RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr));
+			RTE_PKTMBUF_HEADROOM - rxvq->hw->vtnet_hdr_size);
 		start_dp[i].len = sw_ring[i]->buf_len -
-			RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr);
+			RTE_PKTMBUF_HEADROOM + rxvq->hw->vtnet_hdr_size;
 	}
 
 	rxvq->vq_avail_idx += RTE_VIRTIO_VPMD_RX_REARM_THRESH;
@@ -175,8 +175,8 @@ virtio_recv_pkts_vec(void *rx_queue, struct rte_mbuf **rx_pkts,
 	len_adjust = _mm_set_epi16(
 		0, 0,
 		0,
-		(uint16_t) -sizeof(struct virtio_net_hdr),
-		0, (uint16_t) -sizeof(struct virtio_net_hdr),
+		(uint16_t) -rxvq->hw->vtnet_hdr_size,
+		0, (uint16_t) -rxvq->hw->vtnet_hdr_size,
 		0, 0);
 
 	if (unlikely(nb_pkts < RTE_VIRTIO_DESC_PER_LOOP))
-- 
1.9.0

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

* [dpdk-dev] [PATCH v3 6/8] eal: pci: export pci_[un]map_device
  2016-01-14  7:42   ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu
                       ` (4 preceding siblings ...)
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
@ 2016-01-14  7:42     ` Yuanhan Liu
  2016-01-14  7:45       ` Yuanhan Liu
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 7/8] virtio: add 1.0 support Yuanhan Liu
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
  7 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  7:42 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will
invoke pci_map_device internally for us. From that point view, there
is no need to export pci_map_device.

However, for virtio pmd driver, which is designed to work without
binding UIO (or something similar first), pci_map_device() will fail,
which ends up with virtio pmd driver being skipped. Therefore, we can
not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver.

Therefore, this patch exports pci_map_device, and let virtio pmd
call it when necessary.

Cc: David Marchand <david.marchand@6wind.com>
Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
v3: - export pci_unmap_device as well

    - Add few more comments about rte_eal_pci_map_device().
---
 lib/librte_eal/bsdapp/eal/eal_pci.c             |  4 ++--
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |  7 +++++++
 lib/librte_eal/common/eal_common_pci.c          |  4 ++--
 lib/librte_eal/common/eal_private.h             | 18 -----------------
 lib/librte_eal/common/include/rte_pci.h         | 27 +++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c           |  4 ++--
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |  7 +++++++
 7 files changed, 47 insertions(+), 24 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 6c21fbd..95c32c1 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -93,7 +93,7 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused)
 
 /* Map pci device */
 int
-pci_map_device(struct rte_pci_device *dev)
+rte_eal_pci_map_device(struct rte_pci_device *dev)
 {
 	int ret = -1;
 
@@ -115,7 +115,7 @@ pci_map_device(struct rte_pci_device *dev)
 
 /* Unmap pci device */
 void
-pci_unmap_device(struct rte_pci_device *dev)
+rte_eal_pci_unmap_device(struct rte_pci_device *dev)
 {
 	/* try unmapping the NIC resources */
 	switch (dev->kdrv) {
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 9d7adf1..1b28170 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -135,3 +135,10 @@ DPDK_2.2 {
 	rte_xen_dom0_supported;
 
 } DPDK_2.1;
+
+DPDK_2.3 {
+	global:
+
+	rte_eal_pci_map_device;
+	rte_eal_pci_unmap_device;
+} DPDK_2.2;
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index dcfe947..96d5113 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -188,7 +188,7 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 			pci_config_space_set(dev);
 #endif
 			/* map resources for devices that use igb_uio */
-			ret = pci_map_device(dev);
+			ret = rte_eal_pci_map_device(dev);
 			if (ret != 0)
 				return ret;
 		} else if (dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND &&
@@ -254,7 +254,7 @@ rte_eal_pci_detach_dev(struct rte_pci_driver *dr,
 
 		if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
 			/* unmap resources for devices that use igb_uio */
-			pci_unmap_device(dev);
+			rte_eal_pci_unmap_device(dev);
 
 		return 0;
 	}
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index 072e672..2342fa1 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -165,24 +165,6 @@ struct rte_pci_device;
 int pci_unbind_kernel_driver(struct rte_pci_device *dev);
 
 /**
- * Map this device
- *
- * This function is private to EAL.
- *
- * @return
- *   0 on success, negative on error and positive if no driver
- *   is found for the device.
- */
-int pci_map_device(struct rte_pci_device *dev);
-
-/**
- * Unmap this device
- *
- * This function is private to EAL.
- */
-void pci_unmap_device(struct rte_pci_device *dev);
-
-/**
  * Map the PCI resource of a PCI device in virtual memory
  *
  * This function is private to EAL.
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 334c12e..2224109 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -485,6 +485,33 @@ 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);
+/**
+ * Map the PCI device resources in user space virtual memory address
+ *
+ * Note that driver should not call this function when flag
+ * RTE_PCI_DRV_NEED_MAPPING is set, as EAL will do that for
+ * you when it's on.
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device
+ *   to use
+ *
+ * @return
+ *   0 on success, negative on error and positive if no driver
+ *   is found for the device.
+ */
+int rte_eal_pci_map_device(struct rte_pci_device *dev);
+
+/**
+ * Unmap this device
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device
+ *   to use
+ */
+void rte_eal_pci_unmap_device(struct rte_pci_device *dev);
+
+
 
 #ifdef RTE_PCI_CONFIG
 /**
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index bc5b5be..db947da 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -124,7 +124,7 @@ pci_get_kernel_driver_by_path(const char *filename, char *dri_name)
 
 /* Map pci device */
 int
-pci_map_device(struct rte_pci_device *dev)
+rte_eal_pci_map_device(struct rte_pci_device *dev)
 {
 	int ret = -1;
 
@@ -153,7 +153,7 @@ pci_map_device(struct rte_pci_device *dev)
 
 /* Unmap pci device */
 void
-pci_unmap_device(struct rte_pci_device *dev)
+rte_eal_pci_unmap_device(struct rte_pci_device *dev)
 {
 	/* try unmapping the NIC resources using VFIO if it exists */
 	switch (dev->kdrv) {
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index cbe175f..b9937c4 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -138,3 +138,10 @@ DPDK_2.2 {
 	rte_xen_dom0_supported;
 
 } DPDK_2.1;
+
+DPDK_2.3 {
+	global:
+
+	rte_eal_pci_map_device;
+	rte_eal_pci_unmap_device;
+} DPDK_2.2;
-- 
1.9.0

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

* [dpdk-dev] [PATCH v3 7/8] virtio: add 1.0 support
  2016-01-14  7:42   ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu
                       ` (5 preceding siblings ...)
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 6/8] eal: pci: export pci_[un]map_device Yuanhan Liu
@ 2016-01-14  7:42     ` Yuanhan Liu
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
  7 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  7:42 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

Modern (v1.0) virtio pci device defines several pci capabilities.
Each cap has a configure structure corresponding to it, and the
cap.bar and cap.offset fields tell us where to find it.

Firstly, we map the pci resources by rte_eal_pci_map_device().
We then could easily locate to a cfg structure by:

    cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset;

Therefore, the entrance of enabling modern (v1.0) pci device support
is to iterate the pci capability lists, and to locate some configs
we care; and they are:

- common cfg

  For generic virtio and virtuqueu configuration, such as setting/getting
  features, enabling a specific queue, and so on.

- nofity cfg

  Combining with `queue_notify_off' from common cfg, we could use it to
  notify a specific virt queue.

- device cfg

  Where virtio_net_config structure locates.

- isr cfg

  Where to read isr (interrupt status).

If any of above cap is not found, we fallback to the legacy virtio
handling.

If succeed, hw->vtpci_ops is assigned to modern_ops, where all
operations are implemented by reading/writing a (or few) specific
configuration space from above 4 cfg structures. And that's basically
how this patch works.

Besides those changes, virtio 1.0 introduces a new status field:
FEATURES_OK, which is set after features negotiation is done.

Last, set the VIRTIO_F_VERSION_1 feature flag.

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

v2: - re-read status after setting FEATURES_OK to make sure status is
      set correctly.

    - Add isr reading and config irq setting support.

    - Define some pci macro on our own to not get the dependency of
      linux/pci_regs.h, as there should be no such file at non-Linux
      platform

v3: - invoke rte_eal_pci_unmap_device() at uninit stage
---
 doc/guides/rel_notes/release_2_3.rst |   3 +
 drivers/net/virtio/virtio_ethdev.c   |  25 ++-
 drivers/net/virtio/virtio_ethdev.h   |   3 +-
 drivers/net/virtio/virtio_pci.c      | 335 ++++++++++++++++++++++++++++++++++-
 drivers/net/virtio/virtio_pci.h      |  67 +++++++
 drivers/net/virtio/virtqueue.h       |   2 +
 6 files changed, 430 insertions(+), 5 deletions(-)

diff --git a/doc/guides/rel_notes/release_2_3.rst b/doc/guides/rel_notes/release_2_3.rst
index 99de186..c390d97 100644
--- a/doc/guides/rel_notes/release_2_3.rst
+++ b/doc/guides/rel_notes/release_2_3.rst
@@ -4,6 +4,9 @@ DPDK Release 2.3
 New Features
 ------------
 
+* **Virtio 1.0 support.**
+
+  Enabled virtio 1.0 support for virtio pmd driver.
 
 Resolved Issues
 ---------------
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 94e0c4a..deb0382 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return virtio_send_command(hw->cvq, &ctrl, &len, 1);
 }
 
-static void
+static int
 virtio_negotiate_features(struct virtio_hw *hw)
 {
 	uint64_t host_features;
@@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw)
 	hw->guest_features = vtpci_negotiate_features(hw, host_features);
 	PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,
 		hw->guest_features);
+
+	if (hw->modern) {
+		if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) {
+			PMD_INIT_LOG(ERR,
+				"VIRTIO_F_VERSION_1 features is not enabled.");
+			return -1;
+		}
+		vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK);
+		if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) {
+			PMD_INIT_LOG(ERR,
+				"failed to set FEATURES_OK status!");
+			return -1;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -1032,7 +1048,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	/* Tell the host we've known how to drive the device. */
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
-	virtio_negotiate_features(hw);
+	if (virtio_negotiate_features(hw) < 0)
+		return -1;
 
 	/* If host does not support status then disable LSC */
 	if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS))
@@ -1043,7 +1060,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 	rx_func_get(eth_dev);
 
 	/* Setting up rx_header size for the device */
-	if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF))
+	if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) ||
+	    vtpci_with_feature(hw, VIRTIO_F_VERSION_1))
 		hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
 	else
 		hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr);
@@ -1159,6 +1177,7 @@ eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev)
 		rte_intr_callback_unregister(&pci_dev->intr_handle,
 						virtio_interrupt_handler,
 						eth_dev);
+	rte_eal_pci_unmap_device(pci_dev);
 
 	PMD_INIT_LOG(DEBUG, "dev_uninit completed");
 
diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h
index ae2d47d..fed9571 100644
--- a/drivers/net/virtio/virtio_ethdev.h
+++ b/drivers/net/virtio/virtio_ethdev.h
@@ -64,7 +64,8 @@
 	 1u << VIRTIO_NET_F_CTRL_VQ	  |	\
 	 1u << VIRTIO_NET_F_CTRL_RX	  |	\
 	 1u << VIRTIO_NET_F_CTRL_VLAN	  |	\
-	 1u << VIRTIO_NET_F_MRG_RXBUF)
+	 1u << VIRTIO_NET_F_MRG_RXBUF	  |	\
+	 1ULL << VIRTIO_F_VERSION_1)
 
 /*
  * CQ function prototype
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 5eed57e..9b62013 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -41,6 +41,14 @@
 #include "virtio_logs.h"
 #include "virtqueue.h"
 
+/*
+ * Following macros are derieved from linux/pci_regs.h, however,
+ * we can't simply include that header here, as there is no such
+ * file for non-Linux platform.
+ */
+#define PCI_CAPABILITY_LIST	0x34
+#define PCI_CAP_ID_VNDR		0x09
+
 static void
 legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 		       void *dst, int length)
@@ -442,6 +450,204 @@ static const struct virtio_pci_ops legacy_ops = {
 };
 
 
+#define MODERN_READ_DEF(nr_bits, type)		\
+static inline type				\
+modern_read##nr_bits(type *addr)		\
+{						\
+	return *(volatile type *)addr;		\
+}
+
+#define MODERN_WRITE_DEF(nr_bits, type)		\
+static inline void				\
+modern_write##nr_bits(type val, type *addr)	\
+{						\
+	*(volatile type *)addr = val;		\
+}
+
+MODERN_READ_DEF (8, uint8_t)
+MODERN_WRITE_DEF(8, uint8_t)
+
+MODERN_READ_DEF (16, uint16_t)
+MODERN_WRITE_DEF(16, uint16_t)
+
+MODERN_READ_DEF (32, uint32_t)
+MODERN_WRITE_DEF(32, uint32_t)
+
+static inline void
+modern_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
+{
+	modern_write32((uint32_t)val, lo);
+	modern_write32(val >> 32,     hi);
+}
+
+static void
+modern_read_dev_config(struct virtio_hw *hw, uint64_t offset,
+		       void *dst, int length)
+{
+	int i;
+	uint8_t *p;
+	uint8_t old_gen, new_gen;
+
+	do {
+		old_gen = modern_read8(&hw->common_cfg->config_generation);
+
+		p = dst;
+		for (i = 0;  i < length; i++)
+			*p++ = modern_read8((uint8_t *)hw->dev_cfg + offset + i);
+
+		new_gen = modern_read8(&hw->common_cfg->config_generation);
+	} while (old_gen != new_gen);
+}
+
+static void
+modern_write_dev_config(struct virtio_hw *hw, uint64_t offset,
+			void *src, int length)
+{
+	int i;
+	uint8_t *p = src;
+
+	for (i = 0;  i < length; i++)
+		modern_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i);
+}
+
+static uint64_t
+modern_get_features(struct virtio_hw *hw)
+{
+	uint32_t features_lo, features_hi;
+
+	modern_write32(0, &hw->common_cfg->device_feature_select);
+	features_lo = modern_read32(&hw->common_cfg->device_feature);
+
+	modern_write32(1, &hw->common_cfg->device_feature_select);
+	features_hi = modern_read32(&hw->common_cfg->device_feature);
+
+	return ((uint64_t)(features_hi) << 32) | features_lo;
+}
+
+static void
+modern_set_features(struct virtio_hw *hw, uint64_t features)
+{
+	modern_write32(0, &hw->common_cfg->guest_feature_select);
+	modern_write32(features & ((1ULL << 32) - 1),
+		&hw->common_cfg->guest_feature);
+
+	modern_write32(1, &hw->common_cfg->guest_feature_select);
+	modern_write32(features >> 32,
+		&hw->common_cfg->guest_feature);
+}
+
+static uint8_t
+modern_get_status(struct virtio_hw *hw)
+{
+	return modern_read8(&hw->common_cfg->device_status);
+}
+
+static void
+modern_set_status(struct virtio_hw *hw, uint8_t status)
+{
+	modern_write8(status, &hw->common_cfg->device_status);
+}
+
+static void
+modern_reset(struct virtio_hw *hw)
+{
+	modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+	modern_get_status(hw);
+}
+
+static uint8_t
+modern_get_isr(struct virtio_hw *hw)
+{
+	return modern_read8(hw->isr);
+}
+
+static uint16_t
+modern_set_config_irq(struct virtio_hw *hw, uint16_t vec)
+{
+	modern_write16(vec, &hw->common_cfg->msix_config);
+	return modern_read16(&hw->common_cfg->msix_config);
+}
+
+static uint16_t
+modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
+{
+	modern_write16(queue_id, &hw->common_cfg->queue_select);
+	return modern_read16(&hw->common_cfg->queue_size);
+}
+
+static void
+modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
+{
+	uint64_t desc_addr, avail_addr, used_addr;
+	uint16_t notify_off;
+
+	desc_addr = vq->mz->phys_addr;
+	avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
+	used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail,
+							 ring[vq->vq_nentries]),
+				   VIRTIO_PCI_VRING_ALIGN);
+
+	modern_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
+
+	modern_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo,
+					  &hw->common_cfg->queue_desc_hi);
+	modern_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo,
+					   &hw->common_cfg->queue_avail_hi);
+	modern_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo,
+					  &hw->common_cfg->queue_used_hi);
+
+	notify_off = modern_read16(&hw->common_cfg->queue_notify_off);
+	vq->notify_addr = (void *)((uint8_t *)hw->notify_base +
+				notify_off * hw->notify_off_multiplier);
+
+	modern_write16(1, &hw->common_cfg->queue_enable);
+
+	PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index);
+	PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr);
+	PMD_INIT_LOG(DEBUG, "\t aval_addr: %"PRIx64, avail_addr);
+	PMD_INIT_LOG(DEBUG, "\t used_addr: %"PRIx64, used_addr);
+	PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)",
+		vq->notify_addr, notify_off);
+}
+
+static void
+modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
+{
+	modern_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
+
+	modern_write64_twopart(0, &hw->common_cfg->queue_desc_lo,
+				  &hw->common_cfg->queue_desc_hi);
+	modern_write64_twopart(0, &hw->common_cfg->queue_avail_lo,
+				  &hw->common_cfg->queue_avail_hi);
+	modern_write64_twopart(0, &hw->common_cfg->queue_used_lo,
+				  &hw->common_cfg->queue_used_hi);
+
+	modern_write16(0, &hw->common_cfg->queue_enable);
+}
+
+static void
+modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
+{
+	modern_write16(1, vq->notify_addr);
+}
+
+static const struct virtio_pci_ops modern_ops = {
+	.read_dev_cfg	= modern_read_dev_config,
+	.write_dev_cfg	= modern_write_dev_config,
+	.reset		= modern_reset,
+	.get_status	= modern_get_status,
+	.set_status	= modern_set_status,
+	.get_features	= modern_get_features,
+	.set_features	= modern_set_features,
+	.get_isr	= modern_get_isr,
+	.set_config_irq	= modern_set_config_irq,
+	.get_queue_num	= modern_get_queue_num,
+	.setup_queue	= modern_setup_queue,
+	.del_queue	= modern_del_queue,
+	.notify_queue	= modern_notify_queue,
+};
+
+
 void
 vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 		      void *dst, int length)
@@ -495,6 +701,12 @@ vtpci_set_status(struct virtio_hw *hw, uint8_t status)
 }
 
 uint8_t
+vtpci_get_status(struct virtio_hw *hw)
+{
+	return hw->vtpci_ops->get_status(hw);
+}
+
+uint8_t
 vtpci_isr(struct virtio_hw *hw)
 {
 	return hw->vtpci_ops->get_isr(hw);
@@ -508,15 +720,136 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
 	return hw->vtpci_ops->set_config_irq(hw, vec);
 }
 
+static inline void *
+get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)
+{
+	uint8_t  bar    = cap->bar;
+	uint32_t length = cap->length;
+	uint32_t offset = cap->offset;
+	uint8_t *base;
+
+	if (unlikely(bar > 5)) {
+		PMD_INIT_LOG(ERR, "invalid bar: %u", bar);
+		return NULL;
+	}
+
+	if (unlikely(offset + length > dev->mem_resource[bar].len)) {
+		PMD_INIT_LOG(ERR,
+			"invalid cap: overflows bar space: %u > %"PRIu64,
+			offset + length, dev->mem_resource[bar].len);
+		return NULL;
+	}
+
+	base = dev->mem_resource[bar].addr;
+	if (unlikely(base == NULL)) {
+		PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar);
+		return NULL;
+	}
+
+	return base + offset;
+}
+
+static int
+virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
+{
+	uint8_t pos;
+	struct virtio_pci_cap cap;
+	int ret;
+
+	if (rte_eal_pci_map_device(dev) < 0) {
+		PMD_INIT_LOG(DEBUG, "failed to map pci device!");
+		return -1;
+	}
+
+	ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST);
+	if (ret < 0) {
+		PMD_INIT_LOG(DEBUG, "failed to read pci capability list");
+		return -1;
+	}
+
+	while (pos) {
+		ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos);
+		if (ret < 0) {
+			PMD_INIT_LOG(ERR,
+				"failed to read pci cap at pos: %x", pos);
+			break;
+		}
+
+		if (cap.cap_vndr != PCI_CAP_ID_VNDR) {
+			PMD_INIT_LOG(DEBUG,
+				"[%2x] skipping non VNDR cap id: %02x",
+				pos, cap.cap_vndr);
+			goto next;
+		}
+
+		PMD_INIT_LOG(DEBUG,
+			"[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u",
+			pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
+
+		switch (cap.cfg_type) {
+		case VIRTIO_PCI_CAP_COMMON_CFG:
+			hw->common_cfg = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_NOTIFY_CFG:
+			rte_eal_pci_read_config(dev, &hw->notify_off_multiplier,
+						4, pos + sizeof(cap));
+			hw->notify_base = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_DEVICE_CFG:
+			hw->dev_cfg = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_ISR_CFG:
+			hw->isr = get_cfg_addr(dev, &cap);
+			break;
+		}
+
+	next:
+		pos = cap.cap_next;
+	}
+
+	if (hw->common_cfg == NULL || hw->notify_base == NULL ||
+	    hw->dev_cfg == NULL    || hw->isr == NULL) {
+		PMD_INIT_LOG(INFO, "no modern virtio pci device found.");
+		return -1;
+	}
+
+	PMD_INIT_LOG(INFO, "found modern virtio pci device.");
+
+	PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg);
+	PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg);
+	PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr);
+	PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u",
+		hw->notify_base, hw->notify_off_multiplier);
+
+	return 0;
+}
+
 int
 vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 {
-	hw->vtpci_ops = &legacy_ops;
+	hw->dev = dev;
+
+	/*
+	 * Try if we can succeed reading virtio pci caps, which exists
+	 * only on modern pci device. If failed, we fallback to legacy
+	 * virtio handling.
+	 */
+	if (virtio_read_caps(dev, hw) == 0) {
+		PMD_INIT_LOG(INFO, "modern virtio pci detected.");
+		hw->vtpci_ops = &modern_ops;
+		hw->modern    = 1;
+		dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
+		return 0;
+	}
 
+	PMD_INIT_LOG(INFO, "trying with legacy virtio pci.");
 	if (legacy_virtio_resource_init(dev) < 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 3fd86f6..6ade642 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -93,6 +93,7 @@ struct virtqueue;
 #define VIRTIO_CONFIG_STATUS_ACK       0x01
 #define VIRTIO_CONFIG_STATUS_DRIVER    0x02
 #define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04
+#define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08
 #define VIRTIO_CONFIG_STATUS_FAILED    0x80
 
 /*
@@ -141,6 +142,8 @@ struct virtqueue;
 /* We support indirect buffer descriptors */
 #define VIRTIO_RING_F_INDIRECT_DESC	28
 
+#define VIRTIO_F_VERSION_1		32
+
 /*
  * Some VirtIO feature bits (currently bits 28 through 31) are
  * reserved for the transport being used (eg. virtio_ring), the
@@ -163,6 +166,60 @@ struct virtqueue;
  */
 #define VIRTIO_MAX_VIRTQUEUES 8
 
+/* Common configuration */
+#define VIRTIO_PCI_CAP_COMMON_CFG	1
+/* Notifications */
+#define VIRTIO_PCI_CAP_NOTIFY_CFG	2
+/* ISR Status */
+#define VIRTIO_PCI_CAP_ISR_CFG		3
+/* Device specific configuration */
+#define VIRTIO_PCI_CAP_DEVICE_CFG	4
+/* PCI configuration access */
+#define VIRTIO_PCI_CAP_PCI_CFG		5
+
+/* This is the PCI capability header: */
+struct virtio_pci_cap {
+	uint8_t cap_vndr;		/* Generic PCI field: PCI_CAP_ID_VNDR */
+	uint8_t cap_next;		/* Generic PCI field: next ptr. */
+	uint8_t cap_len;		/* Generic PCI field: capability length */
+	uint8_t cfg_type;		/* Identifies the structure. */
+	uint8_t bar;			/* Where to find it. */
+	uint8_t padding[3];		/* Pad to full dword. */
+	uint32_t offset;		/* Offset within bar. */
+	uint32_t length;		/* Length of the structure, in bytes. */
+};
+
+struct virtio_pci_notify_cap {
+	struct virtio_pci_cap cap;
+	uint32_t notify_off_multiplier;	/* Multiplier for queue_notify_off. */
+};
+
+/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */
+struct virtio_pci_common_cfg {
+	/* About the whole device. */
+	uint32_t device_feature_select;	/* read-write */
+	uint32_t device_feature;	/* read-only */
+	uint32_t guest_feature_select;	/* read-write */
+	uint32_t guest_feature;		/* read-write */
+	uint16_t msix_config;		/* read-write */
+	uint16_t num_queues;		/* read-only */
+	uint8_t device_status;		/* read-write */
+	uint8_t config_generation;	/* read-only */
+
+	/* About a specific virtqueue. */
+	uint16_t queue_select;		/* read-write */
+	uint16_t queue_size;		/* read-write, power of 2. */
+	uint16_t queue_msix_vector;	/* read-write */
+	uint16_t queue_enable;		/* read-write */
+	uint16_t queue_notify_off;	/* read-only */
+	uint32_t queue_desc_lo;		/* read-write */
+	uint32_t queue_desc_hi;		/* read-write */
+	uint32_t queue_avail_lo;	/* read-write */
+	uint32_t queue_avail_hi;	/* read-write */
+	uint32_t queue_used_lo;		/* read-write */
+	uint32_t queue_used_hi;		/* read-write */
+};
+
 struct virtio_hw;
 
 struct virtio_pci_ops {
@@ -188,6 +245,8 @@ struct virtio_pci_ops {
 	void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq);
 };
 
+struct virtio_net_config;
+
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
@@ -198,7 +257,14 @@ struct virtio_hw {
 	uint8_t	    vlan_strip;
 	uint8_t	    use_msix;
 	uint8_t     started;
+	uint8_t     modern;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
+	uint32_t    notify_off_multiplier;
+	uint8_t     *isr;
+	uint16_t    *notify_base;
+	struct rte_pci_device *dev;
+	struct virtio_pci_common_cfg *common_cfg;
+	struct virtio_net_config *dev_cfg;
 	const struct virtio_pci_ops *vtpci_ops;
 };
 
@@ -284,6 +350,7 @@ void vtpci_reset(struct virtio_hw *);
 
 void vtpci_reinit_complete(struct virtio_hw *);
 
+uint8_t vtpci_get_status(struct virtio_hw *);
 void vtpci_set_status(struct virtio_hw *, uint8_t);
 
 uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t);
diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h
index d7fb450..99d4fa9 100644
--- a/drivers/net/virtio/virtqueue.h
+++ b/drivers/net/virtio/virtqueue.h
@@ -202,6 +202,8 @@ struct virtqueue {
 	/* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */
 	uint64_t	size_bins[8];
 
+	uint16_t	*notify_addr;
+
 	struct vq_desc_extra {
 		void              *cookie;
 		uint16_t          ndescs;
-- 
1.9.0

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

* [dpdk-dev] [PATCH v3 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c
  2016-01-14  7:42   ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu
                       ` (6 preceding siblings ...)
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 7/8] virtio: add 1.0 support Yuanhan Liu
@ 2016-01-14  7:42     ` Yuanhan Liu
  2016-01-16 10:08       ` Santosh Shukla
  7 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  7:42 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

virtio_pci.c become the only file references those macros; move them there.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_pci.c | 19 +++++++++++++++++++
 drivers/net/virtio/virtio_pci.h | 18 ------------------
 2 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 9b62013..8e26f00 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -49,6 +49,25 @@
 #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))))
+
 static void
 legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 		       void *dst, int length)
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index 6ade642..5400ebd 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -318,24 +318,6 @@ outl_p(unsigned int data, unsigned int port)
 }
 #endif
 
-#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))))
-
 static inline int
 vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-- 
1.9.0

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

* Re: [dpdk-dev] [PATCH v3 6/8] eal: pci: export pci_[un]map_device
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 6/8] eal: pci: export pci_[un]map_device Yuanhan Liu
@ 2016-01-14  7:45       ` Yuanhan Liu
  0 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  7:45 UTC (permalink / raw)
  To: dev; +Cc: Michael S. Tsirkin

On Thu, Jan 14, 2016 at 03:42:50PM +0800, Yuanhan Liu wrote:
> Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will
> invoke pci_map_device internally for us. From that point view, there
> is no need to export pci_map_device.
> 
> However, for virtio pmd driver, which is designed to work without
> binding UIO (or something similar first), pci_map_device() will fail,
> which ends up with virtio pmd driver being skipped. Therefore, we can
> not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver.
> 
> Therefore, this patch exports pci_map_device, and let virtio pmd
> call it when necessary.
> 
> Cc: David Marchand <david.marchand@6wind.com>
> Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>

Oops, forgot to carry the tested-by from Santosh.

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


	--yliu

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

* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support
  2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support Yuanhan Liu
  2016-01-13  3:31     ` Tetsuya Mukawa
@ 2016-01-14  7:47     ` Xie, Huawei
  2016-01-14  7:50       ` Yuanhan Liu
  2016-01-14  7:50     ` Xie, Huawei
  2 siblings, 1 reply; 122+ messages in thread
From: Xie, Huawei @ 2016-01-14  7:47 UTC (permalink / raw)
  To: Yuanhan Liu, dev; +Cc: Michael S. Tsirkin

On 1/12/2016 2:58 PM, Yuanhan Liu wrote:
> Modern (v1.0) virtio pci device defines several pci capabilities.
[snip]
> +static void
> +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
> +{
> +	modern_write16(1, vq->notify_addr);
> +}

Does virtio 1.0 only supports MMIO? MMIO has long VMEXIT latency than
PORT IO.

[snip]

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

* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support
  2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support Yuanhan Liu
  2016-01-13  3:31     ` Tetsuya Mukawa
  2016-01-14  7:47     ` Xie, Huawei
@ 2016-01-14  7:50     ` Xie, Huawei
  2016-01-14  8:38       ` Yuanhan Liu
  2 siblings, 1 reply; 122+ messages in thread
From: Xie, Huawei @ 2016-01-14  7:50 UTC (permalink / raw)
  To: Yuanhan Liu, dev; +Cc: Michael S. Tsirkin

On 1/12/2016 2:58 PM, Yuanhan Liu wrote:
> Modern (v1.0) virtio pci device defines several pci capabilities.
> Each cap has a configure structure corresponding to it, and the
> cap.bar and cap.offset fields tell us where to find it.
>
> Firstly, we map the pci resources by rte_eal_pci_map_device().
> We then could easily locate to a cfg structure by:

s/Locate/Locate to/

>
>     cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset;
>
> Therefore, the entrance of enabling modern (v1.0) pci device support
> is to iterate the pci capability lists, and to locate some configs
> we care; and they are:
>
> - common cfg
>
>   For generic virtio and virtuqueu configuration, such as setting/getting

typo for virtqueue

>   features, enabling a specific queue, and so on.
>
> - nofity cfg
>
>   Combining with `queue_notify_off' from common cfg, we could use it to
>   notify a specific virt queue.
>
> - device cfg
>
>   Where virtio_net_config structure locates.
is located
> If any of above cap is not found, we fallback to the legacy virtio
>
[SNIP]
>  
>  
>  
> +#define MODERN_READ_DEF(nr_bits, type)		\
> +static inline type				\
> +modern_read##nr_bits(type *addr)		\
> +{						\
> +	return *(volatile type *)addr;		\
> +}
> +
> +#define MODERN_WRITE_DEF(nr_bits, type)		\
> +static inline void				\
> +modern_write##nr_bits(type val, type *addr)	\
> +{						\
> +	*(volatile type *)addr = val;		\
> +}
> +
> +MODERN_READ_DEF (8, uint8_t)
> +MODERN_WRITE_DEF(8, uint8_t)
> +
> +MODERN_READ_DEF (16, uint16_t)
> +MODERN_WRITE_DEF(16, uint16_t)
> +
> +MODERN_READ_DEF (32, uint32_t)
> +MODERN_WRITE_DEF(32, uint32_t)
> +
> +static inline void
> +modern_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
> +{
> +	modern_write32((uint32_t)val, lo);
> +	modern_write32(val >> 32,     hi);
> +}
> +

This is normal mmio read/write operation. ioread8/16/32/64 or just
readxx is more meaningful name here.
> +static void
[SNIP]
> +
> +static void
> +modern_write_dev_config(struct virtio_hw *hw, uint64_t offset,
> +			void *src, int length)

define src as const

[snip]
>  
> +static inline void *
> +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)

No explicit inline for non performance critical functions.

> +{
> +	uint8_t  bar    = cap->bar;
> +	uint32_t length = cap->length;
> +	uint32_t offset = cap->offset;
> +	uint8_t *base;
> +
> +	if (unlikely(bar > 5)) {
Don't use constant value number whenever possible

No likely/unlikely for non performance critical functions

> +		PMD_INIT_LOG(ERR, "invalid bar: %u", bar);
> +		return NULL;
> +	}
> +
> +	if (unlikely(offset + length > dev->mem_resource[bar].len)) {
> +		PMD_INIT_LOG(ERR,
> +			"invalid cap: overflows bar space: %u > %"PRIu64,
> +			offset + length, dev->mem_resource[bar].len);
> +		return NULL;
> +	}
> +
> +	base = dev->mem_resource[bar].addr;
> +	if (unlikely(base == NULL)) {
> +		PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar);
> +		return NULL;
> +	}
> +
> +	return base + offset;
> +}
> +
> +static int
> +virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
> +{
> +	uint8_t pos;
> +	struct virtio_pci_cap cap;
> +	int ret;
> +
> +	if (rte_eal_pci_map_device(dev) < 0) {
> +		PMD_INIT_LOG(DEBUG, "failed to map pci device!");

s /DEBUG/ERR/
> +		return -1;
> +	}
> +
> +	ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST);
> +	
[snip]


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

* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support
  2016-01-14  7:47     ` Xie, Huawei
@ 2016-01-14  7:50       ` Yuanhan Liu
  2016-01-14  7:51         ` Xie, Huawei
  0 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  7:50 UTC (permalink / raw)
  To: Xie, Huawei; +Cc: dev, Michael S. Tsirkin

On Thu, Jan 14, 2016 at 07:47:17AM +0000, Xie, Huawei wrote:
> On 1/12/2016 2:58 PM, Yuanhan Liu wrote:
> > Modern (v1.0) virtio pci device defines several pci capabilities.
> [snip]
> > +static void
> > +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
> > +{
> > +	modern_write16(1, vq->notify_addr);
> > +}
> 
> Does virtio 1.0 only supports MMIO? MMIO has long VMEXIT latency than
> PORT IO.

Virtio 1.0 supports three transport layer, including MMIO and PCI. And
we use PCI only in our pmd driver.

	--yliu

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

* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support
  2016-01-14  7:50       ` Yuanhan Liu
@ 2016-01-14  7:51         ` Xie, Huawei
  2016-01-14  7:58           ` Yuanhan Liu
  0 siblings, 1 reply; 122+ messages in thread
From: Xie, Huawei @ 2016-01-14  7:51 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev, Michael S. Tsirkin

On 1/14/2016 3:49 PM, Yuanhan Liu wrote:
> On Thu, Jan 14, 2016 at 07:47:17AM +0000, Xie, Huawei wrote:
>> On 1/12/2016 2:58 PM, Yuanhan Liu wrote:
>>> Modern (v1.0) virtio pci device defines several pci capabilities.
>> [snip]
>>> +static void
>>> +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
>>> +{
>>> +	modern_write16(1, vq->notify_addr);
>>> +}
>> Does virtio 1.0 only supports MMIO? MMIO has long VMEXIT latency than
>> PORT IO.
> Virtio 1.0 supports three transport layer, including MMIO and PCI. And
> we use PCI only in our pmd driver.

I don't mean that MMIO but use memory mapped IO for configuration.

>
> 	--yliu
>


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

* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support
  2016-01-14  7:51         ` Xie, Huawei
@ 2016-01-14  7:58           ` Yuanhan Liu
  2016-01-14  8:08             ` Xie, Huawei
  0 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  7:58 UTC (permalink / raw)
  To: Xie, Huawei; +Cc: dev, Michael S. Tsirkin

On Thu, Jan 14, 2016 at 07:51:08AM +0000, Xie, Huawei wrote:
> On 1/14/2016 3:49 PM, Yuanhan Liu wrote:
> > On Thu, Jan 14, 2016 at 07:47:17AM +0000, Xie, Huawei wrote:
> >> On 1/12/2016 2:58 PM, Yuanhan Liu wrote:
> >>> Modern (v1.0) virtio pci device defines several pci capabilities.
> >> [snip]
> >>> +static void
> >>> +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
> >>> +{
> >>> +	modern_write16(1, vq->notify_addr);
> >>> +}
> >> Does virtio 1.0 only supports MMIO? MMIO has long VMEXIT latency than
> >> PORT IO.
> > Virtio 1.0 supports three transport layer, including MMIO and PCI. And
> > we use PCI only in our pmd driver.
> 
> I don't mean that MMIO but use memory mapped IO for configuration.

Then, yes.

	--yliu

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

* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support
  2016-01-14  7:58           ` Yuanhan Liu
@ 2016-01-14  8:08             ` Xie, Huawei
  2016-01-14  8:22               ` Yuanhan Liu
  0 siblings, 1 reply; 122+ messages in thread
From: Xie, Huawei @ 2016-01-14  8:08 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev, Michael S. Tsirkin

On 1/14/2016 3:58 PM, Yuanhan Liu wrote:
> On Thu, Jan 14, 2016 at 07:51:08AM +0000, Xie, Huawei wrote:
>> On 1/14/2016 3:49 PM, Yuanhan Liu wrote:
>>> On Thu, Jan 14, 2016 at 07:47:17AM +0000, Xie, Huawei wrote:
>>>> On 1/12/2016 2:58 PM, Yuanhan Liu wrote:
>>>>> Modern (v1.0) virtio pci device defines several pci capabilities.
>>>> [snip]
>>>>> +static void
>>>>> +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
>>>>> +{
>>>>> +	modern_write16(1, vq->notify_addr);
>>>>> +}
>>>> Does virtio 1.0 only supports MMIO? MMIO has long VMEXIT latency than
>>>> PORT IO.
>>> Virtio 1.0 supports three transport layer, including MMIO and PCI. And
>>> we use PCI only in our pmd driver.
>> I don't mean that MMIO but use memory mapped IO for configuration.
> Then, yes.

00:03.0 Ethernet controller: Red Hat, Inc Virtio network device
        Subsystem: Red Hat, Inc Device 0001
        Physical Slot: 3
        Flags: bus master, fast devsel, latency 0, IRQ 10
        I/O ports at c100 [size=32]
        Memory at febd1000 (32-bit, non-prefetchable) [size=4K]
        Memory at fe000000 (64-bit, prefetchable) [size=8M]
        Expansion ROM at feb40000 [disabled] [size=256K]
        Capabilities: [98] MSI-X: Enable+ Count=3 Masked-
        Capabilities: [84] Vendor Specific Information: Len=14 <?>
        Capabilities: [70] Vendor Specific Information: Len=14 <?>
        Capabilities: [60] Vendor Specific Information: Len=10 <?>
        Capabilities: [50] Vendor Specific Information: Len=10 <?>
        Capabilities: [40] Vendor Specific Information: Len=10 <?>
        Kernel driver in use: igb_uio
        Kernel modules: virtio_pci

c100 is still there. For the notification, try PORT IO if possible.

>
> 	--yliu
>


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

* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support
  2016-01-14  8:08             ` Xie, Huawei
@ 2016-01-14  8:22               ` Yuanhan Liu
  2016-01-14  8:28                 ` Xie, Huawei
  0 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  8:22 UTC (permalink / raw)
  To: Xie, Huawei; +Cc: dev, Michael S. Tsirkin

On Thu, Jan 14, 2016 at 08:08:28AM +0000, Xie, Huawei wrote:
> On 1/14/2016 3:58 PM, Yuanhan Liu wrote:
> > On Thu, Jan 14, 2016 at 07:51:08AM +0000, Xie, Huawei wrote:
> >> On 1/14/2016 3:49 PM, Yuanhan Liu wrote:
> >>> On Thu, Jan 14, 2016 at 07:47:17AM +0000, Xie, Huawei wrote:
> >>>> On 1/12/2016 2:58 PM, Yuanhan Liu wrote:
> >>>>> Modern (v1.0) virtio pci device defines several pci capabilities.
> >>>> [snip]
> >>>>> +static void
> >>>>> +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
> >>>>> +{
> >>>>> +	modern_write16(1, vq->notify_addr);
> >>>>> +}
> >>>> Does virtio 1.0 only supports MMIO? MMIO has long VMEXIT latency than
> >>>> PORT IO.
> >>> Virtio 1.0 supports three transport layer, including MMIO and PCI. And
> >>> we use PCI only in our pmd driver.
> >> I don't mean that MMIO but use memory mapped IO for configuration.
> > Then, yes.
> 
> 00:03.0 Ethernet controller: Red Hat, Inc Virtio network device
>         Subsystem: Red Hat, Inc Device 0001
>         Physical Slot: 3
>         Flags: bus master, fast devsel, latency 0, IRQ 10
>         I/O ports at c100 [size=32]
>         Memory at febd1000 (32-bit, non-prefetchable) [size=4K]
>         Memory at fe000000 (64-bit, prefetchable) [size=8M]
>         Expansion ROM at feb40000 [disabled] [size=256K]
>         Capabilities: [98] MSI-X: Enable+ Count=3 Masked-
>         Capabilities: [84] Vendor Specific Information: Len=14 <?>
>         Capabilities: [70] Vendor Specific Information: Len=14 <?>
>         Capabilities: [60] Vendor Specific Information: Len=10 <?>
>         Capabilities: [50] Vendor Specific Information: Len=10 <?>
>         Capabilities: [40] Vendor Specific Information: Len=10 <?>
>         Kernel driver in use: igb_uio
>         Kernel modules: virtio_pci
> 
> c100 is still there.

Yes,

> For the notification, try PORT IO if possible.

But it doesn't seem right to me to mix legacy registers in modern pci device.

	--yliu

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

* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support
  2016-01-14  8:22               ` Yuanhan Liu
@ 2016-01-14  8:28                 ` Xie, Huawei
  0 siblings, 0 replies; 122+ messages in thread
From: Xie, Huawei @ 2016-01-14  8:28 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev, Michael S. Tsirkin

On 1/14/2016 4:21 PM, Yuanhan Liu wrote:
> On Thu, Jan 14, 2016 at 08:08:28AM +0000, Xie, Huawei wrote:
>> On 1/14/2016 3:58 PM, Yuanhan Liu wrote:
>>> On Thu, Jan 14, 2016 at 07:51:08AM +0000, Xie, Huawei wrote:
>>>> On 1/14/2016 3:49 PM, Yuanhan Liu wrote:
>>>>> On Thu, Jan 14, 2016 at 07:47:17AM +0000, Xie, Huawei wrote:
>>>>>> On 1/12/2016 2:58 PM, Yuanhan Liu wrote:
>>>>>>> Modern (v1.0) virtio pci device defines several pci capabilities.
>>>>>> [snip]
>>>>>>> +static void
>>>>>>> +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
>>>>>>> +{
>>>>>>> +	modern_write16(1, vq->notify_addr);
>>>>>>> +}
>>>>>> Does virtio 1.0 only supports MMIO? MMIO has long VMEXIT latency than
>>>>>> PORT IO.
>>>>> Virtio 1.0 supports three transport layer, including MMIO and PCI. And
>>>>> we use PCI only in our pmd driver.
>>>> I don't mean that MMIO but use memory mapped IO for configuration.
>>> Then, yes.
>> 00:03.0 Ethernet controller: Red Hat, Inc Virtio network device
>>         Subsystem: Red Hat, Inc Device 0001
>>         Physical Slot: 3
>>         Flags: bus master, fast devsel, latency 0, IRQ 10
>>         I/O ports at c100 [size=32]
>>         Memory at febd1000 (32-bit, non-prefetchable) [size=4K]
>>         Memory at fe000000 (64-bit, prefetchable) [size=8M]
>>         Expansion ROM at feb40000 [disabled] [size=256K]
>>         Capabilities: [98] MSI-X: Enable+ Count=3 Masked-
>>         Capabilities: [84] Vendor Specific Information: Len=14 <?>
>>         Capabilities: [70] Vendor Specific Information: Len=14 <?>
>>         Capabilities: [60] Vendor Specific Information: Len=10 <?>
>>         Capabilities: [50] Vendor Specific Information: Len=10 <?>
>>         Capabilities: [40] Vendor Specific Information: Len=10 <?>
>>         Kernel driver in use: igb_uio
>>         Kernel modules: virtio_pci
>>
>> c100 is still there.
> Yes,
>
>> For the notification, try PORT IO if possible.
> But it doesn't seem right to me to mix legacy registers in modern pci device.

On TLB and cache miss, this could cause plenty of cycles. Considering
that our current focus is dpdkvhost which doesn't need notification, let
us revisit this later.

>
> 	--yliu
>


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

* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support
  2016-01-14  7:50     ` Xie, Huawei
@ 2016-01-14  8:38       ` Yuanhan Liu
  0 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-14  8:38 UTC (permalink / raw)
  To: Xie, Huawei; +Cc: dev, Michael S. Tsirkin

Sigh... I have just send out v3 ...

On Thu, Jan 14, 2016 at 07:50:00AM +0000, Xie, Huawei wrote:
> On 1/12/2016 2:58 PM, Yuanhan Liu wrote:
> > +static inline void
> > +modern_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
> > +{
> > +	modern_write32((uint32_t)val, lo);
> > +	modern_write32(val >> 32,     hi);
> > +}
> > +
> 
> This is normal mmio read/write operation. ioread8/16/32/64 or just
> readxx is more meaningful name here.

I just want to make them looks like modern device related, which they
are.
 
> > +static void
> [SNIP]
> > +
> > +static void
> > +modern_write_dev_config(struct virtio_hw *hw, uint64_t offset,
> > +			void *src, int length)
> 
> define src as const

okay.

> 
> [snip]
> >  
> > +static inline void *
> > +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)
> 
> No explicit inline for non performance critical functions.

okay.

> 
> > +{
> > +	uint8_t  bar    = cap->bar;
> > +	uint32_t length = cap->length;
> > +	uint32_t offset = cap->offset;
> > +	uint8_t *base;
> > +
> > +	if (unlikely(bar > 5)) {
> Don't use constant value number whenever possible

I normally will not bother to define a macro for used once number,
espeically for some well known ones. Say, I won't define

	#define UINT8_MAX_VALUE	0xff
> 
> No likely/unlikely for non performance critical functions

makes sense.

> > +	if (rte_eal_pci_map_device(dev) < 0) {
> > +		PMD_INIT_LOG(DEBUG, "failed to map pci device!");
> 
> s /DEBUG/ERR/

It's not an error; it's expected, say, when no UIO is bond.

	--yliu

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

* [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver
  2016-01-12  6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                     ` (9 preceding siblings ...)
  2016-01-14  7:42   ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu
@ 2016-01-15  4:36   ` Yuanhan Liu
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu
                       ` (9 more replies)
  10 siblings, 10 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-15  4:36 UTC (permalink / raw)
  To: dev


v4: - mark "src" arg as const for write_dev_cfg operation

    - remove unnessary inline, and likely/unlikely

v3: - export pci_unmap_device as well; and invoke it at virtio
      uninit stage.

    - fixed same data corruption bug reported by Qian in simple
      rxtx code path.

    - move VIRTIO_READ/WRITE_REG_X to virtio_pci.c

v2: - fix a data corruption reported by Qian, due to hdr size mismatch.
      check detailes at ptach 5.

    - Add missing config_irq and isr reading support from v1.

    - fix comments from v1.

Almost all difference comes from virtio 1.0 are the PCI layout change:
the major configuration structures are stored at bar space, and their
location is stored at corresponding pci cap structure. Reading/parsing
them is one of the major work of patch 7.

To make handling virtio v1.0 and v0.95 co-exist well, this patch set
introduces a virtio_pci_ops structure, to add another layer so that
we could keep those vtpci_foo_bar "APIs". With that, we could do the
minimum change to add virtio 1.0 support.


Rough test guide
================

Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add
option "disable-modern=false" to qemu virtio-net-pci device to enable
virtio 1.0 (which is disabled by default).

And if you see something like following from 'lspci -v', it means virtio
1.0 is indeed enabled:

    00:04.0 Ethernet controller: Red Hat, Inc Virtio network device
    Subsystem: Red Hat, Inc Device 0001
    Physical Slot: 4
    Flags: bus master, fast devsel, latency 0, IRQ 11
    I/O ports at c040 [size=64]
    Memory at febf1000 (32-bit, non-prefetchable) [size=4K]
    Memory at fe000000 (64-bit, prefetchable) [size=8M]
    Expansion ROM at feb80000 [disabled] [size=256K]
    Capabilities: [98] MSI-X: Enable+ Count=6 Masked-
==> Capabilities: [84] Vendor Specific Information: Len=14 <?>
==> Capabilities: [70] Vendor Specific Information: Len=14 <?>
==> Capabilities: [60] Vendor Specific Information: Len=10 <?>
==> Capabilities: [50] Vendor Specific Information: Len=10 <?>
==> Capabilities: [40] Vendor Specific Information: Len=10 <?>
    Kernel driver in use: virtio-pci
    Kernel modules: virtio_pci

After that, there wasn't anything speical comparing to the old virtio
0.95 pmd driver.


---
Yuanhan Liu (8):
  virtio: don't set vring address again at queue startup
  virtio: introduce struct virtio_pci_ops
  virtio: move left pci stuff to virtio_pci.c
  viritio: switch to 64 bit features
  virtio: retrieve hdr_size from hw->vtnet_hdr_size
  eal: pci: export pci_[un]map_device
  virtio: add 1.0 support
  virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c

 doc/guides/rel_notes/release_2_3.rst            |   3 +
 drivers/net/virtio/virtio_ethdev.c              | 302 +--------
 drivers/net/virtio/virtio_ethdev.h              |   3 +-
 drivers/net/virtio/virtio_pci.c                 | 793 +++++++++++++++++++++++-
 drivers/net/virtio/virtio_pci.h                 | 120 +++-
 drivers/net/virtio/virtio_rxtx.c                |  21 +-
 drivers/net/virtio/virtio_rxtx_simple.c         |  12 +-
 drivers/net/virtio/virtqueue.h                  |   4 +-
 lib/librte_eal/bsdapp/eal/eal_pci.c             |   4 +-
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   7 +
 lib/librte_eal/common/eal_common_pci.c          |   4 +-
 lib/librte_eal/common/eal_private.h             |  18 -
 lib/librte_eal/common/include/rte_pci.h         |  27 +
 lib/librte_eal/linuxapp/eal/eal_pci.c           |   4 +-
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   7 +
 15 files changed, 949 insertions(+), 380 deletions(-)

-- 
1.9.0

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

* [dpdk-dev] [PATCH v4 1/8] virtio: don't set vring address again at queue startup
  2016-01-15  4:36   ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
@ 2016-01-15  4:36     ` Yuanhan Liu
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 2/8] virtio: introduce struct virtio_pci_ops Yuanhan Liu
                       ` (8 subsequent siblings)
  9 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-15  4:36 UTC (permalink / raw)
  To: dev

As we have already set up it at virtio_dev_queue_setup(), and a vq
restart will not reset the settings.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_rxtx.c | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index 74b39ef..b7267c0 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -339,11 +339,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type)
 		vq_update_avail_idx(vq);
 
 		PMD_INIT_LOG(DEBUG, "Allocated %d bufs", nbufs);
-
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 	} else if (queue_type == VTNET_TQ) {
 		if (use_simple_rxtx) {
 			int mid_idx  = vq->vq_nentries >> 1;
@@ -362,16 +357,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type)
 			for (i = mid_idx; i < vq->vq_nentries; i++)
 				vq->vq_ring.avail->ring[i] = i;
 		}
-
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
-	} else {
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 	}
 }
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH v4 2/8] virtio: introduce struct virtio_pci_ops
  2016-01-15  4:36   ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu
@ 2016-01-15  4:36     ` Yuanhan Liu
  2016-01-18 17:21       ` Xie, Huawei
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 3/8] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
                       ` (7 subsequent siblings)
  9 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-15  4:36 UTC (permalink / raw)
  To: dev

Introduce struct virtio_pci_ops, to let legacy virtio (v0.95) and
modern virtio (1.0) have different implementation regarding to a
specific pci action, such as read host status.

With that, this patch reimplements all exported pci functions, in
a way like:

	vtpci_foo_bar(struct virtio_hw *hw)
	{
		hw->vtpci_ops->foo_bar(hw);
	}

So that we need pay attention to those pci related functions only
while adding virtio 1.0 support.

This patch introduced a new vtpci function, vtpci_init(), to do
proper virtio pci settings. It's pretty simple so far: just sets
hw->vtpci_ops to legacy_ops as we don't support 1.0 yet.

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

v2: extra whitespace line removing, and comment on "reading status
    after reset".

    rename the badly taken op name "set_irq" to "set_config_irq".

v4: define "src" arg of write_dev_cfg opertion as const
---
 drivers/net/virtio/virtio_ethdev.c |  22 ++---
 drivers/net/virtio/virtio_pci.c    | 164 ++++++++++++++++++++++++++++++-------
 drivers/net/virtio/virtio_pci.h    |  27 ++++++
 drivers/net/virtio/virtqueue.h     |   2 +-
 4 files changed, 169 insertions(+), 46 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index d928339..6c1d3a0 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -272,9 +272,7 @@ virtio_dev_queue_release(struct virtqueue *vq) {
 
 	if (vq) {
 		hw = vq->hw;
-		/* Select and deactivate the queue */
-		VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+		hw->vtpci_ops->del_queue(hw, vq);
 
 		rte_free(vq->sw_ring);
 		rte_free(vq);
@@ -295,15 +293,13 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
 	struct virtio_hw *hw = dev->data->dev_private;
 	struct virtqueue *vq = NULL;
 
-	/* Write the virtqueue index to the Queue Select Field */
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vtpci_queue_idx);
-	PMD_INIT_LOG(DEBUG, "selecting queue: %u", vtpci_queue_idx);
+	PMD_INIT_LOG(DEBUG, "setting up queue: %u", vtpci_queue_idx);
 
 	/*
 	 * Read the virtqueue size from the Queue Size field
 	 * Always power of 2 and if 0 virtqueue does not exist
 	 */
-	vq_size = VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
+	vq_size = hw->vtpci_ops->get_queue_num(hw, vtpci_queue_idx);
 	PMD_INIT_LOG(DEBUG, "vq_size: %u nb_desc:%u", vq_size, nb_desc);
 	if (vq_size == 0) {
 		PMD_INIT_LOG(ERR, "%s: virtqueue does not exist", __func__);
@@ -436,12 +432,8 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
 		memset(vq->virtio_net_hdr_mz->addr, 0, PAGE_SIZE);
 	}
 
-	/*
-	 * Set guest physical address of the virtqueue
-	 * in VIRTIO_PCI_QUEUE_PFN config register of device
-	 */
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
-			mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+	hw->vtpci_ops->setup_queue(hw, vq);
+
 	*pvq = vq;
 	return 0;
 }
@@ -950,7 +942,7 @@ virtio_negotiate_features(struct virtio_hw *hw)
 		hw->guest_features);
 
 	/* Read device(host) feature bits */
-	host_features = VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+	host_features = hw->vtpci_ops->get_features(hw);
 	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x",
 		host_features);
 
@@ -1287,6 +1279,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 
+	vtpci_init(pci_dev, hw);
+
 	if (virtio_resource_init(pci_dev) < 0)
 		return -1;
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 2245bec..9907fd0 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -34,12 +34,11 @@
 
 #include "virtio_pci.h"
 #include "virtio_logs.h"
+#include "virtqueue.h"
 
-static uint8_t vtpci_get_status(struct virtio_hw *);
-
-void
-vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
-		void *dst, int length)
+static void
+legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset,
+		       void *dst, int length)
 {
 	uint64_t off;
 	uint8_t *d;
@@ -60,22 +59,22 @@ vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 	}
 }
 
-void
-vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
-		void *src, int length)
+static void
+legacy_write_dev_config(struct virtio_hw *hw, uint64_t offset,
+			const void *src, int length)
 {
 	uint64_t off;
-	uint8_t *s;
+	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, *(uint32_t *)s);
+			VIRTIO_WRITE_REG_4(hw, off, *(const uint32_t *)s);
 		} else if (length >= 2) {
 			size = 2;
-			VIRTIO_WRITE_REG_2(hw, off, *(uint16_t *)s);
+			VIRTIO_WRITE_REG_2(hw, off, *(const uint16_t *)s);
 		} else {
 			size = 1;
 			VIRTIO_WRITE_REG_1(hw, off, *s);
@@ -83,30 +82,133 @@ vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
 	}
 }
 
+static uint32_t
+legacy_get_features(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+}
+
+static void
+legacy_set_features(struct virtio_hw *hw, uint32_t features)
+{
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
+}
+
+static uint8_t
+legacy_get_status(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
+}
+
+static void
+legacy_set_status(struct virtio_hw *hw, uint8_t status)
+{
+	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+}
+
+static void
+legacy_reset(struct virtio_hw *hw)
+{
+	legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+}
+
+static uint8_t
+legacy_get_isr(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+}
+
+/* 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);
+}
+
+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);
+}
+
+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);
+
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
+		vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+}
+
+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);
+
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+}
+
+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);
+}
+
+
+static const struct virtio_pci_ops legacy_ops = {
+	.read_dev_cfg	= legacy_read_dev_config,
+	.write_dev_cfg	= legacy_write_dev_config,
+	.reset		= legacy_reset,
+	.get_status	= legacy_get_status,
+	.set_status	= legacy_set_status,
+	.get_features	= legacy_get_features,
+	.set_features	= legacy_set_features,
+	.get_isr	= legacy_get_isr,
+	.set_config_irq	= legacy_set_config_irq,
+	.get_queue_num	= legacy_get_queue_num,
+	.setup_queue	= legacy_setup_queue,
+	.del_queue	= legacy_del_queue,
+	.notify_queue	= legacy_notify_queue,
+};
+
+
+void
+vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
+		      void *dst, int length)
+{
+	hw->vtpci_ops->read_dev_cfg(hw, offset, dst, length);
+}
+
+void
+vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
+		void *src, int length)
+{
+	hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
+}
+
 uint32_t
 vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
 {
 	uint32_t features;
+
 	/*
 	 * Limit negotiated features to what the driver, virtqueue, and
 	 * host all support.
 	 */
 	features = host_features & hw->guest_features;
+	hw->vtpci_ops->set_features(hw, features);
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
 	return features;
 }
 
-
 void
 vtpci_reset(struct virtio_hw *hw)
 {
-	/*
-	 * Setting the status to RESET sets the host device to
-	 * the original, uninitialized state.
-	 */
-	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
-	vtpci_get_status(hw);
+	hw->vtpci_ops->set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+	/* flush status write */
+	hw->vtpci_ops->get_status(hw);
 }
 
 void
@@ -115,26 +217,19 @@ vtpci_reinit_complete(struct virtio_hw *hw)
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK);
 }
 
-static uint8_t
-vtpci_get_status(struct virtio_hw *hw)
-{
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
-}
-
 void
 vtpci_set_status(struct virtio_hw *hw, uint8_t status)
 {
 	if (status != VIRTIO_CONFIG_STATUS_RESET)
-		status = (uint8_t)(status | vtpci_get_status(hw));
+		status |= hw->vtpci_ops->get_status(hw);
 
-	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+	hw->vtpci_ops->set_status(hw, status);
 }
 
 uint8_t
 vtpci_isr(struct virtio_hw *hw)
 {
-
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+	return hw->vtpci_ops->get_isr(hw);
 }
 
 
@@ -142,6 +237,13 @@ vtpci_isr(struct virtio_hw *hw)
 uint16_t
 vtpci_irq_config(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);
+	return hw->vtpci_ops->set_config_irq(hw, vec);
+}
+
+int
+vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw)
+{
+	hw->vtpci_ops = &legacy_ops;
+
+	return 0;
 }
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index 47f722a..2064af0 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -163,6 +163,31 @@ struct virtqueue;
  */
 #define VIRTIO_MAX_VIRTQUEUES 8
 
+struct virtio_hw;
+
+struct virtio_pci_ops {
+	void (*read_dev_cfg)(struct virtio_hw *hw, uint64_t offset,
+			     void *dst, int len);
+	void (*write_dev_cfg)(struct virtio_hw *hw, uint64_t offset,
+			      const void *src, int len);
+	void (*reset)(struct virtio_hw *hw);
+
+	uint8_t (*get_status)(struct virtio_hw *hw);
+	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
+
+	uint32_t (*get_features)(struct virtio_hw *hw);
+	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
+
+	uint8_t (*get_isr)(struct virtio_hw *hw);
+
+	uint16_t (*set_config_irq)(struct virtio_hw *hw, uint16_t vec);
+
+	uint16_t (*get_queue_num)(struct virtio_hw *hw, uint16_t queue_id);
+	void (*setup_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+	void (*del_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+	void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+};
+
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
@@ -174,6 +199,7 @@ struct virtio_hw {
 	uint8_t	    use_msix;
 	uint8_t     started;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
+	const struct virtio_pci_ops *vtpci_ops;
 };
 
 /*
@@ -253,6 +279,7 @@ vtpci_with_feature(struct virtio_hw *hw, uint32_t bit)
 /*
  * Function declaration from virtio_pci.c
  */
+int vtpci_init(struct rte_pci_device *, struct virtio_hw *);
 void vtpci_reset(struct virtio_hw *);
 
 void vtpci_reinit_complete(struct virtio_hw *);
diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h
index 61b3137..d7fb450 100644
--- a/drivers/net/virtio/virtqueue.h
+++ b/drivers/net/virtio/virtqueue.h
@@ -302,7 +302,7 @@ virtqueue_notify(struct virtqueue *vq)
 	 * For virtio on IA, the notificaiton is through io port operation
 	 * which is a serialization instruction itself.
 	 */
-	VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
+	vq->hw->vtpci_ops->notify_queue(vq->hw, vq);
 }
 
 #ifdef RTE_LIBRTE_VIRTIO_DEBUG_DUMP
-- 
1.9.0

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

* [dpdk-dev] [PATCH v4 3/8] virtio: move left pci stuff to virtio_pci.c
  2016-01-15  4:36   ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 2/8] virtio: introduce struct virtio_pci_ops Yuanhan Liu
@ 2016-01-15  4:36     ` Yuanhan Liu
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 4/8] viritio: switch to 64 bit features Yuanhan Liu
                       ` (6 subsequent siblings)
  9 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-15  4:36 UTC (permalink / raw)
  To: dev

virtio_pci.c is a more proper place for pci stuff; virtio_ethdev is not.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_ethdev.c | 265 +-----------------------------------
 drivers/net/virtio/virtio_pci.c    | 270 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 270 insertions(+), 265 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 6c1d3a0..b57224d 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -36,10 +36,6 @@
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
-#ifdef RTE_EXEC_ENV_LINUXAPP
-#include <dirent.h>
-#include <fcntl.h>
-#endif
 
 #include <rte_ethdev.h>
 #include <rte_memcpy.h>
@@ -955,260 +951,6 @@ virtio_negotiate_features(struct virtio_hw *hw)
 		hw->guest_features);
 }
 
-#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
-virtio_has_msix(const struct rte_pci_addr *loc)
-{
-	DIR *d;
-	char dirname[PATH_MAX];
-
-	snprintf(dirname, sizeof(dirname),
-		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
-		     loc->domain, loc->bus, loc->devid, loc->function);
-
-	d = opendir(dirname);
-	if (d)
-		closedir(d);
-
-	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 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
-virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
-{
-	/* nic_uio does not enable interrupts, return 0 (false). */
-	return 0;
-}
-
-static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
-{
-	/* no setup required */
-	return 0;
-}
-#endif
-
 /*
  * Process Virtio Config changed interrupt and call the callback
  * if link state changed.
@@ -1279,14 +1021,9 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 
-	vtpci_init(pci_dev, hw);
-
-	if (virtio_resource_init(pci_dev) < 0)
+	if (vtpci_init(pci_dev, hw) < 0)
 		return -1;
 
-	hw->use_msix = virtio_has_msix(&pci_dev->addr);
-	hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr;
-
 	/* Reset the device although not necessary at startup */
 	vtpci_reset(hw);
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 9907fd0..95aa47d 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -32,6 +32,11 @@
  */
 #include <stdint.h>
 
+#ifdef RTE_EXEC_ENV_LINUXAPP
+ #include <dirent.h>
+ #include <fcntl.h>
+#endif
+
 #include "virtio_pci.h"
 #include "virtio_logs.h"
 #include "virtqueue.h"
@@ -156,6 +161,264 @@ legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
 	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
 }
 
+#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;
+	char dirname[PATH_MAX];
+
+	snprintf(dirname, sizeof(dirname),
+		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
+		     loc->domain, loc->bus, loc->devid, loc->function);
+
+	d = opendir(dirname);
+	if (d)
+		closedir(d);
+
+	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
+legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
+{
+	/* nic_uio does not enable interrupts, return 0 (false). */
+	return 0;
+}
+
+static int
+legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
+{
+	/* no setup required */
+	return 0;
+}
+#endif
 
 static const struct virtio_pci_ops legacy_ops = {
 	.read_dev_cfg	= legacy_read_dev_config,
@@ -241,9 +504,14 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
 }
 
 int
-vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw)
+vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 {
 	hw->vtpci_ops = &legacy_ops;
 
+	if (legacy_virtio_resource_init(dev) < 0)
+		return -1;
+	hw->use_msix = legacy_virtio_has_msix(&dev->addr);
+	hw->io_base  = (uint32_t)(uintptr_t)dev->mem_resource[0].addr;
+
 	return 0;
 }
-- 
1.9.0

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

* [dpdk-dev] [PATCH v4 4/8] viritio: switch to 64 bit features
  2016-01-15  4:36   ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                       ` (2 preceding siblings ...)
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 3/8] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
@ 2016-01-15  4:36     ` Yuanhan Liu
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
                       ` (5 subsequent siblings)
  9 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-15  4:36 UTC (permalink / raw)
  To: dev

Switch to 64 bit features, which virtio 1.0 supports.

While legacy virtio only supports 32 bit features, it complains aloud
and quit when trying to setting > 32 bit features.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_ethdev.c |  8 ++++----
 drivers/net/virtio/virtio_pci.c    | 15 ++++++++++-----
 drivers/net/virtio/virtio_pci.h    | 12 ++++++------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index b57224d..94e0c4a 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -930,16 +930,16 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 static void
 virtio_negotiate_features(struct virtio_hw *hw)
 {
-	uint32_t host_features;
+	uint64_t host_features;
 
 	/* Prepare guest_features: feature that driver wants to support */
 	hw->guest_features = VIRTIO_PMD_GUEST_FEATURES;
-	PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %"PRIx64,
 		hw->guest_features);
 
 	/* Read device(host) feature bits */
 	host_features = hw->vtpci_ops->get_features(hw);
-	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %"PRIx64,
 		host_features);
 
 	/*
@@ -947,7 +947,7 @@ virtio_negotiate_features(struct virtio_hw *hw)
 	 * guest feature bits.
 	 */
 	hw->guest_features = vtpci_negotiate_features(hw, host_features);
-	PMD_INIT_LOG(DEBUG, "features after negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,
 		hw->guest_features);
 }
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 95aa47d..a903316 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -87,15 +87,20 @@ legacy_write_dev_config(struct virtio_hw *hw, uint64_t offset,
 	}
 }
 
-static uint32_t
+static uint64_t
 legacy_get_features(struct virtio_hw *hw)
 {
 	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
 }
 
 static void
-legacy_set_features(struct virtio_hw *hw, uint32_t features)
+legacy_set_features(struct virtio_hw *hw, uint64_t features)
 {
+	if ((features >> 32) != 0) {
+		PMD_DRV_LOG(ERR,
+			"only 32 bit features are allowed for legacy virtio!");
+		return;
+	}
 	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
 }
 
@@ -451,10 +456,10 @@ vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
 	hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
 }
 
-uint32_t
-vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
+uint64_t
+vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features)
 {
-	uint32_t features;
+	uint64_t features;
 
 	/*
 	 * Limit negotiated features to what the driver, virtqueue, and
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index 2064af0..17312f6 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -175,8 +175,8 @@ struct virtio_pci_ops {
 	uint8_t (*get_status)(struct virtio_hw *hw);
 	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
 
-	uint32_t (*get_features)(struct virtio_hw *hw);
-	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
+	uint64_t (*get_features)(struct virtio_hw *hw);
+	void     (*set_features)(struct virtio_hw *hw, uint64_t features);
 
 	uint8_t (*get_isr)(struct virtio_hw *hw);
 
@@ -191,7 +191,7 @@ struct virtio_pci_ops {
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
-	uint32_t    guest_features;
+	uint64_t    guest_features;
 	uint32_t    max_tx_queues;
 	uint32_t    max_rx_queues;
 	uint16_t    vtnet_hdr_size;
@@ -271,9 +271,9 @@ outl_p(unsigned int data, unsigned int port)
 	outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
 
 static inline int
-vtpci_with_feature(struct virtio_hw *hw, uint32_t bit)
+vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-	return (hw->guest_features & (1u << bit)) != 0;
+	return (hw->guest_features & (1ULL << bit)) != 0;
 }
 
 /*
@@ -286,7 +286,7 @@ void vtpci_reinit_complete(struct virtio_hw *);
 
 void vtpci_set_status(struct virtio_hw *, uint8_t);
 
-uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t);
+uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t);
 
 void vtpci_write_dev_config(struct virtio_hw *, uint64_t, void *, int);
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH v4 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size
  2016-01-15  4:36   ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                       ` (3 preceding siblings ...)
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 4/8] viritio: switch to 64 bit features Yuanhan Liu
@ 2016-01-15  4:36     ` Yuanhan Liu
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 6/8] eal: pci: export pci_[un]map_device Yuanhan Liu
                       ` (4 subsequent siblings)
  9 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-15  4:36 UTC (permalink / raw)
  To: dev

The mergeable virtio net hdr format has been the standard and the
only virtio net hdr format since virtio 1.0. Therefore, we can
not hardcode hdr_size to "sizeof(struct virtio_net_hdr)" any more
at virtio_recv_pkts(), otherwise, there would be a mismatch of
hdr size from rte_vhost_enqueue_burst() and virtio_recv_pkts(),
leading a packet corruption.

Instead, we should retrieve it from hw->vtnet_hdr_size; we will
do proper settings at eth_virtio_dev_init() in later patches.

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

v3: retrieve hdr_size from hw->vtnet_hdr_size for simple rxtx
    code path as well: it should not break anything, as simple
    rx and mergeable rx still will not co-exist.
---
 drivers/net/virtio/virtio_rxtx.c        |  6 ++++--
 drivers/net/virtio/virtio_rxtx_simple.c | 12 ++++++------
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index b7267c0..41a1366 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -560,7 +560,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 	struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
 	int error;
 	uint32_t i, nb_enqueued;
-	const uint32_t hdr_size = sizeof(struct virtio_net_hdr);
+	uint32_t hdr_size;
 
 	nb_used = VIRTQUEUE_NUSED(rxvq);
 
@@ -580,6 +580,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 	hw = rxvq->hw;
 	nb_rx = 0;
 	nb_enqueued = 0;
+	hdr_size = hw->vtnet_hdr_size;
 
 	for (i = 0; i < num ; i++) {
 		rxm = rcv_pkts[i];
@@ -664,7 +665,7 @@ virtio_recv_mergeable_pkts(void *rx_queue,
 	uint32_t seg_num;
 	uint16_t extra_idx;
 	uint32_t seg_res;
-	const uint32_t hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+	uint32_t hdr_size;
 
 	nb_used = VIRTQUEUE_NUSED(rxvq);
 
@@ -682,6 +683,7 @@ virtio_recv_mergeable_pkts(void *rx_queue,
 	seg_num = 0;
 	extra_idx = 0;
 	seg_res = 0;
+	hdr_size = hw->vtnet_hdr_size;
 
 	while (i < nb_used) {
 		struct virtio_net_hdr_mrg_rxbuf *header;
diff --git a/drivers/net/virtio/virtio_rxtx_simple.c b/drivers/net/virtio/virtio_rxtx_simple.c
index ff3c11a..3e66e8b 100644
--- a/drivers/net/virtio/virtio_rxtx_simple.c
+++ b/drivers/net/virtio/virtio_rxtx_simple.c
@@ -81,9 +81,9 @@ virtqueue_enqueue_recv_refill_simple(struct virtqueue *vq,
 
 	start_dp = vq->vq_ring.desc;
 	start_dp[desc_idx].addr = (uint64_t)((uintptr_t)cookie->buf_physaddr +
-		RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr));
+		RTE_PKTMBUF_HEADROOM - vq->hw->vtnet_hdr_size);
 	start_dp[desc_idx].len = cookie->buf_len -
-		RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr);
+		RTE_PKTMBUF_HEADROOM + vq->hw->vtnet_hdr_size;
 
 	vq->vq_free_cnt--;
 	vq->vq_avail_idx++;
@@ -120,9 +120,9 @@ virtio_rxq_rearm_vec(struct virtqueue *rxvq)
 
 		start_dp[i].addr =
 			(uint64_t)((uintptr_t)sw_ring[i]->buf_physaddr +
-			RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr));
+			RTE_PKTMBUF_HEADROOM - rxvq->hw->vtnet_hdr_size);
 		start_dp[i].len = sw_ring[i]->buf_len -
-			RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr);
+			RTE_PKTMBUF_HEADROOM + rxvq->hw->vtnet_hdr_size;
 	}
 
 	rxvq->vq_avail_idx += RTE_VIRTIO_VPMD_RX_REARM_THRESH;
@@ -175,8 +175,8 @@ virtio_recv_pkts_vec(void *rx_queue, struct rte_mbuf **rx_pkts,
 	len_adjust = _mm_set_epi16(
 		0, 0,
 		0,
-		(uint16_t) -sizeof(struct virtio_net_hdr),
-		0, (uint16_t) -sizeof(struct virtio_net_hdr),
+		(uint16_t) -rxvq->hw->vtnet_hdr_size,
+		0, (uint16_t) -rxvq->hw->vtnet_hdr_size,
 		0, 0);
 
 	if (unlikely(nb_pkts < RTE_VIRTIO_DESC_PER_LOOP))
-- 
1.9.0

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

* [dpdk-dev] [PATCH v4 6/8] eal: pci: export pci_[un]map_device
  2016-01-15  4:36   ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                       ` (4 preceding siblings ...)
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
@ 2016-01-15  4:36     ` Yuanhan Liu
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support Yuanhan Liu
                       ` (3 subsequent siblings)
  9 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-15  4:36 UTC (permalink / raw)
  To: dev

Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will
invoke pci_map_device internally for us. From that point view, there
is no need to export pci_map_device.

However, for virtio pmd driver, which is designed to work without
binding UIO (or something similar first), pci_map_device() will fail,
which ends up with virtio pmd driver being skipped. Therefore, we can
not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver.

Therefore, this patch exports pci_map_device, and let virtio pmd
call it when necessary.

Cc: David Marchand <david.marchand@6wind.com>
Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-By: Santosh Shukla <sshukla@mvista.com>
---
v3: - export pci_unmap_device as well

    - Add few more comments about rte_eal_pci_map_device().
---
 lib/librte_eal/bsdapp/eal/eal_pci.c             |  4 ++--
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |  7 +++++++
 lib/librte_eal/common/eal_common_pci.c          |  4 ++--
 lib/librte_eal/common/eal_private.h             | 18 -----------------
 lib/librte_eal/common/include/rte_pci.h         | 27 +++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c           |  4 ++--
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |  7 +++++++
 7 files changed, 47 insertions(+), 24 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 6c21fbd..95c32c1 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -93,7 +93,7 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused)
 
 /* Map pci device */
 int
-pci_map_device(struct rte_pci_device *dev)
+rte_eal_pci_map_device(struct rte_pci_device *dev)
 {
 	int ret = -1;
 
@@ -115,7 +115,7 @@ pci_map_device(struct rte_pci_device *dev)
 
 /* Unmap pci device */
 void
-pci_unmap_device(struct rte_pci_device *dev)
+rte_eal_pci_unmap_device(struct rte_pci_device *dev)
 {
 	/* try unmapping the NIC resources */
 	switch (dev->kdrv) {
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 9d7adf1..1b28170 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -135,3 +135,10 @@ DPDK_2.2 {
 	rte_xen_dom0_supported;
 
 } DPDK_2.1;
+
+DPDK_2.3 {
+	global:
+
+	rte_eal_pci_map_device;
+	rte_eal_pci_unmap_device;
+} DPDK_2.2;
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index dcfe947..96d5113 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -188,7 +188,7 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 			pci_config_space_set(dev);
 #endif
 			/* map resources for devices that use igb_uio */
-			ret = pci_map_device(dev);
+			ret = rte_eal_pci_map_device(dev);
 			if (ret != 0)
 				return ret;
 		} else if (dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND &&
@@ -254,7 +254,7 @@ rte_eal_pci_detach_dev(struct rte_pci_driver *dr,
 
 		if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
 			/* unmap resources for devices that use igb_uio */
-			pci_unmap_device(dev);
+			rte_eal_pci_unmap_device(dev);
 
 		return 0;
 	}
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index 072e672..2342fa1 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -165,24 +165,6 @@ struct rte_pci_device;
 int pci_unbind_kernel_driver(struct rte_pci_device *dev);
 
 /**
- * Map this device
- *
- * This function is private to EAL.
- *
- * @return
- *   0 on success, negative on error and positive if no driver
- *   is found for the device.
- */
-int pci_map_device(struct rte_pci_device *dev);
-
-/**
- * Unmap this device
- *
- * This function is private to EAL.
- */
-void pci_unmap_device(struct rte_pci_device *dev);
-
-/**
  * Map the PCI resource of a PCI device in virtual memory
  *
  * This function is private to EAL.
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 334c12e..2224109 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -485,6 +485,33 @@ 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);
+/**
+ * Map the PCI device resources in user space virtual memory address
+ *
+ * Note that driver should not call this function when flag
+ * RTE_PCI_DRV_NEED_MAPPING is set, as EAL will do that for
+ * you when it's on.
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device
+ *   to use
+ *
+ * @return
+ *   0 on success, negative on error and positive if no driver
+ *   is found for the device.
+ */
+int rte_eal_pci_map_device(struct rte_pci_device *dev);
+
+/**
+ * Unmap this device
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device
+ *   to use
+ */
+void rte_eal_pci_unmap_device(struct rte_pci_device *dev);
+
+
 
 #ifdef RTE_PCI_CONFIG
 /**
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index bc5b5be..db947da 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -124,7 +124,7 @@ pci_get_kernel_driver_by_path(const char *filename, char *dri_name)
 
 /* Map pci device */
 int
-pci_map_device(struct rte_pci_device *dev)
+rte_eal_pci_map_device(struct rte_pci_device *dev)
 {
 	int ret = -1;
 
@@ -153,7 +153,7 @@ pci_map_device(struct rte_pci_device *dev)
 
 /* Unmap pci device */
 void
-pci_unmap_device(struct rte_pci_device *dev)
+rte_eal_pci_unmap_device(struct rte_pci_device *dev)
 {
 	/* try unmapping the NIC resources using VFIO if it exists */
 	switch (dev->kdrv) {
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index cbe175f..b9937c4 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -138,3 +138,10 @@ DPDK_2.2 {
 	rte_xen_dom0_supported;
 
 } DPDK_2.1;
+
+DPDK_2.3 {
+	global:
+
+	rte_eal_pci_map_device;
+	rte_eal_pci_unmap_device;
+} DPDK_2.2;
-- 
1.9.0

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

* [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support
  2016-01-15  4:36   ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                       ` (5 preceding siblings ...)
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 6/8] eal: pci: export pci_[un]map_device Yuanhan Liu
@ 2016-01-15  4:36     ` Yuanhan Liu
  2016-01-18 16:38       ` Xie, Huawei
                         ` (2 more replies)
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
                       ` (2 subsequent siblings)
  9 siblings, 3 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-15  4:36 UTC (permalink / raw)
  To: dev

Modern (v1.0) virtio pci device defines several pci capabilities.
Each cap has a configure structure corresponding to it, and the
cap.bar and cap.offset fields tell us where to find it.

Firstly, we map the pci resources by rte_eal_pci_map_device().
We then could easily locate a cfg structure by:

    cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset;

Therefore, the entrance of enabling modern (v1.0) pci device support
is to iterate the pci capability lists, and to locate some configs
we care; and they are:

- common cfg

  For generic virtio and virtqueue configuration, such as setting/getting
  features, enabling a specific queue, and so on.

- nofity cfg

  Combining with `queue_notify_off' from common cfg, we could use it to
  notify a specific virt queue.

- device cfg

  Where virtio_net_config structure is located.

- isr cfg

  Where to read isr (interrupt status).

If any of above cap is not found, we fallback to the legacy virtio
handling.

If succeed, hw->vtpci_ops is assigned to modern_ops, where all
operations are implemented by reading/writing a (or few) specific
configuration space from above 4 cfg structures. And that's basically
how this patch works.

Besides those changes, virtio 1.0 introduces a new status field:
FEATURES_OK, which is set after features negotiation is done.

Last, set the VIRTIO_F_VERSION_1 feature flag.

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

v2: - re-read status after setting FEATURES_OK to make sure status is
      set correctly.

    - Add isr reading and config irq setting support.

    - Define some pci macro on our own to not get the dependency of
      linux/pci_regs.h, as there should be no such file at non-Linux
      platform

v3: - invoke rte_eal_pci_unmap_device() at uninit stage

v4: - remove unnessary inline, and likely/unlikely

    - mark "src" arg as const for write_dev_cfg operation
---
 doc/guides/rel_notes/release_2_3.rst |   3 +
 drivers/net/virtio/virtio_ethdev.c   |  25 ++-
 drivers/net/virtio/virtio_ethdev.h   |   3 +-
 drivers/net/virtio/virtio_pci.c      | 335 ++++++++++++++++++++++++++++++++++-
 drivers/net/virtio/virtio_pci.h      |  67 +++++++
 drivers/net/virtio/virtqueue.h       |   2 +
 6 files changed, 430 insertions(+), 5 deletions(-)

diff --git a/doc/guides/rel_notes/release_2_3.rst b/doc/guides/rel_notes/release_2_3.rst
index 99de186..c390d97 100644
--- a/doc/guides/rel_notes/release_2_3.rst
+++ b/doc/guides/rel_notes/release_2_3.rst
@@ -4,6 +4,9 @@ DPDK Release 2.3
 New Features
 ------------
 
+* **Virtio 1.0 support.**
+
+  Enabled virtio 1.0 support for virtio pmd driver.
 
 Resolved Issues
 ---------------
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 94e0c4a..deb0382 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return virtio_send_command(hw->cvq, &ctrl, &len, 1);
 }
 
-static void
+static int
 virtio_negotiate_features(struct virtio_hw *hw)
 {
 	uint64_t host_features;
@@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw)
 	hw->guest_features = vtpci_negotiate_features(hw, host_features);
 	PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,
 		hw->guest_features);
+
+	if (hw->modern) {
+		if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) {
+			PMD_INIT_LOG(ERR,
+				"VIRTIO_F_VERSION_1 features is not enabled.");
+			return -1;
+		}
+		vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK);
+		if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) {
+			PMD_INIT_LOG(ERR,
+				"failed to set FEATURES_OK status!");
+			return -1;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -1032,7 +1048,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	/* Tell the host we've known how to drive the device. */
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
-	virtio_negotiate_features(hw);
+	if (virtio_negotiate_features(hw) < 0)
+		return -1;
 
 	/* If host does not support status then disable LSC */
 	if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS))
@@ -1043,7 +1060,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 	rx_func_get(eth_dev);
 
 	/* Setting up rx_header size for the device */
-	if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF))
+	if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) ||
+	    vtpci_with_feature(hw, VIRTIO_F_VERSION_1))
 		hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
 	else
 		hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr);
@@ -1159,6 +1177,7 @@ eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev)
 		rte_intr_callback_unregister(&pci_dev->intr_handle,
 						virtio_interrupt_handler,
 						eth_dev);
+	rte_eal_pci_unmap_device(pci_dev);
 
 	PMD_INIT_LOG(DEBUG, "dev_uninit completed");
 
diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h
index ae2d47d..fed9571 100644
--- a/drivers/net/virtio/virtio_ethdev.h
+++ b/drivers/net/virtio/virtio_ethdev.h
@@ -64,7 +64,8 @@
 	 1u << VIRTIO_NET_F_CTRL_VQ	  |	\
 	 1u << VIRTIO_NET_F_CTRL_RX	  |	\
 	 1u << VIRTIO_NET_F_CTRL_VLAN	  |	\
-	 1u << VIRTIO_NET_F_MRG_RXBUF)
+	 1u << VIRTIO_NET_F_MRG_RXBUF	  |	\
+	 1ULL << VIRTIO_F_VERSION_1)
 
 /*
  * CQ function prototype
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index a903316..fe8d6a2 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -41,6 +41,14 @@
 #include "virtio_logs.h"
 #include "virtqueue.h"
 
+/*
+ * Following macros are derieved from linux/pci_regs.h, however,
+ * we can't simply include that header here, as there is no such
+ * file for non-Linux platform.
+ */
+#define PCI_CAPABILITY_LIST	0x34
+#define PCI_CAP_ID_VNDR		0x09
+
 static void
 legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 		       void *dst, int length)
@@ -442,6 +450,204 @@ static const struct virtio_pci_ops legacy_ops = {
 };
 
 
+#define MODERN_READ_DEF(nr_bits, type)		\
+static inline type				\
+io_read##nr_bits(type *addr)			\
+{						\
+	return *(volatile type *)addr;		\
+}
+
+#define MODERN_WRITE_DEF(nr_bits, type)		\
+static inline void				\
+io_write##nr_bits(type val, type *addr)		\
+{						\
+	*(volatile type *)addr = val;		\
+}
+
+MODERN_READ_DEF (8, uint8_t)
+MODERN_WRITE_DEF(8, uint8_t)
+
+MODERN_READ_DEF (16, uint16_t)
+MODERN_WRITE_DEF(16, uint16_t)
+
+MODERN_READ_DEF (32, uint32_t)
+MODERN_WRITE_DEF(32, uint32_t)
+
+static inline void
+io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
+{
+	io_write32((uint32_t)val, lo);
+	io_write32(val >> 32,     hi);
+}
+
+static void
+modern_read_dev_config(struct virtio_hw *hw, uint64_t offset,
+		       void *dst, int length)
+{
+	int i;
+	uint8_t *p;
+	uint8_t old_gen, new_gen;
+
+	do {
+		old_gen = io_read8(&hw->common_cfg->config_generation);
+
+		p = dst;
+		for (i = 0;  i < length; i++)
+			*p++ = io_read8((uint8_t *)hw->dev_cfg + offset + i);
+
+		new_gen = io_read8(&hw->common_cfg->config_generation);
+	} while (old_gen != new_gen);
+}
+
+static void
+modern_write_dev_config(struct virtio_hw *hw, uint64_t offset,
+			const void *src, int length)
+{
+	int i;
+	const uint8_t *p = src;
+
+	for (i = 0;  i < length; i++)
+		io_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i);
+}
+
+static uint64_t
+modern_get_features(struct virtio_hw *hw)
+{
+	uint32_t features_lo, features_hi;
+
+	io_write32(0, &hw->common_cfg->device_feature_select);
+	features_lo = io_read32(&hw->common_cfg->device_feature);
+
+	io_write32(1, &hw->common_cfg->device_feature_select);
+	features_hi = io_read32(&hw->common_cfg->device_feature);
+
+	return ((uint64_t)(features_hi) << 32) | features_lo;
+}
+
+static void
+modern_set_features(struct virtio_hw *hw, uint64_t features)
+{
+	io_write32(0, &hw->common_cfg->guest_feature_select);
+	io_write32(features & ((1ULL << 32) - 1),
+		&hw->common_cfg->guest_feature);
+
+	io_write32(1, &hw->common_cfg->guest_feature_select);
+	io_write32(features >> 32,
+		&hw->common_cfg->guest_feature);
+}
+
+static uint8_t
+modern_get_status(struct virtio_hw *hw)
+{
+	return io_read8(&hw->common_cfg->device_status);
+}
+
+static void
+modern_set_status(struct virtio_hw *hw, uint8_t status)
+{
+	io_write8(status, &hw->common_cfg->device_status);
+}
+
+static void
+modern_reset(struct virtio_hw *hw)
+{
+	modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+	modern_get_status(hw);
+}
+
+static uint8_t
+modern_get_isr(struct virtio_hw *hw)
+{
+	return io_read8(hw->isr);
+}
+
+static uint16_t
+modern_set_config_irq(struct virtio_hw *hw, uint16_t vec)
+{
+	io_write16(vec, &hw->common_cfg->msix_config);
+	return io_read16(&hw->common_cfg->msix_config);
+}
+
+static uint16_t
+modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
+{
+	io_write16(queue_id, &hw->common_cfg->queue_select);
+	return io_read16(&hw->common_cfg->queue_size);
+}
+
+static void
+modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
+{
+	uint64_t desc_addr, avail_addr, used_addr;
+	uint16_t notify_off;
+
+	desc_addr = vq->mz->phys_addr;
+	avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
+	used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail,
+							 ring[vq->vq_nentries]),
+				   VIRTIO_PCI_VRING_ALIGN);
+
+	io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
+
+	io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo,
+				      &hw->common_cfg->queue_desc_hi);
+	io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo,
+				       &hw->common_cfg->queue_avail_hi);
+	io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo,
+				      &hw->common_cfg->queue_used_hi);
+
+	notify_off = io_read16(&hw->common_cfg->queue_notify_off);
+	vq->notify_addr = (void *)((uint8_t *)hw->notify_base +
+				notify_off * hw->notify_off_multiplier);
+
+	io_write16(1, &hw->common_cfg->queue_enable);
+
+	PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index);
+	PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr);
+	PMD_INIT_LOG(DEBUG, "\t aval_addr: %"PRIx64, avail_addr);
+	PMD_INIT_LOG(DEBUG, "\t used_addr: %"PRIx64, used_addr);
+	PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)",
+		vq->notify_addr, notify_off);
+}
+
+static void
+modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
+{
+	io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
+
+	io_write64_twopart(0, &hw->common_cfg->queue_desc_lo,
+				  &hw->common_cfg->queue_desc_hi);
+	io_write64_twopart(0, &hw->common_cfg->queue_avail_lo,
+				  &hw->common_cfg->queue_avail_hi);
+	io_write64_twopart(0, &hw->common_cfg->queue_used_lo,
+				  &hw->common_cfg->queue_used_hi);
+
+	io_write16(0, &hw->common_cfg->queue_enable);
+}
+
+static void
+modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
+{
+	io_write16(1, vq->notify_addr);
+}
+
+static const struct virtio_pci_ops modern_ops = {
+	.read_dev_cfg	= modern_read_dev_config,
+	.write_dev_cfg	= modern_write_dev_config,
+	.reset		= modern_reset,
+	.get_status	= modern_get_status,
+	.set_status	= modern_set_status,
+	.get_features	= modern_get_features,
+	.set_features	= modern_set_features,
+	.get_isr	= modern_get_isr,
+	.set_config_irq	= modern_set_config_irq,
+	.get_queue_num	= modern_get_queue_num,
+	.setup_queue	= modern_setup_queue,
+	.del_queue	= modern_del_queue,
+	.notify_queue	= modern_notify_queue,
+};
+
+
 void
 vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 		      void *dst, int length)
@@ -495,6 +701,12 @@ vtpci_set_status(struct virtio_hw *hw, uint8_t status)
 }
 
 uint8_t
+vtpci_get_status(struct virtio_hw *hw)
+{
+	return hw->vtpci_ops->get_status(hw);
+}
+
+uint8_t
 vtpci_isr(struct virtio_hw *hw)
 {
 	return hw->vtpci_ops->get_isr(hw);
@@ -508,15 +720,136 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
 	return hw->vtpci_ops->set_config_irq(hw, vec);
 }
 
+static void *
+get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)
+{
+	uint8_t  bar    = cap->bar;
+	uint32_t length = cap->length;
+	uint32_t offset = cap->offset;
+	uint8_t *base;
+
+	if (bar > 5) {
+		PMD_INIT_LOG(ERR, "invalid bar: %u", bar);
+		return NULL;
+	}
+
+	if (offset + length > dev->mem_resource[bar].len) {
+		PMD_INIT_LOG(ERR,
+			"invalid cap: overflows bar space: %u > %"PRIu64,
+			offset + length, dev->mem_resource[bar].len);
+		return NULL;
+	}
+
+	base = dev->mem_resource[bar].addr;
+	if (base == NULL) {
+		PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar);
+		return NULL;
+	}
+
+	return base + offset;
+}
+
+static int
+virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
+{
+	uint8_t pos;
+	struct virtio_pci_cap cap;
+	int ret;
+
+	if (rte_eal_pci_map_device(dev) < 0) {
+		PMD_INIT_LOG(DEBUG, "failed to map pci device!");
+		return -1;
+	}
+
+	ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST);
+	if (ret < 0) {
+		PMD_INIT_LOG(DEBUG, "failed to read pci capability list");
+		return -1;
+	}
+
+	while (pos) {
+		ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos);
+		if (ret < 0) {
+			PMD_INIT_LOG(ERR,
+				"failed to read pci cap at pos: %x", pos);
+			break;
+		}
+
+		if (cap.cap_vndr != PCI_CAP_ID_VNDR) {
+			PMD_INIT_LOG(DEBUG,
+				"[%2x] skipping non VNDR cap id: %02x",
+				pos, cap.cap_vndr);
+			goto next;
+		}
+
+		PMD_INIT_LOG(DEBUG,
+			"[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u",
+			pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
+
+		switch (cap.cfg_type) {
+		case VIRTIO_PCI_CAP_COMMON_CFG:
+			hw->common_cfg = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_NOTIFY_CFG:
+			rte_eal_pci_read_config(dev, &hw->notify_off_multiplier,
+						4, pos + sizeof(cap));
+			hw->notify_base = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_DEVICE_CFG:
+			hw->dev_cfg = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_ISR_CFG:
+			hw->isr = get_cfg_addr(dev, &cap);
+			break;
+		}
+
+	next:
+		pos = cap.cap_next;
+	}
+
+	if (hw->common_cfg == NULL || hw->notify_base == NULL ||
+	    hw->dev_cfg == NULL    || hw->isr == NULL) {
+		PMD_INIT_LOG(INFO, "no modern virtio pci device found.");
+		return -1;
+	}
+
+	PMD_INIT_LOG(INFO, "found modern virtio pci device.");
+
+	PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg);
+	PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg);
+	PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr);
+	PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u",
+		hw->notify_base, hw->notify_off_multiplier);
+
+	return 0;
+}
+
 int
 vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 {
-	hw->vtpci_ops = &legacy_ops;
+	hw->dev = dev;
+
+	/*
+	 * Try if we can succeed reading virtio pci caps, which exists
+	 * only on modern pci device. If failed, we fallback to legacy
+	 * virtio handling.
+	 */
+	if (virtio_read_caps(dev, hw) == 0) {
+		PMD_INIT_LOG(INFO, "modern virtio pci detected.");
+		hw->vtpci_ops = &modern_ops;
+		hw->modern    = 1;
+		dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
+		return 0;
+	}
 
+	PMD_INIT_LOG(INFO, "trying with legacy virtio pci.");
 	if (legacy_virtio_resource_init(dev) < 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 17312f6..8174245 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -93,6 +93,7 @@ struct virtqueue;
 #define VIRTIO_CONFIG_STATUS_ACK       0x01
 #define VIRTIO_CONFIG_STATUS_DRIVER    0x02
 #define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04
+#define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08
 #define VIRTIO_CONFIG_STATUS_FAILED    0x80
 
 /*
@@ -141,6 +142,8 @@ struct virtqueue;
 /* We support indirect buffer descriptors */
 #define VIRTIO_RING_F_INDIRECT_DESC	28
 
+#define VIRTIO_F_VERSION_1		32
+
 /*
  * Some VirtIO feature bits (currently bits 28 through 31) are
  * reserved for the transport being used (eg. virtio_ring), the
@@ -163,6 +166,60 @@ struct virtqueue;
  */
 #define VIRTIO_MAX_VIRTQUEUES 8
 
+/* Common configuration */
+#define VIRTIO_PCI_CAP_COMMON_CFG	1
+/* Notifications */
+#define VIRTIO_PCI_CAP_NOTIFY_CFG	2
+/* ISR Status */
+#define VIRTIO_PCI_CAP_ISR_CFG		3
+/* Device specific configuration */
+#define VIRTIO_PCI_CAP_DEVICE_CFG	4
+/* PCI configuration access */
+#define VIRTIO_PCI_CAP_PCI_CFG		5
+
+/* This is the PCI capability header: */
+struct virtio_pci_cap {
+	uint8_t cap_vndr;		/* Generic PCI field: PCI_CAP_ID_VNDR */
+	uint8_t cap_next;		/* Generic PCI field: next ptr. */
+	uint8_t cap_len;		/* Generic PCI field: capability length */
+	uint8_t cfg_type;		/* Identifies the structure. */
+	uint8_t bar;			/* Where to find it. */
+	uint8_t padding[3];		/* Pad to full dword. */
+	uint32_t offset;		/* Offset within bar. */
+	uint32_t length;		/* Length of the structure, in bytes. */
+};
+
+struct virtio_pci_notify_cap {
+	struct virtio_pci_cap cap;
+	uint32_t notify_off_multiplier;	/* Multiplier for queue_notify_off. */
+};
+
+/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */
+struct virtio_pci_common_cfg {
+	/* About the whole device. */
+	uint32_t device_feature_select;	/* read-write */
+	uint32_t device_feature;	/* read-only */
+	uint32_t guest_feature_select;	/* read-write */
+	uint32_t guest_feature;		/* read-write */
+	uint16_t msix_config;		/* read-write */
+	uint16_t num_queues;		/* read-only */
+	uint8_t device_status;		/* read-write */
+	uint8_t config_generation;	/* read-only */
+
+	/* About a specific virtqueue. */
+	uint16_t queue_select;		/* read-write */
+	uint16_t queue_size;		/* read-write, power of 2. */
+	uint16_t queue_msix_vector;	/* read-write */
+	uint16_t queue_enable;		/* read-write */
+	uint16_t queue_notify_off;	/* read-only */
+	uint32_t queue_desc_lo;		/* read-write */
+	uint32_t queue_desc_hi;		/* read-write */
+	uint32_t queue_avail_lo;	/* read-write */
+	uint32_t queue_avail_hi;	/* read-write */
+	uint32_t queue_used_lo;		/* read-write */
+	uint32_t queue_used_hi;		/* read-write */
+};
+
 struct virtio_hw;
 
 struct virtio_pci_ops {
@@ -188,6 +245,8 @@ struct virtio_pci_ops {
 	void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq);
 };
 
+struct virtio_net_config;
+
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
@@ -198,7 +257,14 @@ struct virtio_hw {
 	uint8_t	    vlan_strip;
 	uint8_t	    use_msix;
 	uint8_t     started;
+	uint8_t     modern;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
+	uint32_t    notify_off_multiplier;
+	uint8_t     *isr;
+	uint16_t    *notify_base;
+	struct rte_pci_device *dev;
+	struct virtio_pci_common_cfg *common_cfg;
+	struct virtio_net_config *dev_cfg;
 	const struct virtio_pci_ops *vtpci_ops;
 };
 
@@ -284,6 +350,7 @@ void vtpci_reset(struct virtio_hw *);
 
 void vtpci_reinit_complete(struct virtio_hw *);
 
+uint8_t vtpci_get_status(struct virtio_hw *);
 void vtpci_set_status(struct virtio_hw *, uint8_t);
 
 uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t);
diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h
index d7fb450..99d4fa9 100644
--- a/drivers/net/virtio/virtqueue.h
+++ b/drivers/net/virtio/virtqueue.h
@@ -202,6 +202,8 @@ struct virtqueue {
 	/* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */
 	uint64_t	size_bins[8];
 
+	uint16_t	*notify_addr;
+
 	struct vq_desc_extra {
 		void              *cookie;
 		uint16_t          ndescs;
-- 
1.9.0

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

* [dpdk-dev] [PATCH v4 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c
  2016-01-15  4:36   ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                       ` (6 preceding siblings ...)
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support Yuanhan Liu
@ 2016-01-15  4:36     ` Yuanhan Liu
  2016-01-15  8:57       ` Xu, Qian Q
  2016-01-18  8:04     ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Tetsuya Mukawa
  2016-01-19  8:11     ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu
  9 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-15  4:36 UTC (permalink / raw)
  To: dev

virtio_pci.c is the only file references those macros; move them there.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_pci.c | 19 +++++++++++++++++++
 drivers/net/virtio/virtio_pci.h | 18 ------------------
 2 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index fe8d6a2..a9f179f 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -49,6 +49,25 @@
 #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))))
+
 static void
 legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 		       void *dst, int length)
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index 8174245..99572a0 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -318,24 +318,6 @@ outl_p(unsigned int data, unsigned int port)
 }
 #endif
 
-#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))))
-
 static inline int
 vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-- 
1.9.0

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

* Re: [dpdk-dev] [PATCH v4 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
@ 2016-01-15  8:57       ` Xu, Qian Q
  0 siblings, 0 replies; 122+ messages in thread
From: Xu, Qian Q @ 2016-01-15  8:57 UTC (permalink / raw)
  To: Yuanhan Liu, dev

Tested-by: Qian Xu <qian.q.xu@intel.com>

- Test Commit: ad66a85dce9a707748cb4d9592c13022ae77c067
- OS/Kernel: Fedora 21/4.1.13
- GCC: gcc (GCC) 4.9.2 20141101 (Red Hat 4.9.2-1)
- CPU: Intel(R) Xeon(R) CPU E5-2695 v4 @ 2.10
- NIC: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection (rev 01)
- Target: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection (rev 01)
- Total 2 cases, 2 passed, 0 failed. 

Test Case1: test_func_vhost_user_virtio1.0-pmd with different txqflags 
======================================================================

Note: For virtio1.0 usage, we need use qemu version >2.4, such as 2.4.1 or 2.5.0.

1. Launch the Vhost sample by below commands, socket-mem is set for the vhost sample to use, need ensure that the PCI port located socket has the memory. In our case, the PCI BDF is 81:00.0, so we need assign memory for socket1.::

    taskset -c 18-20 ./examples/vhost/build/vhost-switch -c 0x1c0000 -n 4 --huge-dir /mnt/huge --socket-mem 0,2048 -- -p 1 --mergeable 0 --zero-copy 0 --vm2vm 0 

2. Start VM with 1 virtio, note: we need add "disable-modern=false" to enable virtio 1.0. 

    taskset -c 22-23 \
    /root/qemu-versions/qemu-2.5.0/x86_64-softmmu/qemu-system-x86_64 -name us-vhost-vm1 \
     -cpu host -enable-kvm -m 2048 -object memory-backend-file,id=mem,size=2048M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc \
     -smp cores=2,sockets=1 -drive file=/home/img/vm1.img  \
     -chardev socket,id=char0,path=/home/qxu10/virtio-1.0/dpdk/vhost-net -netdev type=vhost-user,id=mynet1,chardev=char0,vhostforce \
     -device virtio-net-pci,mac=52:54:00:00:00:01,netdev=mynet1,disable-modern=false \
     -netdev tap,id=ipvm1,ifname=tap3,script=/etc/qemu-ifup -device rtl8139,netdev=ipvm1,id=net0,mac=00:00:00:00:10:01 -nographic


3. In the VM, change the config file--common_linuxapp, "CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_INIT=y"; Run dpdk testpmd in VM::

     ./<dpdk_folder>/tools/dpdk_nic_bind.py --bind igb_uio 00:03.0 

     ./<dpdk_folder>/x86_64-native-linuxapp-gcc/app/test-pmd/testpmd -c 0x3 -n 4 -- -i --txqflags 0x0f00 --disable-hw-vlan 
    
     $ >set fwd mac
    
     $ >start tx_first

    We expect similar output as below, and see modern virtio pci detected. 
 
    PMD: virtio_read_caps(): [98] skipping non VNDR cap id: 11
    PMD: virtio_read_caps(): [84] cfg type: 5, bar: 0, offset: 0000, len: 0
    PMD: virtio_read_caps(): [70] cfg type: 2, bar: 4, offset: 3000, len: 4194304
    PMD: virtio_read_caps(): [60] cfg type: 4, bar: 4, offset: 2000, len: 4096
    PMD: virtio_read_caps(): [50] cfg type: 3, bar: 4, offset: 1000, len: 4096
    PMD: virtio_read_caps(): [40] cfg type: 1, bar: 4, offset: 0000, len: 4096
    PMD: virtio_read_caps(): found modern virtio pci device.
    PMD: virtio_read_caps(): common cfg mapped at: 0x7f2c61a83000
    PMD: virtio_read_caps(): device cfg mapped at: 0x7f2c61a85000
    PMD: virtio_read_caps(): isr cfg mapped at: 0x7f2c61a84000
    PMD: virtio_read_caps(): notify base: 0x7f2c61a86000, notify off multiplier: 409                                                                                                                     6
    PMD: vtpci_init(): modern virtio pci detected.


4. Send traffic to virtio1(MAC1=52:54:00:00:00:01) with VLAN ID=1000. Check if virtio packet can be RX/TX and also check the TX packet size is same as the RX packet size.

5. Also run the dpdk testpmd in VM with txqflags=0xf01 for the virtio pmd optimization usage::

     ./<dpdk_folder>/tools/dpdk_nic_bind.py --bind igb_uio 00:03.0

     ./<dpdk_folder>/x86_64-native-linuxapp-gcc/app/test-pmd/testpmd -c 0x3 -n 4 -- -i --txqflags=0x0f01 --disable-hw-vlan 
    
     $ >set fwd mac
    
     $ >start tx_first

6. Send traffic to virtio1(MAC1=52:54:00:00:00:01) and VLAN ID=1000. Check if virtio packet can be RX/TX and also check the TX packet size is same as the RX packet size. Check the packet content is correct.


Test Case2: test_func_vhost_user_one-vm-virtio1.0-one-vm-virtio0.95
===================================================================

1. Launch the Vhost sample by below commands, socket-mem is set for the vhost sample to use, need ensure that the PCI port located socket has the memory. In our case, the PCI BDF is 81:00.0, so we need assign memory for socket1.::

    taskset -c 18-20 ./examples/vhost/build/vhost-switch -c 0x1c0000 -n 4 --huge-dir /mnt/huge --socket-mem 0,2048 -- -p 1 --mergeable 0 --zero-copy 0 --vm2vm 1 

2. Start VM1 with 1 virtio, note: we need add "disable-modern=false" to enable virtio 1.0. 

    taskset -c 22-23 \
    /root/qemu-versions/qemu-2.5.0/x86_64-softmmu/qemu-system-x86_64 -name us-vhost-vm1 \
     -cpu host -enable-kvm -m 2048 -object memory-backend-file,id=mem,size=2048M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc \
     -smp cores=2,sockets=1 -drive file=/home/img/vm1.img  \
     -chardev socket,id=char0,path=/home/qxu10/virtio-1.0/dpdk/vhost-net -netdev type=vhost-user,id=mynet1,chardev=char0,vhostforce \
     -device virtio-net-pci,mac=52:54:00:00:00:01,netdev=mynet1,disable-modern=false \
     -netdev tap,id=ipvm1,ifname=tap3,script=/etc/qemu-ifup -device rtl8139,netdev=ipvm1,id=net0,mac=00:00:00:00:10:01 -nographic

3. Start VM2 with 1 virtio, note: 

    taskset -c 24-25 \
    /root/qemu-versions/qemu-2.5.0/x86_64-softmmu/qemu-system-x86_64 -name us-vhost-vm1 \
     -cpu host -enable-kvm -m 2048 -object memory-backend-file,id=mem,size=2048M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc \
     -smp cores=2,sockets=1 -drive file=/home/img/vm2.img  \
     -chardev socket,id=char0,path=/home/qxu10/virtio-1.0/dpdk/vhost-net -netdev type=vhost-user,id=mynet2,chardev=char0,vhostforce \
     -device virtio-net-pci,mac=52:54:00:00:00:02,netdev=mynet2,disable-modern=true \
     -netdev tap,id=ipvm2,ifname=tap4,script=/etc/qemu-ifup -device rtl8139,netdev=ipvm2,id=net1,mac=00:00:00:00:10:02 -nographic

3. Run dpdk testpmd in VM1 and VM2::

     VM1:     

     ./<dpdk_folder>/tools/dpdk_nic_bind.py --bind igb_uio 00:03.0 

     ./<dpdk_folder>/x86_64-native-linuxapp-gcc/app/test-pmd/testpmd -c 0x3 -n 4 -- -i --txqflags 0x0f00 --disable-hw-vlan --eth-peer=0,52:54:00:00:00:02 
    
     $ >set fwd mac
    
     $ >start tx_first

     VM2: 

     ./<dpdk_folder>/tools/dpdk_nic_bind.py --bind igb_uio 00:03.0 

     ./<dpdk_folder>/x86_64-native-linuxapp-gcc/app/test-pmd/testpmd -c 0x3 -n 4 -- -i --txqflags 0x0f00 --disable-hw-vlan 
    
     $ >set fwd mac
    
     $ >start tx_first

4. Send 100 packets at low rate to virtio1, and the expected flow is ixia-->NIC-->VHOST-->Virtio1-->Virtio2-->Vhost-->NIC->ixia port. Check the packet back at ixia port is content correct, no size change and payload change.

Thanks
Qian

-----Original Message-----
From: Yuanhan Liu [mailto:yuanhan.liu@linux.intel.com] 
Sent: Friday, January 15, 2016 12:36 PM
To: dev@dpdk.org
Cc: Xie, Huawei; Tetsuya Mukawa; Tan, Jianfeng; Xu, Qian Q; Yuanhan Liu
Subject: [PATCH v4 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c

virtio_pci.c is the only file references those macros; move them there.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
 drivers/net/virtio/virtio_pci.c | 19 +++++++++++++++++++  drivers/net/virtio/virtio_pci.h | 18 ------------------
 2 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index fe8d6a2..a9f179f 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -49,6 +49,25 @@
 #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))))
+
 static void
 legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 		       void *dst, int length)
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index 8174245..99572a0 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -318,24 +318,6 @@ outl_p(unsigned int data, unsigned int port)  }  #endif
 
-#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))))
-
 static inline int
 vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)  {
--
1.9.0

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

* Re: [dpdk-dev] [PATCH v3 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c
  2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
@ 2016-01-16 10:08       ` Santosh Shukla
  2016-01-17 14:07         ` Santosh Shukla
  0 siblings, 1 reply; 122+ messages in thread
From: Santosh Shukla @ 2016-01-16 10:08 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev, Michael S. Tsirkin

On Thu, Jan 14, 2016 at 1:12 PM, Yuanhan Liu
<yuanhan.liu@linux.intel.com> wrote:
> virtio_pci.c become the only file references those macros; move them there.
>

My patch VFIO series need virtio_rd/wr So keeping these api in
virtio_pci.h make more sense to me.

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

* Re: [dpdk-dev] [PATCH v3 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c
  2016-01-16 10:08       ` Santosh Shukla
@ 2016-01-17 14:07         ` Santosh Shukla
  0 siblings, 0 replies; 122+ messages in thread
From: Santosh Shukla @ 2016-01-17 14:07 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev, Michael S. Tsirkin

On Sat, Jan 16, 2016 at 3:38 PM, Santosh Shukla <sshukla@mvista.com> wrote:
> On Thu, Jan 14, 2016 at 1:12 PM, Yuanhan Liu
> <yuanhan.liu@linux.intel.com> wrote:
>> virtio_pci.c become the only file references those macros; move them there.
>>
>
> My patch VFIO series need virtio_rd/wr So keeping these api in
> virtio_pci.h make more sense to me.

Ignore my comment, I just finished reading your patch series and wont
see any potential issue in moving my vfio rd/wr api to vfio_pci.c.

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

* Re: [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver
  2016-01-15  4:36   ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                       ` (7 preceding siblings ...)
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
@ 2016-01-18  8:04     ` Tetsuya Mukawa
  2016-01-19  8:11     ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu
  9 siblings, 0 replies; 122+ messages in thread
From: Tetsuya Mukawa @ 2016-01-18  8:04 UTC (permalink / raw)
  To: Yuanhan Liu, dev

On 2016/01/15 13:36, Yuanhan Liu wrote:
> v4: - mark "src" arg as const for write_dev_cfg operation
>
>     - remove unnessary inline, and likely/unlikely
>
> v3: - export pci_unmap_device as well; and invoke it at virtio
>       uninit stage.
>
>     - fixed same data corruption bug reported by Qian in simple
>       rxtx code path.
>
>     - move VIRTIO_READ/WRITE_REG_X to virtio_pci.c
>
> v2: - fix a data corruption reported by Qian, due to hdr size mismatch.
>       check detailes at ptach 5.
>
>     - Add missing config_irq and isr reading support from v1.
>
>     - fix comments from v1.
>
> Almost all difference comes from virtio 1.0 are the PCI layout change:
> the major configuration structures are stored at bar space, and their
> location is stored at corresponding pci cap structure. Reading/parsing
> them is one of the major work of patch 7.
>
> To make handling virtio v1.0 and v0.95 co-exist well, this patch set
> introduces a virtio_pci_ops structure, to add another layer so that
> we could keep those vtpci_foo_bar "APIs". With that, we could do the
> minimum change to add virtio 1.0 support.
>
>
> Rough test guide
> ================
>
> Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add
> option "disable-modern=false" to qemu virtio-net-pci device to enable
> virtio 1.0 (which is disabled by default).
>
> And if you see something like following from 'lspci -v', it means virtio
> 1.0 is indeed enabled:
>
>     00:04.0 Ethernet controller: Red Hat, Inc Virtio network device
>     Subsystem: Red Hat, Inc Device 0001
>     Physical Slot: 4
>     Flags: bus master, fast devsel, latency 0, IRQ 11
>     I/O ports at c040 [size=64]
>     Memory at febf1000 (32-bit, non-prefetchable) [size=4K]
>     Memory at fe000000 (64-bit, prefetchable) [size=8M]
>     Expansion ROM at feb80000 [disabled] [size=256K]
>     Capabilities: [98] MSI-X: Enable+ Count=6 Masked-
> ==> Capabilities: [84] Vendor Specific Information: Len=14 <?>
> ==> Capabilities: [70] Vendor Specific Information: Len=14 <?>
> ==> Capabilities: [60] Vendor Specific Information: Len=10 <?>
> ==> Capabilities: [50] Vendor Specific Information: Len=10 <?>
> ==> Capabilities: [40] Vendor Specific Information: Len=10 <?>
>     Kernel driver in use: virtio-pci
>     Kernel modules: virtio_pci
>
> After that, there wasn't anything speical comparing to the old virtio
> 0.95 pmd driver.
>
>
> ---
> Yuanhan Liu (8):
>   virtio: don't set vring address again at queue startup
>   virtio: introduce struct virtio_pci_ops
>   virtio: move left pci stuff to virtio_pci.c
>   viritio: switch to 64 bit features
>   virtio: retrieve hdr_size from hw->vtnet_hdr_size
>   eal: pci: export pci_[un]map_device
>   virtio: add 1.0 support
>   virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c
>
>  doc/guides/rel_notes/release_2_3.rst            |   3 +
>  drivers/net/virtio/virtio_ethdev.c              | 302 +--------
>  drivers/net/virtio/virtio_ethdev.h              |   3 +-
>  drivers/net/virtio/virtio_pci.c                 | 793 +++++++++++++++++++++++-
>  drivers/net/virtio/virtio_pci.h                 | 120 +++-
>  drivers/net/virtio/virtio_rxtx.c                |  21 +-
>  drivers/net/virtio/virtio_rxtx_simple.c         |  12 +-
>  drivers/net/virtio/virtqueue.h                  |   4 +-
>  lib/librte_eal/bsdapp/eal/eal_pci.c             |   4 +-
>  lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   7 +
>  lib/librte_eal/common/eal_common_pci.c          |   4 +-
>  lib/librte_eal/common/eal_private.h             |  18 -
>  lib/librte_eal/common/include/rte_pci.h         |  27 +
>  lib/librte_eal/linuxapp/eal/eal_pci.c           |   4 +-
>  lib/librte_eal/linuxapp/eal/rte_eal_version.map |   7 +
>  15 files changed, 949 insertions(+), 380 deletions(-)
>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>

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

* Re: [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver
  2016-01-14  6:41       ` Tetsuya Mukawa
@ 2016-01-18  9:04         ` Tetsuya Mukawa
  0 siblings, 0 replies; 122+ messages in thread
From: Tetsuya Mukawa @ 2016-01-18  9:04 UTC (permalink / raw)
  To: Tan, Jianfeng; +Cc: dev, Michael S. Tsirkin

On 2016/01/14 15:41, Tetsuya Mukawa wrote:
>
>>> 2. Abstraction of read/write accesses.
>>>
>>> It may be difficult to cleanly rebase my patches on this patches,
>>> because virtio_read_caps() is not abstracted.
>>> Let me describe it more.
>>> So far, we need to handle below 3 virtio-net devices..
>>>   - physical virtio-net device.
>>>   - virtual virtio-net device in virtio-net PMD. (Jianfeng's patch)
>>>   - virtual virtio-net device in QEMU. (my patch)
>>>
>>> Almost all code of the virtio-net PMD can be shared between above
>>> different cases.
>>> Probably big difference is how to access to configuration space.
>>>
>>> Yuanhan's patch introduces an abstraction layer to hide configuration
>>> space layout and how to access it.
>>> Is it possible to separate?
>>> I guess "access method" will be nice to be abstracted separately from
>>> "configuration space layout".
>>> Probably access method will be defined by "eth_dev->dev_type" and the
>>> PMD name like "eth_cvio".
>>> And "configuration space layout" will be defined by capability list of
>>> PCI configuration layout.
>>>
>>> For example, if access method like below are abstracted separately and
>>> current "virtio_pci.c" is implemented on this abstraction, we can easily
>>> re-use virtio_read_caps().
>>>   - how to read/write virtio configuration space.
>>>   - how to mmap PCI configuration space.
>>>   - how to read/(write) PCI configuration space.
>>
>> I basically agree with you. We have two dimensions here:
>>
>> legacy             modern
>> physical virtio device:                     Use
>> virtio_read_caps_phys() to distinguish
>> virtual virtio device (Tetsuya):       Use virtio_read_caps_virt() to
>> distinguish
>> virtual virtio device (Jianfeng):    does not need a "configuration
>> space layout", no need to distinguish
>>
>> So in vtpci_init(), we needs to test "eth_dev->dev_type" firstly
>>
>> vtpci_init() {
>>     if (eth_dev->dev_type == RTE_ETH_DEV_PCI) {
>>         if (virtio_read_caps_phys()) {
>>             // modern
>>         } else {
>>             // legacy
>>         }
>>     } else {
>>         if (Tetsuya's way) {
>>             if (virtio_read_caps_virt()) {
>>                 // modern
>>             } else {
>>                 // legacy
>>             }
>>         } else {
>>             // Jianfeng's way
>>         }
>>     }
>> }
>>
>> And from Yuanhan's angle, I think he does not need to address this
>> problem. How do you think?
> Yes, I agree he doesn't need.
>
> Firstly, I have implemented like above, then I noticed that
> virtio_read_caps_phy() and virtio_read_caps_virt() are same except for
> access method.
> Anyway, I guess abstracting access method is not so difficult.
> If you are OK, I want to send RFC on Yuanhan's patch. Is it OK?

Hi Jianfeng,

I will submit patches to abstract pci access method.
The patches will be on Yuanhan's latest virtio-1.0 patches.

I guess your container patches also can be on the patches.
Could you please check it?

Thanks,
Tetsuya

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

* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support Yuanhan Liu
@ 2016-01-18 16:38       ` Xie, Huawei
  2016-01-18 16:50       ` Xie, Huawei
  2016-01-18 17:07       ` Xie, Huawei
  2 siblings, 0 replies; 122+ messages in thread
From: Xie, Huawei @ 2016-01-18 16:38 UTC (permalink / raw)
  To: Yuanhan Liu, dev

On 1/15/2016 12:34 PM, Yuanhan Liu wrote:
> Modern (v1.0) virtio pci device defines several pci capabilities.
> Each cap has a configure structure corresponding to it, and the
> cap.bar and cap.offset fields tell us where to find it.
>

[snip]

>  
> +static void *
> +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)
> +{
> +	uint8_t  bar    = cap->bar;
> +	uint32_t length = cap->length;
> +	uint32_t offset = cap->offset;
> +	uint8_t *base;
> +
> +	if (bar > 5) {
> +		PMD_INIT_LOG(ERR, "invalid bar: %u", bar);
> +		return NULL;
> +	}
> +
> +	if (offset + length > dev->mem_resource[bar].len) {

offset + length could overflow 32bit limit

> +		PMD_INIT_LOG(ERR,
> +			"invalid cap: overflows bar space: %u > %"PRIu64,
> +			offset + length, dev->mem_resource[bar].len);
> +		return NULL;
> +	}
> +
> +	

[snip]

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

* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support Yuanhan Liu
  2016-01-18 16:38       ` Xie, Huawei
@ 2016-01-18 16:50       ` Xie, Huawei
  2016-01-19  5:55         ` Yuanhan Liu
  2016-01-18 17:07       ` Xie, Huawei
  2 siblings, 1 reply; 122+ messages in thread
From: Xie, Huawei @ 2016-01-18 16:50 UTC (permalink / raw)
  To: Yuanhan Liu, dev

On 1/15/2016 12:34 PM, Yuanhan Liu wrote:
> -static void
> +static int
>  virtio_negotiate_features(struct virtio_hw *hw)
>  {
>  	uint64_t host_features;
> @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw)
>  	hw->guest_features = vtpci_negotiate_features(hw, host_features);

Here if we are not modern device, we should remove VIRTIO_F_VERSION_1 in
guest features.

>  	PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,
>  		hw->guest_features);
> +
> +	if (hw->modern) {
> +		if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) {
> +			PMD_INIT_LOG(ERR,
> +				"VIRTIO_F_VERSION_1 features is not enabled.");
> +			return -1;
> +		}
> +		vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK);
> +		if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) {
> +			PMD_INIT_LOG(ERR,
> +				"failed to set FEATURES_OK status!");
> +			return -1;
> +		}
> +	}
> +
> +	return 0;
>  }


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

* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support Yuanhan Liu
  2016-01-18 16:38       ` Xie, Huawei
  2016-01-18 16:50       ` Xie, Huawei
@ 2016-01-18 17:07       ` Xie, Huawei
  2016-01-19  1:36         ` Yuanhan Liu
  2 siblings, 1 reply; 122+ messages in thread
From: Xie, Huawei @ 2016-01-18 17:07 UTC (permalink / raw)
  To: Yuanhan Liu, dev

.On 1/15/2016 12:34 PM, Yuanhan Liu wrote:
> Modern (v1.0) virtio pci device defines several pci capabilities.
> Each cap has a configure structure corresponding to it, and the
> cap.bar and cap.offset fields tell us where to find it.
>
[snip]
> +
> +static inline void
> +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
> +{
> +	io_write32((uint32_t)val, lo);
> +	io_write32(val >> 32,     hi);

Firstly your second iowrite32 doesn't do the conversion. The conversion
is duplicated.

> +}
> +
> +static void
> +modern_read_dev_config(struct virtio_hw *hw, uint64_t offset,

here and there, size_t is more accurate for offset as we get it from
offsetof.

> +		       void *dst, int length)
> +{
> +	int i;
> +	uint8_t *p;
> +	uint8_t old_gen, new_gen;
> +
> +	do {
> +		old_gen = io_read8(&hw->common_cfg->config_generation);
> +
> +		p = dst;
> +		for (i = 0;  i < length; i++)
> +			*p++ = io_read8((uint8_t *)hw->dev_cfg + offset + i);
> +
> +		new_gen = io_read8(&hw->common_cfg->config_generation);
> +	} while (old_gen != new_gen);
> +}
> +
> +static void
> +modern_write_dev_config(struct virtio_hw *hw, uint64_t offset,
> +			const void *src, int length)
> +{
> +	int i;
> +	const uint8_t *p = src;
> +
> +	for (i = 0;  i < length; i++)
> +		io_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i);
> +}
> +
> +static uint64_t
> +modern_get_features(struct virtio_hw *hw)
> +{
> +	uint32_t features_lo, features_hi;
> +
> +	io_write32(0, &hw->common_cfg->device_feature_select);
> +	features_lo = io_read32(&hw->common_cfg->device_feature);
> +
> +	io_write32(1, &hw->common_cfg->device_feature_select);
> +	features_hi = io_read32(&hw->common_cfg->device_feature);
> +
> +	return ((uint64_t)(features_hi) << 32) | features_lo;
> +}
> +
> +static void
> +modern_set_features(struct virtio_hw *hw, uint64_t features)
> +{
> +	io_write32(0, &hw->common_cfg->guest_feature_select);
> +	io_write32(features & ((1ULL << 32) - 1),

again, duplicated conversion

> +		&hw->common_cfg->guest_feature);
> +
> +	io_write32(1, &hw->common_cfg->guest_feature_select);
[snip]

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

* Re: [dpdk-dev] [PATCH v4 2/8] virtio: introduce struct virtio_pci_ops
  2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 2/8] virtio: introduce struct virtio_pci_ops Yuanhan Liu
@ 2016-01-18 17:21       ` Xie, Huawei
  0 siblings, 0 replies; 122+ messages in thread
From: Xie, Huawei @ 2016-01-18 17:21 UTC (permalink / raw)
  To: Yuanhan Liu, dev

On 1/15/2016 12:34 PM, Yuanhan Liu wrote:
> +void
> +vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
> +		void *src, int length)
> +{
> +	hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);

missed changing src to const.

> +}


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

* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support
  2016-01-18 17:07       ` Xie, Huawei
@ 2016-01-19  1:36         ` Yuanhan Liu
  2016-01-19  1:51           ` Xie, Huawei
  0 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-19  1:36 UTC (permalink / raw)
  To: Xie, Huawei; +Cc: dev

On Mon, Jan 18, 2016 at 05:07:51PM +0000, Xie, Huawei wrote:
> .On 1/15/2016 12:34 PM, Yuanhan Liu wrote:
> > Modern (v1.0) virtio pci device defines several pci capabilities.
> > Each cap has a configure structure corresponding to it, and the
> > cap.bar and cap.offset fields tell us where to find it.
> >
> [snip]
> > +
> > +static inline void
> > +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
> > +{
> > +	io_write32((uint32_t)val, lo);
> > +	io_write32(val >> 32,     hi);
> 
> Firstly your second iowrite32 doesn't do the conversion.

Because it's not necessary. The first one is for retrieving the low 32
bits.

> The conversion is duplicated.

What do you mean by "duplicated".

	--yliu

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

* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support
  2016-01-19  1:36         ` Yuanhan Liu
@ 2016-01-19  1:51           ` Xie, Huawei
  2016-01-19  2:46             ` Yuanhan Liu
  0 siblings, 1 reply; 122+ messages in thread
From: Xie, Huawei @ 2016-01-19  1:51 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev

On 1/19/2016 9:34 AM, Yuanhan Liu wrote:
> On Mon, Jan 18, 2016 at 05:07:51PM +0000, Xie, Huawei wrote:
>> .On 1/15/2016 12:34 PM, Yuanhan Liu wrote:
>>> Modern (v1.0) virtio pci device defines several pci capabilities.
>>> Each cap has a configure structure corresponding to it, and the
>>> cap.bar and cap.offset fields tell us where to find it.
>>>
>> [snip]
>>> +
>>> +static inline void
>>> +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
>>> +{
>>> +	io_write32((uint32_t)val, lo);
>>> +	io_write32(val >> 32,     hi);
>> Firstly your second iowrite32 doesn't do the conversion.
> Because it's not necessary. The first one is for retrieving the low 32
> bits.

I don't mean the shift operation, but the conversion from 64bit to 32bit.
Same applied to below.

>
>> The conversion is duplicated.
> What do you mean by "duplicated".
>
> 	--yliu
>


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

* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support
  2016-01-19  1:51           ` Xie, Huawei
@ 2016-01-19  2:46             ` Yuanhan Liu
  2016-01-19  2:48               ` Xie, Huawei
  0 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-19  2:46 UTC (permalink / raw)
  To: Xie, Huawei; +Cc: dev

On Tue, Jan 19, 2016 at 01:51:30AM +0000, Xie, Huawei wrote:
> On 1/19/2016 9:34 AM, Yuanhan Liu wrote:
> > On Mon, Jan 18, 2016 at 05:07:51PM +0000, Xie, Huawei wrote:
> >> .On 1/15/2016 12:34 PM, Yuanhan Liu wrote:
> >>> Modern (v1.0) virtio pci device defines several pci capabilities.
> >>> Each cap has a configure structure corresponding to it, and the
> >>> cap.bar and cap.offset fields tell us where to find it.
> >>>
> >> [snip]
> >>> +
> >>> +static inline void
> >>> +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
> >>> +{
> >>> +	io_write32((uint32_t)val, lo);
> >>> +	io_write32(val >> 32,     hi);
> >> Firstly your second iowrite32 doesn't do the conversion.
> > Because it's not necessary. The first one is for retrieving the low 32
> > bits.
> 
> I don't mean the shift operation, but the conversion from 64bit to 32bit.
> Same applied to below.

It's more than a casting here: it's same as "val & (1<<32 - 1)", as
stated above, to retrieve the low 32 bits.

I know it still could work without it, but, hey, what's wrong to make
it explicit?

	--yliu

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

* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support
  2016-01-19  2:46             ` Yuanhan Liu
@ 2016-01-19  2:48               ` Xie, Huawei
  2016-01-19  5:54                 ` Yuanhan Liu
  0 siblings, 1 reply; 122+ messages in thread
From: Xie, Huawei @ 2016-01-19  2:48 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev

On 1/19/2016 10:44 AM, Yuanhan Liu wrote:
> On Tue, Jan 19, 2016 at 01:51:30AM +0000, Xie, Huawei wrote:
>> On 1/19/2016 9:34 AM, Yuanhan Liu wrote:
>>> On Mon, Jan 18, 2016 at 05:07:51PM +0000, Xie, Huawei wrote:
>>>> .On 1/15/2016 12:34 PM, Yuanhan Liu wrote:
>>>>> Modern (v1.0) virtio pci device defines several pci capabilities.
>>>>> Each cap has a configure structure corresponding to it, and the
>>>>> cap.bar and cap.offset fields tell us where to find it.
>>>>>
>>>> [snip]
>>>>> +
>>>>> +static inline void
>>>>> +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
>>>>> +{
>>>>> +	io_write32((uint32_t)val, lo);
>>>>> +	io_write32(val >> 32,     hi);
>>>> Firstly your second iowrite32 doesn't do the conversion.
>>> Because it's not necessary. The first one is for retrieving the low 32
>>> bits.
>> I don't mean the shift operation, but the conversion from 64bit to 32bit.
>> Same applied to below.
> It's more than a casting here: it's same as "val & (1<<32 - 1)", as
> stated above, to retrieve the low 32 bits.
>
> I know it still could work without it, but, hey, what's wrong to make
> it explicit?

Say x = val, y = val >> 32, both with (uint32_t) or both not. Be
consistent and simple.

>
> 	--yliu
>


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

* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support
  2016-01-19  2:48               ` Xie, Huawei
@ 2016-01-19  5:54                 ` Yuanhan Liu
  0 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-19  5:54 UTC (permalink / raw)
  To: Xie, Huawei; +Cc: dev

On Tue, Jan 19, 2016 at 02:48:39AM +0000, Xie, Huawei wrote:
> On 1/19/2016 10:44 AM, Yuanhan Liu wrote:
> > On Tue, Jan 19, 2016 at 01:51:30AM +0000, Xie, Huawei wrote:
> >> On 1/19/2016 9:34 AM, Yuanhan Liu wrote:
> >>> On Mon, Jan 18, 2016 at 05:07:51PM +0000, Xie, Huawei wrote:
> >>>> .On 1/15/2016 12:34 PM, Yuanhan Liu wrote:
> >>>>> Modern (v1.0) virtio pci device defines several pci capabilities.
> >>>>> Each cap has a configure structure corresponding to it, and the
> >>>>> cap.bar and cap.offset fields tell us where to find it.
> >>>>>
> >>>> [snip]
> >>>>> +
> >>>>> +static inline void
> >>>>> +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
> >>>>> +{
> >>>>> +	io_write32((uint32_t)val, lo);
> >>>>> +	io_write32(val >> 32,     hi);
> >>>> Firstly your second iowrite32 doesn't do the conversion.
> >>> Because it's not necessary. The first one is for retrieving the low 32
> >>> bits.
> >> I don't mean the shift operation, but the conversion from 64bit to 32bit.
> >> Same applied to below.
> > It's more than a casting here: it's same as "val & (1<<32 - 1)", as
> > stated above, to retrieve the low 32 bits.
> >
> > I know it still could work without it, but, hey, what's wrong to make
> > it explicit?
> 
> Say x = val, y = val >> 32, both with (uint32_t) or both not. Be
> consistent and simple.


fine.

	--yliu

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

* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support
  2016-01-18 16:50       ` Xie, Huawei
@ 2016-01-19  5:55         ` Yuanhan Liu
  2016-01-19  7:44           ` Xie, Huawei
  0 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-19  5:55 UTC (permalink / raw)
  To: Xie, Huawei; +Cc: dev

On Mon, Jan 18, 2016 at 04:50:16PM +0000, Xie, Huawei wrote:
> On 1/15/2016 12:34 PM, Yuanhan Liu wrote:
> > -static void
> > +static int
> >  virtio_negotiate_features(struct virtio_hw *hw)
> >  {
> >  	uint64_t host_features;
> > @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw)
> >  	hw->guest_features = vtpci_negotiate_features(hw, host_features);
> 
> Here if we are not modern device, we should remove VIRTIO_F_VERSION_1 in
> guest features.

VIRTIO_F_VERSION_1 should not be set for legacy virtio device at all.

	--yliu 

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

* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support
  2016-01-19  5:55         ` Yuanhan Liu
@ 2016-01-19  7:44           ` Xie, Huawei
  2016-01-19  7:54             ` Yuanhan Liu
  2016-01-19  8:02             ` Xie, Huawei
  0 siblings, 2 replies; 122+ messages in thread
From: Xie, Huawei @ 2016-01-19  7:44 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev

On 1/19/2016 1:53 PM, Yuanhan Liu wrote:
> On Mon, Jan 18, 2016 at 04:50:16PM +0000, Xie, Huawei wrote:
>> On 1/15/2016 12:34 PM, Yuanhan Liu wrote:
>>> -static void
>>> +static int
>>>  virtio_negotiate_features(struct virtio_hw *hw)
>>>  {
>>>  	uint64_t host_features;
>>> @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw)
>>>  	hw->guest_features = vtpci_negotiate_features(hw, host_features);
>> Here if we are not modern device, we should remove VIRTIO_F_VERSION_1 in
>> guest features.
> VIRTIO_F_VERSION_1 should not be set for legacy virtio device at all.

Yes, but here this patch sets this VIRTIO_F_VERSION_1 feature even for
legacy virtio device.
It doesn't cause issues, but better remove it for legacy virtio device.

>
> 	--yliu 
>


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

* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support
  2016-01-19  7:44           ` Xie, Huawei
@ 2016-01-19  7:54             ` Yuanhan Liu
  2016-01-19  8:02             ` Xie, Huawei
  1 sibling, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-19  7:54 UTC (permalink / raw)
  To: Xie, Huawei; +Cc: dev

On Tue, Jan 19, 2016 at 07:44:04AM +0000, Xie, Huawei wrote:
> On 1/19/2016 1:53 PM, Yuanhan Liu wrote:
> > On Mon, Jan 18, 2016 at 04:50:16PM +0000, Xie, Huawei wrote:
> >> On 1/15/2016 12:34 PM, Yuanhan Liu wrote:
> >>> -static void
> >>> +static int
> >>>  virtio_negotiate_features(struct virtio_hw *hw)
> >>>  {
> >>>  	uint64_t host_features;
> >>> @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw)
> >>>  	hw->guest_features = vtpci_negotiate_features(hw, host_features);
> >> Here if we are not modern device, we should remove VIRTIO_F_VERSION_1 in
> >> guest features.
> > VIRTIO_F_VERSION_1 should not be set for legacy virtio device at all.
> 
> Yes, but here this patch sets this VIRTIO_F_VERSION_1 feature even for
> legacy virtio device.
> It doesn't cause issues, but better remove it for legacy virtio device.

It's not set for legacy virtio device (at hw->guest_features), how could
you remove it then???

	--yliu

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

* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support
  2016-01-19  7:44           ` Xie, Huawei
  2016-01-19  7:54             ` Yuanhan Liu
@ 2016-01-19  8:02             ` Xie, Huawei
  1 sibling, 0 replies; 122+ messages in thread
From: Xie, Huawei @ 2016-01-19  8:02 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev

On 1/19/2016 3:44 PM, Xie, Huawei wrote:
> On 1/19/2016 1:53 PM, Yuanhan Liu wrote:
>> On Mon, Jan 18, 2016 at 04:50:16PM +0000, Xie, Huawei wrote:
>>> On 1/15/2016 12:34 PM, Yuanhan Liu wrote:
>>>> -static void
>>>> +static int
>>>>  virtio_negotiate_features(struct virtio_hw *hw)
>>>>  {
>>>>  	uint64_t host_features;
>>>> @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw)
>>>>  	hw->guest_features = vtpci_negotiate_features(hw, host_features);
>>> Here if we are not modern device, we should remove VIRTIO_F_VERSION_1 in
>>> guest features.
>> VIRTIO_F_VERSION_1 should not be set for legacy virtio device at all.
> Yes, but here this patch sets this VIRTIO_F_VERSION_1 feature even for
> legacy virtio device.
> It doesn't cause issues, but better remove it for legacy virtio device.

OK, I see the legacy_get_features return a 32bit value which masks the
higher bits which contains the host VIRTIO_F_VERSION_1 feature. This is
very implict.

>> 	--yliu 
>>
>


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

* [dpdk-dev] [PATCH v5 0/9] virtio 1.0 enabling for virtio pmd driver
  2016-01-15  4:36   ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
                       ` (8 preceding siblings ...)
  2016-01-18  8:04     ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Tetsuya Mukawa
@ 2016-01-19  8:11     ` Yuanhan Liu
  2016-01-19  8:11       ` [dpdk-dev] [PATCH v5 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu
                         ` (10 more replies)
  9 siblings, 11 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-19  8:11 UTC (permalink / raw)
  To: dev

v5: minor fixes:

    - fix wrong type of arg "offset" of read/write_dev_config(): patch 2
      is newly added for that.

    - check "offset + length" overflow

Almost all difference comes from virtio 1.0 are the PCI layout change:
the major configuration structures are stored at bar space, and their
location is stored at corresponding pci cap structure. Reading/parsing
them is one of the major work of patch 8.

To make handling virtio v1.0 and v0.95 co-exist well, this patch set
introduces a virtio_pci_ops structure, to add another layer so that
we could keep those vtpci_foo_bar "APIs". With that, we could do the
minimum change to add virtio 1.0 support.


Rough test guide
================

Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add
option "disable-modern=false" to qemu virtio-net-pci device to enable
virtio 1.0 (which is disabled by default).

And if you see something like following from 'lspci -v', it means virtio
1.0 is indeed enabled:

    00:04.0 Ethernet controller: Red Hat, Inc Virtio network device
    Subsystem: Red Hat, Inc Device 0001
    Physical Slot: 4
    Flags: bus master, fast devsel, latency 0, IRQ 11
    I/O ports at c040 [size=64]
    Memory at febf1000 (32-bit, non-prefetchable) [size=4K]
    Memory at fe000000 (64-bit, prefetchable) [size=8M]
    Expansion ROM at feb80000 [disabled] [size=256K]
    Capabilities: [98] MSI-X: Enable+ Count=6 Masked-
==> Capabilities: [84] Vendor Specific Information: Len=14 <?>
==> Capabilities: [70] Vendor Specific Information: Len=14 <?>
==> Capabilities: [60] Vendor Specific Information: Len=10 <?>
==> Capabilities: [50] Vendor Specific Information: Len=10 <?>
==> Capabilities: [40] Vendor Specific Information: Len=10 <?>
    Kernel driver in use: virtio-pci
    Kernel modules: virtio_pci

After that, there wasn't anything speical comparing to the old virtio
0.95 pmd driver.



---
Yuanhan Liu (9):
  virtio: don't set vring address again at queue startup
  virtio: define offset as size_t type
  virtio: introduce struct virtio_pci_ops
  virtio: move left pci stuff to virtio_pci.c
  viritio: switch to 64 bit features
  virtio: retrieve hdr_size from hw->vtnet_hdr_size
  eal: pci: export pci_[un]map_device
  virtio: add 1.0 support
  virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c

 doc/guides/rel_notes/release_2_3.rst            |   3 +
 drivers/net/virtio/virtio_ethdev.c              | 302 +--------
 drivers/net/virtio/virtio_ethdev.h              |   3 +-
 drivers/net/virtio/virtio_pci.c                 | 799 +++++++++++++++++++++++-
 drivers/net/virtio/virtio_pci.h                 | 124 +++-
 drivers/net/virtio/virtio_rxtx.c                |  21 +-
 drivers/net/virtio/virtio_rxtx_simple.c         |  12 +-
 drivers/net/virtio/virtqueue.h                  |   4 +-
 lib/librte_eal/bsdapp/eal/eal_pci.c             |   4 +-
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   7 +
 lib/librte_eal/common/eal_common_pci.c          |   4 +-
 lib/librte_eal/common/eal_private.h             |  18 -
 lib/librte_eal/common/include/rte_pci.h         |  27 +
 lib/librte_eal/linuxapp/eal/eal_pci.c           |   4 +-
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   7 +
 15 files changed, 957 insertions(+), 382 deletions(-)

-- 
1.9.0

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

* [dpdk-dev] [PATCH v5 1/9] virtio: don't set vring address again at queue startup
  2016-01-19  8:11     ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu
@ 2016-01-19  8:11       ` Yuanhan Liu
  2016-01-19  8:11       ` [dpdk-dev] [PATCH v5 2/9] virtio: define offset as size_t type Yuanhan Liu
                         ` (9 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-19  8:11 UTC (permalink / raw)
  To: dev

As we have already set up it at virtio_dev_queue_setup(), and a vq
restart will not reset the settings.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 drivers/net/virtio/virtio_rxtx.c | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index 74b39ef..b7267c0 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -339,11 +339,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type)
 		vq_update_avail_idx(vq);
 
 		PMD_INIT_LOG(DEBUG, "Allocated %d bufs", nbufs);
-
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 	} else if (queue_type == VTNET_TQ) {
 		if (use_simple_rxtx) {
 			int mid_idx  = vq->vq_nentries >> 1;
@@ -362,16 +357,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type)
 			for (i = mid_idx; i < vq->vq_nentries; i++)
 				vq->vq_ring.avail->ring[i] = i;
 		}
-
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
-	} else {
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 	}
 }
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH v5 2/9] virtio: define offset as size_t type
  2016-01-19  8:11     ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu
  2016-01-19  8:11       ` [dpdk-dev] [PATCH v5 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu
@ 2016-01-19  8:11       ` Yuanhan Liu
  2016-01-19  8:11       ` [dpdk-dev] [PATCH v5 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu
                         ` (8 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-19  8:11 UTC (permalink / raw)
  To: dev

offset arg of vtpci_read/write_dev_config is derived from offsetof(),
which is of size_t type, instead of uint64_t. So, define it as size_t
type.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 drivers/net/virtio/virtio_pci.c | 4 ++--
 drivers/net/virtio/virtio_pci.h | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 2245bec..b34b59e 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -38,7 +38,7 @@
 static uint8_t vtpci_get_status(struct virtio_hw *);
 
 void
-vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
+vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
 		void *dst, int length)
 {
 	uint64_t off;
@@ -61,7 +61,7 @@ vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 }
 
 void
-vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
+vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
 		void *src, int length)
 {
 	uint64_t off;
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index 47f722a..fe89c21 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -261,9 +261,9 @@ void vtpci_set_status(struct virtio_hw *, uint8_t);
 
 uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t);
 
-void vtpci_write_dev_config(struct virtio_hw *, uint64_t, void *, int);
+void vtpci_write_dev_config(struct virtio_hw *, size_t, void *, int);
 
-void vtpci_read_dev_config(struct virtio_hw *, uint64_t, void *, int);
+void vtpci_read_dev_config(struct virtio_hw *, size_t, void *, int);
 
 uint8_t vtpci_isr(struct virtio_hw *);
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH v5 3/9] virtio: introduce struct virtio_pci_ops
  2016-01-19  8:11     ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu
  2016-01-19  8:11       ` [dpdk-dev] [PATCH v5 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu
  2016-01-19  8:11       ` [dpdk-dev] [PATCH v5 2/9] virtio: define offset as size_t type Yuanhan Liu
@ 2016-01-19  8:11       ` Yuanhan Liu
  2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
                         ` (7 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-19  8:11 UTC (permalink / raw)
  To: dev

Introduce struct virtio_pci_ops, to let legacy virtio (v0.95) and
modern virtio (1.0) have different implementation regarding to a
specific pci action, such as read host status.

With that, this patch reimplements all exported pci functions, in
a way like:

	vtpci_foo_bar(struct virtio_hw *hw)
	{
		hw->vtpci_ops->foo_bar(hw);
	}

So that we need pay attention to those pci related functions only
while adding virtio 1.0 support.

This patch introduced a new vtpci function, vtpci_init(), to do
proper virtio pci settings. It's pretty simple so far: just sets
hw->vtpci_ops to legacy_ops as we don't support 1.0 yet.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
v5: - define "src" arg of vtpci_write_dev_config()
---
 drivers/net/virtio/virtio_ethdev.c |  22 ++---
 drivers/net/virtio/virtio_pci.c    | 164 ++++++++++++++++++++++++++++++-------
 drivers/net/virtio/virtio_pci.h    |  29 ++++++-
 drivers/net/virtio/virtqueue.h     |   2 +-
 4 files changed, 170 insertions(+), 47 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index d928339..6c1d3a0 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -272,9 +272,7 @@ virtio_dev_queue_release(struct virtqueue *vq) {
 
 	if (vq) {
 		hw = vq->hw;
-		/* Select and deactivate the queue */
-		VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+		hw->vtpci_ops->del_queue(hw, vq);
 
 		rte_free(vq->sw_ring);
 		rte_free(vq);
@@ -295,15 +293,13 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
 	struct virtio_hw *hw = dev->data->dev_private;
 	struct virtqueue *vq = NULL;
 
-	/* Write the virtqueue index to the Queue Select Field */
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vtpci_queue_idx);
-	PMD_INIT_LOG(DEBUG, "selecting queue: %u", vtpci_queue_idx);
+	PMD_INIT_LOG(DEBUG, "setting up queue: %u", vtpci_queue_idx);
 
 	/*
 	 * Read the virtqueue size from the Queue Size field
 	 * Always power of 2 and if 0 virtqueue does not exist
 	 */
-	vq_size = VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
+	vq_size = hw->vtpci_ops->get_queue_num(hw, vtpci_queue_idx);
 	PMD_INIT_LOG(DEBUG, "vq_size: %u nb_desc:%u", vq_size, nb_desc);
 	if (vq_size == 0) {
 		PMD_INIT_LOG(ERR, "%s: virtqueue does not exist", __func__);
@@ -436,12 +432,8 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
 		memset(vq->virtio_net_hdr_mz->addr, 0, PAGE_SIZE);
 	}
 
-	/*
-	 * Set guest physical address of the virtqueue
-	 * in VIRTIO_PCI_QUEUE_PFN config register of device
-	 */
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
-			mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+	hw->vtpci_ops->setup_queue(hw, vq);
+
 	*pvq = vq;
 	return 0;
 }
@@ -950,7 +942,7 @@ virtio_negotiate_features(struct virtio_hw *hw)
 		hw->guest_features);
 
 	/* Read device(host) feature bits */
-	host_features = VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+	host_features = hw->vtpci_ops->get_features(hw);
 	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x",
 		host_features);
 
@@ -1287,6 +1279,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 
+	vtpci_init(pci_dev, hw);
+
 	if (virtio_resource_init(pci_dev) < 0)
 		return -1;
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index b34b59e..8d001e8 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -34,12 +34,11 @@
 
 #include "virtio_pci.h"
 #include "virtio_logs.h"
+#include "virtqueue.h"
 
-static uint8_t vtpci_get_status(struct virtio_hw *);
-
-void
-vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
-		void *dst, int length)
+static void
+legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
+		       void *dst, int length)
 {
 	uint64_t off;
 	uint8_t *d;
@@ -60,22 +59,22 @@ vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
 	}
 }
 
-void
-vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
-		void *src, int length)
+static void
+legacy_write_dev_config(struct virtio_hw *hw, size_t offset,
+			const void *src, int length)
 {
 	uint64_t off;
-	uint8_t *s;
+	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, *(uint32_t *)s);
+			VIRTIO_WRITE_REG_4(hw, off, *(const uint32_t *)s);
 		} else if (length >= 2) {
 			size = 2;
-			VIRTIO_WRITE_REG_2(hw, off, *(uint16_t *)s);
+			VIRTIO_WRITE_REG_2(hw, off, *(const uint16_t *)s);
 		} else {
 			size = 1;
 			VIRTIO_WRITE_REG_1(hw, off, *s);
@@ -83,30 +82,133 @@ vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
 	}
 }
 
+static uint32_t
+legacy_get_features(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+}
+
+static void
+legacy_set_features(struct virtio_hw *hw, uint32_t features)
+{
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
+}
+
+static uint8_t
+legacy_get_status(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
+}
+
+static void
+legacy_set_status(struct virtio_hw *hw, uint8_t status)
+{
+	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+}
+
+static void
+legacy_reset(struct virtio_hw *hw)
+{
+	legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+}
+
+static uint8_t
+legacy_get_isr(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+}
+
+/* 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);
+}
+
+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);
+}
+
+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);
+
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
+		vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+}
+
+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);
+
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+}
+
+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);
+}
+
+
+static const struct virtio_pci_ops legacy_ops = {
+	.read_dev_cfg	= legacy_read_dev_config,
+	.write_dev_cfg	= legacy_write_dev_config,
+	.reset		= legacy_reset,
+	.get_status	= legacy_get_status,
+	.set_status	= legacy_set_status,
+	.get_features	= legacy_get_features,
+	.set_features	= legacy_set_features,
+	.get_isr	= legacy_get_isr,
+	.set_config_irq	= legacy_set_config_irq,
+	.get_queue_num	= legacy_get_queue_num,
+	.setup_queue	= legacy_setup_queue,
+	.del_queue	= legacy_del_queue,
+	.notify_queue	= legacy_notify_queue,
+};
+
+
+void
+vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
+		      void *dst, int length)
+{
+	hw->vtpci_ops->read_dev_cfg(hw, offset, dst, length);
+}
+
+void
+vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
+		       const void *src, int length)
+{
+	hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
+}
+
 uint32_t
 vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
 {
 	uint32_t features;
+
 	/*
 	 * Limit negotiated features to what the driver, virtqueue, and
 	 * host all support.
 	 */
 	features = host_features & hw->guest_features;
+	hw->vtpci_ops->set_features(hw, features);
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
 	return features;
 }
 
-
 void
 vtpci_reset(struct virtio_hw *hw)
 {
-	/*
-	 * Setting the status to RESET sets the host device to
-	 * the original, uninitialized state.
-	 */
-	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
-	vtpci_get_status(hw);
+	hw->vtpci_ops->set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+	/* flush status write */
+	hw->vtpci_ops->get_status(hw);
 }
 
 void
@@ -115,26 +217,19 @@ vtpci_reinit_complete(struct virtio_hw *hw)
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK);
 }
 
-static uint8_t
-vtpci_get_status(struct virtio_hw *hw)
-{
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
-}
-
 void
 vtpci_set_status(struct virtio_hw *hw, uint8_t status)
 {
 	if (status != VIRTIO_CONFIG_STATUS_RESET)
-		status = (uint8_t)(status | vtpci_get_status(hw));
+		status |= hw->vtpci_ops->get_status(hw);
 
-	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+	hw->vtpci_ops->set_status(hw, status);
 }
 
 uint8_t
 vtpci_isr(struct virtio_hw *hw)
 {
-
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+	return hw->vtpci_ops->get_isr(hw);
 }
 
 
@@ -142,6 +237,13 @@ vtpci_isr(struct virtio_hw *hw)
 uint16_t
 vtpci_irq_config(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);
+	return hw->vtpci_ops->set_config_irq(hw, vec);
+}
+
+int
+vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw)
+{
+	hw->vtpci_ops = &legacy_ops;
+
+	return 0;
 }
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index fe89c21..e8e7509 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -163,6 +163,31 @@ struct virtqueue;
  */
 #define VIRTIO_MAX_VIRTQUEUES 8
 
+struct virtio_hw;
+
+struct virtio_pci_ops {
+	void (*read_dev_cfg)(struct virtio_hw *hw, size_t offset,
+			     void *dst, int len);
+	void (*write_dev_cfg)(struct virtio_hw *hw, size_t offset,
+			      const void *src, int len);
+	void (*reset)(struct virtio_hw *hw);
+
+	uint8_t (*get_status)(struct virtio_hw *hw);
+	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
+
+	uint32_t (*get_features)(struct virtio_hw *hw);
+	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
+
+	uint8_t (*get_isr)(struct virtio_hw *hw);
+
+	uint16_t (*set_config_irq)(struct virtio_hw *hw, uint16_t vec);
+
+	uint16_t (*get_queue_num)(struct virtio_hw *hw, uint16_t queue_id);
+	void (*setup_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+	void (*del_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+	void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+};
+
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
@@ -174,6 +199,7 @@ struct virtio_hw {
 	uint8_t	    use_msix;
 	uint8_t     started;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
+	const struct virtio_pci_ops *vtpci_ops;
 };
 
 /*
@@ -253,6 +279,7 @@ vtpci_with_feature(struct virtio_hw *hw, uint32_t bit)
 /*
  * Function declaration from virtio_pci.c
  */
+int vtpci_init(struct rte_pci_device *, struct virtio_hw *);
 void vtpci_reset(struct virtio_hw *);
 
 void vtpci_reinit_complete(struct virtio_hw *);
@@ -261,7 +288,7 @@ void vtpci_set_status(struct virtio_hw *, uint8_t);
 
 uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t);
 
-void vtpci_write_dev_config(struct virtio_hw *, size_t, void *, int);
+void vtpci_write_dev_config(struct virtio_hw *, size_t, const void *, int);
 
 void vtpci_read_dev_config(struct virtio_hw *, size_t, void *, int);
 
diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h
index 61b3137..d7fb450 100644
--- a/drivers/net/virtio/virtqueue.h
+++ b/drivers/net/virtio/virtqueue.h
@@ -302,7 +302,7 @@ virtqueue_notify(struct virtqueue *vq)
 	 * For virtio on IA, the notificaiton is through io port operation
 	 * which is a serialization instruction itself.
 	 */
-	VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
+	vq->hw->vtpci_ops->notify_queue(vq->hw, vq);
 }
 
 #ifdef RTE_LIBRTE_VIRTIO_DEBUG_DUMP
-- 
1.9.0

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

* [dpdk-dev] [PATCH v5 4/9] virtio: move left pci stuff to virtio_pci.c
  2016-01-19  8:11     ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu
                         ` (2 preceding siblings ...)
  2016-01-19  8:11       ` [dpdk-dev] [PATCH v5 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu
@ 2016-01-19  8:12       ` Yuanhan Liu
  2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 5/9] viritio: switch to 64 bit features Yuanhan Liu
                         ` (6 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-19  8:12 UTC (permalink / raw)
  To: dev

virtio_pci.c is a more proper place for pci stuff; virtio_ethdev is not.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 drivers/net/virtio/virtio_ethdev.c | 265 +-----------------------------------
 drivers/net/virtio/virtio_pci.c    | 270 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 270 insertions(+), 265 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 6c1d3a0..b57224d 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -36,10 +36,6 @@
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
-#ifdef RTE_EXEC_ENV_LINUXAPP
-#include <dirent.h>
-#include <fcntl.h>
-#endif
 
 #include <rte_ethdev.h>
 #include <rte_memcpy.h>
@@ -955,260 +951,6 @@ virtio_negotiate_features(struct virtio_hw *hw)
 		hw->guest_features);
 }
 
-#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
-virtio_has_msix(const struct rte_pci_addr *loc)
-{
-	DIR *d;
-	char dirname[PATH_MAX];
-
-	snprintf(dirname, sizeof(dirname),
-		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
-		     loc->domain, loc->bus, loc->devid, loc->function);
-
-	d = opendir(dirname);
-	if (d)
-		closedir(d);
-
-	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 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
-virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
-{
-	/* nic_uio does not enable interrupts, return 0 (false). */
-	return 0;
-}
-
-static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
-{
-	/* no setup required */
-	return 0;
-}
-#endif
-
 /*
  * Process Virtio Config changed interrupt and call the callback
  * if link state changed.
@@ -1279,14 +1021,9 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 
-	vtpci_init(pci_dev, hw);
-
-	if (virtio_resource_init(pci_dev) < 0)
+	if (vtpci_init(pci_dev, hw) < 0)
 		return -1;
 
-	hw->use_msix = virtio_has_msix(&pci_dev->addr);
-	hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr;
-
 	/* Reset the device although not necessary at startup */
 	vtpci_reset(hw);
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 8d001e8..16485fa 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -32,6 +32,11 @@
  */
 #include <stdint.h>
 
+#ifdef RTE_EXEC_ENV_LINUXAPP
+ #include <dirent.h>
+ #include <fcntl.h>
+#endif
+
 #include "virtio_pci.h"
 #include "virtio_logs.h"
 #include "virtqueue.h"
@@ -156,6 +161,264 @@ legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
 	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
 }
 
+#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;
+	char dirname[PATH_MAX];
+
+	snprintf(dirname, sizeof(dirname),
+		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
+		     loc->domain, loc->bus, loc->devid, loc->function);
+
+	d = opendir(dirname);
+	if (d)
+		closedir(d);
+
+	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
+legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
+{
+	/* nic_uio does not enable interrupts, return 0 (false). */
+	return 0;
+}
+
+static int
+legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
+{
+	/* no setup required */
+	return 0;
+}
+#endif
 
 static const struct virtio_pci_ops legacy_ops = {
 	.read_dev_cfg	= legacy_read_dev_config,
@@ -241,9 +504,14 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
 }
 
 int
-vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw)
+vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 {
 	hw->vtpci_ops = &legacy_ops;
 
+	if (legacy_virtio_resource_init(dev) < 0)
+		return -1;
+	hw->use_msix = legacy_virtio_has_msix(&dev->addr);
+	hw->io_base  = (uint32_t)(uintptr_t)dev->mem_resource[0].addr;
+
 	return 0;
 }
-- 
1.9.0

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

* [dpdk-dev] [PATCH v5 5/9] viritio: switch to 64 bit features
  2016-01-19  8:11     ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu
                         ` (3 preceding siblings ...)
  2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
@ 2016-01-19  8:12       ` Yuanhan Liu
  2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
                         ` (5 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-19  8:12 UTC (permalink / raw)
  To: dev

Switch to 64 bit features, which virtio 1.0 supports.

While legacy virtio only supports 32 bit features, it complains aloud
and quit when trying to setting > 32 bit features.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 drivers/net/virtio/virtio_ethdev.c |  8 ++++----
 drivers/net/virtio/virtio_pci.c    | 15 ++++++++++-----
 drivers/net/virtio/virtio_pci.h    | 12 ++++++------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index b57224d..94e0c4a 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -930,16 +930,16 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 static void
 virtio_negotiate_features(struct virtio_hw *hw)
 {
-	uint32_t host_features;
+	uint64_t host_features;
 
 	/* Prepare guest_features: feature that driver wants to support */
 	hw->guest_features = VIRTIO_PMD_GUEST_FEATURES;
-	PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %"PRIx64,
 		hw->guest_features);
 
 	/* Read device(host) feature bits */
 	host_features = hw->vtpci_ops->get_features(hw);
-	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %"PRIx64,
 		host_features);
 
 	/*
@@ -947,7 +947,7 @@ virtio_negotiate_features(struct virtio_hw *hw)
 	 * guest feature bits.
 	 */
 	hw->guest_features = vtpci_negotiate_features(hw, host_features);
-	PMD_INIT_LOG(DEBUG, "features after negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,
 		hw->guest_features);
 }
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 16485fa..5e1c55f 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -87,15 +87,20 @@ legacy_write_dev_config(struct virtio_hw *hw, size_t offset,
 	}
 }
 
-static uint32_t
+static uint64_t
 legacy_get_features(struct virtio_hw *hw)
 {
 	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
 }
 
 static void
-legacy_set_features(struct virtio_hw *hw, uint32_t features)
+legacy_set_features(struct virtio_hw *hw, uint64_t features)
 {
+	if ((features >> 32) != 0) {
+		PMD_DRV_LOG(ERR,
+			"only 32 bit features are allowed for legacy virtio!");
+		return;
+	}
 	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
 }
 
@@ -451,10 +456,10 @@ vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
 	hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
 }
 
-uint32_t
-vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
+uint64_t
+vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features)
 {
-	uint32_t features;
+	uint64_t features;
 
 	/*
 	 * Limit negotiated features to what the driver, virtqueue, and
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index e8e7509..d7bc6bb 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -175,8 +175,8 @@ struct virtio_pci_ops {
 	uint8_t (*get_status)(struct virtio_hw *hw);
 	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
 
-	uint32_t (*get_features)(struct virtio_hw *hw);
-	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
+	uint64_t (*get_features)(struct virtio_hw *hw);
+	void     (*set_features)(struct virtio_hw *hw, uint64_t features);
 
 	uint8_t (*get_isr)(struct virtio_hw *hw);
 
@@ -191,7 +191,7 @@ struct virtio_pci_ops {
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
-	uint32_t    guest_features;
+	uint64_t    guest_features;
 	uint32_t    max_tx_queues;
 	uint32_t    max_rx_queues;
 	uint16_t    vtnet_hdr_size;
@@ -271,9 +271,9 @@ outl_p(unsigned int data, unsigned int port)
 	outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
 
 static inline int
-vtpci_with_feature(struct virtio_hw *hw, uint32_t bit)
+vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-	return (hw->guest_features & (1u << bit)) != 0;
+	return (hw->guest_features & (1ULL << bit)) != 0;
 }
 
 /*
@@ -286,7 +286,7 @@ void vtpci_reinit_complete(struct virtio_hw *);
 
 void vtpci_set_status(struct virtio_hw *, uint8_t);
 
-uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t);
+uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t);
 
 void vtpci_write_dev_config(struct virtio_hw *, size_t, const void *, int);
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH v5 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size
  2016-01-19  8:11     ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu
                         ` (4 preceding siblings ...)
  2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 5/9] viritio: switch to 64 bit features Yuanhan Liu
@ 2016-01-19  8:12       ` Yuanhan Liu
  2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu
                         ` (4 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-19  8:12 UTC (permalink / raw)
  To: dev

The mergeable virtio net hdr format has been the standard and the
only virtio net hdr format since virtio 1.0. Therefore, we can
not hardcode hdr_size to "sizeof(struct virtio_net_hdr)" any more
at virtio_recv_pkts(), otherwise, there would be a mismatch of
hdr size from rte_vhost_enqueue_burst() and virtio_recv_pkts(),
leading a packet corruption.

Instead, we should retrieve it from hw->vtnet_hdr_size; we will
do proper settings at eth_virtio_dev_init() in later patches.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
---
 drivers/net/virtio/virtio_rxtx.c        |  6 ++++--
 drivers/net/virtio/virtio_rxtx_simple.c | 12 ++++++------
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index b7267c0..41a1366 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -560,7 +560,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 	struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
 	int error;
 	uint32_t i, nb_enqueued;
-	const uint32_t hdr_size = sizeof(struct virtio_net_hdr);
+	uint32_t hdr_size;
 
 	nb_used = VIRTQUEUE_NUSED(rxvq);
 
@@ -580,6 +580,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 	hw = rxvq->hw;
 	nb_rx = 0;
 	nb_enqueued = 0;
+	hdr_size = hw->vtnet_hdr_size;
 
 	for (i = 0; i < num ; i++) {
 		rxm = rcv_pkts[i];
@@ -664,7 +665,7 @@ virtio_recv_mergeable_pkts(void *rx_queue,
 	uint32_t seg_num;
 	uint16_t extra_idx;
 	uint32_t seg_res;
-	const uint32_t hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+	uint32_t hdr_size;
 
 	nb_used = VIRTQUEUE_NUSED(rxvq);
 
@@ -682,6 +683,7 @@ virtio_recv_mergeable_pkts(void *rx_queue,
 	seg_num = 0;
 	extra_idx = 0;
 	seg_res = 0;
+	hdr_size = hw->vtnet_hdr_size;
 
 	while (i < nb_used) {
 		struct virtio_net_hdr_mrg_rxbuf *header;
diff --git a/drivers/net/virtio/virtio_rxtx_simple.c b/drivers/net/virtio/virtio_rxtx_simple.c
index ff3c11a..3e66e8b 100644
--- a/drivers/net/virtio/virtio_rxtx_simple.c
+++ b/drivers/net/virtio/virtio_rxtx_simple.c
@@ -81,9 +81,9 @@ virtqueue_enqueue_recv_refill_simple(struct virtqueue *vq,
 
 	start_dp = vq->vq_ring.desc;
 	start_dp[desc_idx].addr = (uint64_t)((uintptr_t)cookie->buf_physaddr +
-		RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr));
+		RTE_PKTMBUF_HEADROOM - vq->hw->vtnet_hdr_size);
 	start_dp[desc_idx].len = cookie->buf_len -
-		RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr);
+		RTE_PKTMBUF_HEADROOM + vq->hw->vtnet_hdr_size;
 
 	vq->vq_free_cnt--;
 	vq->vq_avail_idx++;
@@ -120,9 +120,9 @@ virtio_rxq_rearm_vec(struct virtqueue *rxvq)
 
 		start_dp[i].addr =
 			(uint64_t)((uintptr_t)sw_ring[i]->buf_physaddr +
-			RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr));
+			RTE_PKTMBUF_HEADROOM - rxvq->hw->vtnet_hdr_size);
 		start_dp[i].len = sw_ring[i]->buf_len -
-			RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr);
+			RTE_PKTMBUF_HEADROOM + rxvq->hw->vtnet_hdr_size;
 	}
 
 	rxvq->vq_avail_idx += RTE_VIRTIO_VPMD_RX_REARM_THRESH;
@@ -175,8 +175,8 @@ virtio_recv_pkts_vec(void *rx_queue, struct rte_mbuf **rx_pkts,
 	len_adjust = _mm_set_epi16(
 		0, 0,
 		0,
-		(uint16_t) -sizeof(struct virtio_net_hdr),
-		0, (uint16_t) -sizeof(struct virtio_net_hdr),
+		(uint16_t) -rxvq->hw->vtnet_hdr_size,
+		0, (uint16_t) -rxvq->hw->vtnet_hdr_size,
 		0, 0);
 
 	if (unlikely(nb_pkts < RTE_VIRTIO_DESC_PER_LOOP))
-- 
1.9.0

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

* [dpdk-dev] [PATCH v5 7/9] eal: pci: export pci_[un]map_device
  2016-01-19  8:11     ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu
                         ` (5 preceding siblings ...)
  2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
@ 2016-01-19  8:12       ` Yuanhan Liu
  2016-01-19  8:17         ` David Marchand
  2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support Yuanhan Liu
                         ` (3 subsequent siblings)
  10 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-19  8:12 UTC (permalink / raw)
  To: dev

Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will
invoke pci_map_device internally for us. From that point view, there
is no need to export pci_map_device.

However, for virtio pmd driver, which is designed to work without
binding UIO (or something similar first), pci_map_device() will fail,
which ends up with virtio pmd driver being skipped. Therefore, we can
not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver.

Therefore, this patch exports pci_map_device, and let virtio pmd
call it when necessary.

Cc: David Marchand <david.marchand@6wind.com>
Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-By: Santosh Shukla <sshukla@mvista.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 lib/librte_eal/bsdapp/eal/eal_pci.c             |  4 ++--
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |  7 +++++++
 lib/librte_eal/common/eal_common_pci.c          |  4 ++--
 lib/librte_eal/common/eal_private.h             | 18 -----------------
 lib/librte_eal/common/include/rte_pci.h         | 27 +++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c           |  4 ++--
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |  7 +++++++
 7 files changed, 47 insertions(+), 24 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 6c21fbd..95c32c1 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -93,7 +93,7 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused)
 
 /* Map pci device */
 int
-pci_map_device(struct rte_pci_device *dev)
+rte_eal_pci_map_device(struct rte_pci_device *dev)
 {
 	int ret = -1;
 
@@ -115,7 +115,7 @@ pci_map_device(struct rte_pci_device *dev)
 
 /* Unmap pci device */
 void
-pci_unmap_device(struct rte_pci_device *dev)
+rte_eal_pci_unmap_device(struct rte_pci_device *dev)
 {
 	/* try unmapping the NIC resources */
 	switch (dev->kdrv) {
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 9d7adf1..1b28170 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -135,3 +135,10 @@ DPDK_2.2 {
 	rte_xen_dom0_supported;
 
 } DPDK_2.1;
+
+DPDK_2.3 {
+	global:
+
+	rte_eal_pci_map_device;
+	rte_eal_pci_unmap_device;
+} DPDK_2.2;
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index dcfe947..96d5113 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -188,7 +188,7 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 			pci_config_space_set(dev);
 #endif
 			/* map resources for devices that use igb_uio */
-			ret = pci_map_device(dev);
+			ret = rte_eal_pci_map_device(dev);
 			if (ret != 0)
 				return ret;
 		} else if (dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND &&
@@ -254,7 +254,7 @@ rte_eal_pci_detach_dev(struct rte_pci_driver *dr,
 
 		if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
 			/* unmap resources for devices that use igb_uio */
-			pci_unmap_device(dev);
+			rte_eal_pci_unmap_device(dev);
 
 		return 0;
 	}
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index 072e672..2342fa1 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -165,24 +165,6 @@ struct rte_pci_device;
 int pci_unbind_kernel_driver(struct rte_pci_device *dev);
 
 /**
- * Map this device
- *
- * This function is private to EAL.
- *
- * @return
- *   0 on success, negative on error and positive if no driver
- *   is found for the device.
- */
-int pci_map_device(struct rte_pci_device *dev);
-
-/**
- * Unmap this device
- *
- * This function is private to EAL.
- */
-void pci_unmap_device(struct rte_pci_device *dev);
-
-/**
  * Map the PCI resource of a PCI device in virtual memory
  *
  * This function is private to EAL.
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 334c12e..2224109 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -485,6 +485,33 @@ 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);
+/**
+ * Map the PCI device resources in user space virtual memory address
+ *
+ * Note that driver should not call this function when flag
+ * RTE_PCI_DRV_NEED_MAPPING is set, as EAL will do that for
+ * you when it's on.
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device
+ *   to use
+ *
+ * @return
+ *   0 on success, negative on error and positive if no driver
+ *   is found for the device.
+ */
+int rte_eal_pci_map_device(struct rte_pci_device *dev);
+
+/**
+ * Unmap this device
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device
+ *   to use
+ */
+void rte_eal_pci_unmap_device(struct rte_pci_device *dev);
+
+
 
 #ifdef RTE_PCI_CONFIG
 /**
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index bc5b5be..db947da 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -124,7 +124,7 @@ pci_get_kernel_driver_by_path(const char *filename, char *dri_name)
 
 /* Map pci device */
 int
-pci_map_device(struct rte_pci_device *dev)
+rte_eal_pci_map_device(struct rte_pci_device *dev)
 {
 	int ret = -1;
 
@@ -153,7 +153,7 @@ pci_map_device(struct rte_pci_device *dev)
 
 /* Unmap pci device */
 void
-pci_unmap_device(struct rte_pci_device *dev)
+rte_eal_pci_unmap_device(struct rte_pci_device *dev)
 {
 	/* try unmapping the NIC resources using VFIO if it exists */
 	switch (dev->kdrv) {
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index cbe175f..b9937c4 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -138,3 +138,10 @@ DPDK_2.2 {
 	rte_xen_dom0_supported;
 
 } DPDK_2.1;
+
+DPDK_2.3 {
+	global:
+
+	rte_eal_pci_map_device;
+	rte_eal_pci_unmap_device;
+} DPDK_2.2;
-- 
1.9.0

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

* [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support
  2016-01-19  8:11     ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu
                         ` (6 preceding siblings ...)
  2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu
@ 2016-01-19  8:12       ` Yuanhan Liu
  2016-01-21 11:37         ` Thomas Monjalon
  2016-01-21 11:49         ` Thomas Monjalon
  2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
                         ` (2 subsequent siblings)
  10 siblings, 2 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-19  8:12 UTC (permalink / raw)
  To: dev

Modern (v1.0) virtio pci device defines several pci capabilities.
Each cap has a configure structure corresponding to it, and the
cap.bar and cap.offset fields tell us where to find it.

Firstly, we map the pci resources by rte_eal_pci_map_device().
We then could easily locate a cfg structure by:

    cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset;

Therefore, the entrance of enabling modern (v1.0) pci device support
is to iterate the pci capability lists, and to locate some configs
we care; and they are:

- common cfg

  For generic virtio and virtqueue configuration, such as setting/getting
  features, enabling a specific queue, and so on.

- nofity cfg

  Combining with `queue_notify_off' from common cfg, we could use it to
  notify a specific virt queue.

- device cfg

  Where virtio_net_config structure is located.

- isr cfg

  Where to read isr (interrupt status).

If any of above cap is not found, we fallback to the legacy virtio
handling.

If succeed, hw->vtpci_ops is assigned to modern_ops, where all
operations are implemented by reading/writing a (or few) specific
configuration space from above 4 cfg structures. And that's basically
how this patch works.

Besides those changes, virtio 1.0 introduces a new status field:
FEATURES_OK, which is set after features negotiation is done.

Last, set the VIRTIO_F_VERSION_1 feature flag.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---

v5: - rename MODERN_READ/WRITE_DEF macro name to IO_READ/WRITE_DEF

    - check offset + length overflow
---
 doc/guides/rel_notes/release_2_3.rst |   3 +
 drivers/net/virtio/virtio_ethdev.c   |  25 ++-
 drivers/net/virtio/virtio_ethdev.h   |   3 +-
 drivers/net/virtio/virtio_pci.c      | 341 ++++++++++++++++++++++++++++++++++-
 drivers/net/virtio/virtio_pci.h      |  67 +++++++
 drivers/net/virtio/virtqueue.h       |   2 +
 6 files changed, 436 insertions(+), 5 deletions(-)

diff --git a/doc/guides/rel_notes/release_2_3.rst b/doc/guides/rel_notes/release_2_3.rst
index 99de186..c390d97 100644
--- a/doc/guides/rel_notes/release_2_3.rst
+++ b/doc/guides/rel_notes/release_2_3.rst
@@ -4,6 +4,9 @@ DPDK Release 2.3
 New Features
 ------------
 
+* **Virtio 1.0 support.**
+
+  Enabled virtio 1.0 support for virtio pmd driver.
 
 Resolved Issues
 ---------------
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 94e0c4a..deb0382 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return virtio_send_command(hw->cvq, &ctrl, &len, 1);
 }
 
-static void
+static int
 virtio_negotiate_features(struct virtio_hw *hw)
 {
 	uint64_t host_features;
@@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw)
 	hw->guest_features = vtpci_negotiate_features(hw, host_features);
 	PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,
 		hw->guest_features);
+
+	if (hw->modern) {
+		if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) {
+			PMD_INIT_LOG(ERR,
+				"VIRTIO_F_VERSION_1 features is not enabled.");
+			return -1;
+		}
+		vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK);
+		if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) {
+			PMD_INIT_LOG(ERR,
+				"failed to set FEATURES_OK status!");
+			return -1;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -1032,7 +1048,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	/* Tell the host we've known how to drive the device. */
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
-	virtio_negotiate_features(hw);
+	if (virtio_negotiate_features(hw) < 0)
+		return -1;
 
 	/* If host does not support status then disable LSC */
 	if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS))
@@ -1043,7 +1060,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 	rx_func_get(eth_dev);
 
 	/* Setting up rx_header size for the device */
-	if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF))
+	if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) ||
+	    vtpci_with_feature(hw, VIRTIO_F_VERSION_1))
 		hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
 	else
 		hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr);
@@ -1159,6 +1177,7 @@ eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev)
 		rte_intr_callback_unregister(&pci_dev->intr_handle,
 						virtio_interrupt_handler,
 						eth_dev);
+	rte_eal_pci_unmap_device(pci_dev);
 
 	PMD_INIT_LOG(DEBUG, "dev_uninit completed");
 
diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h
index ae2d47d..fed9571 100644
--- a/drivers/net/virtio/virtio_ethdev.h
+++ b/drivers/net/virtio/virtio_ethdev.h
@@ -64,7 +64,8 @@
 	 1u << VIRTIO_NET_F_CTRL_VQ	  |	\
 	 1u << VIRTIO_NET_F_CTRL_RX	  |	\
 	 1u << VIRTIO_NET_F_CTRL_VLAN	  |	\
-	 1u << VIRTIO_NET_F_MRG_RXBUF)
+	 1u << VIRTIO_NET_F_MRG_RXBUF	  |	\
+	 1ULL << VIRTIO_F_VERSION_1)
 
 /*
  * CQ function prototype
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 5e1c55f..d7a453f 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -41,6 +41,14 @@
 #include "virtio_logs.h"
 #include "virtqueue.h"
 
+/*
+ * Following macros are derieved from linux/pci_regs.h, however,
+ * we can't simply include that header here, as there is no such
+ * file for non-Linux platform.
+ */
+#define PCI_CAPABILITY_LIST	0x34
+#define PCI_CAP_ID_VNDR		0x09
+
 static void
 legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
 		       void *dst, int length)
@@ -442,6 +450,204 @@ static const struct virtio_pci_ops legacy_ops = {
 };
 
 
+#define IO_READ_DEF(nr_bits, type)		\
+static inline type				\
+io_read##nr_bits(type *addr)			\
+{						\
+	return *(volatile type *)addr;		\
+}
+
+#define IO_WRITE_DEF(nr_bits, type)		\
+static inline void				\
+io_write##nr_bits(type val, type *addr)		\
+{						\
+	*(volatile type *)addr = val;		\
+}
+
+IO_READ_DEF (8, uint8_t)
+IO_WRITE_DEF(8, uint8_t)
+
+IO_READ_DEF (16, uint16_t)
+IO_WRITE_DEF(16, uint16_t)
+
+IO_READ_DEF (32, uint32_t)
+IO_WRITE_DEF(32, uint32_t)
+
+static inline void
+io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
+{
+	io_write32(val & ((1ULL << 32) - 1), lo);
+	io_write32(val >> 32,		     hi);
+}
+
+static void
+modern_read_dev_config(struct virtio_hw *hw, size_t offset,
+		       void *dst, int length)
+{
+	int i;
+	uint8_t *p;
+	uint8_t old_gen, new_gen;
+
+	do {
+		old_gen = io_read8(&hw->common_cfg->config_generation);
+
+		p = dst;
+		for (i = 0;  i < length; i++)
+			*p++ = io_read8((uint8_t *)hw->dev_cfg + offset + i);
+
+		new_gen = io_read8(&hw->common_cfg->config_generation);
+	} while (old_gen != new_gen);
+}
+
+static void
+modern_write_dev_config(struct virtio_hw *hw, size_t offset,
+			const void *src, int length)
+{
+	int i;
+	const uint8_t *p = src;
+
+	for (i = 0;  i < length; i++)
+		io_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i);
+}
+
+static uint64_t
+modern_get_features(struct virtio_hw *hw)
+{
+	uint32_t features_lo, features_hi;
+
+	io_write32(0, &hw->common_cfg->device_feature_select);
+	features_lo = io_read32(&hw->common_cfg->device_feature);
+
+	io_write32(1, &hw->common_cfg->device_feature_select);
+	features_hi = io_read32(&hw->common_cfg->device_feature);
+
+	return ((uint64_t)features_hi << 32) | features_lo;
+}
+
+static void
+modern_set_features(struct virtio_hw *hw, uint64_t features)
+{
+	io_write32(0, &hw->common_cfg->guest_feature_select);
+	io_write32(features & ((1ULL << 32) - 1),
+		&hw->common_cfg->guest_feature);
+
+	io_write32(1, &hw->common_cfg->guest_feature_select);
+	io_write32(features >> 32,
+		&hw->common_cfg->guest_feature);
+}
+
+static uint8_t
+modern_get_status(struct virtio_hw *hw)
+{
+	return io_read8(&hw->common_cfg->device_status);
+}
+
+static void
+modern_set_status(struct virtio_hw *hw, uint8_t status)
+{
+	io_write8(status, &hw->common_cfg->device_status);
+}
+
+static void
+modern_reset(struct virtio_hw *hw)
+{
+	modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+	modern_get_status(hw);
+}
+
+static uint8_t
+modern_get_isr(struct virtio_hw *hw)
+{
+	return io_read8(hw->isr);
+}
+
+static uint16_t
+modern_set_config_irq(struct virtio_hw *hw, uint16_t vec)
+{
+	io_write16(vec, &hw->common_cfg->msix_config);
+	return io_read16(&hw->common_cfg->msix_config);
+}
+
+static uint16_t
+modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
+{
+	io_write16(queue_id, &hw->common_cfg->queue_select);
+	return io_read16(&hw->common_cfg->queue_size);
+}
+
+static void
+modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
+{
+	uint64_t desc_addr, avail_addr, used_addr;
+	uint16_t notify_off;
+
+	desc_addr = vq->mz->phys_addr;
+	avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
+	used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail,
+							 ring[vq->vq_nentries]),
+				   VIRTIO_PCI_VRING_ALIGN);
+
+	io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
+
+	io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo,
+				      &hw->common_cfg->queue_desc_hi);
+	io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo,
+				       &hw->common_cfg->queue_avail_hi);
+	io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo,
+				      &hw->common_cfg->queue_used_hi);
+
+	notify_off = io_read16(&hw->common_cfg->queue_notify_off);
+	vq->notify_addr = (void *)((uint8_t *)hw->notify_base +
+				notify_off * hw->notify_off_multiplier);
+
+	io_write16(1, &hw->common_cfg->queue_enable);
+
+	PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index);
+	PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr);
+	PMD_INIT_LOG(DEBUG, "\t aval_addr: %"PRIx64, avail_addr);
+	PMD_INIT_LOG(DEBUG, "\t used_addr: %"PRIx64, used_addr);
+	PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)",
+		vq->notify_addr, notify_off);
+}
+
+static void
+modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
+{
+	io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
+
+	io_write64_twopart(0, &hw->common_cfg->queue_desc_lo,
+				  &hw->common_cfg->queue_desc_hi);
+	io_write64_twopart(0, &hw->common_cfg->queue_avail_lo,
+				  &hw->common_cfg->queue_avail_hi);
+	io_write64_twopart(0, &hw->common_cfg->queue_used_lo,
+				  &hw->common_cfg->queue_used_hi);
+
+	io_write16(0, &hw->common_cfg->queue_enable);
+}
+
+static void
+modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
+{
+	io_write16(1, vq->notify_addr);
+}
+
+static const struct virtio_pci_ops modern_ops = {
+	.read_dev_cfg	= modern_read_dev_config,
+	.write_dev_cfg	= modern_write_dev_config,
+	.reset		= modern_reset,
+	.get_status	= modern_get_status,
+	.set_status	= modern_set_status,
+	.get_features	= modern_get_features,
+	.set_features	= modern_set_features,
+	.get_isr	= modern_get_isr,
+	.set_config_irq	= modern_set_config_irq,
+	.get_queue_num	= modern_get_queue_num,
+	.setup_queue	= modern_setup_queue,
+	.del_queue	= modern_del_queue,
+	.notify_queue	= modern_notify_queue,
+};
+
+
 void
 vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
 		      void *dst, int length)
@@ -495,6 +701,12 @@ vtpci_set_status(struct virtio_hw *hw, uint8_t status)
 }
 
 uint8_t
+vtpci_get_status(struct virtio_hw *hw)
+{
+	return hw->vtpci_ops->get_status(hw);
+}
+
+uint8_t
 vtpci_isr(struct virtio_hw *hw)
 {
 	return hw->vtpci_ops->get_isr(hw);
@@ -508,15 +720,142 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
 	return hw->vtpci_ops->set_config_irq(hw, vec);
 }
 
+static void *
+get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)
+{
+	uint8_t  bar    = cap->bar;
+	uint32_t length = cap->length;
+	uint32_t offset = cap->offset;
+	uint8_t *base;
+
+	if (bar > 5) {
+		PMD_INIT_LOG(ERR, "invalid bar: %u", bar);
+		return NULL;
+	}
+
+	if (offset + length < offset) {
+		PMD_INIT_LOG(ERR, "offset(%u) + lenght(%u) overflows",
+			offset, length);
+		return NULL;
+	}
+
+	if (offset + length > dev->mem_resource[bar].len) {
+		PMD_INIT_LOG(ERR,
+			"invalid cap: overflows bar space: %u > %"PRIu64,
+			offset + length, dev->mem_resource[bar].len);
+		return NULL;
+	}
+
+	base = dev->mem_resource[bar].addr;
+	if (base == NULL) {
+		PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar);
+		return NULL;
+	}
+
+	return base + offset;
+}
+
+static int
+virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
+{
+	uint8_t pos;
+	struct virtio_pci_cap cap;
+	int ret;
+
+	if (rte_eal_pci_map_device(dev) < 0) {
+		PMD_INIT_LOG(DEBUG, "failed to map pci device!");
+		return -1;
+	}
+
+	ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST);
+	if (ret < 0) {
+		PMD_INIT_LOG(DEBUG, "failed to read pci capability list");
+		return -1;
+	}
+
+	while (pos) {
+		ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos);
+		if (ret < 0) {
+			PMD_INIT_LOG(ERR,
+				"failed to read pci cap at pos: %x", pos);
+			break;
+		}
+
+		if (cap.cap_vndr != PCI_CAP_ID_VNDR) {
+			PMD_INIT_LOG(DEBUG,
+				"[%2x] skipping non VNDR cap id: %02x",
+				pos, cap.cap_vndr);
+			goto next;
+		}
+
+		PMD_INIT_LOG(DEBUG,
+			"[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u",
+			pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
+
+		switch (cap.cfg_type) {
+		case VIRTIO_PCI_CAP_COMMON_CFG:
+			hw->common_cfg = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_NOTIFY_CFG:
+			rte_eal_pci_read_config(dev, &hw->notify_off_multiplier,
+						4, pos + sizeof(cap));
+			hw->notify_base = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_DEVICE_CFG:
+			hw->dev_cfg = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_ISR_CFG:
+			hw->isr = get_cfg_addr(dev, &cap);
+			break;
+		}
+
+	next:
+		pos = cap.cap_next;
+	}
+
+	if (hw->common_cfg == NULL || hw->notify_base == NULL ||
+	    hw->dev_cfg == NULL    || hw->isr == NULL) {
+		PMD_INIT_LOG(INFO, "no modern virtio pci device found.");
+		return -1;
+	}
+
+	PMD_INIT_LOG(INFO, "found modern virtio pci device.");
+
+	PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg);
+	PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg);
+	PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr);
+	PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u",
+		hw->notify_base, hw->notify_off_multiplier);
+
+	return 0;
+}
+
 int
 vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 {
-	hw->vtpci_ops = &legacy_ops;
+	hw->dev = dev;
+
+	/*
+	 * Try if we can succeed reading virtio pci caps, which exists
+	 * only on modern pci device. If failed, we fallback to legacy
+	 * virtio handling.
+	 */
+	if (virtio_read_caps(dev, hw) == 0) {
+		PMD_INIT_LOG(INFO, "modern virtio pci detected.");
+		hw->vtpci_ops = &modern_ops;
+		hw->modern    = 1;
+		dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
+		return 0;
+	}
 
+	PMD_INIT_LOG(INFO, "trying with legacy virtio pci.");
 	if (legacy_virtio_resource_init(dev) < 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 d7bc6bb..fcac660 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -93,6 +93,7 @@ struct virtqueue;
 #define VIRTIO_CONFIG_STATUS_ACK       0x01
 #define VIRTIO_CONFIG_STATUS_DRIVER    0x02
 #define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04
+#define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08
 #define VIRTIO_CONFIG_STATUS_FAILED    0x80
 
 /*
@@ -141,6 +142,8 @@ struct virtqueue;
 /* We support indirect buffer descriptors */
 #define VIRTIO_RING_F_INDIRECT_DESC	28
 
+#define VIRTIO_F_VERSION_1		32
+
 /*
  * Some VirtIO feature bits (currently bits 28 through 31) are
  * reserved for the transport being used (eg. virtio_ring), the
@@ -163,6 +166,60 @@ struct virtqueue;
  */
 #define VIRTIO_MAX_VIRTQUEUES 8
 
+/* Common configuration */
+#define VIRTIO_PCI_CAP_COMMON_CFG	1
+/* Notifications */
+#define VIRTIO_PCI_CAP_NOTIFY_CFG	2
+/* ISR Status */
+#define VIRTIO_PCI_CAP_ISR_CFG		3
+/* Device specific configuration */
+#define VIRTIO_PCI_CAP_DEVICE_CFG	4
+/* PCI configuration access */
+#define VIRTIO_PCI_CAP_PCI_CFG		5
+
+/* This is the PCI capability header: */
+struct virtio_pci_cap {
+	uint8_t cap_vndr;		/* Generic PCI field: PCI_CAP_ID_VNDR */
+	uint8_t cap_next;		/* Generic PCI field: next ptr. */
+	uint8_t cap_len;		/* Generic PCI field: capability length */
+	uint8_t cfg_type;		/* Identifies the structure. */
+	uint8_t bar;			/* Where to find it. */
+	uint8_t padding[3];		/* Pad to full dword. */
+	uint32_t offset;		/* Offset within bar. */
+	uint32_t length;		/* Length of the structure, in bytes. */
+};
+
+struct virtio_pci_notify_cap {
+	struct virtio_pci_cap cap;
+	uint32_t notify_off_multiplier;	/* Multiplier for queue_notify_off. */
+};
+
+/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */
+struct virtio_pci_common_cfg {
+	/* About the whole device. */
+	uint32_t device_feature_select;	/* read-write */
+	uint32_t device_feature;	/* read-only */
+	uint32_t guest_feature_select;	/* read-write */
+	uint32_t guest_feature;		/* read-write */
+	uint16_t msix_config;		/* read-write */
+	uint16_t num_queues;		/* read-only */
+	uint8_t device_status;		/* read-write */
+	uint8_t config_generation;	/* read-only */
+
+	/* About a specific virtqueue. */
+	uint16_t queue_select;		/* read-write */
+	uint16_t queue_size;		/* read-write, power of 2. */
+	uint16_t queue_msix_vector;	/* read-write */
+	uint16_t queue_enable;		/* read-write */
+	uint16_t queue_notify_off;	/* read-only */
+	uint32_t queue_desc_lo;		/* read-write */
+	uint32_t queue_desc_hi;		/* read-write */
+	uint32_t queue_avail_lo;	/* read-write */
+	uint32_t queue_avail_hi;	/* read-write */
+	uint32_t queue_used_lo;		/* read-write */
+	uint32_t queue_used_hi;		/* read-write */
+};
+
 struct virtio_hw;
 
 struct virtio_pci_ops {
@@ -188,6 +245,8 @@ struct virtio_pci_ops {
 	void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq);
 };
 
+struct virtio_net_config;
+
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
@@ -198,7 +257,14 @@ struct virtio_hw {
 	uint8_t	    vlan_strip;
 	uint8_t	    use_msix;
 	uint8_t     started;
+	uint8_t     modern;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
+	uint32_t    notify_off_multiplier;
+	uint8_t     *isr;
+	uint16_t    *notify_base;
+	struct rte_pci_device *dev;
+	struct virtio_pci_common_cfg *common_cfg;
+	struct virtio_net_config *dev_cfg;
 	const struct virtio_pci_ops *vtpci_ops;
 };
 
@@ -284,6 +350,7 @@ void vtpci_reset(struct virtio_hw *);
 
 void vtpci_reinit_complete(struct virtio_hw *);
 
+uint8_t vtpci_get_status(struct virtio_hw *);
 void vtpci_set_status(struct virtio_hw *, uint8_t);
 
 uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t);
diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h
index d7fb450..99d4fa9 100644
--- a/drivers/net/virtio/virtqueue.h
+++ b/drivers/net/virtio/virtqueue.h
@@ -202,6 +202,8 @@ struct virtqueue {
 	/* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */
 	uint64_t	size_bins[8];
 
+	uint16_t	*notify_addr;
+
 	struct vq_desc_extra {
 		void              *cookie;
 		uint16_t          ndescs;
-- 
1.9.0

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

* [dpdk-dev] [PATCH v5 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c
  2016-01-19  8:11     ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu
                         ` (7 preceding siblings ...)
  2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support Yuanhan Liu
@ 2016-01-19  8:12       ` Yuanhan Liu
  2016-01-19  8:55       ` [dpdk-dev] [PATCH v5 0/9] virtio 1.0 enabling for virtio pmd driver Xie, Huawei
  2016-01-28  7:54       ` [dpdk-dev] [PATCH v6 " Yuanhan Liu
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-19  8:12 UTC (permalink / raw)
  To: dev

virtio_pci.c is the only file references those macros; move them there.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
---
 drivers/net/virtio/virtio_pci.c | 19 +++++++++++++++++++
 drivers/net/virtio/virtio_pci.h | 18 ------------------
 2 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index d7a453f..6b87429 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -49,6 +49,25 @@
 #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))))
+
 static void
 legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
 		       void *dst, int length)
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index fcac660..0544a07 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -318,24 +318,6 @@ outl_p(unsigned int data, unsigned int port)
 }
 #endif
 
-#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))))
-
 static inline int
 vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-- 
1.9.0

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

* Re: [dpdk-dev] [PATCH v5 7/9] eal: pci: export pci_[un]map_device
  2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu
@ 2016-01-19  8:17         ` David Marchand
  0 siblings, 0 replies; 122+ messages in thread
From: David Marchand @ 2016-01-19  8:17 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev

On Tue, Jan 19, 2016 at 9:12 AM, Yuanhan Liu
<yuanhan.liu@linux.intel.com> wrote:
> Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will
> invoke pci_map_device internally for us. From that point view, there
> is no need to export pci_map_device.
>
> However, for virtio pmd driver, which is designed to work without
> binding UIO (or something similar first), pci_map_device() will fail,
> which ends up with virtio pmd driver being skipped. Therefore, we can
> not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver.
>
> Therefore, this patch exports pci_map_device, and let virtio pmd
> call it when necessary.
>
> Cc: David Marchand <david.marchand@6wind.com>
> Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
> Tested-By: Santosh Shukla <sshukla@mvista.com>
> Tested-by: Qian Xu <qian.q.xu@intel.com>
> Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
> Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>

lgtm
Acked-by: David Marchand <david.marchand@6wind.com>

-- 
David Marchand

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

* Re: [dpdk-dev] [PATCH v5 0/9] virtio 1.0 enabling for virtio pmd driver
  2016-01-19  8:11     ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu
                         ` (8 preceding siblings ...)
  2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
@ 2016-01-19  8:55       ` Xie, Huawei
  2016-01-28  7:54       ` [dpdk-dev] [PATCH v6 " Yuanhan Liu
  10 siblings, 0 replies; 122+ messages in thread
From: Xie, Huawei @ 2016-01-19  8:55 UTC (permalink / raw)
  To: Yuanhan Liu, dev

On 1/19/2016 4:10 PM, Yuanhan Liu wrote:
> v5: minor fixes:
>
>     - fix wrong type of arg "offset" of read/write_dev_config(): patch 2
>       is newly added for that.
>
>     - check "offset + length" overflow
>
> Almost all difference comes from virtio 1.0 are the PCI layout change:
> the major configuration structures are stored at bar space, and their
> location is stored at corresponding pci cap structure. Reading/parsing
> them is one of the major work of patch 8.
>
> To make handling virtio v1.0 and v0.95 co-exist well, this patch set
> introduces a virtio_pci_ops structure, to add another layer so that
> we could keep those vtpci_foo_bar "APIs". With that, we could do the
> minimum change to add virtio 1.0 support.
>
>
> Rough test guide
> ================
>
> Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add
> option "disable-modern=false" to qemu virtio-net-pci device to enable
> virtio 1.0 (which is disabled by default).
>
> And if you see something like following from 'lspci -v', it means virtio
> 1.0 is indeed enabled:
>
>     00:04.0 Ethernet controller: Red Hat, Inc Virtio network device
>     Subsystem: Red Hat, Inc Device 0001
>     Physical Slot: 4
>     Flags: bus master, fast devsel, latency 0, IRQ 11
>     I/O ports at c040 [size=64]
>     Memory at febf1000 (32-bit, non-prefetchable) [size=4K]
>     Memory at fe000000 (64-bit, prefetchable) [size=8M]
>     Expansion ROM at feb80000 [disabled] [size=256K]
>     Capabilities: [98] MSI-X: Enable+ Count=6 Masked-
> ==> Capabilities: [84] Vendor Specific Information: Len=14 <?>
> ==> Capabilities: [70] Vendor Specific Information: Len=14 <?>
> ==> Capabilities: [60] Vendor Specific Information: Len=10 <?>
> ==> Capabilities: [50] Vendor Specific Information: Len=10 <?>
> ==> Capabilities: [40] Vendor Specific Information: Len=10 <?>
>     Kernel driver in use: virtio-pci
>     Kernel modules: virtio_pci
>
> After that, there wasn't anything speical comparing to the old virtio
> 0.95 pmd driver.
>
>
>
> ---
> Yuanhan Liu (9):
>   virtio: don't set vring address again at queue startup
>   virtio: define offset as size_t type
>   virtio: introduce struct virtio_pci_ops
>   virtio: move left pci stuff to virtio_pci.c
>   viritio: switch to 64 bit features
>   virtio: retrieve hdr_size from hw->vtnet_hdr_size
>   eal: pci: export pci_[un]map_device
>   virtio: add 1.0 support
>   virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c
>
>  doc/guides/rel_notes/release_2_3.rst            |   3 +
>  drivers/net/virtio/virtio_ethdev.c              | 302 +--------
>  drivers/net/virtio/virtio_ethdev.h              |   3 +-
>  drivers/net/virtio/virtio_pci.c                 | 799 +++++++++++++++++++++++-
>  drivers/net/virtio/virtio_pci.h                 | 124 +++-
>  drivers/net/virtio/virtio_rxtx.c                |  21 +-
>  drivers/net/virtio/virtio_rxtx_simple.c         |  12 +-
>  drivers/net/virtio/virtqueue.h                  |   4 +-
>  lib/librte_eal/bsdapp/eal/eal_pci.c             |   4 +-
>  lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   7 +
>  lib/librte_eal/common/eal_common_pci.c          |   4 +-
>  lib/librte_eal/common/eal_private.h             |  18 -
>  lib/librte_eal/common/include/rte_pci.h         |  27 +
>  lib/librte_eal/linuxapp/eal/eal_pci.c           |   4 +-
>  lib/librte_eal/linuxapp/eal/rte_eal_version.map |   7 +
>  15 files changed, 957 insertions(+), 382 deletions(-)
>
Acked-by: Huawei Xie <huawei.xie@intel.com>

Next time, please include all the changes made in the change notice.

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

* Re: [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support
  2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support Yuanhan Liu
@ 2016-01-21 11:37         ` Thomas Monjalon
  2016-01-27  3:49           ` Yuanhan Liu
  2016-01-21 11:49         ` Thomas Monjalon
  1 sibling, 1 reply; 122+ messages in thread
From: Thomas Monjalon @ 2016-01-21 11:37 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev

2016-01-19 16:12, Yuanhan Liu:
> +#define IO_READ_DEF(nr_bits, type)             \
> +static inline type                             \
> +io_read##nr_bits(type *addr)                   \
> +{                                              \
> +       return *(volatile type *)addr;          \
> +}
> +
> +#define IO_WRITE_DEF(nr_bits, type)            \
> +static inline void                             \
> +io_write##nr_bits(type val, type *addr)                \
> +{                                              \
> +       *(volatile type *)addr = val;           \
> +}
> +
> +IO_READ_DEF (8, uint8_t)
> +IO_WRITE_DEF(8, uint8_t)
> +
> +IO_READ_DEF (16, uint16_t)
> +IO_WRITE_DEF(16, uint16_t)
> +
> +IO_READ_DEF (32, uint32_t)
> +IO_WRITE_DEF(32, uint32_t)

Yes you can do this.
But not sure you should.

> +static inline void
> +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
> +{
> +       io_write32(val & ((1ULL << 32) - 1), lo);
> +       io_write32(val >> 32,                hi);
> +}

When debugging this code, how GDB behave?
How to find the definition of io_write32() with grep or simple editors?

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

* Re: [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support
  2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support Yuanhan Liu
  2016-01-21 11:37         ` Thomas Monjalon
@ 2016-01-21 11:49         ` Thomas Monjalon
  2016-01-27  3:46           ` Yuanhan Liu
  1 sibling, 1 reply; 122+ messages in thread
From: Thomas Monjalon @ 2016-01-21 11:49 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev

2016-01-19 16:12, Yuanhan Liu:
>  int
>  vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
>  {
> -       hw->vtpci_ops = &legacy_ops;
> +       hw->dev = dev;
> +
> +       /*
> +        * Try if we can succeed reading virtio pci caps, which exists
> +        * only on modern pci device. If failed, we fallback to legacy
> +        * virtio handling.
> +        */
> +       if (virtio_read_caps(dev, hw) == 0) {
> +               PMD_INIT_LOG(INFO, "modern virtio pci detected.");
> +               hw->vtpci_ops = &modern_ops;
> +               hw->modern    = 1;
> +               dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
> +               return 0;
> +       }

RTE_PCI_DRV_INTR_LSC is already set by virtio_resource_init_by_uio().
Do you mean interrupt was not supported with legacy virtio?

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

* Re: [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support
  2016-01-21 11:49         ` Thomas Monjalon
@ 2016-01-27  3:46           ` Yuanhan Liu
  2016-01-27  8:11             ` Thomas Monjalon
  0 siblings, 1 reply; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-27  3:46 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

On Thu, Jan 21, 2016 at 12:49:10PM +0100, Thomas Monjalon wrote:
> 2016-01-19 16:12, Yuanhan Liu:
> >  int
> >  vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
> >  {
> > -       hw->vtpci_ops = &legacy_ops;
> > +       hw->dev = dev;
> > +
> > +       /*
> > +        * Try if we can succeed reading virtio pci caps, which exists
> > +        * only on modern pci device. If failed, we fallback to legacy
> > +        * virtio handling.
> > +        */
> > +       if (virtio_read_caps(dev, hw) == 0) {
> > +               PMD_INIT_LOG(INFO, "modern virtio pci detected.");
> > +               hw->vtpci_ops = &modern_ops;
> > +               hw->modern    = 1;
> > +               dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
> > +               return 0;
> > +       }
> 
> RTE_PCI_DRV_INTR_LSC is already set by virtio_resource_init_by_uio().

We don't go that far here. Here we just detect if it's a modern virtio
device. And if yes, we do some modern initiations, and return.

virtio_resource_init_by_uio() is invoked when virtio_read_caps() fails.

> Do you mean interrupt was not supported with legacy virtio?

Nope. this patch set changes nothing on legacy virtio support.

	--yliu

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

* Re: [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support
  2016-01-21 11:37         ` Thomas Monjalon
@ 2016-01-27  3:49           ` Yuanhan Liu
  0 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-27  3:49 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

On Thu, Jan 21, 2016 at 12:37:42PM +0100, Thomas Monjalon wrote:
> 2016-01-19 16:12, Yuanhan Liu:
> > +#define IO_READ_DEF(nr_bits, type)             \
> > +static inline type                             \
> > +io_read##nr_bits(type *addr)                   \
> > +{                                              \
> > +       return *(volatile type *)addr;          \
> > +}
> > +
> > +#define IO_WRITE_DEF(nr_bits, type)            \
> > +static inline void                             \
> > +io_write##nr_bits(type val, type *addr)                \
> > +{                                              \
> > +       *(volatile type *)addr = val;           \
> > +}
> > +
> > +IO_READ_DEF (8, uint8_t)
> > +IO_WRITE_DEF(8, uint8_t)
> > +
> > +IO_READ_DEF (16, uint16_t)
> > +IO_WRITE_DEF(16, uint16_t)
> > +
> > +IO_READ_DEF (32, uint32_t)
> > +IO_WRITE_DEF(32, uint32_t)
> 
> Yes you can do this.
> But not sure you should.
> 
> > +static inline void
> > +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
> > +{
> > +       io_write32(val & ((1ULL << 32) - 1), lo);
> > +       io_write32(val >> 32,                hi);
> > +}
> 
> When debugging this code, how GDB behave?
> How to find the definition of io_write32() with grep or simple editors?

Okay, I will unfold them.

	--yliu

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

* Re: [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support
  2016-01-27  3:46           ` Yuanhan Liu
@ 2016-01-27  8:11             ` Thomas Monjalon
  0 siblings, 0 replies; 122+ messages in thread
From: Thomas Monjalon @ 2016-01-27  8:11 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev

2016-01-27 11:46, Yuanhan Liu:
> On Thu, Jan 21, 2016 at 12:49:10PM +0100, Thomas Monjalon wrote:
> > 2016-01-19 16:12, Yuanhan Liu:
> > >  int
> > >  vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
> > >  {
> > > -       hw->vtpci_ops = &legacy_ops;
> > > +       hw->dev = dev;
> > > +
> > > +       /*
> > > +        * Try if we can succeed reading virtio pci caps, which exists
> > > +        * only on modern pci device. If failed, we fallback to legacy
> > > +        * virtio handling.
> > > +        */
> > > +       if (virtio_read_caps(dev, hw) == 0) {
> > > +               PMD_INIT_LOG(INFO, "modern virtio pci detected.");
> > > +               hw->vtpci_ops = &modern_ops;
> > > +               hw->modern    = 1;
> > > +               dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
> > > +               return 0;
> > > +       }
> > 
> > RTE_PCI_DRV_INTR_LSC is already set by virtio_resource_init_by_uio().
> 
> We don't go that far here. Here we just detect if it's a modern virtio
> device. And if yes, we do some modern initiations, and return.
> 
> virtio_resource_init_by_uio() is invoked when virtio_read_caps() fails.
> 
> > Do you mean interrupt was not supported with legacy virtio?
> 
> Nope. this patch set changes nothing on legacy virtio support.

Oh yes. I guess I had not seen the return.

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

* [dpdk-dev] [PATCH v6 0/9] virtio 1.0 enabling for virtio pmd driver
  2016-01-19  8:11     ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu
                         ` (9 preceding siblings ...)
  2016-01-19  8:55       ` [dpdk-dev] [PATCH v5 0/9] virtio 1.0 enabling for virtio pmd driver Xie, Huawei
@ 2016-01-28  7:54       ` Yuanhan Liu
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu
                           ` (10 more replies)
  10 siblings, 11 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-28  7:54 UTC (permalink / raw)
  To: dev

v6: unfold IO_READ/WRITE_DEF macro

v5: minor fixes:

    - fix wrong type of arg "offset" of read/write_dev_config(): patch 2
      is newly added for that.

    - check "offset + length" overflow

Almost all difference comes from virtio 1.0 are the PCI layout change:
the major configuration structures are stored at bar space, and their
location is stored at corresponding pci cap structure. Reading/parsing
them is one of the major work of patch 8.

To make handling virtio v1.0 and v0.95 co-exist well, this patch set
introduces a virtio_pci_ops structure, to add another layer so that
we could keep those vtpci_foo_bar "APIs". With that, we could do the
minimum change to add virtio 1.0 support.


Rough test guide
================

Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add
option "disable-modern=false" to qemu virtio-net-pci device to enable
virtio 1.0 (which is disabled by default).

And if you see something like following from 'lspci -v', it means virtio
1.0 is indeed enabled:

    00:04.0 Ethernet controller: Red Hat, Inc Virtio network device
    Subsystem: Red Hat, Inc Device 0001
    Physical Slot: 4
    Flags: bus master, fast devsel, latency 0, IRQ 11
    I/O ports at c040 [size=64]
    Memory at febf1000 (32-bit, non-prefetchable) [size=4K]
    Memory at fe000000 (64-bit, prefetchable) [size=8M]
    Expansion ROM at feb80000 [disabled] [size=256K]
    Capabilities: [98] MSI-X: Enable+ Count=6 Masked-
==> Capabilities: [84] Vendor Specific Information: Len=14 <?>
==> Capabilities: [70] Vendor Specific Information: Len=14 <?>
==> Capabilities: [60] Vendor Specific Information: Len=10 <?>
==> Capabilities: [50] Vendor Specific Information: Len=10 <?>
==> Capabilities: [40] Vendor Specific Information: Len=10 <?>
    Kernel driver in use: virtio-pci
    Kernel modules: virtio_pci

After that, there wasn't anything speical comparing to the old virtio
0.95 pmd driver.


---
Yuanhan Liu (9):
  virtio: don't set vring address again at queue startup
  virtio: define offset as size_t type
  virtio: introduce struct virtio_pci_ops
  virtio: move left pci stuff to virtio_pci.c
  viritio: switch to 64 bit features
  virtio: retrieve hdr_size from hw->vtnet_hdr_size
  eal: pci: export pci_[un]map_device
  virtio: add 1.0 support
  virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c

 doc/guides/rel_notes/release_2_3.rst            |   3 +
 drivers/net/virtio/virtio_ethdev.c              | 302 +--------
 drivers/net/virtio/virtio_ethdev.h              |   3 +-
 drivers/net/virtio/virtio_pci.c                 | 813 +++++++++++++++++++++++-
 drivers/net/virtio/virtio_pci.h                 | 124 +++-
 drivers/net/virtio/virtio_rxtx.c                |  21 +-
 drivers/net/virtio/virtio_rxtx_simple.c         |  12 +-
 drivers/net/virtio/virtqueue.h                  |   4 +-
 lib/librte_eal/bsdapp/eal/eal_pci.c             |   4 +-
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   7 +
 lib/librte_eal/common/eal_common_pci.c          |   4 +-
 lib/librte_eal/common/eal_private.h             |  18 -
 lib/librte_eal/common/include/rte_pci.h         |  27 +
 lib/librte_eal/linuxapp/eal/eal_pci.c           |   4 +-
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   7 +
 15 files changed, 971 insertions(+), 382 deletions(-)

-- 
1.9.0

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

* [dpdk-dev] [PATCH v6 1/9] virtio: don't set vring address again at queue startup
  2016-01-28  7:54       ` [dpdk-dev] [PATCH v6 " Yuanhan Liu
@ 2016-01-28  7:54         ` Yuanhan Liu
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 2/9] virtio: define offset as size_t type Yuanhan Liu
                           ` (9 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-28  7:54 UTC (permalink / raw)
  To: dev

As we have already set up it at virtio_dev_queue_setup(), and a vq
restart will not reset the settings.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
 drivers/net/virtio/virtio_rxtx.c | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index 74b39ef..b7267c0 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -339,11 +339,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type)
 		vq_update_avail_idx(vq);
 
 		PMD_INIT_LOG(DEBUG, "Allocated %d bufs", nbufs);
-
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 	} else if (queue_type == VTNET_TQ) {
 		if (use_simple_rxtx) {
 			int mid_idx  = vq->vq_nentries >> 1;
@@ -362,16 +357,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type)
 			for (i = mid_idx; i < vq->vq_nentries; i++)
 				vq->vq_ring.avail->ring[i] = i;
 		}
-
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
-	} else {
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 	}
 }
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH v6 2/9] virtio: define offset as size_t type
  2016-01-28  7:54       ` [dpdk-dev] [PATCH v6 " Yuanhan Liu
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu
@ 2016-01-28  7:54         ` Yuanhan Liu
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu
                           ` (8 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-28  7:54 UTC (permalink / raw)
  To: dev

offset arg of vtpci_read/write_dev_config is derived from offsetof(),
which is of size_t type, instead of uint64_t. So, define it as size_t
type.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
 drivers/net/virtio/virtio_pci.c | 4 ++--
 drivers/net/virtio/virtio_pci.h | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 2245bec..b34b59e 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -38,7 +38,7 @@
 static uint8_t vtpci_get_status(struct virtio_hw *);
 
 void
-vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
+vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
 		void *dst, int length)
 {
 	uint64_t off;
@@ -61,7 +61,7 @@ vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 }
 
 void
-vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
+vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
 		void *src, int length)
 {
 	uint64_t off;
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index 47f722a..fe89c21 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -261,9 +261,9 @@ void vtpci_set_status(struct virtio_hw *, uint8_t);
 
 uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t);
 
-void vtpci_write_dev_config(struct virtio_hw *, uint64_t, void *, int);
+void vtpci_write_dev_config(struct virtio_hw *, size_t, void *, int);
 
-void vtpci_read_dev_config(struct virtio_hw *, uint64_t, void *, int);
+void vtpci_read_dev_config(struct virtio_hw *, size_t, void *, int);
 
 uint8_t vtpci_isr(struct virtio_hw *);
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH v6 3/9] virtio: introduce struct virtio_pci_ops
  2016-01-28  7:54       ` [dpdk-dev] [PATCH v6 " Yuanhan Liu
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 2/9] virtio: define offset as size_t type Yuanhan Liu
@ 2016-01-28  7:54         ` Yuanhan Liu
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
                           ` (7 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-28  7:54 UTC (permalink / raw)
  To: dev

Introduce struct virtio_pci_ops, to let legacy virtio (v0.95) and
modern virtio (1.0) have different implementation regarding to a
specific pci action, such as read host status.

With that, this patch reimplements all exported pci functions, in
a way like:

	vtpci_foo_bar(struct virtio_hw *hw)
	{
		hw->vtpci_ops->foo_bar(hw);
	}

So that we need pay attention to those pci related functions only
while adding virtio 1.0 support.

This patch introduced a new vtpci function, vtpci_init(), to do
proper virtio pci settings. It's pretty simple so far: just sets
hw->vtpci_ops to legacy_ops as we don't support 1.0 yet.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
v5: - define "src" arg of vtpci_write_dev_config()
---
 drivers/net/virtio/virtio_ethdev.c |  22 ++---
 drivers/net/virtio/virtio_pci.c    | 164 ++++++++++++++++++++++++++++++-------
 drivers/net/virtio/virtio_pci.h    |  29 ++++++-
 drivers/net/virtio/virtqueue.h     |   2 +-
 4 files changed, 170 insertions(+), 47 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index d928339..6c1d3a0 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -272,9 +272,7 @@ virtio_dev_queue_release(struct virtqueue *vq) {
 
 	if (vq) {
 		hw = vq->hw;
-		/* Select and deactivate the queue */
-		VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+		hw->vtpci_ops->del_queue(hw, vq);
 
 		rte_free(vq->sw_ring);
 		rte_free(vq);
@@ -295,15 +293,13 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
 	struct virtio_hw *hw = dev->data->dev_private;
 	struct virtqueue *vq = NULL;
 
-	/* Write the virtqueue index to the Queue Select Field */
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vtpci_queue_idx);
-	PMD_INIT_LOG(DEBUG, "selecting queue: %u", vtpci_queue_idx);
+	PMD_INIT_LOG(DEBUG, "setting up queue: %u", vtpci_queue_idx);
 
 	/*
 	 * Read the virtqueue size from the Queue Size field
 	 * Always power of 2 and if 0 virtqueue does not exist
 	 */
-	vq_size = VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
+	vq_size = hw->vtpci_ops->get_queue_num(hw, vtpci_queue_idx);
 	PMD_INIT_LOG(DEBUG, "vq_size: %u nb_desc:%u", vq_size, nb_desc);
 	if (vq_size == 0) {
 		PMD_INIT_LOG(ERR, "%s: virtqueue does not exist", __func__);
@@ -436,12 +432,8 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
 		memset(vq->virtio_net_hdr_mz->addr, 0, PAGE_SIZE);
 	}
 
-	/*
-	 * Set guest physical address of the virtqueue
-	 * in VIRTIO_PCI_QUEUE_PFN config register of device
-	 */
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
-			mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+	hw->vtpci_ops->setup_queue(hw, vq);
+
 	*pvq = vq;
 	return 0;
 }
@@ -950,7 +942,7 @@ virtio_negotiate_features(struct virtio_hw *hw)
 		hw->guest_features);
 
 	/* Read device(host) feature bits */
-	host_features = VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+	host_features = hw->vtpci_ops->get_features(hw);
 	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x",
 		host_features);
 
@@ -1287,6 +1279,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 
+	vtpci_init(pci_dev, hw);
+
 	if (virtio_resource_init(pci_dev) < 0)
 		return -1;
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index b34b59e..8d001e8 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -34,12 +34,11 @@
 
 #include "virtio_pci.h"
 #include "virtio_logs.h"
+#include "virtqueue.h"
 
-static uint8_t vtpci_get_status(struct virtio_hw *);
-
-void
-vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
-		void *dst, int length)
+static void
+legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
+		       void *dst, int length)
 {
 	uint64_t off;
 	uint8_t *d;
@@ -60,22 +59,22 @@ vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
 	}
 }
 
-void
-vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
-		void *src, int length)
+static void
+legacy_write_dev_config(struct virtio_hw *hw, size_t offset,
+			const void *src, int length)
 {
 	uint64_t off;
-	uint8_t *s;
+	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, *(uint32_t *)s);
+			VIRTIO_WRITE_REG_4(hw, off, *(const uint32_t *)s);
 		} else if (length >= 2) {
 			size = 2;
-			VIRTIO_WRITE_REG_2(hw, off, *(uint16_t *)s);
+			VIRTIO_WRITE_REG_2(hw, off, *(const uint16_t *)s);
 		} else {
 			size = 1;
 			VIRTIO_WRITE_REG_1(hw, off, *s);
@@ -83,30 +82,133 @@ vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
 	}
 }
 
+static uint32_t
+legacy_get_features(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+}
+
+static void
+legacy_set_features(struct virtio_hw *hw, uint32_t features)
+{
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
+}
+
+static uint8_t
+legacy_get_status(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
+}
+
+static void
+legacy_set_status(struct virtio_hw *hw, uint8_t status)
+{
+	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+}
+
+static void
+legacy_reset(struct virtio_hw *hw)
+{
+	legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+}
+
+static uint8_t
+legacy_get_isr(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+}
+
+/* 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);
+}
+
+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);
+}
+
+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);
+
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
+		vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+}
+
+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);
+
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+}
+
+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);
+}
+
+
+static const struct virtio_pci_ops legacy_ops = {
+	.read_dev_cfg	= legacy_read_dev_config,
+	.write_dev_cfg	= legacy_write_dev_config,
+	.reset		= legacy_reset,
+	.get_status	= legacy_get_status,
+	.set_status	= legacy_set_status,
+	.get_features	= legacy_get_features,
+	.set_features	= legacy_set_features,
+	.get_isr	= legacy_get_isr,
+	.set_config_irq	= legacy_set_config_irq,
+	.get_queue_num	= legacy_get_queue_num,
+	.setup_queue	= legacy_setup_queue,
+	.del_queue	= legacy_del_queue,
+	.notify_queue	= legacy_notify_queue,
+};
+
+
+void
+vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
+		      void *dst, int length)
+{
+	hw->vtpci_ops->read_dev_cfg(hw, offset, dst, length);
+}
+
+void
+vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
+		       const void *src, int length)
+{
+	hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
+}
+
 uint32_t
 vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
 {
 	uint32_t features;
+
 	/*
 	 * Limit negotiated features to what the driver, virtqueue, and
 	 * host all support.
 	 */
 	features = host_features & hw->guest_features;
+	hw->vtpci_ops->set_features(hw, features);
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
 	return features;
 }
 
-
 void
 vtpci_reset(struct virtio_hw *hw)
 {
-	/*
-	 * Setting the status to RESET sets the host device to
-	 * the original, uninitialized state.
-	 */
-	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
-	vtpci_get_status(hw);
+	hw->vtpci_ops->set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+	/* flush status write */
+	hw->vtpci_ops->get_status(hw);
 }
 
 void
@@ -115,26 +217,19 @@ vtpci_reinit_complete(struct virtio_hw *hw)
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK);
 }
 
-static uint8_t
-vtpci_get_status(struct virtio_hw *hw)
-{
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
-}
-
 void
 vtpci_set_status(struct virtio_hw *hw, uint8_t status)
 {
 	if (status != VIRTIO_CONFIG_STATUS_RESET)
-		status = (uint8_t)(status | vtpci_get_status(hw));
+		status |= hw->vtpci_ops->get_status(hw);
 
-	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+	hw->vtpci_ops->set_status(hw, status);
 }
 
 uint8_t
 vtpci_isr(struct virtio_hw *hw)
 {
-
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+	return hw->vtpci_ops->get_isr(hw);
 }
 
 
@@ -142,6 +237,13 @@ vtpci_isr(struct virtio_hw *hw)
 uint16_t
 vtpci_irq_config(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);
+	return hw->vtpci_ops->set_config_irq(hw, vec);
+}
+
+int
+vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw)
+{
+	hw->vtpci_ops = &legacy_ops;
+
+	return 0;
 }
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index fe89c21..e8e7509 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -163,6 +163,31 @@ struct virtqueue;
  */
 #define VIRTIO_MAX_VIRTQUEUES 8
 
+struct virtio_hw;
+
+struct virtio_pci_ops {
+	void (*read_dev_cfg)(struct virtio_hw *hw, size_t offset,
+			     void *dst, int len);
+	void (*write_dev_cfg)(struct virtio_hw *hw, size_t offset,
+			      const void *src, int len);
+	void (*reset)(struct virtio_hw *hw);
+
+	uint8_t (*get_status)(struct virtio_hw *hw);
+	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
+
+	uint32_t (*get_features)(struct virtio_hw *hw);
+	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
+
+	uint8_t (*get_isr)(struct virtio_hw *hw);
+
+	uint16_t (*set_config_irq)(struct virtio_hw *hw, uint16_t vec);
+
+	uint16_t (*get_queue_num)(struct virtio_hw *hw, uint16_t queue_id);
+	void (*setup_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+	void (*del_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+	void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+};
+
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
@@ -174,6 +199,7 @@ struct virtio_hw {
 	uint8_t	    use_msix;
 	uint8_t     started;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
+	const struct virtio_pci_ops *vtpci_ops;
 };
 
 /*
@@ -253,6 +279,7 @@ vtpci_with_feature(struct virtio_hw *hw, uint32_t bit)
 /*
  * Function declaration from virtio_pci.c
  */
+int vtpci_init(struct rte_pci_device *, struct virtio_hw *);
 void vtpci_reset(struct virtio_hw *);
 
 void vtpci_reinit_complete(struct virtio_hw *);
@@ -261,7 +288,7 @@ void vtpci_set_status(struct virtio_hw *, uint8_t);
 
 uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t);
 
-void vtpci_write_dev_config(struct virtio_hw *, size_t, void *, int);
+void vtpci_write_dev_config(struct virtio_hw *, size_t, const void *, int);
 
 void vtpci_read_dev_config(struct virtio_hw *, size_t, void *, int);
 
diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h
index 61b3137..d7fb450 100644
--- a/drivers/net/virtio/virtqueue.h
+++ b/drivers/net/virtio/virtqueue.h
@@ -302,7 +302,7 @@ virtqueue_notify(struct virtqueue *vq)
 	 * For virtio on IA, the notificaiton is through io port operation
 	 * which is a serialization instruction itself.
 	 */
-	VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
+	vq->hw->vtpci_ops->notify_queue(vq->hw, vq);
 }
 
 #ifdef RTE_LIBRTE_VIRTIO_DEBUG_DUMP
-- 
1.9.0

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

* [dpdk-dev] [PATCH v6 4/9] virtio: move left pci stuff to virtio_pci.c
  2016-01-28  7:54       ` [dpdk-dev] [PATCH v6 " Yuanhan Liu
                           ` (2 preceding siblings ...)
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu
@ 2016-01-28  7:54         ` Yuanhan Liu
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 5/9] viritio: switch to 64 bit features Yuanhan Liu
                           ` (6 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-28  7:54 UTC (permalink / raw)
  To: dev

virtio_pci.c is a more proper place for pci stuff; virtio_ethdev is not.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
 drivers/net/virtio/virtio_ethdev.c | 265 +-----------------------------------
 drivers/net/virtio/virtio_pci.c    | 270 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 270 insertions(+), 265 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 6c1d3a0..b57224d 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -36,10 +36,6 @@
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
-#ifdef RTE_EXEC_ENV_LINUXAPP
-#include <dirent.h>
-#include <fcntl.h>
-#endif
 
 #include <rte_ethdev.h>
 #include <rte_memcpy.h>
@@ -955,260 +951,6 @@ virtio_negotiate_features(struct virtio_hw *hw)
 		hw->guest_features);
 }
 
-#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
-virtio_has_msix(const struct rte_pci_addr *loc)
-{
-	DIR *d;
-	char dirname[PATH_MAX];
-
-	snprintf(dirname, sizeof(dirname),
-		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
-		     loc->domain, loc->bus, loc->devid, loc->function);
-
-	d = opendir(dirname);
-	if (d)
-		closedir(d);
-
-	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 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
-virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
-{
-	/* nic_uio does not enable interrupts, return 0 (false). */
-	return 0;
-}
-
-static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
-{
-	/* no setup required */
-	return 0;
-}
-#endif
-
 /*
  * Process Virtio Config changed interrupt and call the callback
  * if link state changed.
@@ -1279,14 +1021,9 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 
-	vtpci_init(pci_dev, hw);
-
-	if (virtio_resource_init(pci_dev) < 0)
+	if (vtpci_init(pci_dev, hw) < 0)
 		return -1;
 
-	hw->use_msix = virtio_has_msix(&pci_dev->addr);
-	hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr;
-
 	/* Reset the device although not necessary at startup */
 	vtpci_reset(hw);
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 8d001e8..16485fa 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -32,6 +32,11 @@
  */
 #include <stdint.h>
 
+#ifdef RTE_EXEC_ENV_LINUXAPP
+ #include <dirent.h>
+ #include <fcntl.h>
+#endif
+
 #include "virtio_pci.h"
 #include "virtio_logs.h"
 #include "virtqueue.h"
@@ -156,6 +161,264 @@ legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
 	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
 }
 
+#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;
+	char dirname[PATH_MAX];
+
+	snprintf(dirname, sizeof(dirname),
+		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
+		     loc->domain, loc->bus, loc->devid, loc->function);
+
+	d = opendir(dirname);
+	if (d)
+		closedir(d);
+
+	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
+legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
+{
+	/* nic_uio does not enable interrupts, return 0 (false). */
+	return 0;
+}
+
+static int
+legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
+{
+	/* no setup required */
+	return 0;
+}
+#endif
 
 static const struct virtio_pci_ops legacy_ops = {
 	.read_dev_cfg	= legacy_read_dev_config,
@@ -241,9 +504,14 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
 }
 
 int
-vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw)
+vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 {
 	hw->vtpci_ops = &legacy_ops;
 
+	if (legacy_virtio_resource_init(dev) < 0)
+		return -1;
+	hw->use_msix = legacy_virtio_has_msix(&dev->addr);
+	hw->io_base  = (uint32_t)(uintptr_t)dev->mem_resource[0].addr;
+
 	return 0;
 }
-- 
1.9.0

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

* [dpdk-dev] [PATCH v6 5/9] viritio: switch to 64 bit features
  2016-01-28  7:54       ` [dpdk-dev] [PATCH v6 " Yuanhan Liu
                           ` (3 preceding siblings ...)
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
@ 2016-01-28  7:54         ` Yuanhan Liu
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
                           ` (5 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-28  7:54 UTC (permalink / raw)
  To: dev

Switch to 64 bit features, which virtio 1.0 supports.

While legacy virtio only supports 32 bit features, it complains aloud
and quit when trying to setting > 32 bit features.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
 drivers/net/virtio/virtio_ethdev.c |  8 ++++----
 drivers/net/virtio/virtio_pci.c    | 15 ++++++++++-----
 drivers/net/virtio/virtio_pci.h    | 12 ++++++------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index b57224d..94e0c4a 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -930,16 +930,16 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 static void
 virtio_negotiate_features(struct virtio_hw *hw)
 {
-	uint32_t host_features;
+	uint64_t host_features;
 
 	/* Prepare guest_features: feature that driver wants to support */
 	hw->guest_features = VIRTIO_PMD_GUEST_FEATURES;
-	PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %"PRIx64,
 		hw->guest_features);
 
 	/* Read device(host) feature bits */
 	host_features = hw->vtpci_ops->get_features(hw);
-	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %"PRIx64,
 		host_features);
 
 	/*
@@ -947,7 +947,7 @@ virtio_negotiate_features(struct virtio_hw *hw)
 	 * guest feature bits.
 	 */
 	hw->guest_features = vtpci_negotiate_features(hw, host_features);
-	PMD_INIT_LOG(DEBUG, "features after negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,
 		hw->guest_features);
 }
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 16485fa..5e1c55f 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -87,15 +87,20 @@ legacy_write_dev_config(struct virtio_hw *hw, size_t offset,
 	}
 }
 
-static uint32_t
+static uint64_t
 legacy_get_features(struct virtio_hw *hw)
 {
 	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
 }
 
 static void
-legacy_set_features(struct virtio_hw *hw, uint32_t features)
+legacy_set_features(struct virtio_hw *hw, uint64_t features)
 {
+	if ((features >> 32) != 0) {
+		PMD_DRV_LOG(ERR,
+			"only 32 bit features are allowed for legacy virtio!");
+		return;
+	}
 	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
 }
 
@@ -451,10 +456,10 @@ vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
 	hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
 }
 
-uint32_t
-vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
+uint64_t
+vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features)
 {
-	uint32_t features;
+	uint64_t features;
 
 	/*
 	 * Limit negotiated features to what the driver, virtqueue, and
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index e8e7509..d7bc6bb 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -175,8 +175,8 @@ struct virtio_pci_ops {
 	uint8_t (*get_status)(struct virtio_hw *hw);
 	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
 
-	uint32_t (*get_features)(struct virtio_hw *hw);
-	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
+	uint64_t (*get_features)(struct virtio_hw *hw);
+	void     (*set_features)(struct virtio_hw *hw, uint64_t features);
 
 	uint8_t (*get_isr)(struct virtio_hw *hw);
 
@@ -191,7 +191,7 @@ struct virtio_pci_ops {
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
-	uint32_t    guest_features;
+	uint64_t    guest_features;
 	uint32_t    max_tx_queues;
 	uint32_t    max_rx_queues;
 	uint16_t    vtnet_hdr_size;
@@ -271,9 +271,9 @@ outl_p(unsigned int data, unsigned int port)
 	outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
 
 static inline int
-vtpci_with_feature(struct virtio_hw *hw, uint32_t bit)
+vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-	return (hw->guest_features & (1u << bit)) != 0;
+	return (hw->guest_features & (1ULL << bit)) != 0;
 }
 
 /*
@@ -286,7 +286,7 @@ void vtpci_reinit_complete(struct virtio_hw *);
 
 void vtpci_set_status(struct virtio_hw *, uint8_t);
 
-uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t);
+uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t);
 
 void vtpci_write_dev_config(struct virtio_hw *, size_t, const void *, int);
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH v6 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size
  2016-01-28  7:54       ` [dpdk-dev] [PATCH v6 " Yuanhan Liu
                           ` (4 preceding siblings ...)
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 5/9] viritio: switch to 64 bit features Yuanhan Liu
@ 2016-01-28  7:54         ` Yuanhan Liu
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu
                           ` (4 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-28  7:54 UTC (permalink / raw)
  To: dev

The mergeable virtio net hdr format has been the standard and the
only virtio net hdr format since virtio 1.0. Therefore, we can
not hardcode hdr_size to "sizeof(struct virtio_net_hdr)" any more
at virtio_recv_pkts(), otherwise, there would be a mismatch of
hdr size from rte_vhost_enqueue_burst() and virtio_recv_pkts(),
leading a packet corruption.

Instead, we should retrieve it from hw->vtnet_hdr_size; we will
do proper settings at eth_virtio_dev_init() in later patches.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
---
 drivers/net/virtio/virtio_rxtx.c        |  6 ++++--
 drivers/net/virtio/virtio_rxtx_simple.c | 12 ++++++------
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index b7267c0..41a1366 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -560,7 +560,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 	struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
 	int error;
 	uint32_t i, nb_enqueued;
-	const uint32_t hdr_size = sizeof(struct virtio_net_hdr);
+	uint32_t hdr_size;
 
 	nb_used = VIRTQUEUE_NUSED(rxvq);
 
@@ -580,6 +580,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 	hw = rxvq->hw;
 	nb_rx = 0;
 	nb_enqueued = 0;
+	hdr_size = hw->vtnet_hdr_size;
 
 	for (i = 0; i < num ; i++) {
 		rxm = rcv_pkts[i];
@@ -664,7 +665,7 @@ virtio_recv_mergeable_pkts(void *rx_queue,
 	uint32_t seg_num;
 	uint16_t extra_idx;
 	uint32_t seg_res;
-	const uint32_t hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+	uint32_t hdr_size;
 
 	nb_used = VIRTQUEUE_NUSED(rxvq);
 
@@ -682,6 +683,7 @@ virtio_recv_mergeable_pkts(void *rx_queue,
 	seg_num = 0;
 	extra_idx = 0;
 	seg_res = 0;
+	hdr_size = hw->vtnet_hdr_size;
 
 	while (i < nb_used) {
 		struct virtio_net_hdr_mrg_rxbuf *header;
diff --git a/drivers/net/virtio/virtio_rxtx_simple.c b/drivers/net/virtio/virtio_rxtx_simple.c
index ff3c11a..3e66e8b 100644
--- a/drivers/net/virtio/virtio_rxtx_simple.c
+++ b/drivers/net/virtio/virtio_rxtx_simple.c
@@ -81,9 +81,9 @@ virtqueue_enqueue_recv_refill_simple(struct virtqueue *vq,
 
 	start_dp = vq->vq_ring.desc;
 	start_dp[desc_idx].addr = (uint64_t)((uintptr_t)cookie->buf_physaddr +
-		RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr));
+		RTE_PKTMBUF_HEADROOM - vq->hw->vtnet_hdr_size);
 	start_dp[desc_idx].len = cookie->buf_len -
-		RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr);
+		RTE_PKTMBUF_HEADROOM + vq->hw->vtnet_hdr_size;
 
 	vq->vq_free_cnt--;
 	vq->vq_avail_idx++;
@@ -120,9 +120,9 @@ virtio_rxq_rearm_vec(struct virtqueue *rxvq)
 
 		start_dp[i].addr =
 			(uint64_t)((uintptr_t)sw_ring[i]->buf_physaddr +
-			RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr));
+			RTE_PKTMBUF_HEADROOM - rxvq->hw->vtnet_hdr_size);
 		start_dp[i].len = sw_ring[i]->buf_len -
-			RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr);
+			RTE_PKTMBUF_HEADROOM + rxvq->hw->vtnet_hdr_size;
 	}
 
 	rxvq->vq_avail_idx += RTE_VIRTIO_VPMD_RX_REARM_THRESH;
@@ -175,8 +175,8 @@ virtio_recv_pkts_vec(void *rx_queue, struct rte_mbuf **rx_pkts,
 	len_adjust = _mm_set_epi16(
 		0, 0,
 		0,
-		(uint16_t) -sizeof(struct virtio_net_hdr),
-		0, (uint16_t) -sizeof(struct virtio_net_hdr),
+		(uint16_t) -rxvq->hw->vtnet_hdr_size,
+		0, (uint16_t) -rxvq->hw->vtnet_hdr_size,
 		0, 0);
 
 	if (unlikely(nb_pkts < RTE_VIRTIO_DESC_PER_LOOP))
-- 
1.9.0

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

* [dpdk-dev] [PATCH v6 7/9] eal: pci: export pci_[un]map_device
  2016-01-28  7:54       ` [dpdk-dev] [PATCH v6 " Yuanhan Liu
                           ` (5 preceding siblings ...)
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
@ 2016-01-28  7:54         ` Yuanhan Liu
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 8/9] virtio: add 1.0 support Yuanhan Liu
                           ` (3 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-28  7:54 UTC (permalink / raw)
  To: dev

Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will
invoke pci_map_device internally for us. From that point view, there
is no need to export pci_map_device.

However, for virtio pmd driver, which is designed to work without
binding UIO (or something similar first), pci_map_device() will fail,
which ends up with virtio pmd driver being skipped. Therefore, we can
not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver.

Therefore, this patch exports pci_map_device, and let virtio pmd
call it when necessary.

Cc: David Marchand <david.marchand@6wind.com>
Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-By: Santosh Shukla <sshukla@mvista.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: David Marchand <david.marchand@6wind.com>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
 lib/librte_eal/bsdapp/eal/eal_pci.c             |  4 ++--
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |  7 +++++++
 lib/librte_eal/common/eal_common_pci.c          |  4 ++--
 lib/librte_eal/common/eal_private.h             | 18 -----------------
 lib/librte_eal/common/include/rte_pci.h         | 27 +++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c           |  4 ++--
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |  7 +++++++
 7 files changed, 47 insertions(+), 24 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 6c21fbd..95c32c1 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -93,7 +93,7 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused)
 
 /* Map pci device */
 int
-pci_map_device(struct rte_pci_device *dev)
+rte_eal_pci_map_device(struct rte_pci_device *dev)
 {
 	int ret = -1;
 
@@ -115,7 +115,7 @@ pci_map_device(struct rte_pci_device *dev)
 
 /* Unmap pci device */
 void
-pci_unmap_device(struct rte_pci_device *dev)
+rte_eal_pci_unmap_device(struct rte_pci_device *dev)
 {
 	/* try unmapping the NIC resources */
 	switch (dev->kdrv) {
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 9d7adf1..1b28170 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -135,3 +135,10 @@ DPDK_2.2 {
 	rte_xen_dom0_supported;
 
 } DPDK_2.1;
+
+DPDK_2.3 {
+	global:
+
+	rte_eal_pci_map_device;
+	rte_eal_pci_unmap_device;
+} DPDK_2.2;
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index dcfe947..96d5113 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -188,7 +188,7 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 			pci_config_space_set(dev);
 #endif
 			/* map resources for devices that use igb_uio */
-			ret = pci_map_device(dev);
+			ret = rte_eal_pci_map_device(dev);
 			if (ret != 0)
 				return ret;
 		} else if (dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND &&
@@ -254,7 +254,7 @@ rte_eal_pci_detach_dev(struct rte_pci_driver *dr,
 
 		if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
 			/* unmap resources for devices that use igb_uio */
-			pci_unmap_device(dev);
+			rte_eal_pci_unmap_device(dev);
 
 		return 0;
 	}
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index 072e672..2342fa1 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -165,24 +165,6 @@ struct rte_pci_device;
 int pci_unbind_kernel_driver(struct rte_pci_device *dev);
 
 /**
- * Map this device
- *
- * This function is private to EAL.
- *
- * @return
- *   0 on success, negative on error and positive if no driver
- *   is found for the device.
- */
-int pci_map_device(struct rte_pci_device *dev);
-
-/**
- * Unmap this device
- *
- * This function is private to EAL.
- */
-void pci_unmap_device(struct rte_pci_device *dev);
-
-/**
  * Map the PCI resource of a PCI device in virtual memory
  *
  * This function is private to EAL.
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 334c12e..2224109 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -485,6 +485,33 @@ 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);
+/**
+ * Map the PCI device resources in user space virtual memory address
+ *
+ * Note that driver should not call this function when flag
+ * RTE_PCI_DRV_NEED_MAPPING is set, as EAL will do that for
+ * you when it's on.
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device
+ *   to use
+ *
+ * @return
+ *   0 on success, negative on error and positive if no driver
+ *   is found for the device.
+ */
+int rte_eal_pci_map_device(struct rte_pci_device *dev);
+
+/**
+ * Unmap this device
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device
+ *   to use
+ */
+void rte_eal_pci_unmap_device(struct rte_pci_device *dev);
+
+
 
 #ifdef RTE_PCI_CONFIG
 /**
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index bc5b5be..db947da 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -124,7 +124,7 @@ pci_get_kernel_driver_by_path(const char *filename, char *dri_name)
 
 /* Map pci device */
 int
-pci_map_device(struct rte_pci_device *dev)
+rte_eal_pci_map_device(struct rte_pci_device *dev)
 {
 	int ret = -1;
 
@@ -153,7 +153,7 @@ pci_map_device(struct rte_pci_device *dev)
 
 /* Unmap pci device */
 void
-pci_unmap_device(struct rte_pci_device *dev)
+rte_eal_pci_unmap_device(struct rte_pci_device *dev)
 {
 	/* try unmapping the NIC resources using VFIO if it exists */
 	switch (dev->kdrv) {
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index cbe175f..b9937c4 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -138,3 +138,10 @@ DPDK_2.2 {
 	rte_xen_dom0_supported;
 
 } DPDK_2.1;
+
+DPDK_2.3 {
+	global:
+
+	rte_eal_pci_map_device;
+	rte_eal_pci_unmap_device;
+} DPDK_2.2;
-- 
1.9.0

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

* [dpdk-dev] [PATCH v6 8/9] virtio: add 1.0 support
  2016-01-28  7:54       ` [dpdk-dev] [PATCH v6 " Yuanhan Liu
                           ` (6 preceding siblings ...)
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu
@ 2016-01-28  7:54         ` Yuanhan Liu
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
                           ` (2 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-28  7:54 UTC (permalink / raw)
  To: dev

Modern (v1.0) virtio pci device defines several pci capabilities.
Each cap has a configure structure corresponding to it, and the
cap.bar and cap.offset fields tell us where to find it.

Firstly, we map the pci resources by rte_eal_pci_map_device().
We then could easily locate a cfg structure by:

    cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset;

Therefore, the entrance of enabling modern (v1.0) pci device support
is to iterate the pci capability lists, and to locate some configs
we care; and they are:

- common cfg

  For generic virtio and virtqueue configuration, such as setting/getting
  features, enabling a specific queue, and so on.

- nofity cfg

  Combining with `queue_notify_off' from common cfg, we could use it to
  notify a specific virt queue.

- device cfg

  Where virtio_net_config structure is located.

- isr cfg

  Where to read isr (interrupt status).

If any of above cap is not found, we fallback to the legacy virtio
handling.

If succeed, hw->vtpci_ops is assigned to modern_ops, where all
operations are implemented by reading/writing a (or few) specific
configuration space from above 4 cfg structures. And that's basically
how this patch works.

Besides those changes, virtio 1.0 introduces a new status field:
FEATURES_OK, which is set after features negotiation is done.

Last, set the VIRTIO_F_VERSION_1 feature flag.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---

v6: - unfold DEF_IO_READ/WRITE macros

v5: - rename MODERN_READ/WRITE_DEF macro name to IO_READ/WRITE_DEF

    - check offset + length overflow
---
 doc/guides/rel_notes/release_2_3.rst |   3 +
 drivers/net/virtio/virtio_ethdev.c   |  25 ++-
 drivers/net/virtio/virtio_ethdev.h   |   3 +-
 drivers/net/virtio/virtio_pci.c      | 355 ++++++++++++++++++++++++++++++++++-
 drivers/net/virtio/virtio_pci.h      |  67 +++++++
 drivers/net/virtio/virtqueue.h       |   2 +
 6 files changed, 450 insertions(+), 5 deletions(-)

diff --git a/doc/guides/rel_notes/release_2_3.rst b/doc/guides/rel_notes/release_2_3.rst
index 99de186..c390d97 100644
--- a/doc/guides/rel_notes/release_2_3.rst
+++ b/doc/guides/rel_notes/release_2_3.rst
@@ -4,6 +4,9 @@ DPDK Release 2.3
 New Features
 ------------
 
+* **Virtio 1.0 support.**
+
+  Enabled virtio 1.0 support for virtio pmd driver.
 
 Resolved Issues
 ---------------
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 94e0c4a..deb0382 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return virtio_send_command(hw->cvq, &ctrl, &len, 1);
 }
 
-static void
+static int
 virtio_negotiate_features(struct virtio_hw *hw)
 {
 	uint64_t host_features;
@@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw)
 	hw->guest_features = vtpci_negotiate_features(hw, host_features);
 	PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,
 		hw->guest_features);
+
+	if (hw->modern) {
+		if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) {
+			PMD_INIT_LOG(ERR,
+				"VIRTIO_F_VERSION_1 features is not enabled.");
+			return -1;
+		}
+		vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK);
+		if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) {
+			PMD_INIT_LOG(ERR,
+				"failed to set FEATURES_OK status!");
+			return -1;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -1032,7 +1048,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	/* Tell the host we've known how to drive the device. */
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
-	virtio_negotiate_features(hw);
+	if (virtio_negotiate_features(hw) < 0)
+		return -1;
 
 	/* If host does not support status then disable LSC */
 	if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS))
@@ -1043,7 +1060,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 	rx_func_get(eth_dev);
 
 	/* Setting up rx_header size for the device */
-	if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF))
+	if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) ||
+	    vtpci_with_feature(hw, VIRTIO_F_VERSION_1))
 		hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
 	else
 		hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr);
@@ -1159,6 +1177,7 @@ eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev)
 		rte_intr_callback_unregister(&pci_dev->intr_handle,
 						virtio_interrupt_handler,
 						eth_dev);
+	rte_eal_pci_unmap_device(pci_dev);
 
 	PMD_INIT_LOG(DEBUG, "dev_uninit completed");
 
diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h
index ae2d47d..fed9571 100644
--- a/drivers/net/virtio/virtio_ethdev.h
+++ b/drivers/net/virtio/virtio_ethdev.h
@@ -64,7 +64,8 @@
 	 1u << VIRTIO_NET_F_CTRL_VQ	  |	\
 	 1u << VIRTIO_NET_F_CTRL_RX	  |	\
 	 1u << VIRTIO_NET_F_CTRL_VLAN	  |	\
-	 1u << VIRTIO_NET_F_MRG_RXBUF)
+	 1u << VIRTIO_NET_F_MRG_RXBUF	  |	\
+	 1ULL << VIRTIO_F_VERSION_1)
 
 /*
  * CQ function prototype
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 5e1c55f..2d3143b 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -41,6 +41,14 @@
 #include "virtio_logs.h"
 #include "virtqueue.h"
 
+/*
+ * Following macros are derieved from linux/pci_regs.h, however,
+ * we can't simply include that header here, as there is no such
+ * file for non-Linux platform.
+ */
+#define PCI_CAPABILITY_LIST	0x34
+#define PCI_CAP_ID_VNDR		0x09
+
 static void
 legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
 		       void *dst, int length)
@@ -442,6 +450,218 @@ static const struct virtio_pci_ops legacy_ops = {
 };
 
 
+
+static inline uint8_t
+io_read8(uint8_t *addr)
+{
+	return *(volatile uint8_t *)addr;
+}
+
+static inline void
+io_write8(uint8_t val, uint8_t *addr)
+{
+	*(volatile uint8_t *)addr = val;
+}
+
+static inline uint16_t
+io_read16(uint16_t *addr)
+{
+	return *(volatile uint16_t *)addr;
+}
+
+static inline void
+io_write16(uint16_t val, uint16_t *addr)
+{
+	*(volatile uint16_t *)addr = val;
+}
+
+static inline uint32_t
+io_read32(uint32_t *addr)
+{
+	return *(volatile uint32_t *)addr;
+}
+
+static inline void
+io_write32(uint32_t val, uint32_t *addr)
+{
+	*(volatile uint32_t *)addr = val;
+}
+
+static inline void
+io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
+{
+	io_write32(val & ((1ULL << 32) - 1), lo);
+	io_write32(val >> 32,		     hi);
+}
+
+static void
+modern_read_dev_config(struct virtio_hw *hw, size_t offset,
+		       void *dst, int length)
+{
+	int i;
+	uint8_t *p;
+	uint8_t old_gen, new_gen;
+
+	do {
+		old_gen = io_read8(&hw->common_cfg->config_generation);
+
+		p = dst;
+		for (i = 0;  i < length; i++)
+			*p++ = io_read8((uint8_t *)hw->dev_cfg + offset + i);
+
+		new_gen = io_read8(&hw->common_cfg->config_generation);
+	} while (old_gen != new_gen);
+}
+
+static void
+modern_write_dev_config(struct virtio_hw *hw, size_t offset,
+			const void *src, int length)
+{
+	int i;
+	const uint8_t *p = src;
+
+	for (i = 0;  i < length; i++)
+		io_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i);
+}
+
+static uint64_t
+modern_get_features(struct virtio_hw *hw)
+{
+	uint32_t features_lo, features_hi;
+
+	io_write32(0, &hw->common_cfg->device_feature_select);
+	features_lo = io_read32(&hw->common_cfg->device_feature);
+
+	io_write32(1, &hw->common_cfg->device_feature_select);
+	features_hi = io_read32(&hw->common_cfg->device_feature);
+
+	return ((uint64_t)features_hi << 32) | features_lo;
+}
+
+static void
+modern_set_features(struct virtio_hw *hw, uint64_t features)
+{
+	io_write32(0, &hw->common_cfg->guest_feature_select);
+	io_write32(features & ((1ULL << 32) - 1),
+		&hw->common_cfg->guest_feature);
+
+	io_write32(1, &hw->common_cfg->guest_feature_select);
+	io_write32(features >> 32,
+		&hw->common_cfg->guest_feature);
+}
+
+static uint8_t
+modern_get_status(struct virtio_hw *hw)
+{
+	return io_read8(&hw->common_cfg->device_status);
+}
+
+static void
+modern_set_status(struct virtio_hw *hw, uint8_t status)
+{
+	io_write8(status, &hw->common_cfg->device_status);
+}
+
+static void
+modern_reset(struct virtio_hw *hw)
+{
+	modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+	modern_get_status(hw);
+}
+
+static uint8_t
+modern_get_isr(struct virtio_hw *hw)
+{
+	return io_read8(hw->isr);
+}
+
+static uint16_t
+modern_set_config_irq(struct virtio_hw *hw, uint16_t vec)
+{
+	io_write16(vec, &hw->common_cfg->msix_config);
+	return io_read16(&hw->common_cfg->msix_config);
+}
+
+static uint16_t
+modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
+{
+	io_write16(queue_id, &hw->common_cfg->queue_select);
+	return io_read16(&hw->common_cfg->queue_size);
+}
+
+static void
+modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
+{
+	uint64_t desc_addr, avail_addr, used_addr;
+	uint16_t notify_off;
+
+	desc_addr = vq->mz->phys_addr;
+	avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
+	used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail,
+							 ring[vq->vq_nentries]),
+				   VIRTIO_PCI_VRING_ALIGN);
+
+	io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
+
+	io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo,
+				      &hw->common_cfg->queue_desc_hi);
+	io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo,
+				       &hw->common_cfg->queue_avail_hi);
+	io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo,
+				      &hw->common_cfg->queue_used_hi);
+
+	notify_off = io_read16(&hw->common_cfg->queue_notify_off);
+	vq->notify_addr = (void *)((uint8_t *)hw->notify_base +
+				notify_off * hw->notify_off_multiplier);
+
+	io_write16(1, &hw->common_cfg->queue_enable);
+
+	PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index);
+	PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr);
+	PMD_INIT_LOG(DEBUG, "\t aval_addr: %"PRIx64, avail_addr);
+	PMD_INIT_LOG(DEBUG, "\t used_addr: %"PRIx64, used_addr);
+	PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)",
+		vq->notify_addr, notify_off);
+}
+
+static void
+modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
+{
+	io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
+
+	io_write64_twopart(0, &hw->common_cfg->queue_desc_lo,
+				  &hw->common_cfg->queue_desc_hi);
+	io_write64_twopart(0, &hw->common_cfg->queue_avail_lo,
+				  &hw->common_cfg->queue_avail_hi);
+	io_write64_twopart(0, &hw->common_cfg->queue_used_lo,
+				  &hw->common_cfg->queue_used_hi);
+
+	io_write16(0, &hw->common_cfg->queue_enable);
+}
+
+static void
+modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
+{
+	io_write16(1, vq->notify_addr);
+}
+
+static const struct virtio_pci_ops modern_ops = {
+	.read_dev_cfg	= modern_read_dev_config,
+	.write_dev_cfg	= modern_write_dev_config,
+	.reset		= modern_reset,
+	.get_status	= modern_get_status,
+	.set_status	= modern_set_status,
+	.get_features	= modern_get_features,
+	.set_features	= modern_set_features,
+	.get_isr	= modern_get_isr,
+	.set_config_irq	= modern_set_config_irq,
+	.get_queue_num	= modern_get_queue_num,
+	.setup_queue	= modern_setup_queue,
+	.del_queue	= modern_del_queue,
+	.notify_queue	= modern_notify_queue,
+};
+
+
 void
 vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
 		      void *dst, int length)
@@ -495,6 +715,12 @@ vtpci_set_status(struct virtio_hw *hw, uint8_t status)
 }
 
 uint8_t
+vtpci_get_status(struct virtio_hw *hw)
+{
+	return hw->vtpci_ops->get_status(hw);
+}
+
+uint8_t
 vtpci_isr(struct virtio_hw *hw)
 {
 	return hw->vtpci_ops->get_isr(hw);
@@ -508,15 +734,142 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
 	return hw->vtpci_ops->set_config_irq(hw, vec);
 }
 
+static void *
+get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)
+{
+	uint8_t  bar    = cap->bar;
+	uint32_t length = cap->length;
+	uint32_t offset = cap->offset;
+	uint8_t *base;
+
+	if (bar > 5) {
+		PMD_INIT_LOG(ERR, "invalid bar: %u", bar);
+		return NULL;
+	}
+
+	if (offset + length < offset) {
+		PMD_INIT_LOG(ERR, "offset(%u) + lenght(%u) overflows",
+			offset, length);
+		return NULL;
+	}
+
+	if (offset + length > dev->mem_resource[bar].len) {
+		PMD_INIT_LOG(ERR,
+			"invalid cap: overflows bar space: %u > %"PRIu64,
+			offset + length, dev->mem_resource[bar].len);
+		return NULL;
+	}
+
+	base = dev->mem_resource[bar].addr;
+	if (base == NULL) {
+		PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar);
+		return NULL;
+	}
+
+	return base + offset;
+}
+
+static int
+virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
+{
+	uint8_t pos;
+	struct virtio_pci_cap cap;
+	int ret;
+
+	if (rte_eal_pci_map_device(dev) < 0) {
+		PMD_INIT_LOG(DEBUG, "failed to map pci device!");
+		return -1;
+	}
+
+	ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST);
+	if (ret < 0) {
+		PMD_INIT_LOG(DEBUG, "failed to read pci capability list");
+		return -1;
+	}
+
+	while (pos) {
+		ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos);
+		if (ret < 0) {
+			PMD_INIT_LOG(ERR,
+				"failed to read pci cap at pos: %x", pos);
+			break;
+		}
+
+		if (cap.cap_vndr != PCI_CAP_ID_VNDR) {
+			PMD_INIT_LOG(DEBUG,
+				"[%2x] skipping non VNDR cap id: %02x",
+				pos, cap.cap_vndr);
+			goto next;
+		}
+
+		PMD_INIT_LOG(DEBUG,
+			"[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u",
+			pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
+
+		switch (cap.cfg_type) {
+		case VIRTIO_PCI_CAP_COMMON_CFG:
+			hw->common_cfg = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_NOTIFY_CFG:
+			rte_eal_pci_read_config(dev, &hw->notify_off_multiplier,
+						4, pos + sizeof(cap));
+			hw->notify_base = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_DEVICE_CFG:
+			hw->dev_cfg = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_ISR_CFG:
+			hw->isr = get_cfg_addr(dev, &cap);
+			break;
+		}
+
+	next:
+		pos = cap.cap_next;
+	}
+
+	if (hw->common_cfg == NULL || hw->notify_base == NULL ||
+	    hw->dev_cfg == NULL    || hw->isr == NULL) {
+		PMD_INIT_LOG(INFO, "no modern virtio pci device found.");
+		return -1;
+	}
+
+	PMD_INIT_LOG(INFO, "found modern virtio pci device.");
+
+	PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg);
+	PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg);
+	PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr);
+	PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u",
+		hw->notify_base, hw->notify_off_multiplier);
+
+	return 0;
+}
+
 int
 vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 {
-	hw->vtpci_ops = &legacy_ops;
+	hw->dev = dev;
 
+	/*
+	 * Try if we can succeed reading virtio pci caps, which exists
+	 * only on modern pci device. If failed, we fallback to legacy
+	 * virtio handling.
+	 */
+	if (virtio_read_caps(dev, hw) == 0) {
+		PMD_INIT_LOG(INFO, "modern virtio pci detected.");
+		hw->vtpci_ops = &modern_ops;
+		hw->modern    = 1;
+		dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
+		return 0;
+	}
+
+	PMD_INIT_LOG(INFO, "trying with legacy virtio pci.");
 	if (legacy_virtio_resource_init(dev) < 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 d7bc6bb..fcac660 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -93,6 +93,7 @@ struct virtqueue;
 #define VIRTIO_CONFIG_STATUS_ACK       0x01
 #define VIRTIO_CONFIG_STATUS_DRIVER    0x02
 #define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04
+#define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08
 #define VIRTIO_CONFIG_STATUS_FAILED    0x80
 
 /*
@@ -141,6 +142,8 @@ struct virtqueue;
 /* We support indirect buffer descriptors */
 #define VIRTIO_RING_F_INDIRECT_DESC	28
 
+#define VIRTIO_F_VERSION_1		32
+
 /*
  * Some VirtIO feature bits (currently bits 28 through 31) are
  * reserved for the transport being used (eg. virtio_ring), the
@@ -163,6 +166,60 @@ struct virtqueue;
  */
 #define VIRTIO_MAX_VIRTQUEUES 8
 
+/* Common configuration */
+#define VIRTIO_PCI_CAP_COMMON_CFG	1
+/* Notifications */
+#define VIRTIO_PCI_CAP_NOTIFY_CFG	2
+/* ISR Status */
+#define VIRTIO_PCI_CAP_ISR_CFG		3
+/* Device specific configuration */
+#define VIRTIO_PCI_CAP_DEVICE_CFG	4
+/* PCI configuration access */
+#define VIRTIO_PCI_CAP_PCI_CFG		5
+
+/* This is the PCI capability header: */
+struct virtio_pci_cap {
+	uint8_t cap_vndr;		/* Generic PCI field: PCI_CAP_ID_VNDR */
+	uint8_t cap_next;		/* Generic PCI field: next ptr. */
+	uint8_t cap_len;		/* Generic PCI field: capability length */
+	uint8_t cfg_type;		/* Identifies the structure. */
+	uint8_t bar;			/* Where to find it. */
+	uint8_t padding[3];		/* Pad to full dword. */
+	uint32_t offset;		/* Offset within bar. */
+	uint32_t length;		/* Length of the structure, in bytes. */
+};
+
+struct virtio_pci_notify_cap {
+	struct virtio_pci_cap cap;
+	uint32_t notify_off_multiplier;	/* Multiplier for queue_notify_off. */
+};
+
+/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */
+struct virtio_pci_common_cfg {
+	/* About the whole device. */
+	uint32_t device_feature_select;	/* read-write */
+	uint32_t device_feature;	/* read-only */
+	uint32_t guest_feature_select;	/* read-write */
+	uint32_t guest_feature;		/* read-write */
+	uint16_t msix_config;		/* read-write */
+	uint16_t num_queues;		/* read-only */
+	uint8_t device_status;		/* read-write */
+	uint8_t config_generation;	/* read-only */
+
+	/* About a specific virtqueue. */
+	uint16_t queue_select;		/* read-write */
+	uint16_t queue_size;		/* read-write, power of 2. */
+	uint16_t queue_msix_vector;	/* read-write */
+	uint16_t queue_enable;		/* read-write */
+	uint16_t queue_notify_off;	/* read-only */
+	uint32_t queue_desc_lo;		/* read-write */
+	uint32_t queue_desc_hi;		/* read-write */
+	uint32_t queue_avail_lo;	/* read-write */
+	uint32_t queue_avail_hi;	/* read-write */
+	uint32_t queue_used_lo;		/* read-write */
+	uint32_t queue_used_hi;		/* read-write */
+};
+
 struct virtio_hw;
 
 struct virtio_pci_ops {
@@ -188,6 +245,8 @@ struct virtio_pci_ops {
 	void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq);
 };
 
+struct virtio_net_config;
+
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
@@ -198,7 +257,14 @@ struct virtio_hw {
 	uint8_t	    vlan_strip;
 	uint8_t	    use_msix;
 	uint8_t     started;
+	uint8_t     modern;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
+	uint32_t    notify_off_multiplier;
+	uint8_t     *isr;
+	uint16_t    *notify_base;
+	struct rte_pci_device *dev;
+	struct virtio_pci_common_cfg *common_cfg;
+	struct virtio_net_config *dev_cfg;
 	const struct virtio_pci_ops *vtpci_ops;
 };
 
@@ -284,6 +350,7 @@ void vtpci_reset(struct virtio_hw *);
 
 void vtpci_reinit_complete(struct virtio_hw *);
 
+uint8_t vtpci_get_status(struct virtio_hw *);
 void vtpci_set_status(struct virtio_hw *, uint8_t);
 
 uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t);
diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h
index d7fb450..99d4fa9 100644
--- a/drivers/net/virtio/virtqueue.h
+++ b/drivers/net/virtio/virtqueue.h
@@ -202,6 +202,8 @@ struct virtqueue {
 	/* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */
 	uint64_t	size_bins[8];
 
+	uint16_t	*notify_addr;
+
 	struct vq_desc_extra {
 		void              *cookie;
 		uint16_t          ndescs;
-- 
1.9.0

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

* [dpdk-dev] [PATCH v6 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c
  2016-01-28  7:54       ` [dpdk-dev] [PATCH v6 " Yuanhan Liu
                           ` (7 preceding siblings ...)
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 8/9] virtio: add 1.0 support Yuanhan Liu
@ 2016-01-28  7:54         ` Yuanhan Liu
  2016-02-02 10:46         ` [dpdk-dev] [PATCH v6 0/9] virtio 1.0 enabling for virtio pmd driver Thomas Monjalon
  2016-02-02 13:48         ` [dpdk-dev] [PATCH v7 " Yuanhan Liu
  10 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-01-28  7:54 UTC (permalink / raw)
  To: dev

virtio_pci.c is the only file references those macros; move them there.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
 drivers/net/virtio/virtio_pci.c | 19 +++++++++++++++++++
 drivers/net/virtio/virtio_pci.h | 18 ------------------
 2 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 2d3143b..e16104e 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -49,6 +49,25 @@
 #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))))
+
 static void
 legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
 		       void *dst, int length)
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index fcac660..0544a07 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -318,24 +318,6 @@ outl_p(unsigned int data, unsigned int port)
 }
 #endif
 
-#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))))
-
 static inline int
 vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-- 
1.9.0

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

* Re: [dpdk-dev] [PATCH v6 0/9] virtio 1.0 enabling for virtio pmd driver
  2016-01-28  7:54       ` [dpdk-dev] [PATCH v6 " Yuanhan Liu
                           ` (8 preceding siblings ...)
  2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
@ 2016-02-02 10:46         ` Thomas Monjalon
  2016-02-02 13:00           ` Yuanhan Liu
  2016-02-02 13:48         ` [dpdk-dev] [PATCH v7 " Yuanhan Liu
  10 siblings, 1 reply; 122+ messages in thread
From: Thomas Monjalon @ 2016-02-02 10:46 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev

Hi Yuanhan,

I wanted to apply these patches but I see few checkpatch warnings,
inluding a typo.
Sometimes I fix them myself but I guess you would prefer checking it.

### PATCH v6 4_9

CHECK:SPACING: spaces preferred around that '+' (ctx:VxV)
#571: FILE: drivers/net/virtio/virtio_pci.c:361:
+               left = &ptr[n+1];
                             ^
WARNING:NAKED_SSCANF: unchecked sscanf return value
#582: FILE: drivers/net/virtio/virtio_pci.c:372:
+                       sscanf(ptr, "%04hx-%04hx", &start, &end);

### PATCH v6 5_9

CHECK:CONCATENATED_STRING: Concatenated strings should use spaces between elements
#79: FILE: drivers/net/virtio/virtio_ethdev.c:937:
+       PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %"PRIx64,

CHECK:CONCATENATED_STRING: Concatenated strings should use spaces between elements
#85: FILE: drivers/net/virtio/virtio_ethdev.c:942:
+       PMD_INIT_LOG(DEBUG, "host_features before negotiate = %"PRIx64,

CHECK:CONCATENATED_STRING: Concatenated strings should use spaces between elements
#94: FILE: drivers/net/virtio/virtio_ethdev.c:950:
+       PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64,

### PATCH v6 7_9

WARNING:BAD_SIGN_OFF: 'Tested-by:' is the preferred signature form
#63: 
Tested-By: Santosh Shukla <sshukla@mvista.com>

### PATCH v6 8_9

CHECK:CAMELCASE: Avoid CamelCase: <PRIx64>
#396: FILE: drivers/net/virtio/virtio_pci.c:620:
+       PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr);

CHECK:CONCATENATED_STRING: Concatenated strings should use spaces between elements
#396: FILE: drivers/net/virtio/virtio_pci.c:620:
+       PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr);

CHECK:CONCATENATED_STRING: Concatenated strings should use spaces between elements
#397: FILE: drivers/net/virtio/virtio_pci.c:621:
+       PMD_INIT_LOG(DEBUG, "\t aval_addr: %"PRIx64, avail_addr);

CHECK:CONCATENATED_STRING: Concatenated strings should use spaces between elements
#398: FILE: drivers/net/virtio/virtio_pci.c:622:
+       PMD_INIT_LOG(DEBUG, "\t used_addr: %"PRIx64, used_addr);

WARNING:TYPO_SPELLING: 'lenght' may be misspelled - perhaps 'length'?
#475: FILE: drivers/net/virtio/virtio_pci.c:751:
+               PMD_INIT_LOG(ERR, "offset(%u) + lenght(%u) overflows",

CHECK:CAMELCASE: Avoid CamelCase: <PRIu64>
#482: FILE: drivers/net/virtio/virtio_pci.c:758:
+                       "invalid cap: overflows bar space: %u > %"PRIu64,

CHECK:CONCATENATED_STRING: Concatenated strings should use spaces between elements
#482: FILE: drivers/net/virtio/virtio_pci.c:758:
+                       "invalid cap: overflows bar space: %u > %"PRIu64,

WARNING:INDENTED_LABEL: labels should not be indented
#550: FILE: drivers/net/virtio/virtio_pci.c:826:
+       next:

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

* Re: [dpdk-dev] [PATCH v6 0/9] virtio 1.0 enabling for virtio pmd driver
  2016-02-02 10:46         ` [dpdk-dev] [PATCH v6 0/9] virtio 1.0 enabling for virtio pmd driver Thomas Monjalon
@ 2016-02-02 13:00           ` Yuanhan Liu
  0 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-02-02 13:00 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

On Tue, Feb 02, 2016 at 11:46:54AM +0100, Thomas Monjalon wrote:
> Hi Yuanhan,
> 
> I wanted to apply these patches but I see few checkpatch warnings,
> inluding a typo.
> Sometimes I fix them myself but I guess you would prefer checking it.

Okay; I will fix them all.

	--yliu

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

* [dpdk-dev] [PATCH v7 0/9] virtio 1.0 enabling for virtio pmd driver
  2016-01-28  7:54       ` [dpdk-dev] [PATCH v6 " Yuanhan Liu
                           ` (9 preceding siblings ...)
  2016-02-02 10:46         ` [dpdk-dev] [PATCH v6 0/9] virtio 1.0 enabling for virtio pmd driver Thomas Monjalon
@ 2016-02-02 13:48         ` Yuanhan Liu
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu
                             ` (9 more replies)
  10 siblings, 10 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw)
  To: dev

v7: - make checkpatch a bit happier; few (false) warnings still left.

    - rebase to latest code: fixed a conflict.

v6: unfold IO_READ/WRITE_DEF macro

v5: minor fixes:

    - fix wrong type of arg "offset" of read/write_dev_config(): patch 2
      is newly added for that.

    - check "offset + length" overflow

Almost all difference comes from virtio 1.0 are the PCI layout change:
the major configuration structures are stored at bar space, and their
location is stored at corresponding pci cap structure. Reading/parsing
them is one of the major work of patch 8.

To make handling virtio v1.0 and v0.95 co-exist well, this patch set
introduces a virtio_pci_ops structure, to add another layer so that
we could keep those vtpci_foo_bar "APIs". With that, we could do the
minimum change to add virtio 1.0 support.


Rough test guide
================

Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add
option "disable-modern=false" to qemu virtio-net-pci device to enable
virtio 1.0 (which is disabled by default).

And if you see something like following from 'lspci -v', it means virtio
1.0 is indeed enabled:

    00:04.0 Ethernet controller: Red Hat, Inc Virtio network device
    Subsystem: Red Hat, Inc Device 0001
    Physical Slot: 4
    Flags: bus master, fast devsel, latency 0, IRQ 11
    I/O ports at c040 [size=64]
    Memory at febf1000 (32-bit, non-prefetchable) [size=4K]
    Memory at fe000000 (64-bit, prefetchable) [size=8M]
    Expansion ROM at feb80000 [disabled] [size=256K]
    Capabilities: [98] MSI-X: Enable+ Count=6 Masked-
==> Capabilities: [84] Vendor Specific Information: Len=14 <?>
==> Capabilities: [70] Vendor Specific Information: Len=14 <?>
==> Capabilities: [60] Vendor Specific Information: Len=10 <?>
==> Capabilities: [50] Vendor Specific Information: Len=10 <?>
==> Capabilities: [40] Vendor Specific Information: Len=10 <?>
    Kernel driver in use: virtio-pci
    Kernel modules: virtio_pci

After that, there wasn't anything speical comparing to the old virtio
0.95 pmd driver.


---
Yuanhan Liu (9):
  virtio: don't set vring address again at queue startup
  virtio: define offset as size_t type
  virtio: introduce struct virtio_pci_ops
  virtio: move left pci stuff to virtio_pci.c
  viritio: switch to 64 bit features
  virtio: retrieve hdr_size from hw->vtnet_hdr_size
  eal: pci: export pci_[un]map_device
  virtio: add 1.0 support
  virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c

 doc/guides/rel_notes/release_2_3.rst            |   3 +
 drivers/net/virtio/virtio_ethdev.c              | 302 +--------
 drivers/net/virtio/virtio_ethdev.h              |   3 +-
 drivers/net/virtio/virtio_pci.c                 | 815 +++++++++++++++++++++++-
 drivers/net/virtio/virtio_pci.h                 | 124 +++-
 drivers/net/virtio/virtio_rxtx.c                |  21 +-
 drivers/net/virtio/virtio_rxtx_simple.c         |  12 +-
 drivers/net/virtio/virtqueue.h                  |   4 +-
 lib/librte_eal/bsdapp/eal/eal_pci.c             |   4 +-
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   2 +
 lib/librte_eal/common/eal_common_pci.c          |   4 +-
 lib/librte_eal/common/eal_private.h             |  18 -
 lib/librte_eal/common/include/rte_pci.h         |  27 +
 lib/librte_eal/linuxapp/eal/eal_pci.c           |   4 +-
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   3 +
 15 files changed, 964 insertions(+), 382 deletions(-)

-- 
1.9.0

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

* [dpdk-dev] [PATCH v7 1/9] virtio: don't set vring address again at queue startup
  2016-02-02 13:48         ` [dpdk-dev] [PATCH v7 " Yuanhan Liu
@ 2016-02-02 13:48           ` Yuanhan Liu
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 2/9] virtio: define offset as size_t type Yuanhan Liu
                             ` (8 subsequent siblings)
  9 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw)
  To: dev

As we have already set up it at virtio_dev_queue_setup(), and a vq
restart will not reset the settings.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
 drivers/net/virtio/virtio_rxtx.c | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index 74b39ef..b7267c0 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -339,11 +339,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type)
 		vq_update_avail_idx(vq);
 
 		PMD_INIT_LOG(DEBUG, "Allocated %d bufs", nbufs);
-
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 	} else if (queue_type == VTNET_TQ) {
 		if (use_simple_rxtx) {
 			int mid_idx  = vq->vq_nentries >> 1;
@@ -362,16 +357,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type)
 			for (i = mid_idx; i < vq->vq_nentries; i++)
 				vq->vq_ring.avail->ring[i] = i;
 		}
-
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
-	} else {
-		VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL,
-			vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN,
-			vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 	}
 }
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH v7 2/9] virtio: define offset as size_t type
  2016-02-02 13:48         ` [dpdk-dev] [PATCH v7 " Yuanhan Liu
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu
@ 2016-02-02 13:48           ` Yuanhan Liu
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu
                             ` (7 subsequent siblings)
  9 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw)
  To: dev

offset arg of vtpci_read/write_dev_config is derived from offsetof(),
which is of size_t type, instead of uint64_t. So, define it as size_t
type.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
 drivers/net/virtio/virtio_pci.c | 4 ++--
 drivers/net/virtio/virtio_pci.h | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 2245bec..b34b59e 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -38,7 +38,7 @@
 static uint8_t vtpci_get_status(struct virtio_hw *);
 
 void
-vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
+vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
 		void *dst, int length)
 {
 	uint64_t off;
@@ -61,7 +61,7 @@ vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 }
 
 void
-vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset,
+vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
 		void *src, int length)
 {
 	uint64_t off;
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index 47f722a..fe89c21 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -261,9 +261,9 @@ void vtpci_set_status(struct virtio_hw *, uint8_t);
 
 uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t);
 
-void vtpci_write_dev_config(struct virtio_hw *, uint64_t, void *, int);
+void vtpci_write_dev_config(struct virtio_hw *, size_t, void *, int);
 
-void vtpci_read_dev_config(struct virtio_hw *, uint64_t, void *, int);
+void vtpci_read_dev_config(struct virtio_hw *, size_t, void *, int);
 
 uint8_t vtpci_isr(struct virtio_hw *);
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH v7 3/9] virtio: introduce struct virtio_pci_ops
  2016-02-02 13:48         ` [dpdk-dev] [PATCH v7 " Yuanhan Liu
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 2/9] virtio: define offset as size_t type Yuanhan Liu
@ 2016-02-02 13:48           ` Yuanhan Liu
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
                             ` (6 subsequent siblings)
  9 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw)
  To: dev

Introduce struct virtio_pci_ops, to let legacy virtio (v0.95) and
modern virtio (1.0) have different implementation regarding to a
specific pci action, such as read host status.

With that, this patch reimplements all exported pci functions, in
a way like:

	vtpci_foo_bar(struct virtio_hw *hw)
	{
		hw->vtpci_ops->foo_bar(hw);
	}

So that we need pay attention to those pci related functions only
while adding virtio 1.0 support.

This patch introduced a new vtpci function, vtpci_init(), to do
proper virtio pci settings. It's pretty simple so far: just sets
hw->vtpci_ops to legacy_ops as we don't support 1.0 yet.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
v5: - define "src" arg of vtpci_write_dev_config()
---
 drivers/net/virtio/virtio_ethdev.c |  22 ++---
 drivers/net/virtio/virtio_pci.c    | 164 ++++++++++++++++++++++++++++++-------
 drivers/net/virtio/virtio_pci.h    |  29 ++++++-
 drivers/net/virtio/virtqueue.h     |   2 +-
 4 files changed, 170 insertions(+), 47 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index d928339..6c1d3a0 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -272,9 +272,7 @@ virtio_dev_queue_release(struct virtqueue *vq) {
 
 	if (vq) {
 		hw = vq->hw;
-		/* Select and deactivate the queue */
-		VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
-		VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+		hw->vtpci_ops->del_queue(hw, vq);
 
 		rte_free(vq->sw_ring);
 		rte_free(vq);
@@ -295,15 +293,13 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
 	struct virtio_hw *hw = dev->data->dev_private;
 	struct virtqueue *vq = NULL;
 
-	/* Write the virtqueue index to the Queue Select Field */
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vtpci_queue_idx);
-	PMD_INIT_LOG(DEBUG, "selecting queue: %u", vtpci_queue_idx);
+	PMD_INIT_LOG(DEBUG, "setting up queue: %u", vtpci_queue_idx);
 
 	/*
 	 * Read the virtqueue size from the Queue Size field
 	 * Always power of 2 and if 0 virtqueue does not exist
 	 */
-	vq_size = VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
+	vq_size = hw->vtpci_ops->get_queue_num(hw, vtpci_queue_idx);
 	PMD_INIT_LOG(DEBUG, "vq_size: %u nb_desc:%u", vq_size, nb_desc);
 	if (vq_size == 0) {
 		PMD_INIT_LOG(ERR, "%s: virtqueue does not exist", __func__);
@@ -436,12 +432,8 @@ int virtio_dev_queue_setup(struct rte_eth_dev *dev,
 		memset(vq->virtio_net_hdr_mz->addr, 0, PAGE_SIZE);
 	}
 
-	/*
-	 * Set guest physical address of the virtqueue
-	 * in VIRTIO_PCI_QUEUE_PFN config register of device
-	 */
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
-			mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+	hw->vtpci_ops->setup_queue(hw, vq);
+
 	*pvq = vq;
 	return 0;
 }
@@ -950,7 +942,7 @@ virtio_negotiate_features(struct virtio_hw *hw)
 		hw->guest_features);
 
 	/* Read device(host) feature bits */
-	host_features = VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+	host_features = hw->vtpci_ops->get_features(hw);
 	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x",
 		host_features);
 
@@ -1287,6 +1279,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 
+	vtpci_init(pci_dev, hw);
+
 	if (virtio_resource_init(pci_dev) < 0)
 		return -1;
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index b34b59e..8d001e8 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -34,12 +34,11 @@
 
 #include "virtio_pci.h"
 #include "virtio_logs.h"
+#include "virtqueue.h"
 
-static uint8_t vtpci_get_status(struct virtio_hw *);
-
-void
-vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
-		void *dst, int length)
+static void
+legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
+		       void *dst, int length)
 {
 	uint64_t off;
 	uint8_t *d;
@@ -60,22 +59,22 @@ vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
 	}
 }
 
-void
-vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
-		void *src, int length)
+static void
+legacy_write_dev_config(struct virtio_hw *hw, size_t offset,
+			const void *src, int length)
 {
 	uint64_t off;
-	uint8_t *s;
+	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, *(uint32_t *)s);
+			VIRTIO_WRITE_REG_4(hw, off, *(const uint32_t *)s);
 		} else if (length >= 2) {
 			size = 2;
-			VIRTIO_WRITE_REG_2(hw, off, *(uint16_t *)s);
+			VIRTIO_WRITE_REG_2(hw, off, *(const uint16_t *)s);
 		} else {
 			size = 1;
 			VIRTIO_WRITE_REG_1(hw, off, *s);
@@ -83,30 +82,133 @@ vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
 	}
 }
 
+static uint32_t
+legacy_get_features(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+}
+
+static void
+legacy_set_features(struct virtio_hw *hw, uint32_t features)
+{
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
+}
+
+static uint8_t
+legacy_get_status(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
+}
+
+static void
+legacy_set_status(struct virtio_hw *hw, uint8_t status)
+{
+	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+}
+
+static void
+legacy_reset(struct virtio_hw *hw)
+{
+	legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+}
+
+static uint8_t
+legacy_get_isr(struct virtio_hw *hw)
+{
+	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+}
+
+/* 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);
+}
+
+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);
+}
+
+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);
+
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
+		vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+}
+
+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);
+
+	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+}
+
+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);
+}
+
+
+static const struct virtio_pci_ops legacy_ops = {
+	.read_dev_cfg	= legacy_read_dev_config,
+	.write_dev_cfg	= legacy_write_dev_config,
+	.reset		= legacy_reset,
+	.get_status	= legacy_get_status,
+	.set_status	= legacy_set_status,
+	.get_features	= legacy_get_features,
+	.set_features	= legacy_set_features,
+	.get_isr	= legacy_get_isr,
+	.set_config_irq	= legacy_set_config_irq,
+	.get_queue_num	= legacy_get_queue_num,
+	.setup_queue	= legacy_setup_queue,
+	.del_queue	= legacy_del_queue,
+	.notify_queue	= legacy_notify_queue,
+};
+
+
+void
+vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
+		      void *dst, int length)
+{
+	hw->vtpci_ops->read_dev_cfg(hw, offset, dst, length);
+}
+
+void
+vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
+		       const void *src, int length)
+{
+	hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
+}
+
 uint32_t
 vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
 {
 	uint32_t features;
+
 	/*
 	 * Limit negotiated features to what the driver, virtqueue, and
 	 * host all support.
 	 */
 	features = host_features & hw->guest_features;
+	hw->vtpci_ops->set_features(hw, features);
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
 	return features;
 }
 
-
 void
 vtpci_reset(struct virtio_hw *hw)
 {
-	/*
-	 * Setting the status to RESET sets the host device to
-	 * the original, uninitialized state.
-	 */
-	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
-	vtpci_get_status(hw);
+	hw->vtpci_ops->set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+	/* flush status write */
+	hw->vtpci_ops->get_status(hw);
 }
 
 void
@@ -115,26 +217,19 @@ vtpci_reinit_complete(struct virtio_hw *hw)
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK);
 }
 
-static uint8_t
-vtpci_get_status(struct virtio_hw *hw)
-{
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
-}
-
 void
 vtpci_set_status(struct virtio_hw *hw, uint8_t status)
 {
 	if (status != VIRTIO_CONFIG_STATUS_RESET)
-		status = (uint8_t)(status | vtpci_get_status(hw));
+		status |= hw->vtpci_ops->get_status(hw);
 
-	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+	hw->vtpci_ops->set_status(hw, status);
 }
 
 uint8_t
 vtpci_isr(struct virtio_hw *hw)
 {
-
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+	return hw->vtpci_ops->get_isr(hw);
 }
 
 
@@ -142,6 +237,13 @@ vtpci_isr(struct virtio_hw *hw)
 uint16_t
 vtpci_irq_config(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);
+	return hw->vtpci_ops->set_config_irq(hw, vec);
+}
+
+int
+vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw)
+{
+	hw->vtpci_ops = &legacy_ops;
+
+	return 0;
 }
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index fe89c21..e8e7509 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -163,6 +163,31 @@ struct virtqueue;
  */
 #define VIRTIO_MAX_VIRTQUEUES 8
 
+struct virtio_hw;
+
+struct virtio_pci_ops {
+	void (*read_dev_cfg)(struct virtio_hw *hw, size_t offset,
+			     void *dst, int len);
+	void (*write_dev_cfg)(struct virtio_hw *hw, size_t offset,
+			      const void *src, int len);
+	void (*reset)(struct virtio_hw *hw);
+
+	uint8_t (*get_status)(struct virtio_hw *hw);
+	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
+
+	uint32_t (*get_features)(struct virtio_hw *hw);
+	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
+
+	uint8_t (*get_isr)(struct virtio_hw *hw);
+
+	uint16_t (*set_config_irq)(struct virtio_hw *hw, uint16_t vec);
+
+	uint16_t (*get_queue_num)(struct virtio_hw *hw, uint16_t queue_id);
+	void (*setup_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+	void (*del_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+	void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq);
+};
+
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
@@ -174,6 +199,7 @@ struct virtio_hw {
 	uint8_t	    use_msix;
 	uint8_t     started;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
+	const struct virtio_pci_ops *vtpci_ops;
 };
 
 /*
@@ -253,6 +279,7 @@ vtpci_with_feature(struct virtio_hw *hw, uint32_t bit)
 /*
  * Function declaration from virtio_pci.c
  */
+int vtpci_init(struct rte_pci_device *, struct virtio_hw *);
 void vtpci_reset(struct virtio_hw *);
 
 void vtpci_reinit_complete(struct virtio_hw *);
@@ -261,7 +288,7 @@ void vtpci_set_status(struct virtio_hw *, uint8_t);
 
 uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t);
 
-void vtpci_write_dev_config(struct virtio_hw *, size_t, void *, int);
+void vtpci_write_dev_config(struct virtio_hw *, size_t, const void *, int);
 
 void vtpci_read_dev_config(struct virtio_hw *, size_t, void *, int);
 
diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h
index 61b3137..d7fb450 100644
--- a/drivers/net/virtio/virtqueue.h
+++ b/drivers/net/virtio/virtqueue.h
@@ -302,7 +302,7 @@ virtqueue_notify(struct virtqueue *vq)
 	 * For virtio on IA, the notificaiton is through io port operation
 	 * which is a serialization instruction itself.
 	 */
-	VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
+	vq->hw->vtpci_ops->notify_queue(vq->hw, vq);
 }
 
 #ifdef RTE_LIBRTE_VIRTIO_DEBUG_DUMP
-- 
1.9.0

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

* [dpdk-dev] [PATCH v7 4/9] virtio: move left pci stuff to virtio_pci.c
  2016-02-02 13:48         ` [dpdk-dev] [PATCH v7 " Yuanhan Liu
                             ` (2 preceding siblings ...)
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu
@ 2016-02-02 13:48           ` Yuanhan Liu
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 5/9] viritio: switch to 64 bit features Yuanhan Liu
                             ` (5 subsequent siblings)
  9 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw)
  To: dev

virtio_pci.c is a more proper place for pci stuff; virtio_ethdev is not.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
 drivers/net/virtio/virtio_ethdev.c | 265 +-----------------------------------
 drivers/net/virtio/virtio_pci.c    | 272 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 272 insertions(+), 265 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 6c1d3a0..b57224d 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -36,10 +36,6 @@
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
-#ifdef RTE_EXEC_ENV_LINUXAPP
-#include <dirent.h>
-#include <fcntl.h>
-#endif
 
 #include <rte_ethdev.h>
 #include <rte_memcpy.h>
@@ -955,260 +951,6 @@ virtio_negotiate_features(struct virtio_hw *hw)
 		hw->guest_features);
 }
 
-#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
-virtio_has_msix(const struct rte_pci_addr *loc)
-{
-	DIR *d;
-	char dirname[PATH_MAX];
-
-	snprintf(dirname, sizeof(dirname),
-		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
-		     loc->domain, loc->bus, loc->devid, loc->function);
-
-	d = opendir(dirname);
-	if (d)
-		closedir(d);
-
-	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 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
-virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
-{
-	/* nic_uio does not enable interrupts, return 0 (false). */
-	return 0;
-}
-
-static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
-{
-	/* no setup required */
-	return 0;
-}
-#endif
-
 /*
  * Process Virtio Config changed interrupt and call the callback
  * if link state changed.
@@ -1279,14 +1021,9 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 
-	vtpci_init(pci_dev, hw);
-
-	if (virtio_resource_init(pci_dev) < 0)
+	if (vtpci_init(pci_dev, hw) < 0)
 		return -1;
 
-	hw->use_msix = virtio_has_msix(&pci_dev->addr);
-	hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr;
-
 	/* Reset the device although not necessary at startup */
 	vtpci_reset(hw);
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 8d001e8..e89a044 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -32,6 +32,11 @@
  */
 #include <stdint.h>
 
+#ifdef RTE_EXEC_ENV_LINUXAPP
+ #include <dirent.h>
+ #include <fcntl.h>
+#endif
+
 #include "virtio_pci.h"
 #include "virtio_logs.h"
 #include "virtqueue.h"
@@ -156,6 +161,266 @@ legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
 	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
 }
 
+#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;
+	char dirname[PATH_MAX];
+
+	snprintf(dirname, sizeof(dirname),
+		     SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
+		     loc->domain, loc->bus, loc->devid, loc->function);
+
+	d = opendir(dirname);
+	if (d)
+		closedir(d);
+
+	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
+legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
+{
+	/* nic_uio does not enable interrupts, return 0 (false). */
+	return 0;
+}
+
+static int
+legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
+{
+	/* no setup required */
+	return 0;
+}
+#endif
 
 static const struct virtio_pci_ops legacy_ops = {
 	.read_dev_cfg	= legacy_read_dev_config,
@@ -241,9 +506,14 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
 }
 
 int
-vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw)
+vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 {
 	hw->vtpci_ops = &legacy_ops;
 
+	if (legacy_virtio_resource_init(dev) < 0)
+		return -1;
+	hw->use_msix = legacy_virtio_has_msix(&dev->addr);
+	hw->io_base  = (uint32_t)(uintptr_t)dev->mem_resource[0].addr;
+
 	return 0;
 }
-- 
1.9.0

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

* [dpdk-dev] [PATCH v7 5/9] viritio: switch to 64 bit features
  2016-02-02 13:48         ` [dpdk-dev] [PATCH v7 " Yuanhan Liu
                             ` (3 preceding siblings ...)
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
@ 2016-02-02 13:48           ` Yuanhan Liu
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
                             ` (4 subsequent siblings)
  9 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw)
  To: dev

Switch to 64 bit features, which virtio 1.0 supports.

While legacy virtio only supports 32 bit features, it complains aloud
and quit when trying to setting > 32 bit features.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
 drivers/net/virtio/virtio_ethdev.c |  8 ++++----
 drivers/net/virtio/virtio_pci.c    | 15 ++++++++++-----
 drivers/net/virtio/virtio_pci.h    | 12 ++++++------
 3 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index b57224d..4f84757 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -930,16 +930,16 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 static void
 virtio_negotiate_features(struct virtio_hw *hw)
 {
-	uint32_t host_features;
+	uint64_t host_features;
 
 	/* Prepare guest_features: feature that driver wants to support */
 	hw->guest_features = VIRTIO_PMD_GUEST_FEATURES;
-	PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %" PRIx64,
 		hw->guest_features);
 
 	/* Read device(host) feature bits */
 	host_features = hw->vtpci_ops->get_features(hw);
-	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "host_features before negotiate = %" PRIx64,
 		host_features);
 
 	/*
@@ -947,7 +947,7 @@ virtio_negotiate_features(struct virtio_hw *hw)
 	 * guest feature bits.
 	 */
 	hw->guest_features = vtpci_negotiate_features(hw, host_features);
-	PMD_INIT_LOG(DEBUG, "features after negotiate = %x",
+	PMD_INIT_LOG(DEBUG, "features after negotiate = %" PRIx64,
 		hw->guest_features);
 }
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index e89a044..3961077 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -87,15 +87,20 @@ legacy_write_dev_config(struct virtio_hw *hw, size_t offset,
 	}
 }
 
-static uint32_t
+static uint64_t
 legacy_get_features(struct virtio_hw *hw)
 {
 	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
 }
 
 static void
-legacy_set_features(struct virtio_hw *hw, uint32_t features)
+legacy_set_features(struct virtio_hw *hw, uint64_t features)
 {
+	if ((features >> 32) != 0) {
+		PMD_DRV_LOG(ERR,
+			"only 32 bit features are allowed for legacy virtio!");
+		return;
+	}
 	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
 }
 
@@ -453,10 +458,10 @@ vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
 	hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
 }
 
-uint32_t
-vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
+uint64_t
+vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features)
 {
-	uint32_t features;
+	uint64_t features;
 
 	/*
 	 * Limit negotiated features to what the driver, virtqueue, and
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index e8e7509..d7bc6bb 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -175,8 +175,8 @@ struct virtio_pci_ops {
 	uint8_t (*get_status)(struct virtio_hw *hw);
 	void    (*set_status)(struct virtio_hw *hw, uint8_t status);
 
-	uint32_t (*get_features)(struct virtio_hw *hw);
-	void     (*set_features)(struct virtio_hw *hw, uint32_t features);
+	uint64_t (*get_features)(struct virtio_hw *hw);
+	void     (*set_features)(struct virtio_hw *hw, uint64_t features);
 
 	uint8_t (*get_isr)(struct virtio_hw *hw);
 
@@ -191,7 +191,7 @@ struct virtio_pci_ops {
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
-	uint32_t    guest_features;
+	uint64_t    guest_features;
 	uint32_t    max_tx_queues;
 	uint32_t    max_rx_queues;
 	uint16_t    vtnet_hdr_size;
@@ -271,9 +271,9 @@ outl_p(unsigned int data, unsigned int port)
 	outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
 
 static inline int
-vtpci_with_feature(struct virtio_hw *hw, uint32_t bit)
+vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-	return (hw->guest_features & (1u << bit)) != 0;
+	return (hw->guest_features & (1ULL << bit)) != 0;
 }
 
 /*
@@ -286,7 +286,7 @@ void vtpci_reinit_complete(struct virtio_hw *);
 
 void vtpci_set_status(struct virtio_hw *, uint8_t);
 
-uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t);
+uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t);
 
 void vtpci_write_dev_config(struct virtio_hw *, size_t, const void *, int);
 
-- 
1.9.0

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

* [dpdk-dev] [PATCH v7 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size
  2016-02-02 13:48         ` [dpdk-dev] [PATCH v7 " Yuanhan Liu
                             ` (4 preceding siblings ...)
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 5/9] viritio: switch to 64 bit features Yuanhan Liu
@ 2016-02-02 13:48           ` Yuanhan Liu
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu
                             ` (3 subsequent siblings)
  9 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw)
  To: dev

The mergeable virtio net hdr format has been the standard and the
only virtio net hdr format since virtio 1.0. Therefore, we can
not hardcode hdr_size to "sizeof(struct virtio_net_hdr)" any more
at virtio_recv_pkts(), otherwise, there would be a mismatch of
hdr size from rte_vhost_enqueue_burst() and virtio_recv_pkts(),
leading a packet corruption.

Instead, we should retrieve it from hw->vtnet_hdr_size; we will
do proper settings at eth_virtio_dev_init() in later patches.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
---
 drivers/net/virtio/virtio_rxtx.c        |  6 ++++--
 drivers/net/virtio/virtio_rxtx_simple.c | 12 ++++++------
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index b7267c0..41a1366 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -560,7 +560,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 	struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
 	int error;
 	uint32_t i, nb_enqueued;
-	const uint32_t hdr_size = sizeof(struct virtio_net_hdr);
+	uint32_t hdr_size;
 
 	nb_used = VIRTQUEUE_NUSED(rxvq);
 
@@ -580,6 +580,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 	hw = rxvq->hw;
 	nb_rx = 0;
 	nb_enqueued = 0;
+	hdr_size = hw->vtnet_hdr_size;
 
 	for (i = 0; i < num ; i++) {
 		rxm = rcv_pkts[i];
@@ -664,7 +665,7 @@ virtio_recv_mergeable_pkts(void *rx_queue,
 	uint32_t seg_num;
 	uint16_t extra_idx;
 	uint32_t seg_res;
-	const uint32_t hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+	uint32_t hdr_size;
 
 	nb_used = VIRTQUEUE_NUSED(rxvq);
 
@@ -682,6 +683,7 @@ virtio_recv_mergeable_pkts(void *rx_queue,
 	seg_num = 0;
 	extra_idx = 0;
 	seg_res = 0;
+	hdr_size = hw->vtnet_hdr_size;
 
 	while (i < nb_used) {
 		struct virtio_net_hdr_mrg_rxbuf *header;
diff --git a/drivers/net/virtio/virtio_rxtx_simple.c b/drivers/net/virtio/virtio_rxtx_simple.c
index ff3c11a..3a1de9d 100644
--- a/drivers/net/virtio/virtio_rxtx_simple.c
+++ b/drivers/net/virtio/virtio_rxtx_simple.c
@@ -81,9 +81,9 @@ virtqueue_enqueue_recv_refill_simple(struct virtqueue *vq,
 
 	start_dp = vq->vq_ring.desc;
 	start_dp[desc_idx].addr = (uint64_t)((uintptr_t)cookie->buf_physaddr +
-		RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr));
+		RTE_PKTMBUF_HEADROOM - vq->hw->vtnet_hdr_size);
 	start_dp[desc_idx].len = cookie->buf_len -
-		RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr);
+		RTE_PKTMBUF_HEADROOM + vq->hw->vtnet_hdr_size;
 
 	vq->vq_free_cnt--;
 	vq->vq_avail_idx++;
@@ -120,9 +120,9 @@ virtio_rxq_rearm_vec(struct virtqueue *rxvq)
 
 		start_dp[i].addr =
 			(uint64_t)((uintptr_t)sw_ring[i]->buf_physaddr +
-			RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr));
+			RTE_PKTMBUF_HEADROOM - rxvq->hw->vtnet_hdr_size);
 		start_dp[i].len = sw_ring[i]->buf_len -
-			RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr);
+			RTE_PKTMBUF_HEADROOM + rxvq->hw->vtnet_hdr_size;
 	}
 
 	rxvq->vq_avail_idx += RTE_VIRTIO_VPMD_RX_REARM_THRESH;
@@ -175,8 +175,8 @@ virtio_recv_pkts_vec(void *rx_queue, struct rte_mbuf **rx_pkts,
 	len_adjust = _mm_set_epi16(
 		0, 0,
 		0,
-		(uint16_t) -sizeof(struct virtio_net_hdr),
-		0, (uint16_t) -sizeof(struct virtio_net_hdr),
+		(uint16_t)-rxvq->hw->vtnet_hdr_size,
+		0, (uint16_t)-rxvq->hw->vtnet_hdr_size,
 		0, 0);
 
 	if (unlikely(nb_pkts < RTE_VIRTIO_DESC_PER_LOOP))
-- 
1.9.0

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

* [dpdk-dev] [PATCH v7 7/9] eal: pci: export pci_[un]map_device
  2016-02-02 13:48         ` [dpdk-dev] [PATCH v7 " Yuanhan Liu
                             ` (5 preceding siblings ...)
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
@ 2016-02-02 13:48           ` Yuanhan Liu
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 8/9] virtio: add 1.0 support Yuanhan Liu
                             ` (2 subsequent siblings)
  9 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw)
  To: dev

Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will
invoke pci_map_device internally for us. From that point view, there
is no need to export pci_map_device.

However, for virtio pmd driver, which is designed to work without
binding UIO (or something similar first), pci_map_device() will fail,
which ends up with virtio pmd driver being skipped. Therefore, we can
not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver.

Therefore, this patch exports pci_map_device, and let virtio pmd call
it when necessary.

Cc: David Marchand <david.marchand@6wind.com>
Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Santosh Shukla <sshukla@mvista.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: David Marchand <david.marchand@6wind.com>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
 lib/librte_eal/bsdapp/eal/eal_pci.c             |  4 ++--
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |  2 ++
 lib/librte_eal/common/eal_common_pci.c          |  4 ++--
 lib/librte_eal/common/eal_private.h             | 18 -----------------
 lib/librte_eal/common/include/rte_pci.h         | 27 +++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_pci.c           |  4 ++--
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |  3 +++
 7 files changed, 38 insertions(+), 24 deletions(-)

diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c
index 6c21fbd..95c32c1 100644
--- a/lib/librte_eal/bsdapp/eal/eal_pci.c
+++ b/lib/librte_eal/bsdapp/eal/eal_pci.c
@@ -93,7 +93,7 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused)
 
 /* Map pci device */
 int
-pci_map_device(struct rte_pci_device *dev)
+rte_eal_pci_map_device(struct rte_pci_device *dev)
 {
 	int ret = -1;
 
@@ -115,7 +115,7 @@ pci_map_device(struct rte_pci_device *dev)
 
 /* Unmap pci device */
 void
-pci_unmap_device(struct rte_pci_device *dev)
+rte_eal_pci_unmap_device(struct rte_pci_device *dev)
 {
 	/* try unmapping the NIC resources */
 	switch (dev->kdrv) {
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 6fa9c67..d8ac7f7 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -139,6 +139,8 @@ DPDK_2.2 {
 DPDK_2.3 {
 	global:
 
+	rte_eal_pci_map_device;
+	rte_eal_pci_unmap_device;
 	rte_cpu_feature_table;
 
 } DPDK_2.2;
diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
index dcfe947..96d5113 100644
--- a/lib/librte_eal/common/eal_common_pci.c
+++ b/lib/librte_eal/common/eal_common_pci.c
@@ -188,7 +188,7 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d
 			pci_config_space_set(dev);
 #endif
 			/* map resources for devices that use igb_uio */
-			ret = pci_map_device(dev);
+			ret = rte_eal_pci_map_device(dev);
 			if (ret != 0)
 				return ret;
 		} else if (dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND &&
@@ -254,7 +254,7 @@ rte_eal_pci_detach_dev(struct rte_pci_driver *dr,
 
 		if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
 			/* unmap resources for devices that use igb_uio */
-			pci_unmap_device(dev);
+			rte_eal_pci_unmap_device(dev);
 
 		return 0;
 	}
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index 072e672..2342fa1 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -165,24 +165,6 @@ struct rte_pci_device;
 int pci_unbind_kernel_driver(struct rte_pci_device *dev);
 
 /**
- * Map this device
- *
- * This function is private to EAL.
- *
- * @return
- *   0 on success, negative on error and positive if no driver
- *   is found for the device.
- */
-int pci_map_device(struct rte_pci_device *dev);
-
-/**
- * Unmap this device
- *
- * This function is private to EAL.
- */
-void pci_unmap_device(struct rte_pci_device *dev);
-
-/**
  * Map the PCI resource of a PCI device in virtual memory
  *
  * This function is private to EAL.
diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h
index 334c12e..2224109 100644
--- a/lib/librte_eal/common/include/rte_pci.h
+++ b/lib/librte_eal/common/include/rte_pci.h
@@ -485,6 +485,33 @@ 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);
+/**
+ * Map the PCI device resources in user space virtual memory address
+ *
+ * Note that driver should not call this function when flag
+ * RTE_PCI_DRV_NEED_MAPPING is set, as EAL will do that for
+ * you when it's on.
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device
+ *   to use
+ *
+ * @return
+ *   0 on success, negative on error and positive if no driver
+ *   is found for the device.
+ */
+int rte_eal_pci_map_device(struct rte_pci_device *dev);
+
+/**
+ * Unmap this device
+ *
+ * @param dev
+ *   A pointer to a rte_pci_device structure describing the device
+ *   to use
+ */
+void rte_eal_pci_unmap_device(struct rte_pci_device *dev);
+
+
 
 #ifdef RTE_PCI_CONFIG
 /**
diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c
index bc5b5be..db947da 100644
--- a/lib/librte_eal/linuxapp/eal/eal_pci.c
+++ b/lib/librte_eal/linuxapp/eal/eal_pci.c
@@ -124,7 +124,7 @@ pci_get_kernel_driver_by_path(const char *filename, char *dri_name)
 
 /* Map pci device */
 int
-pci_map_device(struct rte_pci_device *dev)
+rte_eal_pci_map_device(struct rte_pci_device *dev)
 {
 	int ret = -1;
 
@@ -153,7 +153,7 @@ pci_map_device(struct rte_pci_device *dev)
 
 /* Unmap pci device */
 void
-pci_unmap_device(struct rte_pci_device *dev)
+rte_eal_pci_unmap_device(struct rte_pci_device *dev)
 {
 	/* try unmapping the NIC resources using VFIO if it exists */
 	switch (dev->kdrv) {
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index aa4fcbd..4c09c0b 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -142,5 +142,8 @@ DPDK_2.2 {
 DPDK_2.3 {
 	global:
 
+	rte_eal_pci_map_device;
+	rte_eal_pci_unmap_device;
 	rte_cpu_feature_table;
+
 } DPDK_2.2;
-- 
1.9.0

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

* [dpdk-dev] [PATCH v7 8/9] virtio: add 1.0 support
  2016-02-02 13:48         ` [dpdk-dev] [PATCH v7 " Yuanhan Liu
                             ` (6 preceding siblings ...)
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu
@ 2016-02-02 13:48           ` Yuanhan Liu
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
  2016-02-03 15:09           ` [dpdk-dev] [PATCH v7 0/9] virtio 1.0 enabling for virtio pmd driver Thomas Monjalon
  9 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw)
  To: dev

Modern (v1.0) virtio pci device defines several pci capabilities.
Each cap has a configure structure corresponding to it, and the
cap.bar and cap.offset fields tell us where to find it.

Firstly, we map the pci resources by rte_eal_pci_map_device().
We then could easily locate a cfg structure by:

    cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset;

Therefore, the entrance of enabling modern (v1.0) pci device support
is to iterate the pci capability lists, and to locate some configs
we care; and they are:

- common cfg

  For generic virtio and virtqueue configuration, such as setting/getting
  features, enabling a specific queue, and so on.

- nofity cfg

  Combining with `queue_notify_off' from common cfg, we could use it to
  notify a specific virt queue.

- device cfg

  Where virtio_net_config structure is located.

- isr cfg

  Where to read isr (interrupt status).

If any of above cap is not found, we fallback to the legacy virtio
handling.

If succeed, hw->vtpci_ops is assigned to modern_ops, where all
operations are implemented by reading/writing a (or few) specific
configuration space from above 4 cfg structures. And that's basically
how this patch works.

Besides those changes, virtio 1.0 introduces a new status field:
FEATURES_OK, which is set after features negotiation is done.

Last, set the VIRTIO_F_VERSION_1 feature flag.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---

v6: - unfold DEF_IO_READ/WRITE macros

v5: - rename MODERN_READ/WRITE_DEF macro name to IO_READ/WRITE_DEF

    - check offset + length overflow
---
 doc/guides/rel_notes/release_2_3.rst |   3 +
 drivers/net/virtio/virtio_ethdev.c   |  25 ++-
 drivers/net/virtio/virtio_ethdev.h   |   3 +-
 drivers/net/virtio/virtio_pci.c      | 355 ++++++++++++++++++++++++++++++++++-
 drivers/net/virtio/virtio_pci.h      |  67 +++++++
 drivers/net/virtio/virtqueue.h       |   2 +
 6 files changed, 450 insertions(+), 5 deletions(-)

diff --git a/doc/guides/rel_notes/release_2_3.rst b/doc/guides/rel_notes/release_2_3.rst
index 99de186..c390d97 100644
--- a/doc/guides/rel_notes/release_2_3.rst
+++ b/doc/guides/rel_notes/release_2_3.rst
@@ -4,6 +4,9 @@ DPDK Release 2.3
 New Features
 ------------
 
+* **Virtio 1.0 support.**
+
+  Enabled virtio 1.0 support for virtio pmd driver.
 
 Resolved Issues
 ---------------
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 4f84757..755503d 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return virtio_send_command(hw->cvq, &ctrl, &len, 1);
 }
 
-static void
+static int
 virtio_negotiate_features(struct virtio_hw *hw)
 {
 	uint64_t host_features;
@@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw)
 	hw->guest_features = vtpci_negotiate_features(hw, host_features);
 	PMD_INIT_LOG(DEBUG, "features after negotiate = %" PRIx64,
 		hw->guest_features);
+
+	if (hw->modern) {
+		if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) {
+			PMD_INIT_LOG(ERR,
+				"VIRTIO_F_VERSION_1 features is not enabled.");
+			return -1;
+		}
+		vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK);
+		if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) {
+			PMD_INIT_LOG(ERR,
+				"failed to set FEATURES_OK status!");
+			return -1;
+		}
+	}
+
+	return 0;
 }
 
 /*
@@ -1032,7 +1048,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	/* Tell the host we've known how to drive the device. */
 	vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
-	virtio_negotiate_features(hw);
+	if (virtio_negotiate_features(hw) < 0)
+		return -1;
 
 	/* If host does not support status then disable LSC */
 	if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS))
@@ -1043,7 +1060,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 	rx_func_get(eth_dev);
 
 	/* Setting up rx_header size for the device */
-	if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF))
+	if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) ||
+	    vtpci_with_feature(hw, VIRTIO_F_VERSION_1))
 		hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf);
 	else
 		hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr);
@@ -1159,6 +1177,7 @@ eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev)
 		rte_intr_callback_unregister(&pci_dev->intr_handle,
 						virtio_interrupt_handler,
 						eth_dev);
+	rte_eal_pci_unmap_device(pci_dev);
 
 	PMD_INIT_LOG(DEBUG, "dev_uninit completed");
 
diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h
index ae2d47d..fed9571 100644
--- a/drivers/net/virtio/virtio_ethdev.h
+++ b/drivers/net/virtio/virtio_ethdev.h
@@ -64,7 +64,8 @@
 	 1u << VIRTIO_NET_F_CTRL_VQ	  |	\
 	 1u << VIRTIO_NET_F_CTRL_RX	  |	\
 	 1u << VIRTIO_NET_F_CTRL_VLAN	  |	\
-	 1u << VIRTIO_NET_F_MRG_RXBUF)
+	 1u << VIRTIO_NET_F_MRG_RXBUF	  |	\
+	 1ULL << VIRTIO_F_VERSION_1)
 
 /*
  * CQ function prototype
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 3961077..4cdecea 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -41,6 +41,14 @@
 #include "virtio_logs.h"
 #include "virtqueue.h"
 
+/*
+ * Following macros are derieved from linux/pci_regs.h, however,
+ * we can't simply include that header here, as there is no such
+ * file for non-Linux platform.
+ */
+#define PCI_CAPABILITY_LIST	0x34
+#define PCI_CAP_ID_VNDR		0x09
+
 static void
 legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
 		       void *dst, int length)
@@ -444,6 +452,218 @@ static const struct virtio_pci_ops legacy_ops = {
 };
 
 
+
+static inline uint8_t
+io_read8(uint8_t *addr)
+{
+	return *(volatile uint8_t *)addr;
+}
+
+static inline void
+io_write8(uint8_t val, uint8_t *addr)
+{
+	*(volatile uint8_t *)addr = val;
+}
+
+static inline uint16_t
+io_read16(uint16_t *addr)
+{
+	return *(volatile uint16_t *)addr;
+}
+
+static inline void
+io_write16(uint16_t val, uint16_t *addr)
+{
+	*(volatile uint16_t *)addr = val;
+}
+
+static inline uint32_t
+io_read32(uint32_t *addr)
+{
+	return *(volatile uint32_t *)addr;
+}
+
+static inline void
+io_write32(uint32_t val, uint32_t *addr)
+{
+	*(volatile uint32_t *)addr = val;
+}
+
+static inline void
+io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
+{
+	io_write32(val & ((1ULL << 32) - 1), lo);
+	io_write32(val >> 32,		     hi);
+}
+
+static void
+modern_read_dev_config(struct virtio_hw *hw, size_t offset,
+		       void *dst, int length)
+{
+	int i;
+	uint8_t *p;
+	uint8_t old_gen, new_gen;
+
+	do {
+		old_gen = io_read8(&hw->common_cfg->config_generation);
+
+		p = dst;
+		for (i = 0;  i < length; i++)
+			*p++ = io_read8((uint8_t *)hw->dev_cfg + offset + i);
+
+		new_gen = io_read8(&hw->common_cfg->config_generation);
+	} while (old_gen != new_gen);
+}
+
+static void
+modern_write_dev_config(struct virtio_hw *hw, size_t offset,
+			const void *src, int length)
+{
+	int i;
+	const uint8_t *p = src;
+
+	for (i = 0;  i < length; i++)
+		io_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i);
+}
+
+static uint64_t
+modern_get_features(struct virtio_hw *hw)
+{
+	uint32_t features_lo, features_hi;
+
+	io_write32(0, &hw->common_cfg->device_feature_select);
+	features_lo = io_read32(&hw->common_cfg->device_feature);
+
+	io_write32(1, &hw->common_cfg->device_feature_select);
+	features_hi = io_read32(&hw->common_cfg->device_feature);
+
+	return ((uint64_t)features_hi << 32) | features_lo;
+}
+
+static void
+modern_set_features(struct virtio_hw *hw, uint64_t features)
+{
+	io_write32(0, &hw->common_cfg->guest_feature_select);
+	io_write32(features & ((1ULL << 32) - 1),
+		&hw->common_cfg->guest_feature);
+
+	io_write32(1, &hw->common_cfg->guest_feature_select);
+	io_write32(features >> 32,
+		&hw->common_cfg->guest_feature);
+}
+
+static uint8_t
+modern_get_status(struct virtio_hw *hw)
+{
+	return io_read8(&hw->common_cfg->device_status);
+}
+
+static void
+modern_set_status(struct virtio_hw *hw, uint8_t status)
+{
+	io_write8(status, &hw->common_cfg->device_status);
+}
+
+static void
+modern_reset(struct virtio_hw *hw)
+{
+	modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
+	modern_get_status(hw);
+}
+
+static uint8_t
+modern_get_isr(struct virtio_hw *hw)
+{
+	return io_read8(hw->isr);
+}
+
+static uint16_t
+modern_set_config_irq(struct virtio_hw *hw, uint16_t vec)
+{
+	io_write16(vec, &hw->common_cfg->msix_config);
+	return io_read16(&hw->common_cfg->msix_config);
+}
+
+static uint16_t
+modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
+{
+	io_write16(queue_id, &hw->common_cfg->queue_select);
+	return io_read16(&hw->common_cfg->queue_size);
+}
+
+static void
+modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
+{
+	uint64_t desc_addr, avail_addr, used_addr;
+	uint16_t notify_off;
+
+	desc_addr = vq->mz->phys_addr;
+	avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
+	used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail,
+							 ring[vq->vq_nentries]),
+				   VIRTIO_PCI_VRING_ALIGN);
+
+	io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
+
+	io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo,
+				      &hw->common_cfg->queue_desc_hi);
+	io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo,
+				       &hw->common_cfg->queue_avail_hi);
+	io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo,
+				      &hw->common_cfg->queue_used_hi);
+
+	notify_off = io_read16(&hw->common_cfg->queue_notify_off);
+	vq->notify_addr = (void *)((uint8_t *)hw->notify_base +
+				notify_off * hw->notify_off_multiplier);
+
+	io_write16(1, &hw->common_cfg->queue_enable);
+
+	PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index);
+	PMD_INIT_LOG(DEBUG, "\t desc_addr: %" PRIx64, desc_addr);
+	PMD_INIT_LOG(DEBUG, "\t aval_addr: %" PRIx64, avail_addr);
+	PMD_INIT_LOG(DEBUG, "\t used_addr: %" PRIx64, used_addr);
+	PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)",
+		vq->notify_addr, notify_off);
+}
+
+static void
+modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
+{
+	io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
+
+	io_write64_twopart(0, &hw->common_cfg->queue_desc_lo,
+				  &hw->common_cfg->queue_desc_hi);
+	io_write64_twopart(0, &hw->common_cfg->queue_avail_lo,
+				  &hw->common_cfg->queue_avail_hi);
+	io_write64_twopart(0, &hw->common_cfg->queue_used_lo,
+				  &hw->common_cfg->queue_used_hi);
+
+	io_write16(0, &hw->common_cfg->queue_enable);
+}
+
+static void
+modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
+{
+	io_write16(1, vq->notify_addr);
+}
+
+static const struct virtio_pci_ops modern_ops = {
+	.read_dev_cfg	= modern_read_dev_config,
+	.write_dev_cfg	= modern_write_dev_config,
+	.reset		= modern_reset,
+	.get_status	= modern_get_status,
+	.set_status	= modern_set_status,
+	.get_features	= modern_get_features,
+	.set_features	= modern_set_features,
+	.get_isr	= modern_get_isr,
+	.set_config_irq	= modern_set_config_irq,
+	.get_queue_num	= modern_get_queue_num,
+	.setup_queue	= modern_setup_queue,
+	.del_queue	= modern_del_queue,
+	.notify_queue	= modern_notify_queue,
+};
+
+
 void
 vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
 		      void *dst, int length)
@@ -497,6 +717,12 @@ vtpci_set_status(struct virtio_hw *hw, uint8_t status)
 }
 
 uint8_t
+vtpci_get_status(struct virtio_hw *hw)
+{
+	return hw->vtpci_ops->get_status(hw);
+}
+
+uint8_t
 vtpci_isr(struct virtio_hw *hw)
 {
 	return hw->vtpci_ops->get_isr(hw);
@@ -510,15 +736,142 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
 	return hw->vtpci_ops->set_config_irq(hw, vec);
 }
 
+static void *
+get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)
+{
+	uint8_t  bar    = cap->bar;
+	uint32_t length = cap->length;
+	uint32_t offset = cap->offset;
+	uint8_t *base;
+
+	if (bar > 5) {
+		PMD_INIT_LOG(ERR, "invalid bar: %u", bar);
+		return NULL;
+	}
+
+	if (offset + length < offset) {
+		PMD_INIT_LOG(ERR, "offset(%u) + length(%u) overflows",
+			offset, length);
+		return NULL;
+	}
+
+	if (offset + length > dev->mem_resource[bar].len) {
+		PMD_INIT_LOG(ERR,
+			"invalid cap: overflows bar space: %u > %" PRIu64,
+			offset + length, dev->mem_resource[bar].len);
+		return NULL;
+	}
+
+	base = dev->mem_resource[bar].addr;
+	if (base == NULL) {
+		PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar);
+		return NULL;
+	}
+
+	return base + offset;
+}
+
+static int
+virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
+{
+	uint8_t pos;
+	struct virtio_pci_cap cap;
+	int ret;
+
+	if (rte_eal_pci_map_device(dev) < 0) {
+		PMD_INIT_LOG(DEBUG, "failed to map pci device!");
+		return -1;
+	}
+
+	ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST);
+	if (ret < 0) {
+		PMD_INIT_LOG(DEBUG, "failed to read pci capability list");
+		return -1;
+	}
+
+	while (pos) {
+		ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos);
+		if (ret < 0) {
+			PMD_INIT_LOG(ERR,
+				"failed to read pci cap at pos: %x", pos);
+			break;
+		}
+
+		if (cap.cap_vndr != PCI_CAP_ID_VNDR) {
+			PMD_INIT_LOG(DEBUG,
+				"[%2x] skipping non VNDR cap id: %02x",
+				pos, cap.cap_vndr);
+			goto next;
+		}
+
+		PMD_INIT_LOG(DEBUG,
+			"[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u",
+			pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
+
+		switch (cap.cfg_type) {
+		case VIRTIO_PCI_CAP_COMMON_CFG:
+			hw->common_cfg = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_NOTIFY_CFG:
+			rte_eal_pci_read_config(dev, &hw->notify_off_multiplier,
+						4, pos + sizeof(cap));
+			hw->notify_base = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_DEVICE_CFG:
+			hw->dev_cfg = get_cfg_addr(dev, &cap);
+			break;
+		case VIRTIO_PCI_CAP_ISR_CFG:
+			hw->isr = get_cfg_addr(dev, &cap);
+			break;
+		}
+
+next:
+		pos = cap.cap_next;
+	}
+
+	if (hw->common_cfg == NULL || hw->notify_base == NULL ||
+	    hw->dev_cfg == NULL    || hw->isr == NULL) {
+		PMD_INIT_LOG(INFO, "no modern virtio pci device found.");
+		return -1;
+	}
+
+	PMD_INIT_LOG(INFO, "found modern virtio pci device.");
+
+	PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg);
+	PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg);
+	PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr);
+	PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u",
+		hw->notify_base, hw->notify_off_multiplier);
+
+	return 0;
+}
+
 int
 vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
 {
-	hw->vtpci_ops = &legacy_ops;
+	hw->dev = dev;
 
+	/*
+	 * Try if we can succeed reading virtio pci caps, which exists
+	 * only on modern pci device. If failed, we fallback to legacy
+	 * virtio handling.
+	 */
+	if (virtio_read_caps(dev, hw) == 0) {
+		PMD_INIT_LOG(INFO, "modern virtio pci detected.");
+		hw->vtpci_ops = &modern_ops;
+		hw->modern    = 1;
+		dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
+		return 0;
+	}
+
+	PMD_INIT_LOG(INFO, "trying with legacy virtio pci.");
 	if (legacy_virtio_resource_init(dev) < 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 d7bc6bb..fcac660 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -93,6 +93,7 @@ struct virtqueue;
 #define VIRTIO_CONFIG_STATUS_ACK       0x01
 #define VIRTIO_CONFIG_STATUS_DRIVER    0x02
 #define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04
+#define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08
 #define VIRTIO_CONFIG_STATUS_FAILED    0x80
 
 /*
@@ -141,6 +142,8 @@ struct virtqueue;
 /* We support indirect buffer descriptors */
 #define VIRTIO_RING_F_INDIRECT_DESC	28
 
+#define VIRTIO_F_VERSION_1		32
+
 /*
  * Some VirtIO feature bits (currently bits 28 through 31) are
  * reserved for the transport being used (eg. virtio_ring), the
@@ -163,6 +166,60 @@ struct virtqueue;
  */
 #define VIRTIO_MAX_VIRTQUEUES 8
 
+/* Common configuration */
+#define VIRTIO_PCI_CAP_COMMON_CFG	1
+/* Notifications */
+#define VIRTIO_PCI_CAP_NOTIFY_CFG	2
+/* ISR Status */
+#define VIRTIO_PCI_CAP_ISR_CFG		3
+/* Device specific configuration */
+#define VIRTIO_PCI_CAP_DEVICE_CFG	4
+/* PCI configuration access */
+#define VIRTIO_PCI_CAP_PCI_CFG		5
+
+/* This is the PCI capability header: */
+struct virtio_pci_cap {
+	uint8_t cap_vndr;		/* Generic PCI field: PCI_CAP_ID_VNDR */
+	uint8_t cap_next;		/* Generic PCI field: next ptr. */
+	uint8_t cap_len;		/* Generic PCI field: capability length */
+	uint8_t cfg_type;		/* Identifies the structure. */
+	uint8_t bar;			/* Where to find it. */
+	uint8_t padding[3];		/* Pad to full dword. */
+	uint32_t offset;		/* Offset within bar. */
+	uint32_t length;		/* Length of the structure, in bytes. */
+};
+
+struct virtio_pci_notify_cap {
+	struct virtio_pci_cap cap;
+	uint32_t notify_off_multiplier;	/* Multiplier for queue_notify_off. */
+};
+
+/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */
+struct virtio_pci_common_cfg {
+	/* About the whole device. */
+	uint32_t device_feature_select;	/* read-write */
+	uint32_t device_feature;	/* read-only */
+	uint32_t guest_feature_select;	/* read-write */
+	uint32_t guest_feature;		/* read-write */
+	uint16_t msix_config;		/* read-write */
+	uint16_t num_queues;		/* read-only */
+	uint8_t device_status;		/* read-write */
+	uint8_t config_generation;	/* read-only */
+
+	/* About a specific virtqueue. */
+	uint16_t queue_select;		/* read-write */
+	uint16_t queue_size;		/* read-write, power of 2. */
+	uint16_t queue_msix_vector;	/* read-write */
+	uint16_t queue_enable;		/* read-write */
+	uint16_t queue_notify_off;	/* read-only */
+	uint32_t queue_desc_lo;		/* read-write */
+	uint32_t queue_desc_hi;		/* read-write */
+	uint32_t queue_avail_lo;	/* read-write */
+	uint32_t queue_avail_hi;	/* read-write */
+	uint32_t queue_used_lo;		/* read-write */
+	uint32_t queue_used_hi;		/* read-write */
+};
+
 struct virtio_hw;
 
 struct virtio_pci_ops {
@@ -188,6 +245,8 @@ struct virtio_pci_ops {
 	void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq);
 };
 
+struct virtio_net_config;
+
 struct virtio_hw {
 	struct virtqueue *cvq;
 	uint32_t    io_base;
@@ -198,7 +257,14 @@ struct virtio_hw {
 	uint8_t	    vlan_strip;
 	uint8_t	    use_msix;
 	uint8_t     started;
+	uint8_t     modern;
 	uint8_t     mac_addr[ETHER_ADDR_LEN];
+	uint32_t    notify_off_multiplier;
+	uint8_t     *isr;
+	uint16_t    *notify_base;
+	struct rte_pci_device *dev;
+	struct virtio_pci_common_cfg *common_cfg;
+	struct virtio_net_config *dev_cfg;
 	const struct virtio_pci_ops *vtpci_ops;
 };
 
@@ -284,6 +350,7 @@ void vtpci_reset(struct virtio_hw *);
 
 void vtpci_reinit_complete(struct virtio_hw *);
 
+uint8_t vtpci_get_status(struct virtio_hw *);
 void vtpci_set_status(struct virtio_hw *, uint8_t);
 
 uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t);
diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h
index d7fb450..99d4fa9 100644
--- a/drivers/net/virtio/virtqueue.h
+++ b/drivers/net/virtio/virtqueue.h
@@ -202,6 +202,8 @@ struct virtqueue {
 	/* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */
 	uint64_t	size_bins[8];
 
+	uint16_t	*notify_addr;
+
 	struct vq_desc_extra {
 		void              *cookie;
 		uint16_t          ndescs;
-- 
1.9.0

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

* [dpdk-dev] [PATCH v7 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c
  2016-02-02 13:48         ` [dpdk-dev] [PATCH v7 " Yuanhan Liu
                             ` (7 preceding siblings ...)
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 8/9] virtio: add 1.0 support Yuanhan Liu
@ 2016-02-02 13:48           ` Yuanhan Liu
  2016-02-03 15:09           ` [dpdk-dev] [PATCH v7 0/9] virtio 1.0 enabling for virtio pmd driver Thomas Monjalon
  9 siblings, 0 replies; 122+ messages in thread
From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw)
  To: dev

virtio_pci.c is the only file references those macros; move them there.

Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
Tested-by: Qian Xu <qian.q.xu@intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp>
Acked-by: Huawei Xie <huawei.xie@intel.com>
---
 drivers/net/virtio/virtio_pci.c | 19 +++++++++++++++++++
 drivers/net/virtio/virtio_pci.h | 18 ------------------
 2 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index 4cdecea..9fbc2f5 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -49,6 +49,25 @@
 #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))))
+
 static void
 legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
 		       void *dst, int length)
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index fcac660..0544a07 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -318,24 +318,6 @@ outl_p(unsigned int data, unsigned int port)
 }
 #endif
 
-#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))))
-
 static inline int
 vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 {
-- 
1.9.0

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

* Re: [dpdk-dev] [PATCH v7 0/9] virtio 1.0 enabling for virtio pmd driver
  2016-02-02 13:48         ` [dpdk-dev] [PATCH v7 " Yuanhan Liu
                             ` (8 preceding siblings ...)
  2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
@ 2016-02-03 15:09           ` Thomas Monjalon
  9 siblings, 0 replies; 122+ messages in thread
From: Thomas Monjalon @ 2016-02-03 15:09 UTC (permalink / raw)
  To: Yuanhan Liu; +Cc: dev

2016-02-02 21:48, Yuanhan Liu:
> v7: - make checkpatch a bit happier; few (false) warnings still left.
> 
>     - rebase to latest code: fixed a conflict.
> 
> v6: unfold IO_READ/WRITE_DEF macro
> 
> v5: minor fixes:
> 
>     - fix wrong type of arg "offset" of read/write_dev_config(): patch 2
>       is newly added for that.
> 
>     - check "offset + length" overflow
> 
> Almost all difference comes from virtio 1.0 are the PCI layout change:
> the major configuration structures are stored at bar space, and their
> location is stored at corresponding pci cap structure. Reading/parsing
> them is one of the major work of patch 8.
> 
> To make handling virtio v1.0 and v0.95 co-exist well, this patch set
> introduces a virtio_pci_ops structure, to add another layer so that
> we could keep those vtpci_foo_bar "APIs". With that, we could do the
> minimum change to add virtio 1.0 support.

Applied, thanks

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

end of thread, other threads:[~2016-02-03 15:10 UTC | newest]

Thread overview: 122+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-10  3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu
2015-12-10  3:54 ` [dpdk-dev] [PATCH 1/6] virtio: don't set vring address again at queue startup Yuanhan Liu
2015-12-10  3:54 ` [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops Yuanhan Liu
2015-12-29 11:31   ` Tan, Jianfeng
2015-12-30  3:45     ` Yuanhan Liu
2015-12-10  3:54 ` [dpdk-dev] [PATCH 3/6] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
2015-12-10  3:54 ` [dpdk-dev] [PATCH 4/6] viritio: switch to 64 bit features Yuanhan Liu
2015-12-10  3:54 ` [dpdk-dev] [PATCH 5/6] virtio: set RTE_PCI_DRV_NEED_MAPPING flag Yuanhan Liu
2015-12-10  3:54 ` [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support Yuanhan Liu
2015-12-29 11:39   ` Tan, Jianfeng
2015-12-30  3:40     ` Yuanhan Liu
2015-12-10  3:58 ` [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu
2015-12-29 11:19 ` Tan, Jianfeng
2015-12-30  3:53   ` Yuanhan Liu
2016-01-04  3:55   ` Xu, Qian Q
2016-01-04  4:16     ` Yuanhan Liu
2016-01-12  6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
2016-01-12  6:58   ` [dpdk-dev] [PATCH v2 1/7] virtio: don't set vring address again at queue startup Yuanhan Liu
2016-01-12  6:58   ` [dpdk-dev] [PATCH v2 2/7] virtio: introduce struct virtio_pci_ops Yuanhan Liu
2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 3/7] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 4/7] viritio: switch to 64 bit features Yuanhan Liu
2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 5/7] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device Yuanhan Liu
2016-01-12  8:31     ` David Marchand
2016-01-12  8:40       ` Yuanhan Liu
2016-01-12  9:05         ` Yuanhan Liu
2016-01-13 14:44           ` Santosh Shukla
2016-01-12  6:59   ` [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support Yuanhan Liu
2016-01-13  3:31     ` Tetsuya Mukawa
2016-01-13  9:38       ` Yuanhan Liu
2016-01-14  7:47     ` Xie, Huawei
2016-01-14  7:50       ` Yuanhan Liu
2016-01-14  7:51         ` Xie, Huawei
2016-01-14  7:58           ` Yuanhan Liu
2016-01-14  8:08             ` Xie, Huawei
2016-01-14  8:22               ` Yuanhan Liu
2016-01-14  8:28                 ` Xie, Huawei
2016-01-14  7:50     ` Xie, Huawei
2016-01-14  8:38       ` Yuanhan Liu
2016-01-12  7:07   ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
2016-01-14  4:27   ` Tetsuya Mukawa
2016-01-14  5:59     ` Yuanhan Liu
2016-01-14  6:09     ` Tan, Jianfeng
2016-01-14  6:41       ` Tetsuya Mukawa
2016-01-18  9:04         ` Tetsuya Mukawa
2016-01-14  6:45       ` Yuanhan Liu
2016-01-14  7:42   ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu
2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu
2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 2/8] virtio: introduce struct virtio_pci_ops Yuanhan Liu
2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 3/8] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 4/8] viritio: switch to 64 bit features Yuanhan Liu
2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 6/8] eal: pci: export pci_[un]map_device Yuanhan Liu
2016-01-14  7:45       ` Yuanhan Liu
2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 7/8] virtio: add 1.0 support Yuanhan Liu
2016-01-14  7:42     ` [dpdk-dev] [PATCH v3 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
2016-01-16 10:08       ` Santosh Shukla
2016-01-17 14:07         ` Santosh Shukla
2016-01-15  4:36   ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu
2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu
2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 2/8] virtio: introduce struct virtio_pci_ops Yuanhan Liu
2016-01-18 17:21       ` Xie, Huawei
2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 3/8] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 4/8] viritio: switch to 64 bit features Yuanhan Liu
2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 6/8] eal: pci: export pci_[un]map_device Yuanhan Liu
2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support Yuanhan Liu
2016-01-18 16:38       ` Xie, Huawei
2016-01-18 16:50       ` Xie, Huawei
2016-01-19  5:55         ` Yuanhan Liu
2016-01-19  7:44           ` Xie, Huawei
2016-01-19  7:54             ` Yuanhan Liu
2016-01-19  8:02             ` Xie, Huawei
2016-01-18 17:07       ` Xie, Huawei
2016-01-19  1:36         ` Yuanhan Liu
2016-01-19  1:51           ` Xie, Huawei
2016-01-19  2:46             ` Yuanhan Liu
2016-01-19  2:48               ` Xie, Huawei
2016-01-19  5:54                 ` Yuanhan Liu
2016-01-15  4:36     ` [dpdk-dev] [PATCH v4 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
2016-01-15  8:57       ` Xu, Qian Q
2016-01-18  8:04     ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Tetsuya Mukawa
2016-01-19  8:11     ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu
2016-01-19  8:11       ` [dpdk-dev] [PATCH v5 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu
2016-01-19  8:11       ` [dpdk-dev] [PATCH v5 2/9] virtio: define offset as size_t type Yuanhan Liu
2016-01-19  8:11       ` [dpdk-dev] [PATCH v5 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu
2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 5/9] viritio: switch to 64 bit features Yuanhan Liu
2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu
2016-01-19  8:17         ` David Marchand
2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support Yuanhan Liu
2016-01-21 11:37         ` Thomas Monjalon
2016-01-27  3:49           ` Yuanhan Liu
2016-01-21 11:49         ` Thomas Monjalon
2016-01-27  3:46           ` Yuanhan Liu
2016-01-27  8:11             ` Thomas Monjalon
2016-01-19  8:12       ` [dpdk-dev] [PATCH v5 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
2016-01-19  8:55       ` [dpdk-dev] [PATCH v5 0/9] virtio 1.0 enabling for virtio pmd driver Xie, Huawei
2016-01-28  7:54       ` [dpdk-dev] [PATCH v6 " Yuanhan Liu
2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu
2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 2/9] virtio: define offset as size_t type Yuanhan Liu
2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu
2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 5/9] viritio: switch to 64 bit features Yuanhan Liu
2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu
2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 8/9] virtio: add 1.0 support Yuanhan Liu
2016-01-28  7:54         ` [dpdk-dev] [PATCH v6 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
2016-02-02 10:46         ` [dpdk-dev] [PATCH v6 0/9] virtio 1.0 enabling for virtio pmd driver Thomas Monjalon
2016-02-02 13:00           ` Yuanhan Liu
2016-02-02 13:48         ` [dpdk-dev] [PATCH v7 " Yuanhan Liu
2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu
2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 2/9] virtio: define offset as size_t type Yuanhan Liu
2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu
2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu
2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 5/9] viritio: switch to 64 bit features Yuanhan Liu
2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu
2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu
2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 8/9] virtio: add 1.0 support Yuanhan Liu
2016-02-02 13:48           ` [dpdk-dev] [PATCH v7 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu
2016-02-03 15:09           ` [dpdk-dev] [PATCH v7 0/9] virtio 1.0 enabling for virtio pmd driver 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).