[dpdk-dev] [PATCH v6 3/9] virtio: introduce struct virtio_pci_ops

Yuanhan Liu yuanhan.liu at linux.intel.com
Thu Jan 28 08:54:51 CET 2016


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 at linux.intel.com>
Tested-by: Qian Xu <qian.q.xu at intel.com>
Reviewed-by: Tetsuya Mukawa <mukawa at igel.co.jp>
Tested-by: Tetsuya Mukawa <mukawa at igel.co.jp>
Acked-by: Huawei Xie <huawei.xie at 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



More information about the dev mailing list