From d5bbeefca82610c211b26390b0bd6a02704f10eb Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Tue, 2 Feb 2016 21:48:14 +0800 Subject: [PATCH] virtio: introduce PCI implementation structure 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 Tested-by: Qian Xu Reviewed-by: Tetsuya Mukawa Tested-by: Tetsuya Mukawa Acked-by: Huawei Xie --- 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 d92833906d..6c1d3a0050 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 b34b59e67e..8d001e8311 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 fe89c21a24..e8e7509d1d 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 61b3137034..d7fb450562 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 -- 2.20.1