[PATCH v3 2/8] virtio: introduce struct virtio_pci_ops
From: Yuanhan Liu <hidden>
Date: 2016-01-14 07:41:40
Subsystem:
networking drivers, the rest · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
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 <redacted>
---
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