virtio: introduce PCI implementation structure
authorYuanhan Liu <yuanhan.liu@linux.intel.com>
Tue, 2 Feb 2016 13:48:14 +0000 (21:48 +0800)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Wed, 3 Feb 2016 15:07:49 +0000 (16:07 +0100)
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>
drivers/net/virtio/virtio_ethdev.c
drivers/net/virtio/virtio_pci.c
drivers/net/virtio/virtio_pci.h
drivers/net/virtio/virtqueue.h

index d928339..6c1d3a0 100644 (file)
@@ -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;
 
index b34b59e..8d001e8 100644 (file)
 
 #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;
 }
index fe89c21..e8e7509 100644 (file)
@@ -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);
 
index 61b3137..d7fb450 100644 (file)
@@ -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