From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by dpdk.org (Postfix) with ESMTP id CE5528E99 for ; Fri, 15 Jan 2016 05:34:49 +0100 (CET) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga101.fm.intel.com with ESMTP; 14 Jan 2016 20:34:48 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.22,297,1449561600"; d="scan'208";a="727458979" Received: from yliu-dev.sh.intel.com ([10.239.66.49]) by orsmga003.jf.intel.com with ESMTP; 14 Jan 2016 20:34:47 -0800 From: Yuanhan Liu To: dev@dpdk.org Date: Fri, 15 Jan 2016 12:36:05 +0800 Message-Id: <1452832571-6156-3-git-send-email-yuanhan.liu@linux.intel.com> X-Mailer: git-send-email 1.9.0 In-Reply-To: <1452832571-6156-1-git-send-email-yuanhan.liu@linux.intel.com> References: <1452581944-24838-1-git-send-email-yuanhan.liu@linux.intel.com> <1452832571-6156-1-git-send-email-yuanhan.liu@linux.intel.com> Subject: [dpdk-dev] [PATCH v4 2/8] virtio: introduce struct virtio_pci_ops X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 15 Jan 2016 04:34:50 -0000 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 --- 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