* [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling @ 2015-12-10 3:54 Yuanhan Liu 2015-12-10 3:54 ` [dpdk-dev] [PATCH 1/6] virtio: don't set vring address again at queue startup Yuanhan Liu ` (8 more replies) 0 siblings, 9 replies; 122+ messages in thread From: Yuanhan Liu @ 2015-12-10 3:54 UTC (permalink / raw) To: dev Hi, Here is an initial virtio 1.0 pmd driver enabling. Almost all difference comes from virtio 1.0 are the PCI layout change: the major configuration structures are stored at bar space, and their location is stored at corresponding pci cap structure. Reading/parsing them is one of the major work of patch 6. To make handling virtio v1.0 and v0.95 co-exist well, this patch set introduces a virtio_pci_ops structure, to add another layer so that we could keep those vtpci_foo_bar "APIs". With that, we could do the minimum change to add virtio 1.0 support. Note that the enabling is still in rough state, and it's likely I may miss something. So, comments are huge welcome! --yliu --- Yuanhan Liu (6): virtio: don't set vring address again at queue startup virtio: introduce struct virtio_pci_ops virtio: move left pci stuff to virtio_pci.c viritio: switch to 64 bit features virtio: set RTE_PCI_DRV_NEED_MAPPING flag virtio: add virtio v1.0 support drivers/net/virtio/virtio_ethdev.c | 297 +-------------- drivers/net/virtio/virtio_ethdev.h | 3 +- drivers/net/virtio/virtio_pci.c | 752 +++++++++++++++++++++++++++++++++++-- drivers/net/virtio/virtio_pci.h | 100 ++++- drivers/net/virtio/virtio_rxtx.c | 15 - drivers/net/virtio/virtqueue.h | 4 +- 6 files changed, 843 insertions(+), 328 deletions(-) -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH 1/6] virtio: don't set vring address again at queue startup 2015-12-10 3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu @ 2015-12-10 3:54 ` Yuanhan Liu 2015-12-10 3:54 ` [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops Yuanhan Liu ` (7 subsequent siblings) 8 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2015-12-10 3:54 UTC (permalink / raw) To: dev As we have already set up it at virtio_dev_queue_setup(), and a vq restart will not reset the settings. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_rxtx.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c index 74b39ef..b7267c0 100644 --- a/drivers/net/virtio/virtio_rxtx.c +++ b/drivers/net/virtio/virtio_rxtx.c @@ -339,11 +339,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type) vq_update_avail_idx(vq); PMD_INIT_LOG(DEBUG, "Allocated %d bufs", nbufs); - - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); } else if (queue_type == VTNET_TQ) { if (use_simple_rxtx) { int mid_idx = vq->vq_nentries >> 1; @@ -362,16 +357,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type) for (i = mid_idx; i < vq->vq_nentries; i++) vq->vq_ring.avail->ring[i] = i; } - - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); - } else { - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); } } -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops 2015-12-10 3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu 2015-12-10 3:54 ` [dpdk-dev] [PATCH 1/6] virtio: don't set vring address again at queue startup Yuanhan Liu @ 2015-12-10 3:54 ` Yuanhan Liu 2015-12-29 11:31 ` Tan, Jianfeng 2015-12-10 3:54 ` [dpdk-dev] [PATCH 3/6] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu ` (6 subsequent siblings) 8 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2015-12-10 3:54 UTC (permalink / raw) To: dev 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> --- drivers/net/virtio/virtio_ethdev.c | 22 ++--- drivers/net/virtio/virtio_pci.c | 162 ++++++++++++++++++++++++++++++------- drivers/net/virtio/virtio_pci.h | 27 +++++++ drivers/net/virtio/virtqueue.h | 2 +- 4 files changed, 171 insertions(+), 42 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..9bcaa07 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,17 +82,130 @@ 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) +{ + /* + * Setting the status to RESET sets the host device to + * the original, uninitialized state. + */ + legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); + legacy_get_status(hw); +} + +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_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_irq = legacy_set_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; } @@ -101,12 +213,8 @@ vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_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); + hw->vtpci_ops->get_status(hw); } void @@ -115,26 +223,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 +243,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_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..a11a4f6 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_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 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops 2015-12-10 3:54 ` [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops Yuanhan Liu @ 2015-12-29 11:31 ` Tan, Jianfeng 2015-12-30 3:45 ` Yuanhan Liu 0 siblings, 1 reply; 122+ messages in thread From: Tan, Jianfeng @ 2015-12-29 11:31 UTC (permalink / raw) To: Yuanhan Liu, dev > -----Original Message----- > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu > Sent: Thursday, December 10, 2015 11:54 AM > To: dev@dpdk.org > Subject: [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops > > 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. > ... > +static void > +legacy_reset(struct virtio_hw *hw) > +{ > + /* > + * Setting the status to RESET sets the host device to > + * the original, uninitialized state. > + */ > + legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); > + legacy_get_status(hw); May need a comment to explain why here we need to get_status(). > +} > + > +static uint8_t > +legacy_get_isr(struct virtio_hw *hw) > +{ Please delete the following blank line. > + > + return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR); > +} > + > +/* Enable one vector (0) for Link State Intrerrupt */ > +static uint16_t > +legacy_set_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); > +} > + ... > + > +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_irq)(struct virtio_hw *hw, uint16_t vec); > + > + uint16_t (*get_queue_num)(struct virtio_hw *hw, uint16_t > queue_id); How about changing the name into get_queue_size? From my side, queue_num is very confusing. Thanks, Jianfeng > + 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); > +}; > + ... > #ifdef RTE_LIBRTE_VIRTIO_DEBUG_DUMP > -- > 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops 2015-12-29 11:31 ` Tan, Jianfeng @ 2015-12-30 3:45 ` Yuanhan Liu 0 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2015-12-30 3:45 UTC (permalink / raw) To: Tan, Jianfeng; +Cc: dev On Tue, Dec 29, 2015 at 11:31:35AM +0000, Tan, Jianfeng wrote: > > > > -----Original Message----- > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu > > Sent: Thursday, December 10, 2015 11:54 AM > > To: dev@dpdk.org > > Subject: [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops > > > > 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. > > > ... > > +static void > > +legacy_reset(struct virtio_hw *hw) > > +{ > > + /* > > + * Setting the status to RESET sets the host device to > > + * the original, uninitialized state. > > + */ > > + legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); > > + legacy_get_status(hw); > > > May need a comment to explain why here we need to get_status(). I don't know, those are old code; I just moved them into a new function. Maybe I need look into the spec for answer. > > > > +} > > + > > +static uint8_t > > +legacy_get_isr(struct virtio_hw *hw) > > +{ > > Please delete the following blank line. oops ... > > + > > + return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR); > > +} > > + > > +/* Enable one vector (0) for Link State Intrerrupt */ > > +static uint16_t > > +legacy_set_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); > > +} > > + > ... > > + > > +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_irq)(struct virtio_hw *hw, uint16_t vec); > > + > > + uint16_t (*get_queue_num)(struct virtio_hw *hw, uint16_t > > queue_id); > > How about changing the name into get_queue_size? From my side, queue_num is very confusing. I agree with you that queue_size is better here, however, queue_num is taken for being consistent with the virtio spec naming: 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); } --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH 3/6] virtio: move left pci stuff to virtio_pci.c 2015-12-10 3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu 2015-12-10 3:54 ` [dpdk-dev] [PATCH 1/6] virtio: don't set vring address again at queue startup Yuanhan Liu 2015-12-10 3:54 ` [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops Yuanhan Liu @ 2015-12-10 3:54 ` Yuanhan Liu 2015-12-10 3:54 ` [dpdk-dev] [PATCH 4/6] viritio: switch to 64 bit features Yuanhan Liu ` (5 subsequent siblings) 8 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2015-12-10 3:54 UTC (permalink / raw) To: dev virtio_pci.c is a more proper place for pci stuff; virtio_ethdev is not. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_ethdev.c | 265 +----------------------------------- drivers/net/virtio/virtio_pci.c | 270 ++++++++++++++++++++++++++++++++++++- 2 files changed, 270 insertions(+), 265 deletions(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 6c1d3a0..b57224d 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -36,10 +36,6 @@ #include <stdio.h> #include <errno.h> #include <unistd.h> -#ifdef RTE_EXEC_ENV_LINUXAPP -#include <dirent.h> -#include <fcntl.h> -#endif #include <rte_ethdev.h> #include <rte_memcpy.h> @@ -955,260 +951,6 @@ virtio_negotiate_features(struct virtio_hw *hw) hw->guest_features); } -#ifdef RTE_EXEC_ENV_LINUXAPP -static int -parse_sysfs_value(const char *filename, unsigned long *val) -{ - FILE *f; - char buf[BUFSIZ]; - char *end = NULL; - - f = fopen(filename, "r"); - if (f == NULL) { - PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s", - __func__, filename); - return -1; - } - - if (fgets(buf, sizeof(buf), f) == NULL) { - PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s", - __func__, filename); - fclose(f); - return -1; - } - *val = strtoul(buf, &end, 0); - if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { - PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s", - __func__, filename); - fclose(f); - return -1; - } - fclose(f); - return 0; -} - -static int get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen, - unsigned int *uio_num) -{ - struct dirent *e; - DIR *dir; - char dirname[PATH_MAX]; - - /* depending on kernel version, uio can be located in uio/uioX - * or uio:uioX */ - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", - loc->domain, loc->bus, loc->devid, loc->function); - dir = opendir(dirname); - if (dir == NULL) { - /* retry with the parent directory */ - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, - loc->domain, loc->bus, loc->devid, loc->function); - dir = opendir(dirname); - - if (dir == NULL) { - PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname); - return -1; - } - } - - /* take the first file starting with "uio" */ - while ((e = readdir(dir)) != NULL) { - /* format could be uio%d ...*/ - int shortprefix_len = sizeof("uio") - 1; - /* ... or uio:uio%d */ - int longprefix_len = sizeof("uio:uio") - 1; - char *endptr; - - if (strncmp(e->d_name, "uio", 3) != 0) - continue; - - /* first try uio%d */ - errno = 0; - *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); - if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { - snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num); - break; - } - - /* then try uio:uio%d */ - errno = 0; - *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); - if (errno == 0 && endptr != (e->d_name + longprefix_len)) { - snprintf(buf, buflen, "%s/uio:uio%u", dirname, - *uio_num); - break; - } - } - closedir(dir); - - /* No uio resource found */ - if (e == NULL) { - PMD_INIT_LOG(ERR, "Could not find uio resource"); - return -1; - } - - return 0; -} - -static int -virtio_has_msix(const struct rte_pci_addr *loc) -{ - DIR *d; - char dirname[PATH_MAX]; - - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs", - loc->domain, loc->bus, loc->devid, loc->function); - - d = opendir(dirname); - if (d) - closedir(d); - - return (d != NULL); -} - -/* Extract I/O port numbers from sysfs */ -static int virtio_resource_init_by_uio(struct rte_pci_device *pci_dev) -{ - char dirname[PATH_MAX]; - char filename[PATH_MAX]; - unsigned long start, size; - unsigned int uio_num; - - if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0) - return -1; - - /* get portio size */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/size", dirname); - if (parse_sysfs_value(filename, &size) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse size", - __func__); - return -1; - } - - /* get portio start */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/start", dirname); - if (parse_sysfs_value(filename, &start) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", - __func__); - return -1; - } - pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; - pci_dev->mem_resource[0].len = (uint64_t)size; - PMD_INIT_LOG(DEBUG, - "PCI Port IO found start=0x%lx with size=0x%lx", - start, size); - - /* save fd */ - memset(dirname, 0, sizeof(dirname)); - snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num); - pci_dev->intr_handle.fd = open(dirname, O_RDWR); - if (pci_dev->intr_handle.fd < 0) { - PMD_INIT_LOG(ERR, "Cannot open %s: %s\n", - dirname, strerror(errno)); - return -1; - } - - pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO; - pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; - - return 0; -} - -/* Extract port I/O numbers from proc/ioports */ -static int virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev) -{ - uint16_t start, end; - int size; - FILE *fp; - char *line = NULL; - char pci_id[16]; - int found = 0; - size_t linesz; - - snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, - pci_dev->addr.domain, - pci_dev->addr.bus, - pci_dev->addr.devid, - pci_dev->addr.function); - - fp = fopen("/proc/ioports", "r"); - if (fp == NULL) { - PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__); - return -1; - } - - while (getdelim(&line, &linesz, '\n', fp) > 0) { - char *ptr = line; - char *left; - int n; - - n = strcspn(ptr, ":"); - ptr[n] = 0; - left = &ptr[n+1]; - - while (*left && isspace(*left)) - left++; - - if (!strncmp(left, pci_id, strlen(pci_id))) { - found = 1; - - while (*ptr && isspace(*ptr)) - ptr++; - - sscanf(ptr, "%04hx-%04hx", &start, &end); - size = end - start + 1; - - break; - } - } - - free(line); - fclose(fp); - - if (!found) - return -1; - - pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start; - pci_dev->mem_resource[0].len = (uint64_t)size; - PMD_INIT_LOG(DEBUG, - "PCI Port IO found start=0x%x with size=0x%x", - start, size); - - /* can't support lsc interrupt without uio */ - pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; - - return 0; -} - -/* Extract I/O port numbers from sysfs */ -static int virtio_resource_init(struct rte_pci_device *pci_dev) -{ - if (virtio_resource_init_by_uio(pci_dev) == 0) - return 0; - else - return virtio_resource_init_by_ioports(pci_dev); -} - -#else -static int -virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) -{ - /* nic_uio does not enable interrupts, return 0 (false). */ - return 0; -} - -static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) -{ - /* no setup required */ - return 0; -} -#endif - /* * Process Virtio Config changed interrupt and call the callback * if link state changed. @@ -1279,14 +1021,9 @@ 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) + if (vtpci_init(pci_dev, hw) < 0) return -1; - hw->use_msix = virtio_has_msix(&pci_dev->addr); - hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr; - /* Reset the device although not necessary at startup */ vtpci_reset(hw); diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 9bcaa07..0094d5f 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -32,6 +32,11 @@ */ #include <stdint.h> +#ifdef RTE_EXEC_ENV_LINUXAPP + #include <dirent.h> + #include <fcntl.h> +#endif + #include "virtio_pci.h" #include "virtio_logs.h" #include "virtqueue.h" @@ -162,6 +167,264 @@ legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq) VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index); } +#ifdef RTE_EXEC_ENV_LINUXAPP +static int +parse_sysfs_value(const char *filename, unsigned long *val) +{ + FILE *f; + char buf[BUFSIZ]; + char *end = NULL; + + f = fopen(filename, "r"); + if (f == NULL) { + PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s", + __func__, filename); + return -1; + } + + if (fgets(buf, sizeof(buf), f) == NULL) { + PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s", + __func__, filename); + fclose(f); + return -1; + } + *val = strtoul(buf, &end, 0); + if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { + PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s", + __func__, filename); + fclose(f); + return -1; + } + fclose(f); + return 0; +} + +static int +get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen, + unsigned int *uio_num) +{ + struct dirent *e; + DIR *dir; + char dirname[PATH_MAX]; + + /* depending on kernel version, uio can be located in uio/uioX + * or uio:uioX */ + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", + loc->domain, loc->bus, loc->devid, loc->function); + dir = opendir(dirname); + if (dir == NULL) { + /* retry with the parent directory */ + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, + loc->domain, loc->bus, loc->devid, loc->function); + dir = opendir(dirname); + + if (dir == NULL) { + PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname); + return -1; + } + } + + /* take the first file starting with "uio" */ + while ((e = readdir(dir)) != NULL) { + /* format could be uio%d ...*/ + int shortprefix_len = sizeof("uio") - 1; + /* ... or uio:uio%d */ + int longprefix_len = sizeof("uio:uio") - 1; + char *endptr; + + if (strncmp(e->d_name, "uio", 3) != 0) + continue; + + /* first try uio%d */ + errno = 0; + *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); + if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { + snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num); + break; + } + + /* then try uio:uio%d */ + errno = 0; + *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); + if (errno == 0 && endptr != (e->d_name + longprefix_len)) { + snprintf(buf, buflen, "%s/uio:uio%u", dirname, + *uio_num); + break; + } + } + closedir(dir); + + /* No uio resource found */ + if (e == NULL) { + PMD_INIT_LOG(ERR, "Could not find uio resource"); + return -1; + } + + return 0; +} + +static int +legacy_virtio_has_msix(const struct rte_pci_addr *loc) +{ + DIR *d; + char dirname[PATH_MAX]; + + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs", + loc->domain, loc->bus, loc->devid, loc->function); + + d = opendir(dirname); + if (d) + closedir(d); + + return (d != NULL); +} + +/* Extract I/O port numbers from sysfs */ +static int +virtio_resource_init_by_uio(struct rte_pci_device *pci_dev) +{ + char dirname[PATH_MAX]; + char filename[PATH_MAX]; + unsigned long start, size; + unsigned int uio_num; + + if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0) + return -1; + + /* get portio size */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/size", dirname); + if (parse_sysfs_value(filename, &size) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse size", + __func__); + return -1; + } + + /* get portio start */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/start", dirname); + if (parse_sysfs_value(filename, &start) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", + __func__); + return -1; + } + pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; + pci_dev->mem_resource[0].len = (uint64_t)size; + PMD_INIT_LOG(DEBUG, + "PCI Port IO found start=0x%lx with size=0x%lx", + start, size); + + /* save fd */ + memset(dirname, 0, sizeof(dirname)); + snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num); + pci_dev->intr_handle.fd = open(dirname, O_RDWR); + if (pci_dev->intr_handle.fd < 0) { + PMD_INIT_LOG(ERR, "Cannot open %s: %s\n", + dirname, strerror(errno)); + return -1; + } + + pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO; + pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; + + return 0; +} + +/* Extract port I/O numbers from proc/ioports */ +static int +virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev) +{ + uint16_t start, end; + int size; + FILE *fp; + char *line = NULL; + char pci_id[16]; + int found = 0; + size_t linesz; + + snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, + pci_dev->addr.domain, + pci_dev->addr.bus, + pci_dev->addr.devid, + pci_dev->addr.function); + + fp = fopen("/proc/ioports", "r"); + if (fp == NULL) { + PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__); + return -1; + } + + while (getdelim(&line, &linesz, '\n', fp) > 0) { + char *ptr = line; + char *left; + int n; + + n = strcspn(ptr, ":"); + ptr[n] = 0; + left = &ptr[n+1]; + + while (*left && isspace(*left)) + left++; + + if (!strncmp(left, pci_id, strlen(pci_id))) { + found = 1; + + while (*ptr && isspace(*ptr)) + ptr++; + + sscanf(ptr, "%04hx-%04hx", &start, &end); + size = end - start + 1; + + break; + } + } + + free(line); + fclose(fp); + + if (!found) + return -1; + + pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start; + pci_dev->mem_resource[0].len = (uint64_t)size; + PMD_INIT_LOG(DEBUG, + "PCI Port IO found start=0x%x with size=0x%x", + start, size); + + /* can't support lsc interrupt without uio */ + pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; + + return 0; +} + +/* Extract I/O port numbers from sysfs */ +static int +legacy_virtio_resource_init(struct rte_pci_device *pci_dev) +{ + if (virtio_resource_init_by_uio(pci_dev) == 0) + return 0; + else + return virtio_resource_init_by_ioports(pci_dev); +} + +#else +static int +legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) +{ + /* nic_uio does not enable interrupts, return 0 (false). */ + return 0; +} + +static int +legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) +{ + /* no setup required */ + return 0; +} +#endif static const struct virtio_pci_ops legacy_ops = { .read_dev_cfg = legacy_read_dev_config, @@ -247,9 +510,14 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) } int -vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw) +vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) { hw->vtpci_ops = &legacy_ops; + if (legacy_virtio_resource_init(dev) < 0) + return -1; + hw->use_msix = legacy_virtio_has_msix(&dev->addr); + hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr; + return 0; } -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH 4/6] viritio: switch to 64 bit features 2015-12-10 3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu ` (2 preceding siblings ...) 2015-12-10 3:54 ` [dpdk-dev] [PATCH 3/6] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu @ 2015-12-10 3:54 ` Yuanhan Liu 2015-12-10 3:54 ` [dpdk-dev] [PATCH 5/6] virtio: set RTE_PCI_DRV_NEED_MAPPING flag Yuanhan Liu ` (4 subsequent siblings) 8 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2015-12-10 3:54 UTC (permalink / raw) To: dev Switch to 64 bit features, which virtio 1.0 supports. While legacy virtio only supports 32 bit features, it complains aloud and quit when trying to setting > 32 bit features. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_ethdev.c | 8 ++++---- drivers/net/virtio/virtio_pci.c | 15 ++++++++++----- drivers/net/virtio/virtio_pci.h | 12 ++++++------ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index b57224d..94e0c4a 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -930,16 +930,16 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) static void virtio_negotiate_features(struct virtio_hw *hw) { - uint32_t host_features; + uint64_t host_features; /* Prepare guest_features: feature that driver wants to support */ hw->guest_features = VIRTIO_PMD_GUEST_FEATURES; - PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %x", + PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %"PRIx64, hw->guest_features); /* Read device(host) feature bits */ host_features = hw->vtpci_ops->get_features(hw); - PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x", + PMD_INIT_LOG(DEBUG, "host_features before negotiate = %"PRIx64, host_features); /* @@ -947,7 +947,7 @@ virtio_negotiate_features(struct virtio_hw *hw) * guest feature bits. */ hw->guest_features = vtpci_negotiate_features(hw, host_features); - PMD_INIT_LOG(DEBUG, "features after negotiate = %x", + PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, hw->guest_features); } diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 0094d5f..26b0a0c 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -87,15 +87,20 @@ legacy_write_dev_config(struct virtio_hw *hw, uint64_t offset, } } -static uint32_t +static uint64_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) +legacy_set_features(struct virtio_hw *hw, uint64_t features) { + if ((features >> 32) != 0) { + PMD_DRV_LOG(ERR, + "only 32 bit features are allowed for legacy virtio!"); + return; + } VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features); } @@ -457,10 +462,10 @@ vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset, hw->vtpci_ops->write_dev_cfg(hw, offset, src, length); } -uint32_t -vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features) +uint64_t +vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features) { - uint32_t features; + uint64_t features; /* * Limit negotiated features to what the driver, virtqueue, and diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index a11a4f6..0900cd0 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -175,8 +175,8 @@ struct virtio_pci_ops { 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); + uint64_t (*get_features)(struct virtio_hw *hw); + void (*set_features)(struct virtio_hw *hw, uint64_t features); uint8_t (*get_isr)(struct virtio_hw *hw); @@ -191,7 +191,7 @@ struct virtio_pci_ops { struct virtio_hw { struct virtqueue *cvq; uint32_t io_base; - uint32_t guest_features; + uint64_t guest_features; uint32_t max_tx_queues; uint32_t max_rx_queues; uint16_t vtnet_hdr_size; @@ -271,9 +271,9 @@ outl_p(unsigned int data, unsigned int port) outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) static inline int -vtpci_with_feature(struct virtio_hw *hw, uint32_t bit) +vtpci_with_feature(struct virtio_hw *hw, uint64_t bit) { - return (hw->guest_features & (1u << bit)) != 0; + return (hw->guest_features & (1ULL << bit)) != 0; } /* @@ -286,7 +286,7 @@ void vtpci_reinit_complete(struct virtio_hw *); void vtpci_set_status(struct virtio_hw *, uint8_t); -uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t); +uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t); void vtpci_write_dev_config(struct virtio_hw *, uint64_t, void *, int); -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH 5/6] virtio: set RTE_PCI_DRV_NEED_MAPPING flag 2015-12-10 3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu ` (3 preceding siblings ...) 2015-12-10 3:54 ` [dpdk-dev] [PATCH 4/6] viritio: switch to 64 bit features Yuanhan Liu @ 2015-12-10 3:54 ` Yuanhan Liu 2015-12-10 3:54 ` [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support Yuanhan Liu ` (3 subsequent siblings) 8 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2015-12-10 3:54 UTC (permalink / raw) To: dev We need to to map pci bar space for enabling modern virtio pci device, as all modern configs are stored at pci bar space. Setting RTE_PCI_DRV_NEED_MAPPING flag will let eal do that for us. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_ethdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 94e0c4a..9847ed8 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -1169,7 +1169,7 @@ static struct eth_driver rte_virtio_pmd = { .pci_drv = { .name = "rte_virtio_pmd", .id_table = pci_id_virtio_map, - .drv_flags = RTE_PCI_DRV_DETACHABLE, + .drv_flags = RTE_PCI_DRV_DETACHABLE | RTE_PCI_DRV_NEED_MAPPING, }, .eth_dev_init = eth_virtio_dev_init, .eth_dev_uninit = eth_virtio_dev_uninit, -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support 2015-12-10 3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu ` (4 preceding siblings ...) 2015-12-10 3:54 ` [dpdk-dev] [PATCH 5/6] virtio: set RTE_PCI_DRV_NEED_MAPPING flag Yuanhan Liu @ 2015-12-10 3:54 ` Yuanhan Liu 2015-12-29 11:39 ` Tan, Jianfeng 2015-12-10 3:58 ` [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu ` (2 subsequent siblings) 8 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2015-12-10 3:54 UTC (permalink / raw) To: dev Modern (v1.0) virtio pci device defines several pci capabilities. Each cap has a configure structure corresponding to it, and the cap.bar and cap.offset fields tell us where to find it. And thanks to the RTE_PCI_DRV_NEED_MAPPING, which already maps all the bar space for us, we could easily locate to a cfg structure by: cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset; Therefore, the entrance of enabling modern (v1.0) pci device support is to iterate the pci capability lists, and to locate some configs we care; and they are: - common cfg For generic virtio and virtuqueu configuration, such as setting/getting features, enabling a specific queue, and so on. - nofity cfg Combining with `queue_notify_off' from common cfg, we could use it to notify a specific virt queue. - device cfg Where virtio_net_config structure locates. If any of above cap is not found, we fallback to the legacy virtio handling. If succeed, hw->vtpci_ops is assigned to modern_ops, where all operations are implemented by reading/writing a (or few) specific configuration space from above 3 cfg structures. And that's basically how this patch works. Besides those changes, virtio 1.0 introduces a new status field: FEATURES_OK, which is set after features negotiation is done. Last, set the VIRTIO_F_VERSION_1 feature flag. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_ethdev.c | 16 +- drivers/net/virtio/virtio_ethdev.h | 3 +- drivers/net/virtio/virtio_pci.c | 313 ++++++++++++++++++++++++++++++++++++- drivers/net/virtio/virtio_pci.h | 65 ++++++++ drivers/net/virtio/virtqueue.h | 2 + 5 files changed, 395 insertions(+), 4 deletions(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 9847ed8..1f9de01 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) return virtio_send_command(hw->cvq, &ctrl, &len, 1); } -static void +static int virtio_negotiate_features(struct virtio_hw *hw) { uint64_t host_features; @@ -949,6 +949,17 @@ virtio_negotiate_features(struct virtio_hw *hw) hw->guest_features = vtpci_negotiate_features(hw, host_features); PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, hw->guest_features); + + if (hw->modern) { + if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) { + PMD_INIT_LOG(ERR, + "VIRTIO_F_VERSION_1 features is not enabled"); + return -1; + } + vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK); + } + + return 0; } /* @@ -1032,7 +1043,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev) /* Tell the host we've known how to drive the device. */ vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER); - virtio_negotiate_features(hw); + if (virtio_negotiate_features(hw) < 0) + return -1; /* If host does not support status then disable LSC */ if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h index ae2d47d..fed9571 100644 --- a/drivers/net/virtio/virtio_ethdev.h +++ b/drivers/net/virtio/virtio_ethdev.h @@ -64,7 +64,8 @@ 1u << VIRTIO_NET_F_CTRL_VQ | \ 1u << VIRTIO_NET_F_CTRL_RX | \ 1u << VIRTIO_NET_F_CTRL_VLAN | \ - 1u << VIRTIO_NET_F_MRG_RXBUF) + 1u << VIRTIO_NET_F_MRG_RXBUF | \ + 1ULL << VIRTIO_F_VERSION_1) /* * CQ function prototype diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 26b0a0c..7862d7f 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -31,6 +31,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <stdint.h> +#include <linux/pci_regs.h> #ifdef RTE_EXEC_ENV_LINUXAPP #include <dirent.h> @@ -448,6 +449,205 @@ static const struct virtio_pci_ops legacy_ops = { }; +#define MODERN_READ_DEF(nr_bits, type) \ +static inline type \ +modern_read##nr_bits(type *addr) \ +{ \ + return *(volatile type *)addr; \ +} + +#define MODERN_WRITE_DEF(nr_bits, type) \ +static inline void \ +modern_write##nr_bits(type val, type *addr) \ +{ \ + *(volatile type *)addr = val; \ +} + +MODERN_READ_DEF (8, uint8_t) +MODERN_WRITE_DEF(8, uint8_t) + +MODERN_READ_DEF (16, uint16_t) +MODERN_WRITE_DEF(16, uint16_t) + +MODERN_READ_DEF (32, uint32_t) +MODERN_WRITE_DEF(32, uint32_t) + +static inline void +modern_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) +{ + modern_write32((uint32_t)val, lo); + modern_write32(val >> 32, hi); +} + +static void +modern_read_dev_config(struct virtio_hw *hw, uint64_t offset, + void *dst, int length) +{ + int i; + uint8_t *p; + uint8_t old_gen, new_gen; + + do { + old_gen = modern_read8(&hw->common_cfg->config_generation); + + p = dst; + for (i = 0; i < length; i++) + *p++ = modern_read8((uint8_t *)hw->dev_cfg + offset + i); + + new_gen = modern_read8(&hw->common_cfg->config_generation); + } while (old_gen != new_gen); +} + +static void +modern_write_dev_config(struct virtio_hw *hw, uint64_t offset, + void *src, int length) +{ + int i; + uint8_t *p = src; + + for (i = 0; i < length; i++) + modern_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i); +} + +static uint64_t +modern_get_features(struct virtio_hw *hw) +{ + uint32_t features_lo, features_hi; + + modern_write32(0, &hw->common_cfg->device_feature_select); + features_lo = modern_read32(&hw->common_cfg->device_feature); + + modern_write32(1, &hw->common_cfg->device_feature_select); + features_hi = modern_read32(&hw->common_cfg->device_feature); + + return ((uint64_t)(features_hi) << 32) | features_lo; +} + +static void +modern_set_features(struct virtio_hw *hw, uint64_t features) +{ + modern_write32(0, &hw->common_cfg->guest_feature_select); + modern_write32(features & ((1ULL<<32) - 1), + &hw->common_cfg->guest_feature); + + modern_write32(1, &hw->common_cfg->guest_feature_select); + modern_write32(features >> 32, + &hw->common_cfg->guest_feature); +} + +static uint8_t +modern_get_status(struct virtio_hw *hw) +{ + return modern_read8(&hw->common_cfg->device_status); +} + +static void +modern_set_status(struct virtio_hw *hw, uint8_t status) +{ + modern_write8(status, &hw->common_cfg->device_status); +} + +static void +modern_reset(struct virtio_hw *hw) +{ + modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); + modern_get_status(hw); +} + +static uint8_t +modern_get_isr(struct virtio_hw *hw __rte_unused) +{ + /* FIXME: xxx */ + return 0; +} + +static uint16_t +modern_set_irq(struct virtio_hw *hw __rte_unused, uint16_t vec __rte_unused) +{ + /* FIXME: xxx */ + return 0; +} + +static uint16_t +modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) +{ + modern_write16(queue_id, &hw->common_cfg->queue_select); + return modern_read16(&hw->common_cfg->queue_size); +} + +static void +modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + uint64_t desc_addr, avail_addr, used_addr; + uint16_t notify_off; + + desc_addr = vq->mz->phys_addr; + avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc); + used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail, + ring[vq->vq_nentries]), + VIRTIO_PCI_VRING_ALIGN); + + modern_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); + + modern_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + modern_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + modern_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + notify_off = modern_read16(&hw->common_cfg->queue_notify_off); + vq->notify_addr = (void *)((uint8_t *)hw->notify_base + + notify_off * hw->notify_off_multiplier); + + modern_write16(1, &hw->common_cfg->queue_enable); + + PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index); + PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr); + PMD_INIT_LOG(DEBUG, "\t aval_addr: %"PRIx64, avail_addr); + PMD_INIT_LOG(DEBUG, "\t used_addr: %"PRIx64, used_addr); + PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)", + vq->notify_addr, notify_off); +} + +static void +modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + modern_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); + + modern_write64_twopart(0, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + modern_write64_twopart(0, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + modern_write64_twopart(0, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + modern_write16(0, &hw->common_cfg->queue_enable); +} + +static void +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) +{ + modern_write16(1, vq->notify_addr); +} + +static const struct virtio_pci_ops modern_ops = { + .read_dev_cfg = modern_read_dev_config, + .write_dev_cfg = modern_write_dev_config, + .reset = modern_reset, + .get_status = modern_get_status, + .set_status = modern_set_status, + .get_features = modern_get_features, + .set_features = modern_set_features, + .get_isr = modern_get_isr, + .set_irq = modern_set_irq, + .get_queue_num = modern_get_queue_num, + .setup_queue = modern_setup_queue, + .del_queue = modern_del_queue, + .notify_queue = modern_notify_queue, +}; + + void vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset, void *dst, int length) @@ -514,15 +714,126 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) return hw->vtpci_ops->set_irq(hw, vec); } +static inline void * +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) +{ + uint8_t bar = cap->bar; + uint32_t length = cap->length; + uint32_t offset = cap->offset; + uint8_t *base; + + if (unlikely(bar > 5)) { + PMD_INIT_LOG(ERR, "invalid bar: %u", bar); + return NULL; + } + + if (unlikely(offset + length > dev->mem_resource[bar].len)) { + PMD_INIT_LOG(ERR, + "invalid cap: overflows bar space: %u > %"PRIu64, + offset + length, dev->mem_resource[bar].len); + return NULL; + } + + base = dev->mem_resource[bar].addr; + if (unlikely(base == NULL)) { + PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar); + return NULL; + } + + return base + offset; +} + +static int +virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw) +{ + uint8_t pos; + struct virtio_pci_cap cap; + int ret; + + ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST); + if (ret < 0) { + PMD_INIT_LOG(DEBUG, "failed to read pci capability list"); + return -1; + } + + while (pos) { + ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos); + if (ret < 0) { + PMD_INIT_LOG(ERR, + "failed to read pci cap at pos: %x", pos); + break; + } + + if (cap.cap_vndr != PCI_CAP_ID_VNDR) { + PMD_INIT_LOG(DEBUG, + "[%2x] skipping non VNDR cap id: %02x", + pos, cap.cap_vndr); + goto next; + } + + PMD_INIT_LOG(DEBUG, + "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u", + pos, cap.cfg_type, cap.bar, cap.offset, cap.length); + + switch (cap.cfg_type) { + case VIRTIO_PCI_CAP_COMMON_CFG: + hw->common_cfg = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_NOTIFY_CFG: + rte_eal_pci_read_config(dev, &hw->notify_off_multiplier, + 4, pos + sizeof(cap)); + hw->notify_base = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_DEVICE_CFG: + hw->dev_cfg = get_cfg_addr(dev, &cap); + break; + } + + next: + pos = cap.cap_next; + } + + if (hw->common_cfg == NULL || hw->notify_base == NULL || + hw->dev_cfg == NULL) { + PMD_INIT_LOG(INFO, "no modern virtio pci device found."); + return -1; + } + + PMD_INIT_LOG(INFO, "found modern virtio pci device."); + + PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg); + PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg); + PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u", + hw->notify_base, hw->notify_off_multiplier); + + return 0; +} + int vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) { - hw->vtpci_ops = &legacy_ops; + hw->dev = dev; + /* + * Try if we can succeed reading virtio pci caps, which exists + * only on modern pci device. If failed, we fallback to legacy + * virtio hanlding. + */ + if (virtio_read_caps(dev, hw) == 0) { + PMD_INIT_LOG(INFO, "moderen virtio pci detected."); + hw->vtpci_ops = &modern_ops; + hw->modern = 1; + return 0; + } + + PMD_INIT_LOG(INFO, "trying with legacy virtio pci."); if (legacy_virtio_resource_init(dev) < 0) return -1; + + hw->vtpci_ops = &legacy_ops; hw->use_msix = legacy_virtio_has_msix(&dev->addr); hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr; + hw->modern = 0; return 0; } diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index 0900cd0..8ff51d2 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -93,6 +93,7 @@ struct virtqueue; #define VIRTIO_CONFIG_STATUS_ACK 0x01 #define VIRTIO_CONFIG_STATUS_DRIVER 0x02 #define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04 +#define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08 #define VIRTIO_CONFIG_STATUS_FAILED 0x80 /* @@ -141,6 +142,8 @@ struct virtqueue; /* We support indirect buffer descriptors */ #define VIRTIO_RING_F_INDIRECT_DESC 28 +#define VIRTIO_F_VERSION_1 32 + /* * Some VirtIO feature bits (currently bits 28 through 31) are * reserved for the transport being used (eg. virtio_ring), the @@ -163,6 +166,60 @@ struct virtqueue; */ #define VIRTIO_MAX_VIRTQUEUES 8 +/* Common configuration */ +#define VIRTIO_PCI_CAP_COMMON_CFG 1 +/* Notifications */ +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 +/* ISR Status */ +#define VIRTIO_PCI_CAP_ISR_CFG 3 +/* Device specific configuration */ +#define VIRTIO_PCI_CAP_DEVICE_CFG 4 +/* PCI configuration access */ +#define VIRTIO_PCI_CAP_PCI_CFG 5 + +/* This is the PCI capability header: */ +struct virtio_pci_cap { + uint8_t cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */ + uint8_t cap_next; /* Generic PCI field: next ptr. */ + uint8_t cap_len; /* Generic PCI field: capability length */ + uint8_t cfg_type; /* Identifies the structure. */ + uint8_t bar; /* Where to find it. */ + uint8_t padding[3]; /* Pad to full dword. */ + uint32_t offset; /* Offset within bar. */ + uint32_t length; /* Length of the structure, in bytes. */ +}; + +struct virtio_pci_notify_cap { + struct virtio_pci_cap cap; + uint32_t notify_off_multiplier; /* Multiplier for queue_notify_off. */ +}; + +/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */ +struct virtio_pci_common_cfg { + /* About the whole device. */ + uint32_t device_feature_select; /* read-write */ + uint32_t device_feature; /* read-only */ + uint32_t guest_feature_select; /* read-write */ + uint32_t guest_feature; /* read-write */ + uint16_t msix_config; /* read-write */ + uint16_t num_queues; /* read-only */ + uint8_t device_status; /* read-write */ + uint8_t config_generation; /* read-only */ + + /* About a specific virtqueue. */ + uint16_t queue_select; /* read-write */ + uint16_t queue_size; /* read-write, power of 2. */ + uint16_t queue_msix_vector; /* read-write */ + uint16_t queue_enable; /* read-write */ + uint16_t queue_notify_off; /* read-only */ + uint32_t queue_desc_lo; /* read-write */ + uint32_t queue_desc_hi; /* read-write */ + uint32_t queue_avail_lo; /* read-write */ + uint32_t queue_avail_hi; /* read-write */ + uint32_t queue_used_lo; /* read-write */ + uint32_t queue_used_hi; /* read-write */ +}; + struct virtio_hw; struct virtio_pci_ops { @@ -188,6 +245,8 @@ struct virtio_pci_ops { void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq); }; +struct virtio_net_config; + struct virtio_hw { struct virtqueue *cvq; uint32_t io_base; @@ -198,7 +257,13 @@ struct virtio_hw { uint8_t vlan_strip; uint8_t use_msix; uint8_t started; + uint8_t modern; uint8_t mac_addr[ETHER_ADDR_LEN]; + uint32_t notify_off_multiplier; + uint16_t *notify_base; + struct rte_pci_device *dev; + struct virtio_pci_common_cfg *common_cfg; + struct virtio_net_config *dev_cfg; const struct virtio_pci_ops *vtpci_ops; }; diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h index d7fb450..99d4fa9 100644 --- a/drivers/net/virtio/virtqueue.h +++ b/drivers/net/virtio/virtqueue.h @@ -202,6 +202,8 @@ struct virtqueue { /* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */ uint64_t size_bins[8]; + uint16_t *notify_addr; + struct vq_desc_extra { void *cookie; uint16_t ndescs; -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support 2015-12-10 3:54 ` [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support Yuanhan Liu @ 2015-12-29 11:39 ` Tan, Jianfeng 2015-12-30 3:40 ` Yuanhan Liu 0 siblings, 1 reply; 122+ messages in thread From: Tan, Jianfeng @ 2015-12-29 11:39 UTC (permalink / raw) To: Yuanhan Liu, dev > -----Original Message----- > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu > Sent: Thursday, December 10, 2015 11:54 AM > To: dev@dpdk.org > Subject: [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support > ... > Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> > --- > drivers/net/virtio/virtio_ethdev.c | 16 +- > drivers/net/virtio/virtio_ethdev.h | 3 +- > drivers/net/virtio/virtio_pci.c | 313 > ++++++++++++++++++++++++++++++++++++- > drivers/net/virtio/virtio_pci.h | 65 ++++++++ > drivers/net/virtio/virtqueue.h | 2 + > 5 files changed, 395 insertions(+), 4 deletions(-) > As legacy VIRTIO_WRITE_REG_XXXs are only used in virtio_pci.c, move these definitions into virtio_pci.c? > diff --git a/drivers/net/virtio/virtio_ethdev.c > b/drivers/net/virtio/virtio_ethdev.c > index 9847ed8..1f9de01 100644 > --- a/drivers/net/virtio/virtio_ethdev.c > +++ b/drivers/net/virtio/virtio_ethdev.c > @@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, > uint16_t vlan_id, int on) > return virtio_send_command(hw->cvq, &ctrl, &len, 1); > } > > -static void > +static int > virtio_negotiate_features(struct virtio_hw *hw) > { > uint64_t host_features; > @@ -949,6 +949,17 @@ virtio_negotiate_features(struct virtio_hw *hw) > hw->guest_features = vtpci_negotiate_features(hw, host_features); > PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, > hw->guest_features); > + > + if (hw->modern) { > + if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) { > + PMD_INIT_LOG(ERR, > + "VIRTIO_F_VERSION_1 features is not > enabled"); > + return -1; > + } > + vtpci_set_status(hw, > VIRTIO_CONFIG_STATUS_FEATURES_OK); As per Linux code drivers/virtio/virtio.c:virtio_finalize_features(), vtpci_set_status() may fail, and there's a double check. Is it necessary here? > + } > + > + return 0; > } > > /* > @@ -1032,7 +1043,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev) > > /* Tell the host we've known how to drive the device. */ > vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER); > - virtio_negotiate_features(hw); > + if (virtio_negotiate_features(hw) < 0) > + return -1; > > /* If host does not support status then disable LSC */ > if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) > diff --git a/drivers/net/virtio/virtio_ethdev.h > b/drivers/net/virtio/virtio_ethdev.h > index ae2d47d..fed9571 100644 > --- a/drivers/net/virtio/virtio_ethdev.h > +++ b/drivers/net/virtio/virtio_ethdev.h > @@ -64,7 +64,8 @@ > 1u << VIRTIO_NET_F_CTRL_VQ | \ > 1u << VIRTIO_NET_F_CTRL_RX | \ > 1u << VIRTIO_NET_F_CTRL_VLAN | \ > - 1u << VIRTIO_NET_F_MRG_RXBUF) > + 1u << VIRTIO_NET_F_MRG_RXBUF | \ > + 1ULL << VIRTIO_F_VERSION_1) > > /* > * CQ function prototype > diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c > index 26b0a0c..7862d7f 100644 > --- a/drivers/net/virtio/virtio_pci.c > +++ b/drivers/net/virtio/virtio_pci.c > @@ -31,6 +31,7 @@ > * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > DAMAGE. > */ > #include <stdint.h> > +#include <linux/pci_regs.h> Put this "include" into macro RTE_EXEC_ENV_LINUXAPP followed? > > #ifdef RTE_EXEC_ENV_LINUXAPP > #include <dirent.h> > @@ -448,6 +449,205 @@ static const struct virtio_pci_ops legacy_ops = { > }; > > ... > + > +static uint16_t > +modern_set_irq(struct virtio_hw *hw __rte_unused, uint16_t vec > __rte_unused) > +{ > + /* FIXME: xxx */ > + return 0; > +} If not going to support LSC, please give clear indication at related doc. My concern is: this will affect some users, who are using LSC in legacy virtio. (If LSC works well on legacy virtio?). > + > +static uint16_t > +modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) > +{ > + modern_write16(queue_id, &hw->common_cfg->queue_select); > + return modern_read16(&hw->common_cfg->queue_size); > +} > + ... > > +static inline void * > +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) > +{ > + uint8_t bar = cap->bar; > + uint32_t length = cap->length; > + uint32_t offset = cap->offset; > + uint8_t *base; > + Use a macro to substitute hardcoded "5"? > + if (unlikely(bar > 5)) { > + PMD_INIT_LOG(ERR, "invalid bar: %u", bar); > + return NULL; > + } > + ... > int > vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) > { > - hw->vtpci_ops = &legacy_ops; > + hw->dev = dev; > > + /* > + * Try if we can succeed reading virtio pci caps, which exists > + * only on modern pci device. If failed, we fallback to legacy > + * virtio hanlding. hanlding -> handling Thanks, Jianfeng > + */ ... > + > struct vq_desc_extra { > void *cookie; > uint16_t ndescs; > -- > 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support 2015-12-29 11:39 ` Tan, Jianfeng @ 2015-12-30 3:40 ` Yuanhan Liu 0 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2015-12-30 3:40 UTC (permalink / raw) To: Tan, Jianfeng; +Cc: dev On Tue, Dec 29, 2015 at 11:39:47AM +0000, Tan, Jianfeng wrote: > > > > -----Original Message----- > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu > > Sent: Thursday, December 10, 2015 11:54 AM > > To: dev@dpdk.org > > Subject: [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support > > > ... > > Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> > > --- > > drivers/net/virtio/virtio_ethdev.c | 16 +- > > drivers/net/virtio/virtio_ethdev.h | 3 +- > > drivers/net/virtio/virtio_pci.c | 313 > > ++++++++++++++++++++++++++++++++++++- > > drivers/net/virtio/virtio_pci.h | 65 ++++++++ > > drivers/net/virtio/virtqueue.h | 2 + > > 5 files changed, 395 insertions(+), 4 deletions(-) > > > > As legacy VIRTIO_WRITE_REG_XXXs are only used in virtio_pci.c, move these definitions into virtio_pci.c? Yes, and I planned to do it in another series, where I will do more virtio cleanups. (hmm..., maybe I could stack them on top of this series). > > > diff --git a/drivers/net/virtio/virtio_ethdev.c > > b/drivers/net/virtio/virtio_ethdev.c > > index 9847ed8..1f9de01 100644 > > --- a/drivers/net/virtio/virtio_ethdev.c > > +++ b/drivers/net/virtio/virtio_ethdev.c > > @@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, > > uint16_t vlan_id, int on) > > return virtio_send_command(hw->cvq, &ctrl, &len, 1); > > } > > > > -static void > > +static int > > virtio_negotiate_features(struct virtio_hw *hw) > > { > > uint64_t host_features; > > @@ -949,6 +949,17 @@ virtio_negotiate_features(struct virtio_hw *hw) > > hw->guest_features = vtpci_negotiate_features(hw, host_features); > > PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, > > hw->guest_features); > > + > > + if (hw->modern) { > > + if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) { > > + PMD_INIT_LOG(ERR, > > + "VIRTIO_F_VERSION_1 features is not > > enabled"); > > + return -1; > > + } > > + vtpci_set_status(hw, > > VIRTIO_CONFIG_STATUS_FEATURES_OK); > > > As per Linux code drivers/virtio/virtio.c:virtio_finalize_features(), vtpci_set_status() may fail, and there's a double check. > Is it necessary here? Yes, it's necessary: see the spec (3.1.1 Driver Requirements: Device Initialization): 5. Set the FEATURES_OK status bit. The driver MUST NOT accept new feature bits after this step. 6. Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not support our subset of features and the device is unusable. > > > > + } > > + > > + return 0; > > } > > > > /* > > @@ -1032,7 +1043,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev) > > > > /* Tell the host we've known how to drive the device. */ > > vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER); > > - virtio_negotiate_features(hw); > > + if (virtio_negotiate_features(hw) < 0) > > + return -1; > > > > /* If host does not support status then disable LSC */ > > if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) > > diff --git a/drivers/net/virtio/virtio_ethdev.h > > b/drivers/net/virtio/virtio_ethdev.h > > index ae2d47d..fed9571 100644 > > --- a/drivers/net/virtio/virtio_ethdev.h > > +++ b/drivers/net/virtio/virtio_ethdev.h > > @@ -64,7 +64,8 @@ > > 1u << VIRTIO_NET_F_CTRL_VQ | \ > > 1u << VIRTIO_NET_F_CTRL_RX | \ > > 1u << VIRTIO_NET_F_CTRL_VLAN | \ > > - 1u << VIRTIO_NET_F_MRG_RXBUF) > > + 1u << VIRTIO_NET_F_MRG_RXBUF | \ > > + 1ULL << VIRTIO_F_VERSION_1) > > > > /* > > * CQ function prototype > > diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c > > index 26b0a0c..7862d7f 100644 > > --- a/drivers/net/virtio/virtio_pci.c > > +++ b/drivers/net/virtio/virtio_pci.c > > @@ -31,6 +31,7 @@ > > * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > > DAMAGE. > > */ > > #include <stdint.h> > > +#include <linux/pci_regs.h> > > Put this "include" into macro RTE_EXEC_ENV_LINUXAPP followed? We can't simply do that, as we need reference some macros from it in common code path, virtio_read_caps(). But yes, you just remind me that there should be no such header in non-linux platform. We can't include it blindly here. Good catch, btw! What's lucky here is that we just need reference quite few macros, maybe we could just define them by ourself, to get rid of the depency. > > > > > #ifdef RTE_EXEC_ENV_LINUXAPP > > #include <dirent.h> > > @@ -448,6 +449,205 @@ static const struct virtio_pci_ops legacy_ops = { > > }; > > > > > ... > > + > > +static uint16_t > > +modern_set_irq(struct virtio_hw *hw __rte_unused, uint16_t vec > > __rte_unused) > > +{ > > + /* FIXME: xxx */ > > + return 0; > > +} > > If not going to support LSC, please give clear indication at related doc. My concern is: this will affect > some users, who are using LSC in legacy virtio. (If LSC works well on legacy virtio?). TBH, I don't spent too much time on that, therefore, I marked it as FIXME here, with the hope that I will revisit it with more cares in future version. > > + > > +static uint16_t > > +modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) > > +{ > > + modern_write16(queue_id, &hw->common_cfg->queue_select); > > + return modern_read16(&hw->common_cfg->queue_size); > > +} > > + > ... > > > > +static inline void * > > +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) > > +{ > > + uint8_t bar = cap->bar; > > + uint32_t length = cap->length; > > + uint32_t offset = cap->offset; > > + uint8_t *base; > > + > > Use a macro to substitute hardcoded "5"? The fact that 5 is the max bar number is so well known, that I don't think it's necessary to add a macro here. > > + if (unlikely(bar > 5)) { > > + PMD_INIT_LOG(ERR, "invalid bar: %u", bar); > > + return NULL; > > + } > > + > ... > > int > > vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) > > { > > - hw->vtpci_ops = &legacy_ops; > > + hw->dev = dev; > > > > + /* > > + * Try if we can succeed reading virtio pci caps, which exists > > + * only on modern pci device. If failed, we fallback to legacy > > + * virtio hanlding. > > hanlding -> handling Oops, and thanks. --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling 2015-12-10 3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu ` (5 preceding siblings ...) 2015-12-10 3:54 ` [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support Yuanhan Liu @ 2015-12-10 3:58 ` Yuanhan Liu 2015-12-29 11:19 ` Tan, Jianfeng 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu 8 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2015-12-10 3:58 UTC (permalink / raw) To: Michael S. Tsirkin; +Cc: dev Michael, Sorry that I forgot to CC you. (In fact, I intended to, but there is a tiny bug at my send-email script :( It'd be great if you could take some time to review it. Thanks. --yliu On Thu, Dec 10, 2015 at 11:54:04AM +0800, Yuanhan Liu wrote: > Hi, > > Here is an initial virtio 1.0 pmd driver enabling. > > Almost all difference comes from virtio 1.0 are the PCI layout change: > the major configuration structures are stored at bar space, and their > location is stored at corresponding pci cap structure. Reading/parsing > them is one of the major work of patch 6. > > To make handling virtio v1.0 and v0.95 co-exist well, this patch set > introduces a virtio_pci_ops structure, to add another layer so that > we could keep those vtpci_foo_bar "APIs". With that, we could do the > minimum change to add virtio 1.0 support. > > Note that the enabling is still in rough state, and it's likely I may > miss something. So, comments are huge welcome! > > --yliu > > --- > Yuanhan Liu (6): > virtio: don't set vring address again at queue startup > virtio: introduce struct virtio_pci_ops > virtio: move left pci stuff to virtio_pci.c > viritio: switch to 64 bit features > virtio: set RTE_PCI_DRV_NEED_MAPPING flag > virtio: add virtio v1.0 support > > drivers/net/virtio/virtio_ethdev.c | 297 +-------------- > drivers/net/virtio/virtio_ethdev.h | 3 +- > drivers/net/virtio/virtio_pci.c | 752 +++++++++++++++++++++++++++++++++++-- > drivers/net/virtio/virtio_pci.h | 100 ++++- > drivers/net/virtio/virtio_rxtx.c | 15 - > drivers/net/virtio/virtqueue.h | 4 +- > 6 files changed, 843 insertions(+), 328 deletions(-) > > -- > 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling 2015-12-10 3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu ` (6 preceding siblings ...) 2015-12-10 3:58 ` [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu @ 2015-12-29 11:19 ` Tan, Jianfeng 2015-12-30 3:53 ` Yuanhan Liu 2016-01-04 3:55 ` Xu, Qian Q 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu 8 siblings, 2 replies; 122+ messages in thread From: Tan, Jianfeng @ 2015-12-29 11:19 UTC (permalink / raw) To: Yuanhan Liu, dev > -----Original Message----- > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu > Sent: Thursday, December 10, 2015 11:54 AM > To: dev@dpdk.org > Subject: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling > > Hi, > > Here is an initial virtio 1.0 pmd driver enabling. > > Almost all difference comes from virtio 1.0 are the PCI layout change: > the major configuration structures are stored at bar space, and their > location is stored at corresponding pci cap structure. Reading/parsing > them is one of the major work of patch 6. > > To make handling virtio v1.0 and v0.95 co-exist well, this patch set > introduces a virtio_pci_ops structure, to add another layer so that > we could keep those vtpci_foo_bar "APIs". With that, we could do the > minimum change to add virtio 1.0 support. Please point out from which version, qemu starts to support virtio 1.0 net devices. Thanks, Jianfeng > > Note that the enabling is still in rough state, and it's likely I may > miss something. So, comments are huge welcome! > > --yliu > > --- > Yuanhan Liu (6): > virtio: don't set vring address again at queue startup > virtio: introduce struct virtio_pci_ops > virtio: move left pci stuff to virtio_pci.c > viritio: switch to 64 bit features > virtio: set RTE_PCI_DRV_NEED_MAPPING flag > virtio: add virtio v1.0 support > > drivers/net/virtio/virtio_ethdev.c | 297 +-------------- > drivers/net/virtio/virtio_ethdev.h | 3 +- > drivers/net/virtio/virtio_pci.c | 752 > +++++++++++++++++++++++++++++++++++-- > drivers/net/virtio/virtio_pci.h | 100 ++++- > drivers/net/virtio/virtio_rxtx.c | 15 - > drivers/net/virtio/virtqueue.h | 4 +- > 6 files changed, 843 insertions(+), 328 deletions(-) > > -- > 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling 2015-12-29 11:19 ` Tan, Jianfeng @ 2015-12-30 3:53 ` Yuanhan Liu 2016-01-04 3:55 ` Xu, Qian Q 1 sibling, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2015-12-30 3:53 UTC (permalink / raw) To: Tan, Jianfeng; +Cc: dev On Tue, Dec 29, 2015 at 11:19:20AM +0000, Tan, Jianfeng wrote: > > > > -----Original Message----- > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu > > Sent: Thursday, December 10, 2015 11:54 AM > > To: dev@dpdk.org > > Subject: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling > > > > Hi, > > > > Here is an initial virtio 1.0 pmd driver enabling. > > > > Almost all difference comes from virtio 1.0 are the PCI layout change: > > the major configuration structures are stored at bar space, and their > > location is stored at corresponding pci cap structure. Reading/parsing > > them is one of the major work of patch 6. > > > > To make handling virtio v1.0 and v0.95 co-exist well, this patch set > > introduces a virtio_pci_ops structure, to add another layer so that > > we could keep those vtpci_foo_bar "APIs". With that, we could do the > > minimum change to add virtio 1.0 support. > > > Please point out from which version, qemu starts to support virtio 1.0 net devices. I didn't bother to check: I always use the latest qemu, the one build from git. To test it, you need to add 'disable-modern=false' option to the virtio-net-pci device. I have added a simple test guide on internal jira. And I should have done so here; will add the test guide in next version. --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling 2015-12-29 11:19 ` Tan, Jianfeng 2015-12-30 3:53 ` Yuanhan Liu @ 2016-01-04 3:55 ` Xu, Qian Q 2016-01-04 4:16 ` Yuanhan Liu 1 sibling, 1 reply; 122+ messages in thread From: Xu, Qian Q @ 2016-01-04 3:55 UTC (permalink / raw) To: Tan, Jianfeng, Yuanhan Liu, dev Does dpdk vhost-switch sample support virtio1.0? I tried it but seems not working. Thanks Qian -----Original Message----- From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tan, Jianfeng Sent: Tuesday, December 29, 2015 7:19 PM To: Yuanhan Liu; dev@dpdk.org Subject: Re: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling > -----Original Message----- > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu > Sent: Thursday, December 10, 2015 11:54 AM > To: dev@dpdk.org > Subject: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling > > Hi, > > Here is an initial virtio 1.0 pmd driver enabling. > > Almost all difference comes from virtio 1.0 are the PCI layout change: > the major configuration structures are stored at bar space, and their > location is stored at corresponding pci cap structure. Reading/parsing > them is one of the major work of patch 6. > > To make handling virtio v1.0 and v0.95 co-exist well, this patch set > introduces a virtio_pci_ops structure, to add another layer so that we > could keep those vtpci_foo_bar "APIs". With that, we could do the > minimum change to add virtio 1.0 support. Please point out from which version, qemu starts to support virtio 1.0 net devices. Thanks, Jianfeng > > Note that the enabling is still in rough state, and it's likely I may > miss something. So, comments are huge welcome! > > --yliu > > --- > Yuanhan Liu (6): > virtio: don't set vring address again at queue startup > virtio: introduce struct virtio_pci_ops > virtio: move left pci stuff to virtio_pci.c > viritio: switch to 64 bit features > virtio: set RTE_PCI_DRV_NEED_MAPPING flag > virtio: add virtio v1.0 support > > drivers/net/virtio/virtio_ethdev.c | 297 +-------------- > drivers/net/virtio/virtio_ethdev.h | 3 +- > drivers/net/virtio/virtio_pci.c | 752 > +++++++++++++++++++++++++++++++++++-- > drivers/net/virtio/virtio_pci.h | 100 ++++- > drivers/net/virtio/virtio_rxtx.c | 15 - > drivers/net/virtio/virtqueue.h | 4 +- > 6 files changed, 843 insertions(+), 328 deletions(-) > > -- > 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling 2016-01-04 3:55 ` Xu, Qian Q @ 2016-01-04 4:16 ` Yuanhan Liu 0 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-04 4:16 UTC (permalink / raw) To: Xu, Qian Q; +Cc: dev On Mon, Jan 04, 2016 at 03:55:14AM +0000, Xu, Qian Q wrote: > Does dpdk vhost-switch sample support virtio1.0? I tried it but seems not working. It has nothing to do with vhost-switch sample. It worked from my test; you may come to find me offline to see what might be wrong on your side. --yliu > > Thanks > Qian > > > -----Original Message----- > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Tan, Jianfeng > Sent: Tuesday, December 29, 2015 7:19 PM > To: Yuanhan Liu; dev@dpdk.org > Subject: Re: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling > > > > > -----Original Message----- > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Yuanhan Liu > > Sent: Thursday, December 10, 2015 11:54 AM > > To: dev@dpdk.org > > Subject: [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling > > > > Hi, > > > > Here is an initial virtio 1.0 pmd driver enabling. > > > > Almost all difference comes from virtio 1.0 are the PCI layout change: > > the major configuration structures are stored at bar space, and their > > location is stored at corresponding pci cap structure. Reading/parsing > > them is one of the major work of patch 6. > > > > To make handling virtio v1.0 and v0.95 co-exist well, this patch set > > introduces a virtio_pci_ops structure, to add another layer so that we > > could keep those vtpci_foo_bar "APIs". With that, we could do the > > minimum change to add virtio 1.0 support. > > > Please point out from which version, qemu starts to support virtio 1.0 net devices. > > Thanks, > Jianfeng > > > > > Note that the enabling is still in rough state, and it's likely I may > > miss something. So, comments are huge welcome! > > > > --yliu > > > > --- > > Yuanhan Liu (6): > > virtio: don't set vring address again at queue startup > > virtio: introduce struct virtio_pci_ops > > virtio: move left pci stuff to virtio_pci.c > > viritio: switch to 64 bit features > > virtio: set RTE_PCI_DRV_NEED_MAPPING flag > > virtio: add virtio v1.0 support > > > > drivers/net/virtio/virtio_ethdev.c | 297 +-------------- > > drivers/net/virtio/virtio_ethdev.h | 3 +- > > drivers/net/virtio/virtio_pci.c | 752 > > +++++++++++++++++++++++++++++++++++-- > > drivers/net/virtio/virtio_pci.h | 100 ++++- > > drivers/net/virtio/virtio_rxtx.c | 15 - > > drivers/net/virtio/virtqueue.h | 4 +- > > 6 files changed, 843 insertions(+), 328 deletions(-) > > > > -- > > 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver 2015-12-10 3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu ` (7 preceding siblings ...) 2015-12-29 11:19 ` Tan, Jianfeng @ 2016-01-12 6:58 ` Yuanhan Liu 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 1/7] virtio: don't set vring address again at queue startup Yuanhan Liu ` (10 more replies) 8 siblings, 11 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-12 6:58 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin v2: - fix a data corruption reported by Qian, due to hdr size mismatch. check detailes at ptach 5. - Add missing config_irq and isr reading support from v1. - fix comments from v1. Almost all difference comes from virtio 1.0 are the PCI layout change: the major configuration structures are stored at bar space, and their location is stored at corresponding pci cap structure. Reading/parsing them is one of the major work of patch 7. To make handling virtio v1.0 and v0.95 co-exist well, this patch set introduces a virtio_pci_ops structure, to add another layer so that we could keep those vtpci_foo_bar "APIs". With that, we could do the minimum change to add virtio 1.0 support. --- Yuanhan Liu (7): virtio: don't set vring address again at queue startup virtio: introduce struct virtio_pci_ops virtio: move left pci stuff to virtio_pci.c viritio: switch to 64 bit features virtio: retrieve hdr_size from hw->vtnet_hdr_size eal: pci: export pci_map_device virtio: add 1.0 support doc/guides/rel_notes/release_2_3.rst | 3 + drivers/net/virtio/virtio_ethdev.c | 301 +--------- drivers/net/virtio/virtio_ethdev.h | 3 +- drivers/net/virtio/virtio_pci.c | 768 +++++++++++++++++++++++- drivers/net/virtio/virtio_pci.h | 102 +++- drivers/net/virtio/virtio_rxtx.c | 21 +- drivers/net/virtio/virtqueue.h | 4 +- lib/librte_eal/bsdapp/eal/eal_pci.c | 2 +- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 6 + lib/librte_eal/common/eal_common_pci.c | 2 +- lib/librte_eal/common/eal_private.h | 11 - lib/librte_eal/common/include/rte_pci.h | 11 + lib/librte_eal/linuxapp/eal/eal_pci.c | 2 +- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 6 + 14 files changed, 899 insertions(+), 343 deletions(-) -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v2 1/7] virtio: don't set vring address again at queue startup 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu @ 2016-01-12 6:58 ` Yuanhan Liu 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 2/7] virtio: introduce struct virtio_pci_ops Yuanhan Liu ` (9 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-12 6:58 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin As we have already set up it at virtio_dev_queue_setup(), and a vq restart will not reset the settings. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_rxtx.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c index 74b39ef..b7267c0 100644 --- a/drivers/net/virtio/virtio_rxtx.c +++ b/drivers/net/virtio/virtio_rxtx.c @@ -339,11 +339,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type) vq_update_avail_idx(vq); PMD_INIT_LOG(DEBUG, "Allocated %d bufs", nbufs); - - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); } else if (queue_type == VTNET_TQ) { if (use_simple_rxtx) { int mid_idx = vq->vq_nentries >> 1; @@ -362,16 +357,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type) for (i = mid_idx; i < vq->vq_nentries; i++) vq->vq_ring.avail->ring[i] = i; } - - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); - } else { - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); } } -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v2 2/7] virtio: introduce struct virtio_pci_ops 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 1/7] virtio: don't set vring address again at queue startup Yuanhan Liu @ 2016-01-12 6:58 ` Yuanhan Liu 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 3/7] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu ` (8 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-12 6:58 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin 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> --- 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 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v2 3/7] virtio: move left pci stuff to virtio_pci.c 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 1/7] virtio: don't set vring address again at queue startup Yuanhan Liu 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 2/7] virtio: introduce struct virtio_pci_ops Yuanhan Liu @ 2016-01-12 6:59 ` Yuanhan Liu 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 4/7] viritio: switch to 64 bit features Yuanhan Liu ` (7 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-12 6:59 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin virtio_pci.c is a more proper place for pci stuff; virtio_ethdev is not. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_ethdev.c | 265 +----------------------------------- drivers/net/virtio/virtio_pci.c | 270 ++++++++++++++++++++++++++++++++++++- 2 files changed, 270 insertions(+), 265 deletions(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 6c1d3a0..b57224d 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -36,10 +36,6 @@ #include <stdio.h> #include <errno.h> #include <unistd.h> -#ifdef RTE_EXEC_ENV_LINUXAPP -#include <dirent.h> -#include <fcntl.h> -#endif #include <rte_ethdev.h> #include <rte_memcpy.h> @@ -955,260 +951,6 @@ virtio_negotiate_features(struct virtio_hw *hw) hw->guest_features); } -#ifdef RTE_EXEC_ENV_LINUXAPP -static int -parse_sysfs_value(const char *filename, unsigned long *val) -{ - FILE *f; - char buf[BUFSIZ]; - char *end = NULL; - - f = fopen(filename, "r"); - if (f == NULL) { - PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s", - __func__, filename); - return -1; - } - - if (fgets(buf, sizeof(buf), f) == NULL) { - PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s", - __func__, filename); - fclose(f); - return -1; - } - *val = strtoul(buf, &end, 0); - if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { - PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s", - __func__, filename); - fclose(f); - return -1; - } - fclose(f); - return 0; -} - -static int get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen, - unsigned int *uio_num) -{ - struct dirent *e; - DIR *dir; - char dirname[PATH_MAX]; - - /* depending on kernel version, uio can be located in uio/uioX - * or uio:uioX */ - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", - loc->domain, loc->bus, loc->devid, loc->function); - dir = opendir(dirname); - if (dir == NULL) { - /* retry with the parent directory */ - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, - loc->domain, loc->bus, loc->devid, loc->function); - dir = opendir(dirname); - - if (dir == NULL) { - PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname); - return -1; - } - } - - /* take the first file starting with "uio" */ - while ((e = readdir(dir)) != NULL) { - /* format could be uio%d ...*/ - int shortprefix_len = sizeof("uio") - 1; - /* ... or uio:uio%d */ - int longprefix_len = sizeof("uio:uio") - 1; - char *endptr; - - if (strncmp(e->d_name, "uio", 3) != 0) - continue; - - /* first try uio%d */ - errno = 0; - *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); - if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { - snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num); - break; - } - - /* then try uio:uio%d */ - errno = 0; - *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); - if (errno == 0 && endptr != (e->d_name + longprefix_len)) { - snprintf(buf, buflen, "%s/uio:uio%u", dirname, - *uio_num); - break; - } - } - closedir(dir); - - /* No uio resource found */ - if (e == NULL) { - PMD_INIT_LOG(ERR, "Could not find uio resource"); - return -1; - } - - return 0; -} - -static int -virtio_has_msix(const struct rte_pci_addr *loc) -{ - DIR *d; - char dirname[PATH_MAX]; - - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs", - loc->domain, loc->bus, loc->devid, loc->function); - - d = opendir(dirname); - if (d) - closedir(d); - - return (d != NULL); -} - -/* Extract I/O port numbers from sysfs */ -static int virtio_resource_init_by_uio(struct rte_pci_device *pci_dev) -{ - char dirname[PATH_MAX]; - char filename[PATH_MAX]; - unsigned long start, size; - unsigned int uio_num; - - if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0) - return -1; - - /* get portio size */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/size", dirname); - if (parse_sysfs_value(filename, &size) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse size", - __func__); - return -1; - } - - /* get portio start */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/start", dirname); - if (parse_sysfs_value(filename, &start) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", - __func__); - return -1; - } - pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; - pci_dev->mem_resource[0].len = (uint64_t)size; - PMD_INIT_LOG(DEBUG, - "PCI Port IO found start=0x%lx with size=0x%lx", - start, size); - - /* save fd */ - memset(dirname, 0, sizeof(dirname)); - snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num); - pci_dev->intr_handle.fd = open(dirname, O_RDWR); - if (pci_dev->intr_handle.fd < 0) { - PMD_INIT_LOG(ERR, "Cannot open %s: %s\n", - dirname, strerror(errno)); - return -1; - } - - pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO; - pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; - - return 0; -} - -/* Extract port I/O numbers from proc/ioports */ -static int virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev) -{ - uint16_t start, end; - int size; - FILE *fp; - char *line = NULL; - char pci_id[16]; - int found = 0; - size_t linesz; - - snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, - pci_dev->addr.domain, - pci_dev->addr.bus, - pci_dev->addr.devid, - pci_dev->addr.function); - - fp = fopen("/proc/ioports", "r"); - if (fp == NULL) { - PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__); - return -1; - } - - while (getdelim(&line, &linesz, '\n', fp) > 0) { - char *ptr = line; - char *left; - int n; - - n = strcspn(ptr, ":"); - ptr[n] = 0; - left = &ptr[n+1]; - - while (*left && isspace(*left)) - left++; - - if (!strncmp(left, pci_id, strlen(pci_id))) { - found = 1; - - while (*ptr && isspace(*ptr)) - ptr++; - - sscanf(ptr, "%04hx-%04hx", &start, &end); - size = end - start + 1; - - break; - } - } - - free(line); - fclose(fp); - - if (!found) - return -1; - - pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start; - pci_dev->mem_resource[0].len = (uint64_t)size; - PMD_INIT_LOG(DEBUG, - "PCI Port IO found start=0x%x with size=0x%x", - start, size); - - /* can't support lsc interrupt without uio */ - pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; - - return 0; -} - -/* Extract I/O port numbers from sysfs */ -static int virtio_resource_init(struct rte_pci_device *pci_dev) -{ - if (virtio_resource_init_by_uio(pci_dev) == 0) - return 0; - else - return virtio_resource_init_by_ioports(pci_dev); -} - -#else -static int -virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) -{ - /* nic_uio does not enable interrupts, return 0 (false). */ - return 0; -} - -static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) -{ - /* no setup required */ - return 0; -} -#endif - /* * Process Virtio Config changed interrupt and call the callback * if link state changed. @@ -1279,14 +1021,9 @@ 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) + if (vtpci_init(pci_dev, hw) < 0) return -1; - hw->use_msix = virtio_has_msix(&pci_dev->addr); - hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr; - /* Reset the device although not necessary at startup */ vtpci_reset(hw); diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 9930efa..03d623b 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -32,6 +32,11 @@ */ #include <stdint.h> +#ifdef RTE_EXEC_ENV_LINUXAPP + #include <dirent.h> + #include <fcntl.h> +#endif + #include "virtio_pci.h" #include "virtio_logs.h" #include "virtqueue.h" @@ -156,6 +161,264 @@ legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq) VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index); } +#ifdef RTE_EXEC_ENV_LINUXAPP +static int +parse_sysfs_value(const char *filename, unsigned long *val) +{ + FILE *f; + char buf[BUFSIZ]; + char *end = NULL; + + f = fopen(filename, "r"); + if (f == NULL) { + PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s", + __func__, filename); + return -1; + } + + if (fgets(buf, sizeof(buf), f) == NULL) { + PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s", + __func__, filename); + fclose(f); + return -1; + } + *val = strtoul(buf, &end, 0); + if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { + PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s", + __func__, filename); + fclose(f); + return -1; + } + fclose(f); + return 0; +} + +static int +get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen, + unsigned int *uio_num) +{ + struct dirent *e; + DIR *dir; + char dirname[PATH_MAX]; + + /* depending on kernel version, uio can be located in uio/uioX + * or uio:uioX */ + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", + loc->domain, loc->bus, loc->devid, loc->function); + dir = opendir(dirname); + if (dir == NULL) { + /* retry with the parent directory */ + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, + loc->domain, loc->bus, loc->devid, loc->function); + dir = opendir(dirname); + + if (dir == NULL) { + PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname); + return -1; + } + } + + /* take the first file starting with "uio" */ + while ((e = readdir(dir)) != NULL) { + /* format could be uio%d ...*/ + int shortprefix_len = sizeof("uio") - 1; + /* ... or uio:uio%d */ + int longprefix_len = sizeof("uio:uio") - 1; + char *endptr; + + if (strncmp(e->d_name, "uio", 3) != 0) + continue; + + /* first try uio%d */ + errno = 0; + *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); + if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { + snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num); + break; + } + + /* then try uio:uio%d */ + errno = 0; + *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); + if (errno == 0 && endptr != (e->d_name + longprefix_len)) { + snprintf(buf, buflen, "%s/uio:uio%u", dirname, + *uio_num); + break; + } + } + closedir(dir); + + /* No uio resource found */ + if (e == NULL) { + PMD_INIT_LOG(ERR, "Could not find uio resource"); + return -1; + } + + return 0; +} + +static int +legacy_virtio_has_msix(const struct rte_pci_addr *loc) +{ + DIR *d; + char dirname[PATH_MAX]; + + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs", + loc->domain, loc->bus, loc->devid, loc->function); + + d = opendir(dirname); + if (d) + closedir(d); + + return (d != NULL); +} + +/* Extract I/O port numbers from sysfs */ +static int +virtio_resource_init_by_uio(struct rte_pci_device *pci_dev) +{ + char dirname[PATH_MAX]; + char filename[PATH_MAX]; + unsigned long start, size; + unsigned int uio_num; + + if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0) + return -1; + + /* get portio size */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/size", dirname); + if (parse_sysfs_value(filename, &size) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse size", + __func__); + return -1; + } + + /* get portio start */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/start", dirname); + if (parse_sysfs_value(filename, &start) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", + __func__); + return -1; + } + pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; + pci_dev->mem_resource[0].len = (uint64_t)size; + PMD_INIT_LOG(DEBUG, + "PCI Port IO found start=0x%lx with size=0x%lx", + start, size); + + /* save fd */ + memset(dirname, 0, sizeof(dirname)); + snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num); + pci_dev->intr_handle.fd = open(dirname, O_RDWR); + if (pci_dev->intr_handle.fd < 0) { + PMD_INIT_LOG(ERR, "Cannot open %s: %s\n", + dirname, strerror(errno)); + return -1; + } + + pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO; + pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; + + return 0; +} + +/* Extract port I/O numbers from proc/ioports */ +static int +virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev) +{ + uint16_t start, end; + int size; + FILE *fp; + char *line = NULL; + char pci_id[16]; + int found = 0; + size_t linesz; + + snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, + pci_dev->addr.domain, + pci_dev->addr.bus, + pci_dev->addr.devid, + pci_dev->addr.function); + + fp = fopen("/proc/ioports", "r"); + if (fp == NULL) { + PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__); + return -1; + } + + while (getdelim(&line, &linesz, '\n', fp) > 0) { + char *ptr = line; + char *left; + int n; + + n = strcspn(ptr, ":"); + ptr[n] = 0; + left = &ptr[n+1]; + + while (*left && isspace(*left)) + left++; + + if (!strncmp(left, pci_id, strlen(pci_id))) { + found = 1; + + while (*ptr && isspace(*ptr)) + ptr++; + + sscanf(ptr, "%04hx-%04hx", &start, &end); + size = end - start + 1; + + break; + } + } + + free(line); + fclose(fp); + + if (!found) + return -1; + + pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start; + pci_dev->mem_resource[0].len = (uint64_t)size; + PMD_INIT_LOG(DEBUG, + "PCI Port IO found start=0x%x with size=0x%x", + start, size); + + /* can't support lsc interrupt without uio */ + pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; + + return 0; +} + +/* Extract I/O port numbers from sysfs */ +static int +legacy_virtio_resource_init(struct rte_pci_device *pci_dev) +{ + if (virtio_resource_init_by_uio(pci_dev) == 0) + return 0; + else + return virtio_resource_init_by_ioports(pci_dev); +} + +#else +static int +legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) +{ + /* nic_uio does not enable interrupts, return 0 (false). */ + return 0; +} + +static int +legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) +{ + /* no setup required */ + return 0; +} +#endif static const struct virtio_pci_ops legacy_ops = { .read_dev_cfg = legacy_read_dev_config, @@ -241,9 +504,14 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) } int -vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw) +vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) { hw->vtpci_ops = &legacy_ops; + if (legacy_virtio_resource_init(dev) < 0) + return -1; + hw->use_msix = legacy_virtio_has_msix(&dev->addr); + hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr; + return 0; } -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v2 4/7] viritio: switch to 64 bit features 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (2 preceding siblings ...) 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 3/7] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu @ 2016-01-12 6:59 ` Yuanhan Liu 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 5/7] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu ` (6 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-12 6:59 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin Switch to 64 bit features, which virtio 1.0 supports. While legacy virtio only supports 32 bit features, it complains aloud and quit when trying to setting > 32 bit features. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_ethdev.c | 8 ++++---- drivers/net/virtio/virtio_pci.c | 15 ++++++++++----- drivers/net/virtio/virtio_pci.h | 12 ++++++------ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index b57224d..94e0c4a 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -930,16 +930,16 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) static void virtio_negotiate_features(struct virtio_hw *hw) { - uint32_t host_features; + uint64_t host_features; /* Prepare guest_features: feature that driver wants to support */ hw->guest_features = VIRTIO_PMD_GUEST_FEATURES; - PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %x", + PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %"PRIx64, hw->guest_features); /* Read device(host) feature bits */ host_features = hw->vtpci_ops->get_features(hw); - PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x", + PMD_INIT_LOG(DEBUG, "host_features before negotiate = %"PRIx64, host_features); /* @@ -947,7 +947,7 @@ virtio_negotiate_features(struct virtio_hw *hw) * guest feature bits. */ hw->guest_features = vtpci_negotiate_features(hw, host_features); - PMD_INIT_LOG(DEBUG, "features after negotiate = %x", + PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, hw->guest_features); } diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 03d623b..5eed57e 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -87,15 +87,20 @@ legacy_write_dev_config(struct virtio_hw *hw, uint64_t offset, } } -static uint32_t +static uint64_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) +legacy_set_features(struct virtio_hw *hw, uint64_t features) { + if ((features >> 32) != 0) { + PMD_DRV_LOG(ERR, + "only 32 bit features are allowed for legacy virtio!"); + return; + } VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features); } @@ -451,10 +456,10 @@ vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset, hw->vtpci_ops->write_dev_cfg(hw, offset, src, length); } -uint32_t -vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features) +uint64_t +vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features) { - uint32_t features; + uint64_t features; /* * Limit negotiated features to what the driver, virtqueue, and diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index ee7d265..3fd86f6 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -175,8 +175,8 @@ struct virtio_pci_ops { 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); + uint64_t (*get_features)(struct virtio_hw *hw); + void (*set_features)(struct virtio_hw *hw, uint64_t features); uint8_t (*get_isr)(struct virtio_hw *hw); @@ -191,7 +191,7 @@ struct virtio_pci_ops { struct virtio_hw { struct virtqueue *cvq; uint32_t io_base; - uint32_t guest_features; + uint64_t guest_features; uint32_t max_tx_queues; uint32_t max_rx_queues; uint16_t vtnet_hdr_size; @@ -271,9 +271,9 @@ outl_p(unsigned int data, unsigned int port) outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) static inline int -vtpci_with_feature(struct virtio_hw *hw, uint32_t bit) +vtpci_with_feature(struct virtio_hw *hw, uint64_t bit) { - return (hw->guest_features & (1u << bit)) != 0; + return (hw->guest_features & (1ULL << bit)) != 0; } /* @@ -286,7 +286,7 @@ void vtpci_reinit_complete(struct virtio_hw *); void vtpci_set_status(struct virtio_hw *, uint8_t); -uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t); +uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t); void vtpci_write_dev_config(struct virtio_hw *, uint64_t, void *, int); -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v2 5/7] virtio: retrieve hdr_size from hw->vtnet_hdr_size 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (3 preceding siblings ...) 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 4/7] viritio: switch to 64 bit features Yuanhan Liu @ 2016-01-12 6:59 ` Yuanhan Liu 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device Yuanhan Liu ` (5 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-12 6:59 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin The mergeable virtio net hdr format has been the standard and the only virtio net hdr format since virtio 1.0. Therefore, we could not hardcode hdr_size to "sizeof(struct virtio_net_hdr)" any more at virtio_recv_pkts(), otherwise, there would be a mismatch of hdr size from rte_vhost_enqueue_burst() and virtio_recv_pkts(), leading a packet corruption. Instead, we should retrieve it from hw->vtnet_hdr_size; we will do proper settings at eth_virtio_dev_init(). Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_rxtx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c index b7267c0..41a1366 100644 --- a/drivers/net/virtio/virtio_rxtx.c +++ b/drivers/net/virtio/virtio_rxtx.c @@ -560,7 +560,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ]; int error; uint32_t i, nb_enqueued; - const uint32_t hdr_size = sizeof(struct virtio_net_hdr); + uint32_t hdr_size; nb_used = VIRTQUEUE_NUSED(rxvq); @@ -580,6 +580,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) hw = rxvq->hw; nb_rx = 0; nb_enqueued = 0; + hdr_size = hw->vtnet_hdr_size; for (i = 0; i < num ; i++) { rxm = rcv_pkts[i]; @@ -664,7 +665,7 @@ virtio_recv_mergeable_pkts(void *rx_queue, uint32_t seg_num; uint16_t extra_idx; uint32_t seg_res; - const uint32_t hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); + uint32_t hdr_size; nb_used = VIRTQUEUE_NUSED(rxvq); @@ -682,6 +683,7 @@ virtio_recv_mergeable_pkts(void *rx_queue, seg_num = 0; extra_idx = 0; seg_res = 0; + hdr_size = hw->vtnet_hdr_size; while (i < nb_used) { struct virtio_net_hdr_mrg_rxbuf *header; -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (4 preceding siblings ...) 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 5/7] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu @ 2016-01-12 6:59 ` Yuanhan Liu 2016-01-12 8:31 ` David Marchand 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support Yuanhan Liu ` (4 subsequent siblings) 10 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2016-01-12 6:59 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will invoke pci_map_device internally for us. From that point view, there is no need to export pci_map_device. However, for virtio pmd driver, which is designed to work without binding UIO (or something similar first), pci_map_device() will fail, which ends up with virtio pmd driver being skipped. Therefore, we can not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver. Therefore, this patch exports pci_map_device, and let virtio pmd call it when necessary. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- lib/librte_eal/bsdapp/eal/eal_pci.c | 2 +- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 6 ++++++ lib/librte_eal/common/eal_common_pci.c | 2 +- lib/librte_eal/common/eal_private.h | 11 ----------- lib/librte_eal/common/include/rte_pci.h | 11 +++++++++++ lib/librte_eal/linuxapp/eal/eal_pci.c | 2 +- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 6 ++++++ 7 files changed, 26 insertions(+), 14 deletions(-) diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c index 6c21fbd..adb0915 100644 --- a/lib/librte_eal/bsdapp/eal/eal_pci.c +++ b/lib/librte_eal/bsdapp/eal/eal_pci.c @@ -93,7 +93,7 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused) /* Map pci device */ int -pci_map_device(struct rte_pci_device *dev) +rte_eal_pci_map_device(struct rte_pci_device *dev) { int ret = -1; diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map index 9d7adf1..b166c3c 100644 --- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map +++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map @@ -135,3 +135,9 @@ DPDK_2.2 { rte_xen_dom0_supported; } DPDK_2.1; + +DPDK_2.3 { + global: + + rte_eal_pci_map_device; +} DPDK_2.2; diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c index dcfe947..486d921 100644 --- a/lib/librte_eal/common/eal_common_pci.c +++ b/lib/librte_eal/common/eal_common_pci.c @@ -188,7 +188,7 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d pci_config_space_set(dev); #endif /* map resources for devices that use igb_uio */ - ret = pci_map_device(dev); + ret = rte_eal_pci_map_device(dev); if (ret != 0) return ret; } else if (dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND && diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h index 072e672..ae710b7 100644 --- a/lib/librte_eal/common/eal_private.h +++ b/lib/librte_eal/common/eal_private.h @@ -165,17 +165,6 @@ struct rte_pci_device; int pci_unbind_kernel_driver(struct rte_pci_device *dev); /** - * Map this device - * - * This function is private to EAL. - * - * @return - * 0 on success, negative on error and positive if no driver - * is found for the device. - */ -int pci_map_device(struct rte_pci_device *dev); - -/** * Unmap this device * * This function is private to EAL. diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h index 334c12e..e9e1725 100644 --- a/lib/librte_eal/common/include/rte_pci.h +++ b/lib/librte_eal/common/include/rte_pci.h @@ -485,6 +485,17 @@ int rte_eal_pci_read_config(const struct rte_pci_device *device, */ int rte_eal_pci_write_config(const struct rte_pci_device *device, const void *buf, size_t len, off_t offset); +/** + * Map this device + * + * This function is private to EAL. + * + * @return + * 0 on success, negative on error and positive if no driver + * is found for the device. + */ +int rte_eal_pci_map_device(struct rte_pci_device *dev); + #ifdef RTE_PCI_CONFIG /** diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c index bc5b5be..a8cef37 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c @@ -124,7 +124,7 @@ pci_get_kernel_driver_by_path(const char *filename, char *dri_name) /* Map pci device */ int -pci_map_device(struct rte_pci_device *dev) +rte_eal_pci_map_device(struct rte_pci_device *dev) { int ret = -1; diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map index cbe175f..7b12282 100644 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map @@ -138,3 +138,9 @@ DPDK_2.2 { rte_xen_dom0_supported; } DPDK_2.1; + +DPDK_2.3 { + global: + + rte_eal_pci_map_device; +} DPDK_2.2; -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device Yuanhan Liu @ 2016-01-12 8:31 ` David Marchand 2016-01-12 8:40 ` Yuanhan Liu 0 siblings, 1 reply; 122+ messages in thread From: David Marchand @ 2016-01-12 8:31 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev, Michael S. Tsirkin On Tue, Jan 12, 2016 at 7:59 AM, Yuanhan Liu <yuanhan.liu@linux.intel.com> wrote: > Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will > invoke pci_map_device internally for us. From that point view, there > is no need to export pci_map_device. > > However, for virtio pmd driver, which is designed to work without > binding UIO (or something similar first), pci_map_device() will fail, > which ends up with virtio pmd driver being skipped. Therefore, we can > not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver. > > Therefore, this patch exports pci_map_device, and let virtio pmd > call it when necessary. > Well, if you introduce map function, I suppose, for hotplug, you would need unmap. [snip] diff --git a/lib/librte_eal/common/include/rte_pci.h > b/lib/librte_eal/common/include/rte_pci.h > index 334c12e..e9e1725 100644 > --- a/lib/librte_eal/common/include/rte_pci.h > +++ b/lib/librte_eal/common/include/rte_pci.h > @@ -485,6 +485,17 @@ int rte_eal_pci_read_config(const struct > rte_pci_device *device, > */ > int rte_eal_pci_write_config(const struct rte_pci_device *device, > const void *buf, size_t len, off_t offset); > +/** > + * Map this device > + * > + * This function is private to EAL. > + * > + * @return > + * 0 on success, negative on error and positive if no driver > + * is found for the device. > + */ > +int rte_eal_pci_map_device(struct rte_pci_device *dev); > + > If you export it, then this can not be marked as private anymore. Description could be better (I agree it was not that great before). And a little comment on when to call: driver should not set RTE_PCI_DRV_NEED_MAPPING flag if it wants to use it. The rest looks good to me. -- David Marchand ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device 2016-01-12 8:31 ` David Marchand @ 2016-01-12 8:40 ` Yuanhan Liu 2016-01-12 9:05 ` Yuanhan Liu 0 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2016-01-12 8:40 UTC (permalink / raw) To: David Marchand; +Cc: dev On Tue, Jan 12, 2016 at 09:31:05AM +0100, David Marchand wrote: > On Tue, Jan 12, 2016 at 7:59 AM, Yuanhan Liu <yuanhan.liu@linux.intel.com> > wrote: > > Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will > invoke pci_map_device internally for us. From that point view, there > is no need to export pci_map_device. > > However, for virtio pmd driver, which is designed to work without > binding UIO (or something similar first), pci_map_device() will fail, > which ends up with virtio pmd driver being skipped. Therefore, we can > not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver. > > Therefore, this patch exports pci_map_device, and let virtio pmd > call it when necessary. > > > Well, if you introduce map function, I suppose, for hotplug, you would need > unmap. Good remind. Thanks. I will export pci_unmap_device as well. > [snip] > > > diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/ > common/include/rte_pci.h > index 334c12e..e9e1725 100644 > --- a/lib/librte_eal/common/include/rte_pci.h > +++ b/lib/librte_eal/common/include/rte_pci.h > @@ -485,6 +485,17 @@ int rte_eal_pci_read_config(const struct > rte_pci_device *device, > */ > int rte_eal_pci_write_config(const struct rte_pci_device *device, > const void *buf, size_t len, off_t offset); > +/** > + * Map this device > + * > + * This function is private to EAL. > + * > + * @return > + * 0 on success, negative on error and positive if no driver > + * is found for the device. > + */ > +int rte_eal_pci_map_device(struct rte_pci_device *dev); > + > > > If you export it, then this can not be marked as private anymore. Oops, a silly C&P error. Will fix it. > Description could be better (I agree it was not that great before). > And a little comment on when to call: driver should not set > RTE_PCI_DRV_NEED_MAPPING flag if it wants to use it. Good suggestion. > The rest looks good to me. Thanks. --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device 2016-01-12 8:40 ` Yuanhan Liu @ 2016-01-12 9:05 ` Yuanhan Liu 2016-01-13 14:44 ` Santosh Shukla 0 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2016-01-12 9:05 UTC (permalink / raw) To: David Marchand; +Cc: dev On Tue, Jan 12, 2016 at 04:40:43PM +0800, Yuanhan Liu wrote: > On Tue, Jan 12, 2016 at 09:31:05AM +0100, David Marchand wrote: > > On Tue, Jan 12, 2016 at 7:59 AM, Yuanhan Liu <yuanhan.liu@linux.intel.com> > > wrote: > > > > Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will > > invoke pci_map_device internally for us. From that point view, there > > is no need to export pci_map_device. > > > > However, for virtio pmd driver, which is designed to work without > > binding UIO (or something similar first), pci_map_device() will fail, > > which ends up with virtio pmd driver being skipped. Therefore, we can > > not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver. > > > > Therefore, this patch exports pci_map_device, and let virtio pmd > > call it when necessary. > > > > > > Well, if you introduce map function, I suppose, for hotplug, you would need > > unmap. > > Good remind. Thanks. I will export pci_unmap_device as well. And here you go. --yliu -- >8 -- >From aa3d9d0fa827781d1563fd4c06ba04a8fafdc41c Mon Sep 17 00:00:00 2001 From: Yuanhan Liu <yuanhan.liu@linux.intel.com> Date: Mon, 11 Jan 2016 16:51:35 +0800 Subject: [PATCH] eal: pci: export pci_[un]map_device Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will invoke pci_map_device internally for us. From that point view, there is no need to export pci_map_device. However, for virtio pmd driver, which is designed to work without binding UIO (or something similar first), pci_map_device() will fail, which ends up with virtio pmd driver being skipped. Therefore, we can not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver. Therefore, this patch exports pci_map_device, and let virtio pmd call it when necessary. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- v2: - export pci_unmap_device as well - Add few more comments about rte_eal_pci_map_device(). --- lib/librte_eal/bsdapp/eal/eal_pci.c | 4 ++-- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 7 +++++++ lib/librte_eal/common/eal_common_pci.c | 4 ++-- lib/librte_eal/common/eal_private.h | 18 ----------------- lib/librte_eal/common/include/rte_pci.h | 27 +++++++++++++++++++++++++ lib/librte_eal/linuxapp/eal/eal_pci.c | 4 ++-- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +++++++ 7 files changed, 47 insertions(+), 24 deletions(-) diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c index 6c21fbd..95c32c1 100644 --- a/lib/librte_eal/bsdapp/eal/eal_pci.c +++ b/lib/librte_eal/bsdapp/eal/eal_pci.c @@ -93,7 +93,7 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused) /* Map pci device */ int -pci_map_device(struct rte_pci_device *dev) +rte_eal_pci_map_device(struct rte_pci_device *dev) { int ret = -1; @@ -115,7 +115,7 @@ pci_map_device(struct rte_pci_device *dev) /* Unmap pci device */ void -pci_unmap_device(struct rte_pci_device *dev) +rte_eal_pci_unmap_device(struct rte_pci_device *dev) { /* try unmapping the NIC resources */ switch (dev->kdrv) { diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map index 9d7adf1..1b28170 100644 --- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map +++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map @@ -135,3 +135,10 @@ DPDK_2.2 { rte_xen_dom0_supported; } DPDK_2.1; + +DPDK_2.3 { + global: + + rte_eal_pci_map_device; + rte_eal_pci_unmap_device; +} DPDK_2.2; diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c index dcfe947..96d5113 100644 --- a/lib/librte_eal/common/eal_common_pci.c +++ b/lib/librte_eal/common/eal_common_pci.c @@ -188,7 +188,7 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d pci_config_space_set(dev); #endif /* map resources for devices that use igb_uio */ - ret = pci_map_device(dev); + ret = rte_eal_pci_map_device(dev); if (ret != 0) return ret; } else if (dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND && @@ -254,7 +254,7 @@ rte_eal_pci_detach_dev(struct rte_pci_driver *dr, if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING) /* unmap resources for devices that use igb_uio */ - pci_unmap_device(dev); + rte_eal_pci_unmap_device(dev); return 0; } diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h index 072e672..2342fa1 100644 --- a/lib/librte_eal/common/eal_private.h +++ b/lib/librte_eal/common/eal_private.h @@ -165,24 +165,6 @@ struct rte_pci_device; int pci_unbind_kernel_driver(struct rte_pci_device *dev); /** - * Map this device - * - * This function is private to EAL. - * - * @return - * 0 on success, negative on error and positive if no driver - * is found for the device. - */ -int pci_map_device(struct rte_pci_device *dev); - -/** - * Unmap this device - * - * This function is private to EAL. - */ -void pci_unmap_device(struct rte_pci_device *dev); - -/** * Map the PCI resource of a PCI device in virtual memory * * This function is private to EAL. diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h index 334c12e..2224109 100644 --- a/lib/librte_eal/common/include/rte_pci.h +++ b/lib/librte_eal/common/include/rte_pci.h @@ -485,6 +485,33 @@ int rte_eal_pci_read_config(const struct rte_pci_device *device, */ int rte_eal_pci_write_config(const struct rte_pci_device *device, const void *buf, size_t len, off_t offset); +/** + * Map the PCI device resources in user space virtual memory address + * + * Note that driver should not call this function when flag + * RTE_PCI_DRV_NEED_MAPPING is set, as EAL will do that for + * you when it's on. + * + * @param dev + * A pointer to a rte_pci_device structure describing the device + * to use + * + * @return + * 0 on success, negative on error and positive if no driver + * is found for the device. + */ +int rte_eal_pci_map_device(struct rte_pci_device *dev); + +/** + * Unmap this device + * + * @param dev + * A pointer to a rte_pci_device structure describing the device + * to use + */ +void rte_eal_pci_unmap_device(struct rte_pci_device *dev); + + #ifdef RTE_PCI_CONFIG /** diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c index bc5b5be..db947da 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c @@ -124,7 +124,7 @@ pci_get_kernel_driver_by_path(const char *filename, char *dri_name) /* Map pci device */ int -pci_map_device(struct rte_pci_device *dev) +rte_eal_pci_map_device(struct rte_pci_device *dev) { int ret = -1; @@ -153,7 +153,7 @@ pci_map_device(struct rte_pci_device *dev) /* Unmap pci device */ void -pci_unmap_device(struct rte_pci_device *dev) +rte_eal_pci_unmap_device(struct rte_pci_device *dev) { /* try unmapping the NIC resources using VFIO if it exists */ switch (dev->kdrv) { diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map index cbe175f..b9937c4 100644 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map @@ -138,3 +138,10 @@ DPDK_2.2 { rte_xen_dom0_supported; } DPDK_2.1; + +DPDK_2.3 { + global: + + rte_eal_pci_map_device; + rte_eal_pci_unmap_device; +} DPDK_2.2; -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device 2016-01-12 9:05 ` Yuanhan Liu @ 2016-01-13 14:44 ` Santosh Shukla 0 siblings, 0 replies; 122+ messages in thread From: Santosh Shukla @ 2016-01-13 14:44 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev On Tue, Jan 12, 2016 at 2:35 PM, Yuanhan Liu <yuanhan.liu@linux.intel.com> wrote: > On Tue, Jan 12, 2016 at 04:40:43PM +0800, Yuanhan Liu wrote: >> On Tue, Jan 12, 2016 at 09:31:05AM +0100, David Marchand wrote: >> > On Tue, Jan 12, 2016 at 7:59 AM, Yuanhan Liu <yuanhan.liu@linux.intel.com> >> > wrote: >> > >> > Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will >> > invoke pci_map_device internally for us. From that point view, there >> > is no need to export pci_map_device. >> > >> > However, for virtio pmd driver, which is designed to work without >> > binding UIO (or something similar first), pci_map_device() will fail, >> > which ends up with virtio pmd driver being skipped. Therefore, we can >> > not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver. >> > >> > Therefore, this patch exports pci_map_device, and let virtio pmd >> > call it when necessary. >> > >> > >> > Well, if you introduce map function, I suppose, for hotplug, you would need >> > unmap. >> >> Good remind. Thanks. I will export pci_unmap_device as well. > > And here you go. > > --yliu > > -- >8 -- > From aa3d9d0fa827781d1563fd4c06ba04a8fafdc41c Mon Sep 17 00:00:00 2001 > From: Yuanhan Liu <yuanhan.liu@linux.intel.com> > Date: Mon, 11 Jan 2016 16:51:35 +0800 > Subject: [PATCH] eal: pci: export pci_[un]map_device > > Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will > invoke pci_map_device internally for us. From that point view, there > is no need to export pci_map_device. > > However, for virtio pmd driver, which is designed to work without > binding UIO (or something similar first), pci_map_device() will fail, > which ends up with virtio pmd driver being skipped. Therefore, we can > not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver. > > Therefore, this patch exports pci_map_device, and let virtio pmd > call it when necessary. > > Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> > --- > v2: - export pci_unmap_device as well > > - Add few more comments about rte_eal_pci_map_device(). This patch tested for vfio-noIOMMU mode for arm64 platform. Tested-By: Santosh Shukla <sshukla@mvista.com> ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (5 preceding siblings ...) 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device Yuanhan Liu @ 2016-01-12 6:59 ` Yuanhan Liu 2016-01-13 3:31 ` Tetsuya Mukawa ` (2 more replies) 2016-01-12 7:07 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (3 subsequent siblings) 10 siblings, 3 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-12 6:59 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin Modern (v1.0) virtio pci device defines several pci capabilities. Each cap has a configure structure corresponding to it, and the cap.bar and cap.offset fields tell us where to find it. Firstly, we map the pci resources by rte_eal_pci_map_device(). We then could easily locate to a cfg structure by: cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset; Therefore, the entrance of enabling modern (v1.0) pci device support is to iterate the pci capability lists, and to locate some configs we care; and they are: - common cfg For generic virtio and virtuqueu configuration, such as setting/getting features, enabling a specific queue, and so on. - nofity cfg Combining with `queue_notify_off' from common cfg, we could use it to notify a specific virt queue. - device cfg Where virtio_net_config structure locates. - isr cfg Where to read isr (interrupt status). If any of above cap is not found, we fallback to the legacy virtio handling. If succeed, hw->vtpci_ops is assigned to modern_ops, where all operations are implemented by reading/writing a (or few) specific configuration space from above 4 cfg structures. And that's basically how this patch works. Besides those changes, virtio 1.0 introduces a new status field: FEATURES_OK, which is set after features negotiation is done. Last, set the VIRTIO_F_VERSION_1 feature flag. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- v2: - re-read status after setting FEATURES_OK to make sure status is set correctly. - Add isr reading and config irq setting support. - Define some pci macro on our own to not get the dependency of linux/pci_regs.h, as there should be no such file at non-Linux platform --- doc/guides/rel_notes/release_2_3.rst | 3 + drivers/net/virtio/virtio_ethdev.c | 24 ++- drivers/net/virtio/virtio_ethdev.h | 3 +- drivers/net/virtio/virtio_pci.c | 335 ++++++++++++++++++++++++++++++++++- drivers/net/virtio/virtio_pci.h | 67 +++++++ drivers/net/virtio/virtqueue.h | 2 + 6 files changed, 429 insertions(+), 5 deletions(-) diff --git a/doc/guides/rel_notes/release_2_3.rst b/doc/guides/rel_notes/release_2_3.rst index 99de186..c390d97 100644 --- a/doc/guides/rel_notes/release_2_3.rst +++ b/doc/guides/rel_notes/release_2_3.rst @@ -4,6 +4,9 @@ DPDK Release 2.3 New Features ------------ +* **Virtio 1.0 support.** + + Enabled virtio 1.0 support for virtio pmd driver. Resolved Issues --------------- diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 94e0c4a..1afaba4 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) return virtio_send_command(hw->cvq, &ctrl, &len, 1); } -static void +static int virtio_negotiate_features(struct virtio_hw *hw) { uint64_t host_features; @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw) hw->guest_features = vtpci_negotiate_features(hw, host_features); PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, hw->guest_features); + + if (hw->modern) { + if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) { + PMD_INIT_LOG(ERR, + "VIRTIO_F_VERSION_1 features is not enabled."); + return -1; + } + vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK); + if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) { + PMD_INIT_LOG(ERR, + "failed to set FEATURES_OK status!"); + return -1; + } + } + + return 0; } /* @@ -1032,7 +1048,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev) /* Tell the host we've known how to drive the device. */ vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER); - virtio_negotiate_features(hw); + if (virtio_negotiate_features(hw) < 0) + return -1; /* If host does not support status then disable LSC */ if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) @@ -1043,7 +1060,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev) rx_func_get(eth_dev); /* Setting up rx_header size for the device */ - if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) + if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) || + vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); else hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr); diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h index ae2d47d..fed9571 100644 --- a/drivers/net/virtio/virtio_ethdev.h +++ b/drivers/net/virtio/virtio_ethdev.h @@ -64,7 +64,8 @@ 1u << VIRTIO_NET_F_CTRL_VQ | \ 1u << VIRTIO_NET_F_CTRL_RX | \ 1u << VIRTIO_NET_F_CTRL_VLAN | \ - 1u << VIRTIO_NET_F_MRG_RXBUF) + 1u << VIRTIO_NET_F_MRG_RXBUF | \ + 1ULL << VIRTIO_F_VERSION_1) /* * CQ function prototype diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 5eed57e..9b62013 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -41,6 +41,14 @@ #include "virtio_logs.h" #include "virtqueue.h" +/* + * Following macros are derieved from linux/pci_regs.h, however, + * we can't simply include that header here, as there is no such + * file for non-Linux platform. + */ +#define PCI_CAPABILITY_LIST 0x34 +#define PCI_CAP_ID_VNDR 0x09 + static void legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset, void *dst, int length) @@ -442,6 +450,204 @@ static const struct virtio_pci_ops legacy_ops = { }; +#define MODERN_READ_DEF(nr_bits, type) \ +static inline type \ +modern_read##nr_bits(type *addr) \ +{ \ + return *(volatile type *)addr; \ +} + +#define MODERN_WRITE_DEF(nr_bits, type) \ +static inline void \ +modern_write##nr_bits(type val, type *addr) \ +{ \ + *(volatile type *)addr = val; \ +} + +MODERN_READ_DEF (8, uint8_t) +MODERN_WRITE_DEF(8, uint8_t) + +MODERN_READ_DEF (16, uint16_t) +MODERN_WRITE_DEF(16, uint16_t) + +MODERN_READ_DEF (32, uint32_t) +MODERN_WRITE_DEF(32, uint32_t) + +static inline void +modern_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) +{ + modern_write32((uint32_t)val, lo); + modern_write32(val >> 32, hi); +} + +static void +modern_read_dev_config(struct virtio_hw *hw, uint64_t offset, + void *dst, int length) +{ + int i; + uint8_t *p; + uint8_t old_gen, new_gen; + + do { + old_gen = modern_read8(&hw->common_cfg->config_generation); + + p = dst; + for (i = 0; i < length; i++) + *p++ = modern_read8((uint8_t *)hw->dev_cfg + offset + i); + + new_gen = modern_read8(&hw->common_cfg->config_generation); + } while (old_gen != new_gen); +} + +static void +modern_write_dev_config(struct virtio_hw *hw, uint64_t offset, + void *src, int length) +{ + int i; + uint8_t *p = src; + + for (i = 0; i < length; i++) + modern_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i); +} + +static uint64_t +modern_get_features(struct virtio_hw *hw) +{ + uint32_t features_lo, features_hi; + + modern_write32(0, &hw->common_cfg->device_feature_select); + features_lo = modern_read32(&hw->common_cfg->device_feature); + + modern_write32(1, &hw->common_cfg->device_feature_select); + features_hi = modern_read32(&hw->common_cfg->device_feature); + + return ((uint64_t)(features_hi) << 32) | features_lo; +} + +static void +modern_set_features(struct virtio_hw *hw, uint64_t features) +{ + modern_write32(0, &hw->common_cfg->guest_feature_select); + modern_write32(features & ((1ULL << 32) - 1), + &hw->common_cfg->guest_feature); + + modern_write32(1, &hw->common_cfg->guest_feature_select); + modern_write32(features >> 32, + &hw->common_cfg->guest_feature); +} + +static uint8_t +modern_get_status(struct virtio_hw *hw) +{ + return modern_read8(&hw->common_cfg->device_status); +} + +static void +modern_set_status(struct virtio_hw *hw, uint8_t status) +{ + modern_write8(status, &hw->common_cfg->device_status); +} + +static void +modern_reset(struct virtio_hw *hw) +{ + modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); + modern_get_status(hw); +} + +static uint8_t +modern_get_isr(struct virtio_hw *hw) +{ + return modern_read8(hw->isr); +} + +static uint16_t +modern_set_config_irq(struct virtio_hw *hw, uint16_t vec) +{ + modern_write16(vec, &hw->common_cfg->msix_config); + return modern_read16(&hw->common_cfg->msix_config); +} + +static uint16_t +modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) +{ + modern_write16(queue_id, &hw->common_cfg->queue_select); + return modern_read16(&hw->common_cfg->queue_size); +} + +static void +modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + uint64_t desc_addr, avail_addr, used_addr; + uint16_t notify_off; + + desc_addr = vq->mz->phys_addr; + avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc); + used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail, + ring[vq->vq_nentries]), + VIRTIO_PCI_VRING_ALIGN); + + modern_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); + + modern_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + modern_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + modern_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + notify_off = modern_read16(&hw->common_cfg->queue_notify_off); + vq->notify_addr = (void *)((uint8_t *)hw->notify_base + + notify_off * hw->notify_off_multiplier); + + modern_write16(1, &hw->common_cfg->queue_enable); + + PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index); + PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr); + PMD_INIT_LOG(DEBUG, "\t aval_addr: %"PRIx64, avail_addr); + PMD_INIT_LOG(DEBUG, "\t used_addr: %"PRIx64, used_addr); + PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)", + vq->notify_addr, notify_off); +} + +static void +modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + modern_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); + + modern_write64_twopart(0, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + modern_write64_twopart(0, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + modern_write64_twopart(0, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + modern_write16(0, &hw->common_cfg->queue_enable); +} + +static void +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) +{ + modern_write16(1, vq->notify_addr); +} + +static const struct virtio_pci_ops modern_ops = { + .read_dev_cfg = modern_read_dev_config, + .write_dev_cfg = modern_write_dev_config, + .reset = modern_reset, + .get_status = modern_get_status, + .set_status = modern_set_status, + .get_features = modern_get_features, + .set_features = modern_set_features, + .get_isr = modern_get_isr, + .set_config_irq = modern_set_config_irq, + .get_queue_num = modern_get_queue_num, + .setup_queue = modern_setup_queue, + .del_queue = modern_del_queue, + .notify_queue = modern_notify_queue, +}; + + void vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset, void *dst, int length) @@ -495,6 +701,12 @@ vtpci_set_status(struct virtio_hw *hw, uint8_t status) } uint8_t +vtpci_get_status(struct virtio_hw *hw) +{ + return hw->vtpci_ops->get_status(hw); +} + +uint8_t vtpci_isr(struct virtio_hw *hw) { return hw->vtpci_ops->get_isr(hw); @@ -508,15 +720,136 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) return hw->vtpci_ops->set_config_irq(hw, vec); } +static inline void * +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) +{ + uint8_t bar = cap->bar; + uint32_t length = cap->length; + uint32_t offset = cap->offset; + uint8_t *base; + + if (unlikely(bar > 5)) { + PMD_INIT_LOG(ERR, "invalid bar: %u", bar); + return NULL; + } + + if (unlikely(offset + length > dev->mem_resource[bar].len)) { + PMD_INIT_LOG(ERR, + "invalid cap: overflows bar space: %u > %"PRIu64, + offset + length, dev->mem_resource[bar].len); + return NULL; + } + + base = dev->mem_resource[bar].addr; + if (unlikely(base == NULL)) { + PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar); + return NULL; + } + + return base + offset; +} + +static int +virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw) +{ + uint8_t pos; + struct virtio_pci_cap cap; + int ret; + + if (rte_eal_pci_map_device(dev) < 0) { + PMD_INIT_LOG(DEBUG, "failed to map pci device!"); + return -1; + } + + ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST); + if (ret < 0) { + PMD_INIT_LOG(DEBUG, "failed to read pci capability list"); + return -1; + } + + while (pos) { + ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos); + if (ret < 0) { + PMD_INIT_LOG(ERR, + "failed to read pci cap at pos: %x", pos); + break; + } + + if (cap.cap_vndr != PCI_CAP_ID_VNDR) { + PMD_INIT_LOG(DEBUG, + "[%2x] skipping non VNDR cap id: %02x", + pos, cap.cap_vndr); + goto next; + } + + PMD_INIT_LOG(DEBUG, + "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u", + pos, cap.cfg_type, cap.bar, cap.offset, cap.length); + + switch (cap.cfg_type) { + case VIRTIO_PCI_CAP_COMMON_CFG: + hw->common_cfg = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_NOTIFY_CFG: + rte_eal_pci_read_config(dev, &hw->notify_off_multiplier, + 4, pos + sizeof(cap)); + hw->notify_base = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_DEVICE_CFG: + hw->dev_cfg = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_ISR_CFG: + hw->isr = get_cfg_addr(dev, &cap); + break; + } + + next: + pos = cap.cap_next; + } + + if (hw->common_cfg == NULL || hw->notify_base == NULL || + hw->dev_cfg == NULL || hw->isr == NULL) { + PMD_INIT_LOG(INFO, "no modern virtio pci device found."); + return -1; + } + + PMD_INIT_LOG(INFO, "found modern virtio pci device."); + + PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg); + PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg); + PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr); + PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u", + hw->notify_base, hw->notify_off_multiplier); + + return 0; +} + int vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) { - hw->vtpci_ops = &legacy_ops; + hw->dev = dev; + + /* + * Try if we can succeed reading virtio pci caps, which exists + * only on modern pci device. If failed, we fallback to legacy + * virtio handling. + */ + if (virtio_read_caps(dev, hw) == 0) { + PMD_INIT_LOG(INFO, "modern virtio pci detected."); + hw->vtpci_ops = &modern_ops; + hw->modern = 1; + dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; + return 0; + } + PMD_INIT_LOG(INFO, "trying with legacy virtio pci."); if (legacy_virtio_resource_init(dev) < 0) return -1; + + hw->vtpci_ops = &legacy_ops; hw->use_msix = legacy_virtio_has_msix(&dev->addr); hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr; + hw->modern = 0; return 0; } diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index 3fd86f6..6ade642 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -93,6 +93,7 @@ struct virtqueue; #define VIRTIO_CONFIG_STATUS_ACK 0x01 #define VIRTIO_CONFIG_STATUS_DRIVER 0x02 #define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04 +#define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08 #define VIRTIO_CONFIG_STATUS_FAILED 0x80 /* @@ -141,6 +142,8 @@ struct virtqueue; /* We support indirect buffer descriptors */ #define VIRTIO_RING_F_INDIRECT_DESC 28 +#define VIRTIO_F_VERSION_1 32 + /* * Some VirtIO feature bits (currently bits 28 through 31) are * reserved for the transport being used (eg. virtio_ring), the @@ -163,6 +166,60 @@ struct virtqueue; */ #define VIRTIO_MAX_VIRTQUEUES 8 +/* Common configuration */ +#define VIRTIO_PCI_CAP_COMMON_CFG 1 +/* Notifications */ +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 +/* ISR Status */ +#define VIRTIO_PCI_CAP_ISR_CFG 3 +/* Device specific configuration */ +#define VIRTIO_PCI_CAP_DEVICE_CFG 4 +/* PCI configuration access */ +#define VIRTIO_PCI_CAP_PCI_CFG 5 + +/* This is the PCI capability header: */ +struct virtio_pci_cap { + uint8_t cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */ + uint8_t cap_next; /* Generic PCI field: next ptr. */ + uint8_t cap_len; /* Generic PCI field: capability length */ + uint8_t cfg_type; /* Identifies the structure. */ + uint8_t bar; /* Where to find it. */ + uint8_t padding[3]; /* Pad to full dword. */ + uint32_t offset; /* Offset within bar. */ + uint32_t length; /* Length of the structure, in bytes. */ +}; + +struct virtio_pci_notify_cap { + struct virtio_pci_cap cap; + uint32_t notify_off_multiplier; /* Multiplier for queue_notify_off. */ +}; + +/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */ +struct virtio_pci_common_cfg { + /* About the whole device. */ + uint32_t device_feature_select; /* read-write */ + uint32_t device_feature; /* read-only */ + uint32_t guest_feature_select; /* read-write */ + uint32_t guest_feature; /* read-write */ + uint16_t msix_config; /* read-write */ + uint16_t num_queues; /* read-only */ + uint8_t device_status; /* read-write */ + uint8_t config_generation; /* read-only */ + + /* About a specific virtqueue. */ + uint16_t queue_select; /* read-write */ + uint16_t queue_size; /* read-write, power of 2. */ + uint16_t queue_msix_vector; /* read-write */ + uint16_t queue_enable; /* read-write */ + uint16_t queue_notify_off; /* read-only */ + uint32_t queue_desc_lo; /* read-write */ + uint32_t queue_desc_hi; /* read-write */ + uint32_t queue_avail_lo; /* read-write */ + uint32_t queue_avail_hi; /* read-write */ + uint32_t queue_used_lo; /* read-write */ + uint32_t queue_used_hi; /* read-write */ +}; + struct virtio_hw; struct virtio_pci_ops { @@ -188,6 +245,8 @@ struct virtio_pci_ops { void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq); }; +struct virtio_net_config; + struct virtio_hw { struct virtqueue *cvq; uint32_t io_base; @@ -198,7 +257,14 @@ struct virtio_hw { uint8_t vlan_strip; uint8_t use_msix; uint8_t started; + uint8_t modern; uint8_t mac_addr[ETHER_ADDR_LEN]; + uint32_t notify_off_multiplier; + uint8_t *isr; + uint16_t *notify_base; + struct rte_pci_device *dev; + struct virtio_pci_common_cfg *common_cfg; + struct virtio_net_config *dev_cfg; const struct virtio_pci_ops *vtpci_ops; }; @@ -284,6 +350,7 @@ void vtpci_reset(struct virtio_hw *); void vtpci_reinit_complete(struct virtio_hw *); +uint8_t vtpci_get_status(struct virtio_hw *); void vtpci_set_status(struct virtio_hw *, uint8_t); uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t); diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h index d7fb450..99d4fa9 100644 --- a/drivers/net/virtio/virtqueue.h +++ b/drivers/net/virtio/virtqueue.h @@ -202,6 +202,8 @@ struct virtqueue { /* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */ uint64_t size_bins[8]; + uint16_t *notify_addr; + struct vq_desc_extra { void *cookie; uint16_t ndescs; -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support Yuanhan Liu @ 2016-01-13 3:31 ` Tetsuya Mukawa 2016-01-13 9:38 ` Yuanhan Liu 2016-01-14 7:47 ` Xie, Huawei 2016-01-14 7:50 ` Xie, Huawei 2 siblings, 1 reply; 122+ messages in thread From: Tetsuya Mukawa @ 2016-01-13 3:31 UTC (permalink / raw) To: Yuanhan Liu, dev; +Cc: Michael S. Tsirkin On 2016/01/12 15:59, Yuanhan Liu wrote: > +static int > +virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw) > +{ > + uint8_t pos; > + struct virtio_pci_cap cap; > + int ret; > + > + if (rte_eal_pci_map_device(dev) < 0) { > + PMD_INIT_LOG(DEBUG, "failed to map pci device!"); > + return -1; > + } > + Do you need to call rte_eal_pci_unmap_device() in somewhere in this file? Anyway, I've reviewed and tested your all patches. And it seems except for it, I guess your patches are good. Thanks, Tetsuya ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support 2016-01-13 3:31 ` Tetsuya Mukawa @ 2016-01-13 9:38 ` Yuanhan Liu 0 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-13 9:38 UTC (permalink / raw) To: Tetsuya Mukawa; +Cc: dev, Michael S. Tsirkin On Wed, Jan 13, 2016 at 12:31:43PM +0900, Tetsuya Mukawa wrote: > On 2016/01/12 15:59, Yuanhan Liu wrote: > > +static int > > +virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw) > > +{ > > + uint8_t pos; > > + struct virtio_pci_cap cap; > > + int ret; > > + > > + if (rte_eal_pci_map_device(dev) < 0) { > > + PMD_INIT_LOG(DEBUG, "failed to map pci device!"); > > + return -1; > > + } > > + > > Do you need to call rte_eal_pci_unmap_device() in somewhere in this file? Yes, we should. I will see where I can find a proper place for it in next version; eth_virtio_dev_uninit sounds like a good option. > Anyway, I've reviewed and tested your all patches. > And it seems except for it, I guess your patches are good. Thank you for reviewing and testing it! --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support Yuanhan Liu 2016-01-13 3:31 ` Tetsuya Mukawa @ 2016-01-14 7:47 ` Xie, Huawei 2016-01-14 7:50 ` Yuanhan Liu 2016-01-14 7:50 ` Xie, Huawei 2 siblings, 1 reply; 122+ messages in thread From: Xie, Huawei @ 2016-01-14 7:47 UTC (permalink / raw) To: Yuanhan Liu, dev; +Cc: Michael S. Tsirkin On 1/12/2016 2:58 PM, Yuanhan Liu wrote: > Modern (v1.0) virtio pci device defines several pci capabilities. [snip] > +static void > +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) > +{ > + modern_write16(1, vq->notify_addr); > +} Does virtio 1.0 only supports MMIO? MMIO has long VMEXIT latency than PORT IO. [snip] ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support 2016-01-14 7:47 ` Xie, Huawei @ 2016-01-14 7:50 ` Yuanhan Liu 2016-01-14 7:51 ` Xie, Huawei 0 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 7:50 UTC (permalink / raw) To: Xie, Huawei; +Cc: dev, Michael S. Tsirkin On Thu, Jan 14, 2016 at 07:47:17AM +0000, Xie, Huawei wrote: > On 1/12/2016 2:58 PM, Yuanhan Liu wrote: > > Modern (v1.0) virtio pci device defines several pci capabilities. > [snip] > > +static void > > +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) > > +{ > > + modern_write16(1, vq->notify_addr); > > +} > > Does virtio 1.0 only supports MMIO? MMIO has long VMEXIT latency than > PORT IO. Virtio 1.0 supports three transport layer, including MMIO and PCI. And we use PCI only in our pmd driver. --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support 2016-01-14 7:50 ` Yuanhan Liu @ 2016-01-14 7:51 ` Xie, Huawei 2016-01-14 7:58 ` Yuanhan Liu 0 siblings, 1 reply; 122+ messages in thread From: Xie, Huawei @ 2016-01-14 7:51 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev, Michael S. Tsirkin On 1/14/2016 3:49 PM, Yuanhan Liu wrote: > On Thu, Jan 14, 2016 at 07:47:17AM +0000, Xie, Huawei wrote: >> On 1/12/2016 2:58 PM, Yuanhan Liu wrote: >>> Modern (v1.0) virtio pci device defines several pci capabilities. >> [snip] >>> +static void >>> +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) >>> +{ >>> + modern_write16(1, vq->notify_addr); >>> +} >> Does virtio 1.0 only supports MMIO? MMIO has long VMEXIT latency than >> PORT IO. > Virtio 1.0 supports three transport layer, including MMIO and PCI. And > we use PCI only in our pmd driver. I don't mean that MMIO but use memory mapped IO for configuration. > > --yliu > ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support 2016-01-14 7:51 ` Xie, Huawei @ 2016-01-14 7:58 ` Yuanhan Liu 2016-01-14 8:08 ` Xie, Huawei 0 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 7:58 UTC (permalink / raw) To: Xie, Huawei; +Cc: dev, Michael S. Tsirkin On Thu, Jan 14, 2016 at 07:51:08AM +0000, Xie, Huawei wrote: > On 1/14/2016 3:49 PM, Yuanhan Liu wrote: > > On Thu, Jan 14, 2016 at 07:47:17AM +0000, Xie, Huawei wrote: > >> On 1/12/2016 2:58 PM, Yuanhan Liu wrote: > >>> Modern (v1.0) virtio pci device defines several pci capabilities. > >> [snip] > >>> +static void > >>> +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) > >>> +{ > >>> + modern_write16(1, vq->notify_addr); > >>> +} > >> Does virtio 1.0 only supports MMIO? MMIO has long VMEXIT latency than > >> PORT IO. > > Virtio 1.0 supports three transport layer, including MMIO and PCI. And > > we use PCI only in our pmd driver. > > I don't mean that MMIO but use memory mapped IO for configuration. Then, yes. --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support 2016-01-14 7:58 ` Yuanhan Liu @ 2016-01-14 8:08 ` Xie, Huawei 2016-01-14 8:22 ` Yuanhan Liu 0 siblings, 1 reply; 122+ messages in thread From: Xie, Huawei @ 2016-01-14 8:08 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev, Michael S. Tsirkin On 1/14/2016 3:58 PM, Yuanhan Liu wrote: > On Thu, Jan 14, 2016 at 07:51:08AM +0000, Xie, Huawei wrote: >> On 1/14/2016 3:49 PM, Yuanhan Liu wrote: >>> On Thu, Jan 14, 2016 at 07:47:17AM +0000, Xie, Huawei wrote: >>>> On 1/12/2016 2:58 PM, Yuanhan Liu wrote: >>>>> Modern (v1.0) virtio pci device defines several pci capabilities. >>>> [snip] >>>>> +static void >>>>> +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) >>>>> +{ >>>>> + modern_write16(1, vq->notify_addr); >>>>> +} >>>> Does virtio 1.0 only supports MMIO? MMIO has long VMEXIT latency than >>>> PORT IO. >>> Virtio 1.0 supports three transport layer, including MMIO and PCI. And >>> we use PCI only in our pmd driver. >> I don't mean that MMIO but use memory mapped IO for configuration. > Then, yes. 00:03.0 Ethernet controller: Red Hat, Inc Virtio network device Subsystem: Red Hat, Inc Device 0001 Physical Slot: 3 Flags: bus master, fast devsel, latency 0, IRQ 10 I/O ports at c100 [size=32] Memory at febd1000 (32-bit, non-prefetchable) [size=4K] Memory at fe000000 (64-bit, prefetchable) [size=8M] Expansion ROM at feb40000 [disabled] [size=256K] Capabilities: [98] MSI-X: Enable+ Count=3 Masked- Capabilities: [84] Vendor Specific Information: Len=14 <?> Capabilities: [70] Vendor Specific Information: Len=14 <?> Capabilities: [60] Vendor Specific Information: Len=10 <?> Capabilities: [50] Vendor Specific Information: Len=10 <?> Capabilities: [40] Vendor Specific Information: Len=10 <?> Kernel driver in use: igb_uio Kernel modules: virtio_pci c100 is still there. For the notification, try PORT IO if possible. > > --yliu > ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support 2016-01-14 8:08 ` Xie, Huawei @ 2016-01-14 8:22 ` Yuanhan Liu 2016-01-14 8:28 ` Xie, Huawei 0 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 8:22 UTC (permalink / raw) To: Xie, Huawei; +Cc: dev, Michael S. Tsirkin On Thu, Jan 14, 2016 at 08:08:28AM +0000, Xie, Huawei wrote: > On 1/14/2016 3:58 PM, Yuanhan Liu wrote: > > On Thu, Jan 14, 2016 at 07:51:08AM +0000, Xie, Huawei wrote: > >> On 1/14/2016 3:49 PM, Yuanhan Liu wrote: > >>> On Thu, Jan 14, 2016 at 07:47:17AM +0000, Xie, Huawei wrote: > >>>> On 1/12/2016 2:58 PM, Yuanhan Liu wrote: > >>>>> Modern (v1.0) virtio pci device defines several pci capabilities. > >>>> [snip] > >>>>> +static void > >>>>> +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) > >>>>> +{ > >>>>> + modern_write16(1, vq->notify_addr); > >>>>> +} > >>>> Does virtio 1.0 only supports MMIO? MMIO has long VMEXIT latency than > >>>> PORT IO. > >>> Virtio 1.0 supports three transport layer, including MMIO and PCI. And > >>> we use PCI only in our pmd driver. > >> I don't mean that MMIO but use memory mapped IO for configuration. > > Then, yes. > > 00:03.0 Ethernet controller: Red Hat, Inc Virtio network device > Subsystem: Red Hat, Inc Device 0001 > Physical Slot: 3 > Flags: bus master, fast devsel, latency 0, IRQ 10 > I/O ports at c100 [size=32] > Memory at febd1000 (32-bit, non-prefetchable) [size=4K] > Memory at fe000000 (64-bit, prefetchable) [size=8M] > Expansion ROM at feb40000 [disabled] [size=256K] > Capabilities: [98] MSI-X: Enable+ Count=3 Masked- > Capabilities: [84] Vendor Specific Information: Len=14 <?> > Capabilities: [70] Vendor Specific Information: Len=14 <?> > Capabilities: [60] Vendor Specific Information: Len=10 <?> > Capabilities: [50] Vendor Specific Information: Len=10 <?> > Capabilities: [40] Vendor Specific Information: Len=10 <?> > Kernel driver in use: igb_uio > Kernel modules: virtio_pci > > c100 is still there. Yes, > For the notification, try PORT IO if possible. But it doesn't seem right to me to mix legacy registers in modern pci device. --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support 2016-01-14 8:22 ` Yuanhan Liu @ 2016-01-14 8:28 ` Xie, Huawei 0 siblings, 0 replies; 122+ messages in thread From: Xie, Huawei @ 2016-01-14 8:28 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev, Michael S. Tsirkin On 1/14/2016 4:21 PM, Yuanhan Liu wrote: > On Thu, Jan 14, 2016 at 08:08:28AM +0000, Xie, Huawei wrote: >> On 1/14/2016 3:58 PM, Yuanhan Liu wrote: >>> On Thu, Jan 14, 2016 at 07:51:08AM +0000, Xie, Huawei wrote: >>>> On 1/14/2016 3:49 PM, Yuanhan Liu wrote: >>>>> On Thu, Jan 14, 2016 at 07:47:17AM +0000, Xie, Huawei wrote: >>>>>> On 1/12/2016 2:58 PM, Yuanhan Liu wrote: >>>>>>> Modern (v1.0) virtio pci device defines several pci capabilities. >>>>>> [snip] >>>>>>> +static void >>>>>>> +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) >>>>>>> +{ >>>>>>> + modern_write16(1, vq->notify_addr); >>>>>>> +} >>>>>> Does virtio 1.0 only supports MMIO? MMIO has long VMEXIT latency than >>>>>> PORT IO. >>>>> Virtio 1.0 supports three transport layer, including MMIO and PCI. And >>>>> we use PCI only in our pmd driver. >>>> I don't mean that MMIO but use memory mapped IO for configuration. >>> Then, yes. >> 00:03.0 Ethernet controller: Red Hat, Inc Virtio network device >> Subsystem: Red Hat, Inc Device 0001 >> Physical Slot: 3 >> Flags: bus master, fast devsel, latency 0, IRQ 10 >> I/O ports at c100 [size=32] >> Memory at febd1000 (32-bit, non-prefetchable) [size=4K] >> Memory at fe000000 (64-bit, prefetchable) [size=8M] >> Expansion ROM at feb40000 [disabled] [size=256K] >> Capabilities: [98] MSI-X: Enable+ Count=3 Masked- >> Capabilities: [84] Vendor Specific Information: Len=14 <?> >> Capabilities: [70] Vendor Specific Information: Len=14 <?> >> Capabilities: [60] Vendor Specific Information: Len=10 <?> >> Capabilities: [50] Vendor Specific Information: Len=10 <?> >> Capabilities: [40] Vendor Specific Information: Len=10 <?> >> Kernel driver in use: igb_uio >> Kernel modules: virtio_pci >> >> c100 is still there. > Yes, > >> For the notification, try PORT IO if possible. > But it doesn't seem right to me to mix legacy registers in modern pci device. On TLB and cache miss, this could cause plenty of cycles. Considering that our current focus is dpdkvhost which doesn't need notification, let us revisit this later. > > --yliu > ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support Yuanhan Liu 2016-01-13 3:31 ` Tetsuya Mukawa 2016-01-14 7:47 ` Xie, Huawei @ 2016-01-14 7:50 ` Xie, Huawei 2016-01-14 8:38 ` Yuanhan Liu 2 siblings, 1 reply; 122+ messages in thread From: Xie, Huawei @ 2016-01-14 7:50 UTC (permalink / raw) To: Yuanhan Liu, dev; +Cc: Michael S. Tsirkin On 1/12/2016 2:58 PM, Yuanhan Liu wrote: > Modern (v1.0) virtio pci device defines several pci capabilities. > Each cap has a configure structure corresponding to it, and the > cap.bar and cap.offset fields tell us where to find it. > > Firstly, we map the pci resources by rte_eal_pci_map_device(). > We then could easily locate to a cfg structure by: s/Locate/Locate to/ > > cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset; > > Therefore, the entrance of enabling modern (v1.0) pci device support > is to iterate the pci capability lists, and to locate some configs > we care; and they are: > > - common cfg > > For generic virtio and virtuqueu configuration, such as setting/getting typo for virtqueue > features, enabling a specific queue, and so on. > > - nofity cfg > > Combining with `queue_notify_off' from common cfg, we could use it to > notify a specific virt queue. > > - device cfg > > Where virtio_net_config structure locates. is located > If any of above cap is not found, we fallback to the legacy virtio > [SNIP] > > > > +#define MODERN_READ_DEF(nr_bits, type) \ > +static inline type \ > +modern_read##nr_bits(type *addr) \ > +{ \ > + return *(volatile type *)addr; \ > +} > + > +#define MODERN_WRITE_DEF(nr_bits, type) \ > +static inline void \ > +modern_write##nr_bits(type val, type *addr) \ > +{ \ > + *(volatile type *)addr = val; \ > +} > + > +MODERN_READ_DEF (8, uint8_t) > +MODERN_WRITE_DEF(8, uint8_t) > + > +MODERN_READ_DEF (16, uint16_t) > +MODERN_WRITE_DEF(16, uint16_t) > + > +MODERN_READ_DEF (32, uint32_t) > +MODERN_WRITE_DEF(32, uint32_t) > + > +static inline void > +modern_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) > +{ > + modern_write32((uint32_t)val, lo); > + modern_write32(val >> 32, hi); > +} > + This is normal mmio read/write operation. ioread8/16/32/64 or just readxx is more meaningful name here. > +static void [SNIP] > + > +static void > +modern_write_dev_config(struct virtio_hw *hw, uint64_t offset, > + void *src, int length) define src as const [snip] > > +static inline void * > +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) No explicit inline for non performance critical functions. > +{ > + uint8_t bar = cap->bar; > + uint32_t length = cap->length; > + uint32_t offset = cap->offset; > + uint8_t *base; > + > + if (unlikely(bar > 5)) { Don't use constant value number whenever possible No likely/unlikely for non performance critical functions > + PMD_INIT_LOG(ERR, "invalid bar: %u", bar); > + return NULL; > + } > + > + if (unlikely(offset + length > dev->mem_resource[bar].len)) { > + PMD_INIT_LOG(ERR, > + "invalid cap: overflows bar space: %u > %"PRIu64, > + offset + length, dev->mem_resource[bar].len); > + return NULL; > + } > + > + base = dev->mem_resource[bar].addr; > + if (unlikely(base == NULL)) { > + PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar); > + return NULL; > + } > + > + return base + offset; > +} > + > +static int > +virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw) > +{ > + uint8_t pos; > + struct virtio_pci_cap cap; > + int ret; > + > + if (rte_eal_pci_map_device(dev) < 0) { > + PMD_INIT_LOG(DEBUG, "failed to map pci device!"); s /DEBUG/ERR/ > + return -1; > + } > + > + ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST); > + [snip] ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support 2016-01-14 7:50 ` Xie, Huawei @ 2016-01-14 8:38 ` Yuanhan Liu 0 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 8:38 UTC (permalink / raw) To: Xie, Huawei; +Cc: dev, Michael S. Tsirkin Sigh... I have just send out v3 ... On Thu, Jan 14, 2016 at 07:50:00AM +0000, Xie, Huawei wrote: > On 1/12/2016 2:58 PM, Yuanhan Liu wrote: > > +static inline void > > +modern_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) > > +{ > > + modern_write32((uint32_t)val, lo); > > + modern_write32(val >> 32, hi); > > +} > > + > > This is normal mmio read/write operation. ioread8/16/32/64 or just > readxx is more meaningful name here. I just want to make them looks like modern device related, which they are. > > +static void > [SNIP] > > + > > +static void > > +modern_write_dev_config(struct virtio_hw *hw, uint64_t offset, > > + void *src, int length) > > define src as const okay. > > [snip] > > > > +static inline void * > > +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) > > No explicit inline for non performance critical functions. okay. > > > +{ > > + uint8_t bar = cap->bar; > > + uint32_t length = cap->length; > > + uint32_t offset = cap->offset; > > + uint8_t *base; > > + > > + if (unlikely(bar > 5)) { > Don't use constant value number whenever possible I normally will not bother to define a macro for used once number, espeically for some well known ones. Say, I won't define #define UINT8_MAX_VALUE 0xff > > No likely/unlikely for non performance critical functions makes sense. > > + if (rte_eal_pci_map_device(dev) < 0) { > > + PMD_INIT_LOG(DEBUG, "failed to map pci device!"); > > s /DEBUG/ERR/ It's not an error; it's expected, say, when no UIO is bond. --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (6 preceding siblings ...) 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support Yuanhan Liu @ 2016-01-12 7:07 ` Yuanhan Liu 2016-01-14 4:27 ` Tetsuya Mukawa ` (2 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-12 7:07 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin On Tue, Jan 12, 2016 at 02:58:57PM +0800, Yuanhan Liu wrote: > v2: - fix a data corruption reported by Qian, due to hdr size mismatch. > check detailes at ptach 5. > > - Add missing config_irq and isr reading support from v1. > > - fix comments from v1. > > Almost all difference comes from virtio 1.0 are the PCI layout change: > the major configuration structures are stored at bar space, and their > location is stored at corresponding pci cap structure. Reading/parsing > them is one of the major work of patch 7. > > To make handling virtio v1.0 and v0.95 co-exist well, this patch set > introduces a virtio_pci_ops structure, to add another layer so that > we could keep those vtpci_foo_bar "APIs". With that, we could do the > minimum change to add virtio 1.0 support. Oops, I just found that I missed a simple test guide here, as promised before. And here it is: Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add option "disable-modern=false" to qemu virtio-net-pci device to enable virtio 1.0 (which is disabled by default). And if you see something like following from 'lspci -v', it means virtio 1.0 is indeed enabled: 00:04.0 Ethernet controller: Red Hat, Inc Virtio network device Subsystem: Red Hat, Inc Device 0001 Physical Slot: 4 Flags: bus master, fast devsel, latency 0, IRQ 11 I/O ports at c040 [size=64] Memory at febf1000 (32-bit, non-prefetchable) [size=4K] Memory at fe000000 (64-bit, prefetchable) [size=8M] Expansion ROM at feb80000 [disabled] [size=256K] Capabilities: [98] MSI-X: Enable+ Count=6 Masked- ==> Capabilities: [84] Vendor Specific Information: Len=14 <?> ==> Capabilities: [70] Vendor Specific Information: Len=14 <?> ==> Capabilities: [60] Vendor Specific Information: Len=10 <?> ==> Capabilities: [50] Vendor Specific Information: Len=10 <?> ==> Capabilities: [40] Vendor Specific Information: Len=10 <?> Kernel driver in use: virtio-pci Kernel modules: virtio_pci After that, there wasn't anything speical comparing to the old virtio 0.95 pmd driver. --yliu > > --- > Yuanhan Liu (7): > virtio: don't set vring address again at queue startup > virtio: introduce struct virtio_pci_ops > virtio: move left pci stuff to virtio_pci.c > viritio: switch to 64 bit features > virtio: retrieve hdr_size from hw->vtnet_hdr_size > eal: pci: export pci_map_device > virtio: add 1.0 support > > doc/guides/rel_notes/release_2_3.rst | 3 + > drivers/net/virtio/virtio_ethdev.c | 301 +--------- > drivers/net/virtio/virtio_ethdev.h | 3 +- > drivers/net/virtio/virtio_pci.c | 768 +++++++++++++++++++++++- > drivers/net/virtio/virtio_pci.h | 102 +++- > drivers/net/virtio/virtio_rxtx.c | 21 +- > drivers/net/virtio/virtqueue.h | 4 +- > lib/librte_eal/bsdapp/eal/eal_pci.c | 2 +- > lib/librte_eal/bsdapp/eal/rte_eal_version.map | 6 + > lib/librte_eal/common/eal_common_pci.c | 2 +- > lib/librte_eal/common/eal_private.h | 11 - > lib/librte_eal/common/include/rte_pci.h | 11 + > lib/librte_eal/linuxapp/eal/eal_pci.c | 2 +- > lib/librte_eal/linuxapp/eal/rte_eal_version.map | 6 + > 14 files changed, 899 insertions(+), 343 deletions(-) > > -- > 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (7 preceding siblings ...) 2016-01-12 7:07 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu @ 2016-01-14 4:27 ` Tetsuya Mukawa 2016-01-14 5:59 ` Yuanhan Liu 2016-01-14 6:09 ` Tan, Jianfeng 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu 10 siblings, 2 replies; 122+ messages in thread From: Tetsuya Mukawa @ 2016-01-14 4:27 UTC (permalink / raw) To: Yuanhan Liu, dev, Tan Jianfeng; +Cc: Michael S. Tsirkin On 2016/01/12 15:58, Yuanhan Liu wrote: > v2: - fix a data corruption reported by Qian, due to hdr size mismatch. > check detailes at ptach 5. > > - Add missing config_irq and isr reading support from v1. > > - fix comments from v1. > > Almost all difference comes from virtio 1.0 are the PCI layout change: > the major configuration structures are stored at bar space, and their > location is stored at corresponding pci cap structure. Reading/parsing > them is one of the major work of patch 7. > > To make handling virtio v1.0 and v0.95 co-exist well, this patch set > introduces a virtio_pci_ops structure, to add another layer so that > we could keep those vtpci_foo_bar "APIs". With that, we could do the > minimum change to add virtio 1.0 support. > > > --- > Yuanhan Liu (7): > virtio: don't set vring address again at queue startup > virtio: introduce struct virtio_pci_ops > virtio: move left pci stuff to virtio_pci.c > viritio: switch to 64 bit features > virtio: retrieve hdr_size from hw->vtnet_hdr_size > eal: pci: export pci_map_device > virtio: add 1.0 support > > doc/guides/rel_notes/release_2_3.rst | 3 + > drivers/net/virtio/virtio_ethdev.c | 301 +--------- > drivers/net/virtio/virtio_ethdev.h | 3 +- > drivers/net/virtio/virtio_pci.c | 768 +++++++++++++++++++++++- > drivers/net/virtio/virtio_pci.h | 102 +++- > drivers/net/virtio/virtio_rxtx.c | 21 +- > drivers/net/virtio/virtqueue.h | 4 +- > lib/librte_eal/bsdapp/eal/eal_pci.c | 2 +- > lib/librte_eal/bsdapp/eal/rte_eal_version.map | 6 + > lib/librte_eal/common/eal_common_pci.c | 2 +- > lib/librte_eal/common/eal_private.h | 11 - > lib/librte_eal/common/include/rte_pci.h | 11 + > lib/librte_eal/linuxapp/eal/eal_pci.c | 2 +- > lib/librte_eal/linuxapp/eal/rte_eal_version.map | 6 + > 14 files changed, 899 insertions(+), 343 deletions(-) > Hi Yuanhan and Jianfeng, Thanks for great patches. I want to use VIRTIO-1.0 feature for my virtio container patch, because it will solve 44 bit memory address limitation. (So far, legacy virtio-net device only receives queue address under (1 << (32 + 12)).) I have a few comments to rebase virtio container patches on this patches. 1. VIRTIO_READ_REG_X So far, VIRTIO_READ_REG_1/2/4 are defined in virtio_pci.h. But these macros are only referred by virtio_pci.c. How about moving the macros to virtio_pci.c? 2. Abstraction of read/write accesses. It may be difficult to cleanly rebase my patches on this patches, because virtio_read_caps() is not abstracted. Let me describe it more. So far, we need to handle below 3 virtio-net devices.. - physical virtio-net device. - virtual virtio-net device in virtio-net PMD. (Jianfeng's patch) - virtual virtio-net device in QEMU. (my patch) Almost all code of the virtio-net PMD can be shared between above different cases. Probably big difference is how to access to configuration space. Yuanhan's patch introduces an abstraction layer to hide configuration space layout and how to access it. Is it possible to separate? I guess "access method" will be nice to be abstracted separately from "configuration space layout". Probably access method will be defined by "eth_dev->dev_type" and the PMD name like "eth_cvio". And "configuration space layout" will be defined by capability list of PCI configuration layout. For example, if access method like below are abstracted separately and current "virtio_pci.c" is implemented on this abstraction, we can easily re-use virtio_read_caps(). - how to read/write virtio configuration space. - how to mmap PCI configuration space. - how to read/(write) PCI configuration space. Thanks, Tetsuya ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver 2016-01-14 4:27 ` Tetsuya Mukawa @ 2016-01-14 5:59 ` Yuanhan Liu 2016-01-14 6:09 ` Tan, Jianfeng 1 sibling, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 5:59 UTC (permalink / raw) To: Tetsuya Mukawa; +Cc: dev, Michael S. Tsirkin On Thu, Jan 14, 2016 at 01:27:37PM +0900, Tetsuya Mukawa wrote: > On 2016/01/12 15:58, Yuanhan Liu wrote: > > v2: - fix a data corruption reported by Qian, due to hdr size mismatch. > > check detailes at ptach 5. > > > > - Add missing config_irq and isr reading support from v1. > > > > - fix comments from v1. > > > > Almost all difference comes from virtio 1.0 are the PCI layout change: > > the major configuration structures are stored at bar space, and their > > location is stored at corresponding pci cap structure. Reading/parsing > > them is one of the major work of patch 7. > > > > To make handling virtio v1.0 and v0.95 co-exist well, this patch set > > introduces a virtio_pci_ops structure, to add another layer so that > > we could keep those vtpci_foo_bar "APIs". With that, we could do the > > minimum change to add virtio 1.0 support. > > > > > > Hi Yuanhan and Jianfeng, > > Thanks for great patches. > I want to use VIRTIO-1.0 feature for my virtio container patch, because > it will solve 44 bit memory address limitation. > (So far, legacy virtio-net device only receives queue address under (1 > << (32 + 12)).) > > I have a few comments to rebase virtio container patches on this patches. > > 1. VIRTIO_READ_REG_X > > So far, VIRTIO_READ_REG_1/2/4 are defined in virtio_pci.h. > But these macros are only referred by virtio_pci.c. > How about moving the macros to virtio_pci.c? Jianfeng had same suggestion. I could do that in next version then. > 2. Abstraction of read/write accesses. > > It may be difficult to cleanly rebase my patches on this patches, > because virtio_read_caps() is not abstracted. I don't think we can/need abstract virtio_read_caps() here. As that detects wheter it is a legacy or modern (virtio 1.0) virtio device or not. If virtio_read_caps failes, which could either due to pci map failed, or because malformed pci layout, we fallback to legacy virtio 1.0 handling, using io port read/write to do configuration. > Let me describe it more. > So far, we need to handle below 3 virtio-net devices.. > - physical virtio-net device. > - virtual virtio-net device in virtio-net PMD. (Jianfeng's patch) > - virtual virtio-net device in QEMU. (my patch) > > Almost all code of the virtio-net PMD can be shared between above > different cases. > Probably big difference is how to access to configuration space. > > Yuanhan's patch introduces an abstraction layer to hide configuration > space layout and how to access it. Actually, I didn't introduce the abstraction for pci device access. It's just a simple "if ... else ..." case here: use io port read/write, the VIRTIO_READ/WRITE_REG_X macros, to do access for legacy virtio, otherwise for modern virtio, use direct mapped memory read/write access: modern_read/writex. > Is it possible to separate? As stated, there is no mix, therefore no need for seperation. But you could add another access abstraction layer, and assign it properly later, say, by checking eth_dev->dev_type as you suggested below. > I guess "access method" will be nice to be abstracted separately from > "configuration space layout". > Probably access method will be defined by "eth_dev->dev_type" and the > PMD name like "eth_cvio". > And "configuration space layout" will be defined by capability list of > PCI configuration layout. > > For example, if access method like below are abstracted separately and > current "virtio_pci.c" is implemented on this abstraction, we can easily > re-use virtio_read_caps(). > - how to read/write virtio configuration space. It's abstracted by virtio_pci_ops. > - how to mmap PCI configuration space. > - how to read/(write) PCI configuration space. For now, it's actually done by EAL, or by functions provided by EAL. I haven't read your (as well Jianfeng's) code yet, but seems that you need implement another set of functions for above needes for your virtio device. If so, I'd suggest you (or Jianfeng) to do the abstraction based on my patchset: what I am kind of sure is that I should not add those abstraction here, simply for it has nothing to do with virtio 1.0 enabling. --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver 2016-01-14 4:27 ` Tetsuya Mukawa 2016-01-14 5:59 ` Yuanhan Liu @ 2016-01-14 6:09 ` Tan, Jianfeng 2016-01-14 6:41 ` Tetsuya Mukawa 2016-01-14 6:45 ` Yuanhan Liu 1 sibling, 2 replies; 122+ messages in thread From: Tan, Jianfeng @ 2016-01-14 6:09 UTC (permalink / raw) To: Tetsuya Mukawa, Yuanhan Liu, dev; +Cc: Michael S. Tsirkin Hi Tetsuya, On 1/14/2016 12:27 PM, Tetsuya Mukawa wrote: > On 2016/01/12 15:58, Yuanhan Liu wrote: > Hi Yuanhan and Jianfeng, > > Thanks for great patches. > I want to use VIRTIO-1.0 feature for my virtio container patch, because > it will solve 44 bit memory address limitation. > (So far, legacy virtio-net device only receives queue address under (1 > << (32 + 12)).) I suppose you are specifying the code below: /* * Virtio PCI device VIRTIO_PCI_QUEUE_PF register is 32bit, * and only accepts 32 bit page frame number. * Check if the allocated physical memory exceeds 16TB. */ if ((mz->phys_addr + vq->vq_ring_size - 1) >> (VIRTIO_PCI_QUEUE_ADDR_SHIFT + 32)) { PMD_INIT_LOG(ERR, "vring address shouldn't be above 16TB!"); rte_free(vq); return -ENOMEM; } So you don't need to add extra cmd option, right? > > I have a few comments to rebase virtio container patches on this patches. > > 1. VIRTIO_READ_REG_X > > So far, VIRTIO_READ_REG_1/2/4 are defined in virtio_pci.h. > But these macros are only referred by virtio_pci.c. > How about moving the macros to virtio_pci.c? +1 for this. > > 2. Abstraction of read/write accesses. > > It may be difficult to cleanly rebase my patches on this patches, > because virtio_read_caps() is not abstracted. > Let me describe it more. > So far, we need to handle below 3 virtio-net devices.. > - physical virtio-net device. > - virtual virtio-net device in virtio-net PMD. (Jianfeng's patch) > - virtual virtio-net device in QEMU. (my patch) > > Almost all code of the virtio-net PMD can be shared between above > different cases. > Probably big difference is how to access to configuration space. > > Yuanhan's patch introduces an abstraction layer to hide configuration > space layout and how to access it. > Is it possible to separate? > I guess "access method" will be nice to be abstracted separately from > "configuration space layout". > Probably access method will be defined by "eth_dev->dev_type" and the > PMD name like "eth_cvio". > And "configuration space layout" will be defined by capability list of > PCI configuration layout. > > For example, if access method like below are abstracted separately and > current "virtio_pci.c" is implemented on this abstraction, we can easily > re-use virtio_read_caps(). > - how to read/write virtio configuration space. > - how to mmap PCI configuration space. > - how to read/(write) PCI configuration space. I basically agree with you. We have two dimensions here: legacy modern physical virtio device: Use virtio_read_caps_phys() to distinguish virtual virtio device (Tetsuya): Use virtio_read_caps_virt() to distinguish virtual virtio device (Jianfeng): does not need a "configuration space layout", no need to distinguish So in vtpci_init(), we needs to test "eth_dev->dev_type" firstly vtpci_init() { if (eth_dev->dev_type == RTE_ETH_DEV_PCI) { if (virtio_read_caps_phys()) { // modern } else { // legacy } } else { if (Tetsuya's way) { if (virtio_read_caps_virt()) { // modern } else { // legacy } } else { // Jianfeng's way } } } And from Yuanhan's angle, I think he does not need to address this problem. How do you think? Thanks, Jianfeng > > Thanks, > Tetsuya ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver 2016-01-14 6:09 ` Tan, Jianfeng @ 2016-01-14 6:41 ` Tetsuya Mukawa 2016-01-18 9:04 ` Tetsuya Mukawa 2016-01-14 6:45 ` Yuanhan Liu 1 sibling, 1 reply; 122+ messages in thread From: Tetsuya Mukawa @ 2016-01-14 6:41 UTC (permalink / raw) To: Tan, Jianfeng, Yuanhan Liu, dev; +Cc: Michael S. Tsirkin On 2016/01/14 15:09, Tan, Jianfeng wrote: > > Hi Tetsuya, > > On 1/14/2016 12:27 PM, Tetsuya Mukawa wrote: >> On 2016/01/12 15:58, Yuanhan Liu wrote: >> Hi Yuanhan and Jianfeng, >> >> Thanks for great patches. >> I want to use VIRTIO-1.0 feature for my virtio container patch, because >> it will solve 44 bit memory address limitation. >> (So far, legacy virtio-net device only receives queue address under (1 >> << (32 + 12)).) > > I suppose you are specifying the code below: > /* > * Virtio PCI device VIRTIO_PCI_QUEUE_PF register is 32bit, > * and only accepts 32 bit page frame number. > * Check if the allocated physical memory exceeds 16TB. > */ > if ((mz->phys_addr + vq->vq_ring_size - 1) >> > (VIRTIO_PCI_QUEUE_ADDR_SHIFT + 32)) { > PMD_INIT_LOG(ERR, "vring address shouldn't be above > 16TB!"); > rte_free(vq); > return -ENOMEM; > } > > So you don't need to add extra cmd option, right? Yes, this is the code. In our case, instead of using physical address, virtual address will be used, right? Problem is that virtual address will be over (1 << 44) without specifying some mmap options. Probably we need to specify "MAP_FIXED" option while mmapping EAL memory to get lower address. But if we can use VIRTIO-1.0, we can specify 64bit address, then we don't need to do something tricky mmaping. > >> >> I have a few comments to rebase virtio container patches on this >> patches. >> >> 1. VIRTIO_READ_REG_X >> >> So far, VIRTIO_READ_REG_1/2/4 are defined in virtio_pci.h. >> But these macros are only referred by virtio_pci.c. >> How about moving the macros to virtio_pci.c? > > +1 for this. > >> >> 2. Abstraction of read/write accesses. >> >> It may be difficult to cleanly rebase my patches on this patches, >> because virtio_read_caps() is not abstracted. >> Let me describe it more. >> So far, we need to handle below 3 virtio-net devices.. >> - physical virtio-net device. >> - virtual virtio-net device in virtio-net PMD. (Jianfeng's patch) >> - virtual virtio-net device in QEMU. (my patch) >> >> Almost all code of the virtio-net PMD can be shared between above >> different cases. >> Probably big difference is how to access to configuration space. >> >> Yuanhan's patch introduces an abstraction layer to hide configuration >> space layout and how to access it. >> Is it possible to separate? >> I guess "access method" will be nice to be abstracted separately from >> "configuration space layout". >> Probably access method will be defined by "eth_dev->dev_type" and the >> PMD name like "eth_cvio". >> And "configuration space layout" will be defined by capability list of >> PCI configuration layout. >> >> For example, if access method like below are abstracted separately and >> current "virtio_pci.c" is implemented on this abstraction, we can easily >> re-use virtio_read_caps(). >> - how to read/write virtio configuration space. >> - how to mmap PCI configuration space. >> - how to read/(write) PCI configuration space. > > > I basically agree with you. We have two dimensions here: > > legacy modern > physical virtio device: Use > virtio_read_caps_phys() to distinguish > virtual virtio device (Tetsuya): Use virtio_read_caps_virt() to > distinguish > virtual virtio device (Jianfeng): does not need a "configuration > space layout", no need to distinguish > > So in vtpci_init(), we needs to test "eth_dev->dev_type" firstly > > vtpci_init() { > if (eth_dev->dev_type == RTE_ETH_DEV_PCI) { > if (virtio_read_caps_phys()) { > // modern > } else { > // legacy > } > } else { > if (Tetsuya's way) { > if (virtio_read_caps_virt()) { > // modern > } else { > // legacy > } > } else { > // Jianfeng's way > } > } > } > > And from Yuanhan's angle, I think he does not need to address this > problem. How do you think? Yes, I agree he doesn't need. Firstly, I have implemented like above, then I noticed that virtio_read_caps_phy() and virtio_read_caps_virt() are same except for access method. Anyway, I guess abstracting access method is not so difficult. If you are OK, I want to send RFC on Yuanhan's patch. Is it OK? Thanks, Tetsuya ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver 2016-01-14 6:41 ` Tetsuya Mukawa @ 2016-01-18 9:04 ` Tetsuya Mukawa 0 siblings, 0 replies; 122+ messages in thread From: Tetsuya Mukawa @ 2016-01-18 9:04 UTC (permalink / raw) To: Tan, Jianfeng; +Cc: dev, Michael S. Tsirkin On 2016/01/14 15:41, Tetsuya Mukawa wrote: > >>> 2. Abstraction of read/write accesses. >>> >>> It may be difficult to cleanly rebase my patches on this patches, >>> because virtio_read_caps() is not abstracted. >>> Let me describe it more. >>> So far, we need to handle below 3 virtio-net devices.. >>> - physical virtio-net device. >>> - virtual virtio-net device in virtio-net PMD. (Jianfeng's patch) >>> - virtual virtio-net device in QEMU. (my patch) >>> >>> Almost all code of the virtio-net PMD can be shared between above >>> different cases. >>> Probably big difference is how to access to configuration space. >>> >>> Yuanhan's patch introduces an abstraction layer to hide configuration >>> space layout and how to access it. >>> Is it possible to separate? >>> I guess "access method" will be nice to be abstracted separately from >>> "configuration space layout". >>> Probably access method will be defined by "eth_dev->dev_type" and the >>> PMD name like "eth_cvio". >>> And "configuration space layout" will be defined by capability list of >>> PCI configuration layout. >>> >>> For example, if access method like below are abstracted separately and >>> current "virtio_pci.c" is implemented on this abstraction, we can easily >>> re-use virtio_read_caps(). >>> - how to read/write virtio configuration space. >>> - how to mmap PCI configuration space. >>> - how to read/(write) PCI configuration space. >> >> I basically agree with you. We have two dimensions here: >> >> legacy modern >> physical virtio device: Use >> virtio_read_caps_phys() to distinguish >> virtual virtio device (Tetsuya): Use virtio_read_caps_virt() to >> distinguish >> virtual virtio device (Jianfeng): does not need a "configuration >> space layout", no need to distinguish >> >> So in vtpci_init(), we needs to test "eth_dev->dev_type" firstly >> >> vtpci_init() { >> if (eth_dev->dev_type == RTE_ETH_DEV_PCI) { >> if (virtio_read_caps_phys()) { >> // modern >> } else { >> // legacy >> } >> } else { >> if (Tetsuya's way) { >> if (virtio_read_caps_virt()) { >> // modern >> } else { >> // legacy >> } >> } else { >> // Jianfeng's way >> } >> } >> } >> >> And from Yuanhan's angle, I think he does not need to address this >> problem. How do you think? > Yes, I agree he doesn't need. > > Firstly, I have implemented like above, then I noticed that > virtio_read_caps_phy() and virtio_read_caps_virt() are same except for > access method. > Anyway, I guess abstracting access method is not so difficult. > If you are OK, I want to send RFC on Yuanhan's patch. Is it OK? Hi Jianfeng, I will submit patches to abstract pci access method. The patches will be on Yuanhan's latest virtio-1.0 patches. I guess your container patches also can be on the patches. Could you please check it? Thanks, Tetsuya ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver 2016-01-14 6:09 ` Tan, Jianfeng 2016-01-14 6:41 ` Tetsuya Mukawa @ 2016-01-14 6:45 ` Yuanhan Liu 1 sibling, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 6:45 UTC (permalink / raw) To: Tan, Jianfeng; +Cc: dev, Michael S. Tsirkin On Thu, Jan 14, 2016 at 02:09:18PM +0800, Tan, Jianfeng wrote: ... > I basically agree with you. We have two dimensions here: > > legacy modern > physical virtio device: Use virtio_read_caps_phys() to > distinguish > virtual virtio device (Tetsuya): Use virtio_read_caps_virt() to > distinguish > virtual virtio device (Jianfeng): does not need a "configuration space > layout", no need to distinguish I guess you meant to build a form or something, but seems you failed :) > > So in vtpci_init(), we needs to test "eth_dev->dev_type" firstly > > vtpci_init() { > if (eth_dev->dev_type == RTE_ETH_DEV_PCI) { > if (virtio_read_caps_phys()) { > // modern > } else { > // legacy > } > } else { > if (Tetsuya's way) { > if (virtio_read_caps_virt()) { > // modern > } else { > // legacy > } > } else { > // Jianfeng's way > } > } > } Normally, I'd like to hide the details inside virtio_read_caps(): I don't want similar codes to be appeared twice. And if it can be simply done by "if (eth_dev->dev_type == ...)", I'd like to do it in this way. If not, introducing another set of operation abstractions as suggested in my another email might be a better option. > And from Yuanhan's angle, I think he does not need to address this problem. Yep; it just has nothing to do with this patch set. --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v3 0/8] virtio 1.0 enabling for virtio pmd driver 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (8 preceding siblings ...) 2016-01-14 4:27 ` Tetsuya Mukawa @ 2016-01-14 7:42 ` Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu ` (7 more replies) 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu 10 siblings, 8 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 7:42 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin v3: - export pci_unmap_device as well; and invoke it at virtio uninit stage. - fixed same data corruption bug reported by Qian in simple rxtx code path. - move VIRTIO_READ/WRITE_REG_X to virtio_pci.c v2: - fix a data corruption reported by Qian, due to hdr size mismatch. check detailes at ptach 5. - Add missing config_irq and isr reading support from v1. - fix comments from v1. Almost all difference comes from virtio 1.0 are the PCI layout change: the major configuration structures are stored at bar space, and their location is stored at corresponding pci cap structure. Reading/parsing them is one of the major work of patch 7. To make handling virtio v1.0 and v0.95 co-exist well, this patch set introduces a virtio_pci_ops structure, to add another layer so that we could keep those vtpci_foo_bar "APIs". With that, we could do the minimum change to add virtio 1.0 support. Rough test guide ================ Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add option "disable-modern=false" to qemu virtio-net-pci device to enable virtio 1.0 (which is disabled by default). And if you see something like following from 'lspci -v', it means virtio 1.0 is indeed enabled: 00:04.0 Ethernet controller: Red Hat, Inc Virtio network device Subsystem: Red Hat, Inc Device 0001 Physical Slot: 4 Flags: bus master, fast devsel, latency 0, IRQ 11 I/O ports at c040 [size=64] Memory at febf1000 (32-bit, non-prefetchable) [size=4K] Memory at fe000000 (64-bit, prefetchable) [size=8M] Expansion ROM at feb80000 [disabled] [size=256K] Capabilities: [98] MSI-X: Enable+ Count=6 Masked- ==> Capabilities: [84] Vendor Specific Information: Len=14 <?> ==> Capabilities: [70] Vendor Specific Information: Len=14 <?> ==> Capabilities: [60] Vendor Specific Information: Len=10 <?> ==> Capabilities: [50] Vendor Specific Information: Len=10 <?> ==> Capabilities: [40] Vendor Specific Information: Len=10 <?> Kernel driver in use: virtio-pci Kernel modules: virtio_pci After that, there wasn't anything speical comparing to the old virtio 0.95 pmd driver. --- Yuanhan Liu (8): virtio: don't set vring address again at queue startup virtio: introduce struct virtio_pci_ops virtio: move left pci stuff to virtio_pci.c viritio: switch to 64 bit features virtio: retrieve hdr_size from hw->vtnet_hdr_size eal: pci: export pci_[un]map_device virtio: add 1.0 support virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c doc/guides/rel_notes/release_2_3.rst | 3 + drivers/net/virtio/virtio_ethdev.c | 302 +-------- drivers/net/virtio/virtio_ethdev.h | 3 +- drivers/net/virtio/virtio_pci.c | 787 +++++++++++++++++++++++- drivers/net/virtio/virtio_pci.h | 120 +++- drivers/net/virtio/virtio_rxtx.c | 21 +- drivers/net/virtio/virtio_rxtx_simple.c | 12 +- drivers/net/virtio/virtqueue.h | 4 +- lib/librte_eal/bsdapp/eal/eal_pci.c | 4 +- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 7 + lib/librte_eal/common/eal_common_pci.c | 4 +- lib/librte_eal/common/eal_private.h | 18 - lib/librte_eal/common/include/rte_pci.h | 27 + lib/librte_eal/linuxapp/eal/eal_pci.c | 4 +- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 + 15 files changed, 946 insertions(+), 377 deletions(-) -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v3 1/8] virtio: don't set vring address again at queue startup 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu @ 2016-01-14 7:42 ` Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 2/8] virtio: introduce struct virtio_pci_ops Yuanhan Liu ` (6 subsequent siblings) 7 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 7:42 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin As we have already set up it at virtio_dev_queue_setup(), and a vq restart will not reset the settings. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_rxtx.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c index 74b39ef..b7267c0 100644 --- a/drivers/net/virtio/virtio_rxtx.c +++ b/drivers/net/virtio/virtio_rxtx.c @@ -339,11 +339,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type) vq_update_avail_idx(vq); PMD_INIT_LOG(DEBUG, "Allocated %d bufs", nbufs); - - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); } else if (queue_type == VTNET_TQ) { if (use_simple_rxtx) { int mid_idx = vq->vq_nentries >> 1; @@ -362,16 +357,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type) for (i = mid_idx; i < vq->vq_nentries; i++) vq->vq_ring.avail->ring[i] = i; } - - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); - } else { - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); } } -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v3 2/8] virtio: introduce struct virtio_pci_ops 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu @ 2016-01-14 7:42 ` Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 3/8] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu ` (5 subsequent siblings) 7 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 7:42 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin 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> --- 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 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v3 3/8] virtio: move left pci stuff to virtio_pci.c 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 2/8] virtio: introduce struct virtio_pci_ops Yuanhan Liu @ 2016-01-14 7:42 ` Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 4/8] viritio: switch to 64 bit features Yuanhan Liu ` (4 subsequent siblings) 7 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 7:42 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin virtio_pci.c is a more proper place for pci stuff; virtio_ethdev.c is not. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_ethdev.c | 265 +----------------------------------- drivers/net/virtio/virtio_pci.c | 270 ++++++++++++++++++++++++++++++++++++- 2 files changed, 270 insertions(+), 265 deletions(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 6c1d3a0..b57224d 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -36,10 +36,6 @@ #include <stdio.h> #include <errno.h> #include <unistd.h> -#ifdef RTE_EXEC_ENV_LINUXAPP -#include <dirent.h> -#include <fcntl.h> -#endif #include <rte_ethdev.h> #include <rte_memcpy.h> @@ -955,260 +951,6 @@ virtio_negotiate_features(struct virtio_hw *hw) hw->guest_features); } -#ifdef RTE_EXEC_ENV_LINUXAPP -static int -parse_sysfs_value(const char *filename, unsigned long *val) -{ - FILE *f; - char buf[BUFSIZ]; - char *end = NULL; - - f = fopen(filename, "r"); - if (f == NULL) { - PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s", - __func__, filename); - return -1; - } - - if (fgets(buf, sizeof(buf), f) == NULL) { - PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s", - __func__, filename); - fclose(f); - return -1; - } - *val = strtoul(buf, &end, 0); - if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { - PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s", - __func__, filename); - fclose(f); - return -1; - } - fclose(f); - return 0; -} - -static int get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen, - unsigned int *uio_num) -{ - struct dirent *e; - DIR *dir; - char dirname[PATH_MAX]; - - /* depending on kernel version, uio can be located in uio/uioX - * or uio:uioX */ - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", - loc->domain, loc->bus, loc->devid, loc->function); - dir = opendir(dirname); - if (dir == NULL) { - /* retry with the parent directory */ - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, - loc->domain, loc->bus, loc->devid, loc->function); - dir = opendir(dirname); - - if (dir == NULL) { - PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname); - return -1; - } - } - - /* take the first file starting with "uio" */ - while ((e = readdir(dir)) != NULL) { - /* format could be uio%d ...*/ - int shortprefix_len = sizeof("uio") - 1; - /* ... or uio:uio%d */ - int longprefix_len = sizeof("uio:uio") - 1; - char *endptr; - - if (strncmp(e->d_name, "uio", 3) != 0) - continue; - - /* first try uio%d */ - errno = 0; - *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); - if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { - snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num); - break; - } - - /* then try uio:uio%d */ - errno = 0; - *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); - if (errno == 0 && endptr != (e->d_name + longprefix_len)) { - snprintf(buf, buflen, "%s/uio:uio%u", dirname, - *uio_num); - break; - } - } - closedir(dir); - - /* No uio resource found */ - if (e == NULL) { - PMD_INIT_LOG(ERR, "Could not find uio resource"); - return -1; - } - - return 0; -} - -static int -virtio_has_msix(const struct rte_pci_addr *loc) -{ - DIR *d; - char dirname[PATH_MAX]; - - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs", - loc->domain, loc->bus, loc->devid, loc->function); - - d = opendir(dirname); - if (d) - closedir(d); - - return (d != NULL); -} - -/* Extract I/O port numbers from sysfs */ -static int virtio_resource_init_by_uio(struct rte_pci_device *pci_dev) -{ - char dirname[PATH_MAX]; - char filename[PATH_MAX]; - unsigned long start, size; - unsigned int uio_num; - - if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0) - return -1; - - /* get portio size */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/size", dirname); - if (parse_sysfs_value(filename, &size) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse size", - __func__); - return -1; - } - - /* get portio start */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/start", dirname); - if (parse_sysfs_value(filename, &start) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", - __func__); - return -1; - } - pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; - pci_dev->mem_resource[0].len = (uint64_t)size; - PMD_INIT_LOG(DEBUG, - "PCI Port IO found start=0x%lx with size=0x%lx", - start, size); - - /* save fd */ - memset(dirname, 0, sizeof(dirname)); - snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num); - pci_dev->intr_handle.fd = open(dirname, O_RDWR); - if (pci_dev->intr_handle.fd < 0) { - PMD_INIT_LOG(ERR, "Cannot open %s: %s\n", - dirname, strerror(errno)); - return -1; - } - - pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO; - pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; - - return 0; -} - -/* Extract port I/O numbers from proc/ioports */ -static int virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev) -{ - uint16_t start, end; - int size; - FILE *fp; - char *line = NULL; - char pci_id[16]; - int found = 0; - size_t linesz; - - snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, - pci_dev->addr.domain, - pci_dev->addr.bus, - pci_dev->addr.devid, - pci_dev->addr.function); - - fp = fopen("/proc/ioports", "r"); - if (fp == NULL) { - PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__); - return -1; - } - - while (getdelim(&line, &linesz, '\n', fp) > 0) { - char *ptr = line; - char *left; - int n; - - n = strcspn(ptr, ":"); - ptr[n] = 0; - left = &ptr[n+1]; - - while (*left && isspace(*left)) - left++; - - if (!strncmp(left, pci_id, strlen(pci_id))) { - found = 1; - - while (*ptr && isspace(*ptr)) - ptr++; - - sscanf(ptr, "%04hx-%04hx", &start, &end); - size = end - start + 1; - - break; - } - } - - free(line); - fclose(fp); - - if (!found) - return -1; - - pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start; - pci_dev->mem_resource[0].len = (uint64_t)size; - PMD_INIT_LOG(DEBUG, - "PCI Port IO found start=0x%x with size=0x%x", - start, size); - - /* can't support lsc interrupt without uio */ - pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; - - return 0; -} - -/* Extract I/O port numbers from sysfs */ -static int virtio_resource_init(struct rte_pci_device *pci_dev) -{ - if (virtio_resource_init_by_uio(pci_dev) == 0) - return 0; - else - return virtio_resource_init_by_ioports(pci_dev); -} - -#else -static int -virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) -{ - /* nic_uio does not enable interrupts, return 0 (false). */ - return 0; -} - -static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) -{ - /* no setup required */ - return 0; -} -#endif - /* * Process Virtio Config changed interrupt and call the callback * if link state changed. @@ -1279,14 +1021,9 @@ 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) + if (vtpci_init(pci_dev, hw) < 0) return -1; - hw->use_msix = virtio_has_msix(&pci_dev->addr); - hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr; - /* Reset the device although not necessary at startup */ vtpci_reset(hw); diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 9930efa..03d623b 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -32,6 +32,11 @@ */ #include <stdint.h> +#ifdef RTE_EXEC_ENV_LINUXAPP + #include <dirent.h> + #include <fcntl.h> +#endif + #include "virtio_pci.h" #include "virtio_logs.h" #include "virtqueue.h" @@ -156,6 +161,264 @@ legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq) VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index); } +#ifdef RTE_EXEC_ENV_LINUXAPP +static int +parse_sysfs_value(const char *filename, unsigned long *val) +{ + FILE *f; + char buf[BUFSIZ]; + char *end = NULL; + + f = fopen(filename, "r"); + if (f == NULL) { + PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s", + __func__, filename); + return -1; + } + + if (fgets(buf, sizeof(buf), f) == NULL) { + PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s", + __func__, filename); + fclose(f); + return -1; + } + *val = strtoul(buf, &end, 0); + if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { + PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s", + __func__, filename); + fclose(f); + return -1; + } + fclose(f); + return 0; +} + +static int +get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen, + unsigned int *uio_num) +{ + struct dirent *e; + DIR *dir; + char dirname[PATH_MAX]; + + /* depending on kernel version, uio can be located in uio/uioX + * or uio:uioX */ + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", + loc->domain, loc->bus, loc->devid, loc->function); + dir = opendir(dirname); + if (dir == NULL) { + /* retry with the parent directory */ + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, + loc->domain, loc->bus, loc->devid, loc->function); + dir = opendir(dirname); + + if (dir == NULL) { + PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname); + return -1; + } + } + + /* take the first file starting with "uio" */ + while ((e = readdir(dir)) != NULL) { + /* format could be uio%d ...*/ + int shortprefix_len = sizeof("uio") - 1; + /* ... or uio:uio%d */ + int longprefix_len = sizeof("uio:uio") - 1; + char *endptr; + + if (strncmp(e->d_name, "uio", 3) != 0) + continue; + + /* first try uio%d */ + errno = 0; + *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); + if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { + snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num); + break; + } + + /* then try uio:uio%d */ + errno = 0; + *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); + if (errno == 0 && endptr != (e->d_name + longprefix_len)) { + snprintf(buf, buflen, "%s/uio:uio%u", dirname, + *uio_num); + break; + } + } + closedir(dir); + + /* No uio resource found */ + if (e == NULL) { + PMD_INIT_LOG(ERR, "Could not find uio resource"); + return -1; + } + + return 0; +} + +static int +legacy_virtio_has_msix(const struct rte_pci_addr *loc) +{ + DIR *d; + char dirname[PATH_MAX]; + + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs", + loc->domain, loc->bus, loc->devid, loc->function); + + d = opendir(dirname); + if (d) + closedir(d); + + return (d != NULL); +} + +/* Extract I/O port numbers from sysfs */ +static int +virtio_resource_init_by_uio(struct rte_pci_device *pci_dev) +{ + char dirname[PATH_MAX]; + char filename[PATH_MAX]; + unsigned long start, size; + unsigned int uio_num; + + if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0) + return -1; + + /* get portio size */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/size", dirname); + if (parse_sysfs_value(filename, &size) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse size", + __func__); + return -1; + } + + /* get portio start */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/start", dirname); + if (parse_sysfs_value(filename, &start) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", + __func__); + return -1; + } + pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; + pci_dev->mem_resource[0].len = (uint64_t)size; + PMD_INIT_LOG(DEBUG, + "PCI Port IO found start=0x%lx with size=0x%lx", + start, size); + + /* save fd */ + memset(dirname, 0, sizeof(dirname)); + snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num); + pci_dev->intr_handle.fd = open(dirname, O_RDWR); + if (pci_dev->intr_handle.fd < 0) { + PMD_INIT_LOG(ERR, "Cannot open %s: %s\n", + dirname, strerror(errno)); + return -1; + } + + pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO; + pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; + + return 0; +} + +/* Extract port I/O numbers from proc/ioports */ +static int +virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev) +{ + uint16_t start, end; + int size; + FILE *fp; + char *line = NULL; + char pci_id[16]; + int found = 0; + size_t linesz; + + snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, + pci_dev->addr.domain, + pci_dev->addr.bus, + pci_dev->addr.devid, + pci_dev->addr.function); + + fp = fopen("/proc/ioports", "r"); + if (fp == NULL) { + PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__); + return -1; + } + + while (getdelim(&line, &linesz, '\n', fp) > 0) { + char *ptr = line; + char *left; + int n; + + n = strcspn(ptr, ":"); + ptr[n] = 0; + left = &ptr[n+1]; + + while (*left && isspace(*left)) + left++; + + if (!strncmp(left, pci_id, strlen(pci_id))) { + found = 1; + + while (*ptr && isspace(*ptr)) + ptr++; + + sscanf(ptr, "%04hx-%04hx", &start, &end); + size = end - start + 1; + + break; + } + } + + free(line); + fclose(fp); + + if (!found) + return -1; + + pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start; + pci_dev->mem_resource[0].len = (uint64_t)size; + PMD_INIT_LOG(DEBUG, + "PCI Port IO found start=0x%x with size=0x%x", + start, size); + + /* can't support lsc interrupt without uio */ + pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; + + return 0; +} + +/* Extract I/O port numbers from sysfs */ +static int +legacy_virtio_resource_init(struct rte_pci_device *pci_dev) +{ + if (virtio_resource_init_by_uio(pci_dev) == 0) + return 0; + else + return virtio_resource_init_by_ioports(pci_dev); +} + +#else +static int +legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) +{ + /* nic_uio does not enable interrupts, return 0 (false). */ + return 0; +} + +static int +legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) +{ + /* no setup required */ + return 0; +} +#endif static const struct virtio_pci_ops legacy_ops = { .read_dev_cfg = legacy_read_dev_config, @@ -241,9 +504,14 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) } int -vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw) +vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) { hw->vtpci_ops = &legacy_ops; + if (legacy_virtio_resource_init(dev) < 0) + return -1; + hw->use_msix = legacy_virtio_has_msix(&dev->addr); + hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr; + return 0; } -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v3 4/8] viritio: switch to 64 bit features 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu ` (2 preceding siblings ...) 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 3/8] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu @ 2016-01-14 7:42 ` Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu ` (3 subsequent siblings) 7 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 7:42 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin Switch to 64 bit features, that virtio 1.0 supports. While legacy virtio only supports 32 bit features, here we complain aloud and quit when trying to setting > 32 bit features for legacy device. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_ethdev.c | 8 ++++---- drivers/net/virtio/virtio_pci.c | 15 ++++++++++----- drivers/net/virtio/virtio_pci.h | 12 ++++++------ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index b57224d..94e0c4a 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -930,16 +930,16 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) static void virtio_negotiate_features(struct virtio_hw *hw) { - uint32_t host_features; + uint64_t host_features; /* Prepare guest_features: feature that driver wants to support */ hw->guest_features = VIRTIO_PMD_GUEST_FEATURES; - PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %x", + PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %"PRIx64, hw->guest_features); /* Read device(host) feature bits */ host_features = hw->vtpci_ops->get_features(hw); - PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x", + PMD_INIT_LOG(DEBUG, "host_features before negotiate = %"PRIx64, host_features); /* @@ -947,7 +947,7 @@ virtio_negotiate_features(struct virtio_hw *hw) * guest feature bits. */ hw->guest_features = vtpci_negotiate_features(hw, host_features); - PMD_INIT_LOG(DEBUG, "features after negotiate = %x", + PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, hw->guest_features); } diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 03d623b..5eed57e 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -87,15 +87,20 @@ legacy_write_dev_config(struct virtio_hw *hw, uint64_t offset, } } -static uint32_t +static uint64_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) +legacy_set_features(struct virtio_hw *hw, uint64_t features) { + if ((features >> 32) != 0) { + PMD_DRV_LOG(ERR, + "only 32 bit features are allowed for legacy virtio!"); + return; + } VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features); } @@ -451,10 +456,10 @@ vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset, hw->vtpci_ops->write_dev_cfg(hw, offset, src, length); } -uint32_t -vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features) +uint64_t +vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features) { - uint32_t features; + uint64_t features; /* * Limit negotiated features to what the driver, virtqueue, and diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index ee7d265..3fd86f6 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -175,8 +175,8 @@ struct virtio_pci_ops { 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); + uint64_t (*get_features)(struct virtio_hw *hw); + void (*set_features)(struct virtio_hw *hw, uint64_t features); uint8_t (*get_isr)(struct virtio_hw *hw); @@ -191,7 +191,7 @@ struct virtio_pci_ops { struct virtio_hw { struct virtqueue *cvq; uint32_t io_base; - uint32_t guest_features; + uint64_t guest_features; uint32_t max_tx_queues; uint32_t max_rx_queues; uint16_t vtnet_hdr_size; @@ -271,9 +271,9 @@ outl_p(unsigned int data, unsigned int port) outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) static inline int -vtpci_with_feature(struct virtio_hw *hw, uint32_t bit) +vtpci_with_feature(struct virtio_hw *hw, uint64_t bit) { - return (hw->guest_features & (1u << bit)) != 0; + return (hw->guest_features & (1ULL << bit)) != 0; } /* @@ -286,7 +286,7 @@ void vtpci_reinit_complete(struct virtio_hw *); void vtpci_set_status(struct virtio_hw *, uint8_t); -uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t); +uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t); void vtpci_write_dev_config(struct virtio_hw *, uint64_t, void *, int); -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v3 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu ` (3 preceding siblings ...) 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 4/8] viritio: switch to 64 bit features Yuanhan Liu @ 2016-01-14 7:42 ` Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 6/8] eal: pci: export pci_[un]map_device Yuanhan Liu ` (2 subsequent siblings) 7 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 7:42 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin The mergeable virtio net hdr format has been the standard and the only virtio net hdr format since virtio 1.0. Therefore, we can not hardcode hdr_size to "sizeof(struct virtio_net_hdr)" any more at virtio_recv_pkts(), otherwise, there would be a mismatch of hdr size from rte_vhost_enqueue_burst() and virtio_recv_pkts(), leading a packet corruption. Instead, we should retrieve it from hw->vtnet_hdr_size; we will do proper settings at eth_virtio_dev_init() in later patches. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- v3: retrieve hdr_size from hw->vtnet_hdr_size for simple rxtx code path as well: it should not break anything, as simple rx and mergeable rx still will not co-exist. --- drivers/net/virtio/virtio_rxtx.c | 6 ++++-- drivers/net/virtio/virtio_rxtx_simple.c | 12 ++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c index b7267c0..41a1366 100644 --- a/drivers/net/virtio/virtio_rxtx.c +++ b/drivers/net/virtio/virtio_rxtx.c @@ -560,7 +560,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ]; int error; uint32_t i, nb_enqueued; - const uint32_t hdr_size = sizeof(struct virtio_net_hdr); + uint32_t hdr_size; nb_used = VIRTQUEUE_NUSED(rxvq); @@ -580,6 +580,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) hw = rxvq->hw; nb_rx = 0; nb_enqueued = 0; + hdr_size = hw->vtnet_hdr_size; for (i = 0; i < num ; i++) { rxm = rcv_pkts[i]; @@ -664,7 +665,7 @@ virtio_recv_mergeable_pkts(void *rx_queue, uint32_t seg_num; uint16_t extra_idx; uint32_t seg_res; - const uint32_t hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); + uint32_t hdr_size; nb_used = VIRTQUEUE_NUSED(rxvq); @@ -682,6 +683,7 @@ virtio_recv_mergeable_pkts(void *rx_queue, seg_num = 0; extra_idx = 0; seg_res = 0; + hdr_size = hw->vtnet_hdr_size; while (i < nb_used) { struct virtio_net_hdr_mrg_rxbuf *header; diff --git a/drivers/net/virtio/virtio_rxtx_simple.c b/drivers/net/virtio/virtio_rxtx_simple.c index ff3c11a..3e66e8b 100644 --- a/drivers/net/virtio/virtio_rxtx_simple.c +++ b/drivers/net/virtio/virtio_rxtx_simple.c @@ -81,9 +81,9 @@ virtqueue_enqueue_recv_refill_simple(struct virtqueue *vq, start_dp = vq->vq_ring.desc; start_dp[desc_idx].addr = (uint64_t)((uintptr_t)cookie->buf_physaddr + - RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr)); + RTE_PKTMBUF_HEADROOM - vq->hw->vtnet_hdr_size); start_dp[desc_idx].len = cookie->buf_len - - RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr); + RTE_PKTMBUF_HEADROOM + vq->hw->vtnet_hdr_size; vq->vq_free_cnt--; vq->vq_avail_idx++; @@ -120,9 +120,9 @@ virtio_rxq_rearm_vec(struct virtqueue *rxvq) start_dp[i].addr = (uint64_t)((uintptr_t)sw_ring[i]->buf_physaddr + - RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr)); + RTE_PKTMBUF_HEADROOM - rxvq->hw->vtnet_hdr_size); start_dp[i].len = sw_ring[i]->buf_len - - RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr); + RTE_PKTMBUF_HEADROOM + rxvq->hw->vtnet_hdr_size; } rxvq->vq_avail_idx += RTE_VIRTIO_VPMD_RX_REARM_THRESH; @@ -175,8 +175,8 @@ virtio_recv_pkts_vec(void *rx_queue, struct rte_mbuf **rx_pkts, len_adjust = _mm_set_epi16( 0, 0, 0, - (uint16_t) -sizeof(struct virtio_net_hdr), - 0, (uint16_t) -sizeof(struct virtio_net_hdr), + (uint16_t) -rxvq->hw->vtnet_hdr_size, + 0, (uint16_t) -rxvq->hw->vtnet_hdr_size, 0, 0); if (unlikely(nb_pkts < RTE_VIRTIO_DESC_PER_LOOP)) -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v3 6/8] eal: pci: export pci_[un]map_device 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu ` (4 preceding siblings ...) 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu @ 2016-01-14 7:42 ` Yuanhan Liu 2016-01-14 7:45 ` Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 7/8] virtio: add 1.0 support Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu 7 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 7:42 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will invoke pci_map_device internally for us. From that point view, there is no need to export pci_map_device. However, for virtio pmd driver, which is designed to work without binding UIO (or something similar first), pci_map_device() will fail, which ends up with virtio pmd driver being skipped. Therefore, we can not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver. Therefore, this patch exports pci_map_device, and let virtio pmd call it when necessary. Cc: David Marchand <david.marchand@6wind.com> Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- v3: - export pci_unmap_device as well - Add few more comments about rte_eal_pci_map_device(). --- lib/librte_eal/bsdapp/eal/eal_pci.c | 4 ++-- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 7 +++++++ lib/librte_eal/common/eal_common_pci.c | 4 ++-- lib/librte_eal/common/eal_private.h | 18 ----------------- lib/librte_eal/common/include/rte_pci.h | 27 +++++++++++++++++++++++++ lib/librte_eal/linuxapp/eal/eal_pci.c | 4 ++-- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +++++++ 7 files changed, 47 insertions(+), 24 deletions(-) diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c index 6c21fbd..95c32c1 100644 --- a/lib/librte_eal/bsdapp/eal/eal_pci.c +++ b/lib/librte_eal/bsdapp/eal/eal_pci.c @@ -93,7 +93,7 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused) /* Map pci device */ int -pci_map_device(struct rte_pci_device *dev) +rte_eal_pci_map_device(struct rte_pci_device *dev) { int ret = -1; @@ -115,7 +115,7 @@ pci_map_device(struct rte_pci_device *dev) /* Unmap pci device */ void -pci_unmap_device(struct rte_pci_device *dev) +rte_eal_pci_unmap_device(struct rte_pci_device *dev) { /* try unmapping the NIC resources */ switch (dev->kdrv) { diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map index 9d7adf1..1b28170 100644 --- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map +++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map @@ -135,3 +135,10 @@ DPDK_2.2 { rte_xen_dom0_supported; } DPDK_2.1; + +DPDK_2.3 { + global: + + rte_eal_pci_map_device; + rte_eal_pci_unmap_device; +} DPDK_2.2; diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c index dcfe947..96d5113 100644 --- a/lib/librte_eal/common/eal_common_pci.c +++ b/lib/librte_eal/common/eal_common_pci.c @@ -188,7 +188,7 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d pci_config_space_set(dev); #endif /* map resources for devices that use igb_uio */ - ret = pci_map_device(dev); + ret = rte_eal_pci_map_device(dev); if (ret != 0) return ret; } else if (dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND && @@ -254,7 +254,7 @@ rte_eal_pci_detach_dev(struct rte_pci_driver *dr, if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING) /* unmap resources for devices that use igb_uio */ - pci_unmap_device(dev); + rte_eal_pci_unmap_device(dev); return 0; } diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h index 072e672..2342fa1 100644 --- a/lib/librte_eal/common/eal_private.h +++ b/lib/librte_eal/common/eal_private.h @@ -165,24 +165,6 @@ struct rte_pci_device; int pci_unbind_kernel_driver(struct rte_pci_device *dev); /** - * Map this device - * - * This function is private to EAL. - * - * @return - * 0 on success, negative on error and positive if no driver - * is found for the device. - */ -int pci_map_device(struct rte_pci_device *dev); - -/** - * Unmap this device - * - * This function is private to EAL. - */ -void pci_unmap_device(struct rte_pci_device *dev); - -/** * Map the PCI resource of a PCI device in virtual memory * * This function is private to EAL. diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h index 334c12e..2224109 100644 --- a/lib/librte_eal/common/include/rte_pci.h +++ b/lib/librte_eal/common/include/rte_pci.h @@ -485,6 +485,33 @@ int rte_eal_pci_read_config(const struct rte_pci_device *device, */ int rte_eal_pci_write_config(const struct rte_pci_device *device, const void *buf, size_t len, off_t offset); +/** + * Map the PCI device resources in user space virtual memory address + * + * Note that driver should not call this function when flag + * RTE_PCI_DRV_NEED_MAPPING is set, as EAL will do that for + * you when it's on. + * + * @param dev + * A pointer to a rte_pci_device structure describing the device + * to use + * + * @return + * 0 on success, negative on error and positive if no driver + * is found for the device. + */ +int rte_eal_pci_map_device(struct rte_pci_device *dev); + +/** + * Unmap this device + * + * @param dev + * A pointer to a rte_pci_device structure describing the device + * to use + */ +void rte_eal_pci_unmap_device(struct rte_pci_device *dev); + + #ifdef RTE_PCI_CONFIG /** diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c index bc5b5be..db947da 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c @@ -124,7 +124,7 @@ pci_get_kernel_driver_by_path(const char *filename, char *dri_name) /* Map pci device */ int -pci_map_device(struct rte_pci_device *dev) +rte_eal_pci_map_device(struct rte_pci_device *dev) { int ret = -1; @@ -153,7 +153,7 @@ pci_map_device(struct rte_pci_device *dev) /* Unmap pci device */ void -pci_unmap_device(struct rte_pci_device *dev) +rte_eal_pci_unmap_device(struct rte_pci_device *dev) { /* try unmapping the NIC resources using VFIO if it exists */ switch (dev->kdrv) { diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map index cbe175f..b9937c4 100644 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map @@ -138,3 +138,10 @@ DPDK_2.2 { rte_xen_dom0_supported; } DPDK_2.1; + +DPDK_2.3 { + global: + + rte_eal_pci_map_device; + rte_eal_pci_unmap_device; +} DPDK_2.2; -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v3 6/8] eal: pci: export pci_[un]map_device 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 6/8] eal: pci: export pci_[un]map_device Yuanhan Liu @ 2016-01-14 7:45 ` Yuanhan Liu 0 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 7:45 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin On Thu, Jan 14, 2016 at 03:42:50PM +0800, Yuanhan Liu wrote: > Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will > invoke pci_map_device internally for us. From that point view, there > is no need to export pci_map_device. > > However, for virtio pmd driver, which is designed to work without > binding UIO (or something similar first), pci_map_device() will fail, > which ends up with virtio pmd driver being skipped. Therefore, we can > not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver. > > Therefore, this patch exports pci_map_device, and let virtio pmd > call it when necessary. > > Cc: David Marchand <david.marchand@6wind.com> > Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> Oops, forgot to carry the tested-by from Santosh. Tested-By: Santosh Shukla <sshukla@mvista.com> --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v3 7/8] virtio: add 1.0 support 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu ` (5 preceding siblings ...) 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 6/8] eal: pci: export pci_[un]map_device Yuanhan Liu @ 2016-01-14 7:42 ` Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu 7 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 7:42 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin Modern (v1.0) virtio pci device defines several pci capabilities. Each cap has a configure structure corresponding to it, and the cap.bar and cap.offset fields tell us where to find it. Firstly, we map the pci resources by rte_eal_pci_map_device(). We then could easily locate to a cfg structure by: cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset; Therefore, the entrance of enabling modern (v1.0) pci device support is to iterate the pci capability lists, and to locate some configs we care; and they are: - common cfg For generic virtio and virtuqueu configuration, such as setting/getting features, enabling a specific queue, and so on. - nofity cfg Combining with `queue_notify_off' from common cfg, we could use it to notify a specific virt queue. - device cfg Where virtio_net_config structure locates. - isr cfg Where to read isr (interrupt status). If any of above cap is not found, we fallback to the legacy virtio handling. If succeed, hw->vtpci_ops is assigned to modern_ops, where all operations are implemented by reading/writing a (or few) specific configuration space from above 4 cfg structures. And that's basically how this patch works. Besides those changes, virtio 1.0 introduces a new status field: FEATURES_OK, which is set after features negotiation is done. Last, set the VIRTIO_F_VERSION_1 feature flag. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- v2: - re-read status after setting FEATURES_OK to make sure status is set correctly. - Add isr reading and config irq setting support. - Define some pci macro on our own to not get the dependency of linux/pci_regs.h, as there should be no such file at non-Linux platform v3: - invoke rte_eal_pci_unmap_device() at uninit stage --- doc/guides/rel_notes/release_2_3.rst | 3 + drivers/net/virtio/virtio_ethdev.c | 25 ++- drivers/net/virtio/virtio_ethdev.h | 3 +- drivers/net/virtio/virtio_pci.c | 335 ++++++++++++++++++++++++++++++++++- drivers/net/virtio/virtio_pci.h | 67 +++++++ drivers/net/virtio/virtqueue.h | 2 + 6 files changed, 430 insertions(+), 5 deletions(-) diff --git a/doc/guides/rel_notes/release_2_3.rst b/doc/guides/rel_notes/release_2_3.rst index 99de186..c390d97 100644 --- a/doc/guides/rel_notes/release_2_3.rst +++ b/doc/guides/rel_notes/release_2_3.rst @@ -4,6 +4,9 @@ DPDK Release 2.3 New Features ------------ +* **Virtio 1.0 support.** + + Enabled virtio 1.0 support for virtio pmd driver. Resolved Issues --------------- diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 94e0c4a..deb0382 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) return virtio_send_command(hw->cvq, &ctrl, &len, 1); } -static void +static int virtio_negotiate_features(struct virtio_hw *hw) { uint64_t host_features; @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw) hw->guest_features = vtpci_negotiate_features(hw, host_features); PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, hw->guest_features); + + if (hw->modern) { + if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) { + PMD_INIT_LOG(ERR, + "VIRTIO_F_VERSION_1 features is not enabled."); + return -1; + } + vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK); + if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) { + PMD_INIT_LOG(ERR, + "failed to set FEATURES_OK status!"); + return -1; + } + } + + return 0; } /* @@ -1032,7 +1048,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev) /* Tell the host we've known how to drive the device. */ vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER); - virtio_negotiate_features(hw); + if (virtio_negotiate_features(hw) < 0) + return -1; /* If host does not support status then disable LSC */ if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) @@ -1043,7 +1060,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev) rx_func_get(eth_dev); /* Setting up rx_header size for the device */ - if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) + if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) || + vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); else hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr); @@ -1159,6 +1177,7 @@ eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev) rte_intr_callback_unregister(&pci_dev->intr_handle, virtio_interrupt_handler, eth_dev); + rte_eal_pci_unmap_device(pci_dev); PMD_INIT_LOG(DEBUG, "dev_uninit completed"); diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h index ae2d47d..fed9571 100644 --- a/drivers/net/virtio/virtio_ethdev.h +++ b/drivers/net/virtio/virtio_ethdev.h @@ -64,7 +64,8 @@ 1u << VIRTIO_NET_F_CTRL_VQ | \ 1u << VIRTIO_NET_F_CTRL_RX | \ 1u << VIRTIO_NET_F_CTRL_VLAN | \ - 1u << VIRTIO_NET_F_MRG_RXBUF) + 1u << VIRTIO_NET_F_MRG_RXBUF | \ + 1ULL << VIRTIO_F_VERSION_1) /* * CQ function prototype diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 5eed57e..9b62013 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -41,6 +41,14 @@ #include "virtio_logs.h" #include "virtqueue.h" +/* + * Following macros are derieved from linux/pci_regs.h, however, + * we can't simply include that header here, as there is no such + * file for non-Linux platform. + */ +#define PCI_CAPABILITY_LIST 0x34 +#define PCI_CAP_ID_VNDR 0x09 + static void legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset, void *dst, int length) @@ -442,6 +450,204 @@ static const struct virtio_pci_ops legacy_ops = { }; +#define MODERN_READ_DEF(nr_bits, type) \ +static inline type \ +modern_read##nr_bits(type *addr) \ +{ \ + return *(volatile type *)addr; \ +} + +#define MODERN_WRITE_DEF(nr_bits, type) \ +static inline void \ +modern_write##nr_bits(type val, type *addr) \ +{ \ + *(volatile type *)addr = val; \ +} + +MODERN_READ_DEF (8, uint8_t) +MODERN_WRITE_DEF(8, uint8_t) + +MODERN_READ_DEF (16, uint16_t) +MODERN_WRITE_DEF(16, uint16_t) + +MODERN_READ_DEF (32, uint32_t) +MODERN_WRITE_DEF(32, uint32_t) + +static inline void +modern_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) +{ + modern_write32((uint32_t)val, lo); + modern_write32(val >> 32, hi); +} + +static void +modern_read_dev_config(struct virtio_hw *hw, uint64_t offset, + void *dst, int length) +{ + int i; + uint8_t *p; + uint8_t old_gen, new_gen; + + do { + old_gen = modern_read8(&hw->common_cfg->config_generation); + + p = dst; + for (i = 0; i < length; i++) + *p++ = modern_read8((uint8_t *)hw->dev_cfg + offset + i); + + new_gen = modern_read8(&hw->common_cfg->config_generation); + } while (old_gen != new_gen); +} + +static void +modern_write_dev_config(struct virtio_hw *hw, uint64_t offset, + void *src, int length) +{ + int i; + uint8_t *p = src; + + for (i = 0; i < length; i++) + modern_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i); +} + +static uint64_t +modern_get_features(struct virtio_hw *hw) +{ + uint32_t features_lo, features_hi; + + modern_write32(0, &hw->common_cfg->device_feature_select); + features_lo = modern_read32(&hw->common_cfg->device_feature); + + modern_write32(1, &hw->common_cfg->device_feature_select); + features_hi = modern_read32(&hw->common_cfg->device_feature); + + return ((uint64_t)(features_hi) << 32) | features_lo; +} + +static void +modern_set_features(struct virtio_hw *hw, uint64_t features) +{ + modern_write32(0, &hw->common_cfg->guest_feature_select); + modern_write32(features & ((1ULL << 32) - 1), + &hw->common_cfg->guest_feature); + + modern_write32(1, &hw->common_cfg->guest_feature_select); + modern_write32(features >> 32, + &hw->common_cfg->guest_feature); +} + +static uint8_t +modern_get_status(struct virtio_hw *hw) +{ + return modern_read8(&hw->common_cfg->device_status); +} + +static void +modern_set_status(struct virtio_hw *hw, uint8_t status) +{ + modern_write8(status, &hw->common_cfg->device_status); +} + +static void +modern_reset(struct virtio_hw *hw) +{ + modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); + modern_get_status(hw); +} + +static uint8_t +modern_get_isr(struct virtio_hw *hw) +{ + return modern_read8(hw->isr); +} + +static uint16_t +modern_set_config_irq(struct virtio_hw *hw, uint16_t vec) +{ + modern_write16(vec, &hw->common_cfg->msix_config); + return modern_read16(&hw->common_cfg->msix_config); +} + +static uint16_t +modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) +{ + modern_write16(queue_id, &hw->common_cfg->queue_select); + return modern_read16(&hw->common_cfg->queue_size); +} + +static void +modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + uint64_t desc_addr, avail_addr, used_addr; + uint16_t notify_off; + + desc_addr = vq->mz->phys_addr; + avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc); + used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail, + ring[vq->vq_nentries]), + VIRTIO_PCI_VRING_ALIGN); + + modern_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); + + modern_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + modern_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + modern_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + notify_off = modern_read16(&hw->common_cfg->queue_notify_off); + vq->notify_addr = (void *)((uint8_t *)hw->notify_base + + notify_off * hw->notify_off_multiplier); + + modern_write16(1, &hw->common_cfg->queue_enable); + + PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index); + PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr); + PMD_INIT_LOG(DEBUG, "\t aval_addr: %"PRIx64, avail_addr); + PMD_INIT_LOG(DEBUG, "\t used_addr: %"PRIx64, used_addr); + PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)", + vq->notify_addr, notify_off); +} + +static void +modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + modern_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); + + modern_write64_twopart(0, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + modern_write64_twopart(0, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + modern_write64_twopart(0, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + modern_write16(0, &hw->common_cfg->queue_enable); +} + +static void +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) +{ + modern_write16(1, vq->notify_addr); +} + +static const struct virtio_pci_ops modern_ops = { + .read_dev_cfg = modern_read_dev_config, + .write_dev_cfg = modern_write_dev_config, + .reset = modern_reset, + .get_status = modern_get_status, + .set_status = modern_set_status, + .get_features = modern_get_features, + .set_features = modern_set_features, + .get_isr = modern_get_isr, + .set_config_irq = modern_set_config_irq, + .get_queue_num = modern_get_queue_num, + .setup_queue = modern_setup_queue, + .del_queue = modern_del_queue, + .notify_queue = modern_notify_queue, +}; + + void vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset, void *dst, int length) @@ -495,6 +701,12 @@ vtpci_set_status(struct virtio_hw *hw, uint8_t status) } uint8_t +vtpci_get_status(struct virtio_hw *hw) +{ + return hw->vtpci_ops->get_status(hw); +} + +uint8_t vtpci_isr(struct virtio_hw *hw) { return hw->vtpci_ops->get_isr(hw); @@ -508,15 +720,136 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) return hw->vtpci_ops->set_config_irq(hw, vec); } +static inline void * +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) +{ + uint8_t bar = cap->bar; + uint32_t length = cap->length; + uint32_t offset = cap->offset; + uint8_t *base; + + if (unlikely(bar > 5)) { + PMD_INIT_LOG(ERR, "invalid bar: %u", bar); + return NULL; + } + + if (unlikely(offset + length > dev->mem_resource[bar].len)) { + PMD_INIT_LOG(ERR, + "invalid cap: overflows bar space: %u > %"PRIu64, + offset + length, dev->mem_resource[bar].len); + return NULL; + } + + base = dev->mem_resource[bar].addr; + if (unlikely(base == NULL)) { + PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar); + return NULL; + } + + return base + offset; +} + +static int +virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw) +{ + uint8_t pos; + struct virtio_pci_cap cap; + int ret; + + if (rte_eal_pci_map_device(dev) < 0) { + PMD_INIT_LOG(DEBUG, "failed to map pci device!"); + return -1; + } + + ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST); + if (ret < 0) { + PMD_INIT_LOG(DEBUG, "failed to read pci capability list"); + return -1; + } + + while (pos) { + ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos); + if (ret < 0) { + PMD_INIT_LOG(ERR, + "failed to read pci cap at pos: %x", pos); + break; + } + + if (cap.cap_vndr != PCI_CAP_ID_VNDR) { + PMD_INIT_LOG(DEBUG, + "[%2x] skipping non VNDR cap id: %02x", + pos, cap.cap_vndr); + goto next; + } + + PMD_INIT_LOG(DEBUG, + "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u", + pos, cap.cfg_type, cap.bar, cap.offset, cap.length); + + switch (cap.cfg_type) { + case VIRTIO_PCI_CAP_COMMON_CFG: + hw->common_cfg = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_NOTIFY_CFG: + rte_eal_pci_read_config(dev, &hw->notify_off_multiplier, + 4, pos + sizeof(cap)); + hw->notify_base = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_DEVICE_CFG: + hw->dev_cfg = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_ISR_CFG: + hw->isr = get_cfg_addr(dev, &cap); + break; + } + + next: + pos = cap.cap_next; + } + + if (hw->common_cfg == NULL || hw->notify_base == NULL || + hw->dev_cfg == NULL || hw->isr == NULL) { + PMD_INIT_LOG(INFO, "no modern virtio pci device found."); + return -1; + } + + PMD_INIT_LOG(INFO, "found modern virtio pci device."); + + PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg); + PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg); + PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr); + PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u", + hw->notify_base, hw->notify_off_multiplier); + + return 0; +} + int vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) { - hw->vtpci_ops = &legacy_ops; + hw->dev = dev; + + /* + * Try if we can succeed reading virtio pci caps, which exists + * only on modern pci device. If failed, we fallback to legacy + * virtio handling. + */ + if (virtio_read_caps(dev, hw) == 0) { + PMD_INIT_LOG(INFO, "modern virtio pci detected."); + hw->vtpci_ops = &modern_ops; + hw->modern = 1; + dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; + return 0; + } + PMD_INIT_LOG(INFO, "trying with legacy virtio pci."); if (legacy_virtio_resource_init(dev) < 0) return -1; + + hw->vtpci_ops = &legacy_ops; hw->use_msix = legacy_virtio_has_msix(&dev->addr); hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr; + hw->modern = 0; return 0; } diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index 3fd86f6..6ade642 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -93,6 +93,7 @@ struct virtqueue; #define VIRTIO_CONFIG_STATUS_ACK 0x01 #define VIRTIO_CONFIG_STATUS_DRIVER 0x02 #define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04 +#define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08 #define VIRTIO_CONFIG_STATUS_FAILED 0x80 /* @@ -141,6 +142,8 @@ struct virtqueue; /* We support indirect buffer descriptors */ #define VIRTIO_RING_F_INDIRECT_DESC 28 +#define VIRTIO_F_VERSION_1 32 + /* * Some VirtIO feature bits (currently bits 28 through 31) are * reserved for the transport being used (eg. virtio_ring), the @@ -163,6 +166,60 @@ struct virtqueue; */ #define VIRTIO_MAX_VIRTQUEUES 8 +/* Common configuration */ +#define VIRTIO_PCI_CAP_COMMON_CFG 1 +/* Notifications */ +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 +/* ISR Status */ +#define VIRTIO_PCI_CAP_ISR_CFG 3 +/* Device specific configuration */ +#define VIRTIO_PCI_CAP_DEVICE_CFG 4 +/* PCI configuration access */ +#define VIRTIO_PCI_CAP_PCI_CFG 5 + +/* This is the PCI capability header: */ +struct virtio_pci_cap { + uint8_t cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */ + uint8_t cap_next; /* Generic PCI field: next ptr. */ + uint8_t cap_len; /* Generic PCI field: capability length */ + uint8_t cfg_type; /* Identifies the structure. */ + uint8_t bar; /* Where to find it. */ + uint8_t padding[3]; /* Pad to full dword. */ + uint32_t offset; /* Offset within bar. */ + uint32_t length; /* Length of the structure, in bytes. */ +}; + +struct virtio_pci_notify_cap { + struct virtio_pci_cap cap; + uint32_t notify_off_multiplier; /* Multiplier for queue_notify_off. */ +}; + +/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */ +struct virtio_pci_common_cfg { + /* About the whole device. */ + uint32_t device_feature_select; /* read-write */ + uint32_t device_feature; /* read-only */ + uint32_t guest_feature_select; /* read-write */ + uint32_t guest_feature; /* read-write */ + uint16_t msix_config; /* read-write */ + uint16_t num_queues; /* read-only */ + uint8_t device_status; /* read-write */ + uint8_t config_generation; /* read-only */ + + /* About a specific virtqueue. */ + uint16_t queue_select; /* read-write */ + uint16_t queue_size; /* read-write, power of 2. */ + uint16_t queue_msix_vector; /* read-write */ + uint16_t queue_enable; /* read-write */ + uint16_t queue_notify_off; /* read-only */ + uint32_t queue_desc_lo; /* read-write */ + uint32_t queue_desc_hi; /* read-write */ + uint32_t queue_avail_lo; /* read-write */ + uint32_t queue_avail_hi; /* read-write */ + uint32_t queue_used_lo; /* read-write */ + uint32_t queue_used_hi; /* read-write */ +}; + struct virtio_hw; struct virtio_pci_ops { @@ -188,6 +245,8 @@ struct virtio_pci_ops { void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq); }; +struct virtio_net_config; + struct virtio_hw { struct virtqueue *cvq; uint32_t io_base; @@ -198,7 +257,14 @@ struct virtio_hw { uint8_t vlan_strip; uint8_t use_msix; uint8_t started; + uint8_t modern; uint8_t mac_addr[ETHER_ADDR_LEN]; + uint32_t notify_off_multiplier; + uint8_t *isr; + uint16_t *notify_base; + struct rte_pci_device *dev; + struct virtio_pci_common_cfg *common_cfg; + struct virtio_net_config *dev_cfg; const struct virtio_pci_ops *vtpci_ops; }; @@ -284,6 +350,7 @@ void vtpci_reset(struct virtio_hw *); void vtpci_reinit_complete(struct virtio_hw *); +uint8_t vtpci_get_status(struct virtio_hw *); void vtpci_set_status(struct virtio_hw *, uint8_t); uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t); diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h index d7fb450..99d4fa9 100644 --- a/drivers/net/virtio/virtqueue.h +++ b/drivers/net/virtio/virtqueue.h @@ -202,6 +202,8 @@ struct virtqueue { /* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */ uint64_t size_bins[8]; + uint16_t *notify_addr; + struct vq_desc_extra { void *cookie; uint16_t ndescs; -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v3 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu ` (6 preceding siblings ...) 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 7/8] virtio: add 1.0 support Yuanhan Liu @ 2016-01-14 7:42 ` Yuanhan Liu 2016-01-16 10:08 ` Santosh Shukla 7 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2016-01-14 7:42 UTC (permalink / raw) To: dev; +Cc: Michael S. Tsirkin virtio_pci.c become the only file references those macros; move them there. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_pci.c | 19 +++++++++++++++++++ drivers/net/virtio/virtio_pci.h | 18 ------------------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 9b62013..8e26f00 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -49,6 +49,25 @@ #define PCI_CAPABILITY_LIST 0x34 #define PCI_CAP_ID_VNDR 0x09 + +#define VIRTIO_PCI_REG_ADDR(hw, reg) \ + (unsigned short)((hw)->io_base + (reg)) + +#define VIRTIO_READ_REG_1(hw, reg) \ + inb((VIRTIO_PCI_REG_ADDR((hw), (reg)))) +#define VIRTIO_WRITE_REG_1(hw, reg, value) \ + outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + +#define VIRTIO_READ_REG_2(hw, reg) \ + inw((VIRTIO_PCI_REG_ADDR((hw), (reg)))) +#define VIRTIO_WRITE_REG_2(hw, reg, value) \ + outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + +#define VIRTIO_READ_REG_4(hw, reg) \ + inl((VIRTIO_PCI_REG_ADDR((hw), (reg)))) +#define VIRTIO_WRITE_REG_4(hw, reg, value) \ + outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + static void legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset, void *dst, int length) diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index 6ade642..5400ebd 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -318,24 +318,6 @@ outl_p(unsigned int data, unsigned int port) } #endif -#define VIRTIO_PCI_REG_ADDR(hw, reg) \ - (unsigned short)((hw)->io_base + (reg)) - -#define VIRTIO_READ_REG_1(hw, reg) \ - inb((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_1(hw, reg, value) \ - outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - -#define VIRTIO_READ_REG_2(hw, reg) \ - inw((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_2(hw, reg, value) \ - outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - -#define VIRTIO_READ_REG_4(hw, reg) \ - inl((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_4(hw, reg, value) \ - outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - static inline int vtpci_with_feature(struct virtio_hw *hw, uint64_t bit) { -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v3 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu @ 2016-01-16 10:08 ` Santosh Shukla 2016-01-17 14:07 ` Santosh Shukla 0 siblings, 1 reply; 122+ messages in thread From: Santosh Shukla @ 2016-01-16 10:08 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev, Michael S. Tsirkin On Thu, Jan 14, 2016 at 1:12 PM, Yuanhan Liu <yuanhan.liu@linux.intel.com> wrote: > virtio_pci.c become the only file references those macros; move them there. > My patch VFIO series need virtio_rd/wr So keeping these api in virtio_pci.h make more sense to me. ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v3 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c 2016-01-16 10:08 ` Santosh Shukla @ 2016-01-17 14:07 ` Santosh Shukla 0 siblings, 0 replies; 122+ messages in thread From: Santosh Shukla @ 2016-01-17 14:07 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev, Michael S. Tsirkin On Sat, Jan 16, 2016 at 3:38 PM, Santosh Shukla <sshukla@mvista.com> wrote: > On Thu, Jan 14, 2016 at 1:12 PM, Yuanhan Liu > <yuanhan.liu@linux.intel.com> wrote: >> virtio_pci.c become the only file references those macros; move them there. >> > > My patch VFIO series need virtio_rd/wr So keeping these api in > virtio_pci.h make more sense to me. Ignore my comment, I just finished reading your patch series and wont see any potential issue in moving my vfio rd/wr api to vfio_pci.c. ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (9 preceding siblings ...) 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu @ 2016-01-15 4:36 ` Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu ` (9 more replies) 10 siblings, 10 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-15 4:36 UTC (permalink / raw) To: dev v4: - mark "src" arg as const for write_dev_cfg operation - remove unnessary inline, and likely/unlikely v3: - export pci_unmap_device as well; and invoke it at virtio uninit stage. - fixed same data corruption bug reported by Qian in simple rxtx code path. - move VIRTIO_READ/WRITE_REG_X to virtio_pci.c v2: - fix a data corruption reported by Qian, due to hdr size mismatch. check detailes at ptach 5. - Add missing config_irq and isr reading support from v1. - fix comments from v1. Almost all difference comes from virtio 1.0 are the PCI layout change: the major configuration structures are stored at bar space, and their location is stored at corresponding pci cap structure. Reading/parsing them is one of the major work of patch 7. To make handling virtio v1.0 and v0.95 co-exist well, this patch set introduces a virtio_pci_ops structure, to add another layer so that we could keep those vtpci_foo_bar "APIs". With that, we could do the minimum change to add virtio 1.0 support. Rough test guide ================ Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add option "disable-modern=false" to qemu virtio-net-pci device to enable virtio 1.0 (which is disabled by default). And if you see something like following from 'lspci -v', it means virtio 1.0 is indeed enabled: 00:04.0 Ethernet controller: Red Hat, Inc Virtio network device Subsystem: Red Hat, Inc Device 0001 Physical Slot: 4 Flags: bus master, fast devsel, latency 0, IRQ 11 I/O ports at c040 [size=64] Memory at febf1000 (32-bit, non-prefetchable) [size=4K] Memory at fe000000 (64-bit, prefetchable) [size=8M] Expansion ROM at feb80000 [disabled] [size=256K] Capabilities: [98] MSI-X: Enable+ Count=6 Masked- ==> Capabilities: [84] Vendor Specific Information: Len=14 <?> ==> Capabilities: [70] Vendor Specific Information: Len=14 <?> ==> Capabilities: [60] Vendor Specific Information: Len=10 <?> ==> Capabilities: [50] Vendor Specific Information: Len=10 <?> ==> Capabilities: [40] Vendor Specific Information: Len=10 <?> Kernel driver in use: virtio-pci Kernel modules: virtio_pci After that, there wasn't anything speical comparing to the old virtio 0.95 pmd driver. --- Yuanhan Liu (8): virtio: don't set vring address again at queue startup virtio: introduce struct virtio_pci_ops virtio: move left pci stuff to virtio_pci.c viritio: switch to 64 bit features virtio: retrieve hdr_size from hw->vtnet_hdr_size eal: pci: export pci_[un]map_device virtio: add 1.0 support virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c doc/guides/rel_notes/release_2_3.rst | 3 + drivers/net/virtio/virtio_ethdev.c | 302 +-------- drivers/net/virtio/virtio_ethdev.h | 3 +- drivers/net/virtio/virtio_pci.c | 793 +++++++++++++++++++++++- drivers/net/virtio/virtio_pci.h | 120 +++- drivers/net/virtio/virtio_rxtx.c | 21 +- drivers/net/virtio/virtio_rxtx_simple.c | 12 +- drivers/net/virtio/virtqueue.h | 4 +- lib/librte_eal/bsdapp/eal/eal_pci.c | 4 +- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 7 + lib/librte_eal/common/eal_common_pci.c | 4 +- lib/librte_eal/common/eal_private.h | 18 - lib/librte_eal/common/include/rte_pci.h | 27 + lib/librte_eal/linuxapp/eal/eal_pci.c | 4 +- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 + 15 files changed, 949 insertions(+), 380 deletions(-) -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v4 1/8] virtio: don't set vring address again at queue startup 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu @ 2016-01-15 4:36 ` Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 2/8] virtio: introduce struct virtio_pci_ops Yuanhan Liu ` (8 subsequent siblings) 9 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-15 4:36 UTC (permalink / raw) To: dev As we have already set up it at virtio_dev_queue_setup(), and a vq restart will not reset the settings. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_rxtx.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c index 74b39ef..b7267c0 100644 --- a/drivers/net/virtio/virtio_rxtx.c +++ b/drivers/net/virtio/virtio_rxtx.c @@ -339,11 +339,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type) vq_update_avail_idx(vq); PMD_INIT_LOG(DEBUG, "Allocated %d bufs", nbufs); - - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); } else if (queue_type == VTNET_TQ) { if (use_simple_rxtx) { int mid_idx = vq->vq_nentries >> 1; @@ -362,16 +357,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type) for (i = mid_idx; i < vq->vq_nentries; i++) vq->vq_ring.avail->ring[i] = i; } - - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); - } else { - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); } } -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v4 2/8] virtio: introduce struct virtio_pci_ops 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu @ 2016-01-15 4:36 ` Yuanhan Liu 2016-01-18 17:21 ` Xie, Huawei 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 3/8] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu ` (7 subsequent siblings) 9 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2016-01-15 4:36 UTC (permalink / raw) To: dev 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> --- 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 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v4 2/8] virtio: introduce struct virtio_pci_ops 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 2/8] virtio: introduce struct virtio_pci_ops Yuanhan Liu @ 2016-01-18 17:21 ` Xie, Huawei 0 siblings, 0 replies; 122+ messages in thread From: Xie, Huawei @ 2016-01-18 17:21 UTC (permalink / raw) To: Yuanhan Liu, dev On 1/15/2016 12:34 PM, Yuanhan Liu wrote: > +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); missed changing src to const. > +} ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v4 3/8] virtio: move left pci stuff to virtio_pci.c 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 2/8] virtio: introduce struct virtio_pci_ops Yuanhan Liu @ 2016-01-15 4:36 ` Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 4/8] viritio: switch to 64 bit features Yuanhan Liu ` (6 subsequent siblings) 9 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-15 4:36 UTC (permalink / raw) To: dev virtio_pci.c is a more proper place for pci stuff; virtio_ethdev is not. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_ethdev.c | 265 +----------------------------------- drivers/net/virtio/virtio_pci.c | 270 ++++++++++++++++++++++++++++++++++++- 2 files changed, 270 insertions(+), 265 deletions(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 6c1d3a0..b57224d 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -36,10 +36,6 @@ #include <stdio.h> #include <errno.h> #include <unistd.h> -#ifdef RTE_EXEC_ENV_LINUXAPP -#include <dirent.h> -#include <fcntl.h> -#endif #include <rte_ethdev.h> #include <rte_memcpy.h> @@ -955,260 +951,6 @@ virtio_negotiate_features(struct virtio_hw *hw) hw->guest_features); } -#ifdef RTE_EXEC_ENV_LINUXAPP -static int -parse_sysfs_value(const char *filename, unsigned long *val) -{ - FILE *f; - char buf[BUFSIZ]; - char *end = NULL; - - f = fopen(filename, "r"); - if (f == NULL) { - PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s", - __func__, filename); - return -1; - } - - if (fgets(buf, sizeof(buf), f) == NULL) { - PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s", - __func__, filename); - fclose(f); - return -1; - } - *val = strtoul(buf, &end, 0); - if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { - PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s", - __func__, filename); - fclose(f); - return -1; - } - fclose(f); - return 0; -} - -static int get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen, - unsigned int *uio_num) -{ - struct dirent *e; - DIR *dir; - char dirname[PATH_MAX]; - - /* depending on kernel version, uio can be located in uio/uioX - * or uio:uioX */ - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", - loc->domain, loc->bus, loc->devid, loc->function); - dir = opendir(dirname); - if (dir == NULL) { - /* retry with the parent directory */ - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, - loc->domain, loc->bus, loc->devid, loc->function); - dir = opendir(dirname); - - if (dir == NULL) { - PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname); - return -1; - } - } - - /* take the first file starting with "uio" */ - while ((e = readdir(dir)) != NULL) { - /* format could be uio%d ...*/ - int shortprefix_len = sizeof("uio") - 1; - /* ... or uio:uio%d */ - int longprefix_len = sizeof("uio:uio") - 1; - char *endptr; - - if (strncmp(e->d_name, "uio", 3) != 0) - continue; - - /* first try uio%d */ - errno = 0; - *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); - if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { - snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num); - break; - } - - /* then try uio:uio%d */ - errno = 0; - *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); - if (errno == 0 && endptr != (e->d_name + longprefix_len)) { - snprintf(buf, buflen, "%s/uio:uio%u", dirname, - *uio_num); - break; - } - } - closedir(dir); - - /* No uio resource found */ - if (e == NULL) { - PMD_INIT_LOG(ERR, "Could not find uio resource"); - return -1; - } - - return 0; -} - -static int -virtio_has_msix(const struct rte_pci_addr *loc) -{ - DIR *d; - char dirname[PATH_MAX]; - - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs", - loc->domain, loc->bus, loc->devid, loc->function); - - d = opendir(dirname); - if (d) - closedir(d); - - return (d != NULL); -} - -/* Extract I/O port numbers from sysfs */ -static int virtio_resource_init_by_uio(struct rte_pci_device *pci_dev) -{ - char dirname[PATH_MAX]; - char filename[PATH_MAX]; - unsigned long start, size; - unsigned int uio_num; - - if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0) - return -1; - - /* get portio size */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/size", dirname); - if (parse_sysfs_value(filename, &size) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse size", - __func__); - return -1; - } - - /* get portio start */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/start", dirname); - if (parse_sysfs_value(filename, &start) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", - __func__); - return -1; - } - pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; - pci_dev->mem_resource[0].len = (uint64_t)size; - PMD_INIT_LOG(DEBUG, - "PCI Port IO found start=0x%lx with size=0x%lx", - start, size); - - /* save fd */ - memset(dirname, 0, sizeof(dirname)); - snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num); - pci_dev->intr_handle.fd = open(dirname, O_RDWR); - if (pci_dev->intr_handle.fd < 0) { - PMD_INIT_LOG(ERR, "Cannot open %s: %s\n", - dirname, strerror(errno)); - return -1; - } - - pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO; - pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; - - return 0; -} - -/* Extract port I/O numbers from proc/ioports */ -static int virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev) -{ - uint16_t start, end; - int size; - FILE *fp; - char *line = NULL; - char pci_id[16]; - int found = 0; - size_t linesz; - - snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, - pci_dev->addr.domain, - pci_dev->addr.bus, - pci_dev->addr.devid, - pci_dev->addr.function); - - fp = fopen("/proc/ioports", "r"); - if (fp == NULL) { - PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__); - return -1; - } - - while (getdelim(&line, &linesz, '\n', fp) > 0) { - char *ptr = line; - char *left; - int n; - - n = strcspn(ptr, ":"); - ptr[n] = 0; - left = &ptr[n+1]; - - while (*left && isspace(*left)) - left++; - - if (!strncmp(left, pci_id, strlen(pci_id))) { - found = 1; - - while (*ptr && isspace(*ptr)) - ptr++; - - sscanf(ptr, "%04hx-%04hx", &start, &end); - size = end - start + 1; - - break; - } - } - - free(line); - fclose(fp); - - if (!found) - return -1; - - pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start; - pci_dev->mem_resource[0].len = (uint64_t)size; - PMD_INIT_LOG(DEBUG, - "PCI Port IO found start=0x%x with size=0x%x", - start, size); - - /* can't support lsc interrupt without uio */ - pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; - - return 0; -} - -/* Extract I/O port numbers from sysfs */ -static int virtio_resource_init(struct rte_pci_device *pci_dev) -{ - if (virtio_resource_init_by_uio(pci_dev) == 0) - return 0; - else - return virtio_resource_init_by_ioports(pci_dev); -} - -#else -static int -virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) -{ - /* nic_uio does not enable interrupts, return 0 (false). */ - return 0; -} - -static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) -{ - /* no setup required */ - return 0; -} -#endif - /* * Process Virtio Config changed interrupt and call the callback * if link state changed. @@ -1279,14 +1021,9 @@ 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) + if (vtpci_init(pci_dev, hw) < 0) return -1; - hw->use_msix = virtio_has_msix(&pci_dev->addr); - hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr; - /* Reset the device although not necessary at startup */ vtpci_reset(hw); diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 9907fd0..95aa47d 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -32,6 +32,11 @@ */ #include <stdint.h> +#ifdef RTE_EXEC_ENV_LINUXAPP + #include <dirent.h> + #include <fcntl.h> +#endif + #include "virtio_pci.h" #include "virtio_logs.h" #include "virtqueue.h" @@ -156,6 +161,264 @@ legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq) VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index); } +#ifdef RTE_EXEC_ENV_LINUXAPP +static int +parse_sysfs_value(const char *filename, unsigned long *val) +{ + FILE *f; + char buf[BUFSIZ]; + char *end = NULL; + + f = fopen(filename, "r"); + if (f == NULL) { + PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s", + __func__, filename); + return -1; + } + + if (fgets(buf, sizeof(buf), f) == NULL) { + PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s", + __func__, filename); + fclose(f); + return -1; + } + *val = strtoul(buf, &end, 0); + if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { + PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s", + __func__, filename); + fclose(f); + return -1; + } + fclose(f); + return 0; +} + +static int +get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen, + unsigned int *uio_num) +{ + struct dirent *e; + DIR *dir; + char dirname[PATH_MAX]; + + /* depending on kernel version, uio can be located in uio/uioX + * or uio:uioX */ + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", + loc->domain, loc->bus, loc->devid, loc->function); + dir = opendir(dirname); + if (dir == NULL) { + /* retry with the parent directory */ + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, + loc->domain, loc->bus, loc->devid, loc->function); + dir = opendir(dirname); + + if (dir == NULL) { + PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname); + return -1; + } + } + + /* take the first file starting with "uio" */ + while ((e = readdir(dir)) != NULL) { + /* format could be uio%d ...*/ + int shortprefix_len = sizeof("uio") - 1; + /* ... or uio:uio%d */ + int longprefix_len = sizeof("uio:uio") - 1; + char *endptr; + + if (strncmp(e->d_name, "uio", 3) != 0) + continue; + + /* first try uio%d */ + errno = 0; + *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); + if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { + snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num); + break; + } + + /* then try uio:uio%d */ + errno = 0; + *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); + if (errno == 0 && endptr != (e->d_name + longprefix_len)) { + snprintf(buf, buflen, "%s/uio:uio%u", dirname, + *uio_num); + break; + } + } + closedir(dir); + + /* No uio resource found */ + if (e == NULL) { + PMD_INIT_LOG(ERR, "Could not find uio resource"); + return -1; + } + + return 0; +} + +static int +legacy_virtio_has_msix(const struct rte_pci_addr *loc) +{ + DIR *d; + char dirname[PATH_MAX]; + + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs", + loc->domain, loc->bus, loc->devid, loc->function); + + d = opendir(dirname); + if (d) + closedir(d); + + return (d != NULL); +} + +/* Extract I/O port numbers from sysfs */ +static int +virtio_resource_init_by_uio(struct rte_pci_device *pci_dev) +{ + char dirname[PATH_MAX]; + char filename[PATH_MAX]; + unsigned long start, size; + unsigned int uio_num; + + if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0) + return -1; + + /* get portio size */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/size", dirname); + if (parse_sysfs_value(filename, &size) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse size", + __func__); + return -1; + } + + /* get portio start */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/start", dirname); + if (parse_sysfs_value(filename, &start) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", + __func__); + return -1; + } + pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; + pci_dev->mem_resource[0].len = (uint64_t)size; + PMD_INIT_LOG(DEBUG, + "PCI Port IO found start=0x%lx with size=0x%lx", + start, size); + + /* save fd */ + memset(dirname, 0, sizeof(dirname)); + snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num); + pci_dev->intr_handle.fd = open(dirname, O_RDWR); + if (pci_dev->intr_handle.fd < 0) { + PMD_INIT_LOG(ERR, "Cannot open %s: %s\n", + dirname, strerror(errno)); + return -1; + } + + pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO; + pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; + + return 0; +} + +/* Extract port I/O numbers from proc/ioports */ +static int +virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev) +{ + uint16_t start, end; + int size; + FILE *fp; + char *line = NULL; + char pci_id[16]; + int found = 0; + size_t linesz; + + snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, + pci_dev->addr.domain, + pci_dev->addr.bus, + pci_dev->addr.devid, + pci_dev->addr.function); + + fp = fopen("/proc/ioports", "r"); + if (fp == NULL) { + PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__); + return -1; + } + + while (getdelim(&line, &linesz, '\n', fp) > 0) { + char *ptr = line; + char *left; + int n; + + n = strcspn(ptr, ":"); + ptr[n] = 0; + left = &ptr[n+1]; + + while (*left && isspace(*left)) + left++; + + if (!strncmp(left, pci_id, strlen(pci_id))) { + found = 1; + + while (*ptr && isspace(*ptr)) + ptr++; + + sscanf(ptr, "%04hx-%04hx", &start, &end); + size = end - start + 1; + + break; + } + } + + free(line); + fclose(fp); + + if (!found) + return -1; + + pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start; + pci_dev->mem_resource[0].len = (uint64_t)size; + PMD_INIT_LOG(DEBUG, + "PCI Port IO found start=0x%x with size=0x%x", + start, size); + + /* can't support lsc interrupt without uio */ + pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; + + return 0; +} + +/* Extract I/O port numbers from sysfs */ +static int +legacy_virtio_resource_init(struct rte_pci_device *pci_dev) +{ + if (virtio_resource_init_by_uio(pci_dev) == 0) + return 0; + else + return virtio_resource_init_by_ioports(pci_dev); +} + +#else +static int +legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) +{ + /* nic_uio does not enable interrupts, return 0 (false). */ + return 0; +} + +static int +legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) +{ + /* no setup required */ + return 0; +} +#endif static const struct virtio_pci_ops legacy_ops = { .read_dev_cfg = legacy_read_dev_config, @@ -241,9 +504,14 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) } int -vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw) +vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) { hw->vtpci_ops = &legacy_ops; + if (legacy_virtio_resource_init(dev) < 0) + return -1; + hw->use_msix = legacy_virtio_has_msix(&dev->addr); + hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr; + return 0; } -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v4 4/8] viritio: switch to 64 bit features 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (2 preceding siblings ...) 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 3/8] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu @ 2016-01-15 4:36 ` Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu ` (5 subsequent siblings) 9 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-15 4:36 UTC (permalink / raw) To: dev Switch to 64 bit features, which virtio 1.0 supports. While legacy virtio only supports 32 bit features, it complains aloud and quit when trying to setting > 32 bit features. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_ethdev.c | 8 ++++---- drivers/net/virtio/virtio_pci.c | 15 ++++++++++----- drivers/net/virtio/virtio_pci.h | 12 ++++++------ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index b57224d..94e0c4a 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -930,16 +930,16 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) static void virtio_negotiate_features(struct virtio_hw *hw) { - uint32_t host_features; + uint64_t host_features; /* Prepare guest_features: feature that driver wants to support */ hw->guest_features = VIRTIO_PMD_GUEST_FEATURES; - PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %x", + PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %"PRIx64, hw->guest_features); /* Read device(host) feature bits */ host_features = hw->vtpci_ops->get_features(hw); - PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x", + PMD_INIT_LOG(DEBUG, "host_features before negotiate = %"PRIx64, host_features); /* @@ -947,7 +947,7 @@ virtio_negotiate_features(struct virtio_hw *hw) * guest feature bits. */ hw->guest_features = vtpci_negotiate_features(hw, host_features); - PMD_INIT_LOG(DEBUG, "features after negotiate = %x", + PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, hw->guest_features); } diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 95aa47d..a903316 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -87,15 +87,20 @@ legacy_write_dev_config(struct virtio_hw *hw, uint64_t offset, } } -static uint32_t +static uint64_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) +legacy_set_features(struct virtio_hw *hw, uint64_t features) { + if ((features >> 32) != 0) { + PMD_DRV_LOG(ERR, + "only 32 bit features are allowed for legacy virtio!"); + return; + } VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features); } @@ -451,10 +456,10 @@ vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset, hw->vtpci_ops->write_dev_cfg(hw, offset, src, length); } -uint32_t -vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features) +uint64_t +vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features) { - uint32_t features; + uint64_t features; /* * Limit negotiated features to what the driver, virtqueue, and diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index 2064af0..17312f6 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -175,8 +175,8 @@ struct virtio_pci_ops { 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); + uint64_t (*get_features)(struct virtio_hw *hw); + void (*set_features)(struct virtio_hw *hw, uint64_t features); uint8_t (*get_isr)(struct virtio_hw *hw); @@ -191,7 +191,7 @@ struct virtio_pci_ops { struct virtio_hw { struct virtqueue *cvq; uint32_t io_base; - uint32_t guest_features; + uint64_t guest_features; uint32_t max_tx_queues; uint32_t max_rx_queues; uint16_t vtnet_hdr_size; @@ -271,9 +271,9 @@ outl_p(unsigned int data, unsigned int port) outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) static inline int -vtpci_with_feature(struct virtio_hw *hw, uint32_t bit) +vtpci_with_feature(struct virtio_hw *hw, uint64_t bit) { - return (hw->guest_features & (1u << bit)) != 0; + return (hw->guest_features & (1ULL << bit)) != 0; } /* @@ -286,7 +286,7 @@ void vtpci_reinit_complete(struct virtio_hw *); void vtpci_set_status(struct virtio_hw *, uint8_t); -uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t); +uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t); void vtpci_write_dev_config(struct virtio_hw *, uint64_t, void *, int); -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v4 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (3 preceding siblings ...) 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 4/8] viritio: switch to 64 bit features Yuanhan Liu @ 2016-01-15 4:36 ` Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 6/8] eal: pci: export pci_[un]map_device Yuanhan Liu ` (4 subsequent siblings) 9 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-15 4:36 UTC (permalink / raw) To: dev The mergeable virtio net hdr format has been the standard and the only virtio net hdr format since virtio 1.0. Therefore, we can not hardcode hdr_size to "sizeof(struct virtio_net_hdr)" any more at virtio_recv_pkts(), otherwise, there would be a mismatch of hdr size from rte_vhost_enqueue_burst() and virtio_recv_pkts(), leading a packet corruption. Instead, we should retrieve it from hw->vtnet_hdr_size; we will do proper settings at eth_virtio_dev_init() in later patches. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- v3: retrieve hdr_size from hw->vtnet_hdr_size for simple rxtx code path as well: it should not break anything, as simple rx and mergeable rx still will not co-exist. --- drivers/net/virtio/virtio_rxtx.c | 6 ++++-- drivers/net/virtio/virtio_rxtx_simple.c | 12 ++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c index b7267c0..41a1366 100644 --- a/drivers/net/virtio/virtio_rxtx.c +++ b/drivers/net/virtio/virtio_rxtx.c @@ -560,7 +560,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ]; int error; uint32_t i, nb_enqueued; - const uint32_t hdr_size = sizeof(struct virtio_net_hdr); + uint32_t hdr_size; nb_used = VIRTQUEUE_NUSED(rxvq); @@ -580,6 +580,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) hw = rxvq->hw; nb_rx = 0; nb_enqueued = 0; + hdr_size = hw->vtnet_hdr_size; for (i = 0; i < num ; i++) { rxm = rcv_pkts[i]; @@ -664,7 +665,7 @@ virtio_recv_mergeable_pkts(void *rx_queue, uint32_t seg_num; uint16_t extra_idx; uint32_t seg_res; - const uint32_t hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); + uint32_t hdr_size; nb_used = VIRTQUEUE_NUSED(rxvq); @@ -682,6 +683,7 @@ virtio_recv_mergeable_pkts(void *rx_queue, seg_num = 0; extra_idx = 0; seg_res = 0; + hdr_size = hw->vtnet_hdr_size; while (i < nb_used) { struct virtio_net_hdr_mrg_rxbuf *header; diff --git a/drivers/net/virtio/virtio_rxtx_simple.c b/drivers/net/virtio/virtio_rxtx_simple.c index ff3c11a..3e66e8b 100644 --- a/drivers/net/virtio/virtio_rxtx_simple.c +++ b/drivers/net/virtio/virtio_rxtx_simple.c @@ -81,9 +81,9 @@ virtqueue_enqueue_recv_refill_simple(struct virtqueue *vq, start_dp = vq->vq_ring.desc; start_dp[desc_idx].addr = (uint64_t)((uintptr_t)cookie->buf_physaddr + - RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr)); + RTE_PKTMBUF_HEADROOM - vq->hw->vtnet_hdr_size); start_dp[desc_idx].len = cookie->buf_len - - RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr); + RTE_PKTMBUF_HEADROOM + vq->hw->vtnet_hdr_size; vq->vq_free_cnt--; vq->vq_avail_idx++; @@ -120,9 +120,9 @@ virtio_rxq_rearm_vec(struct virtqueue *rxvq) start_dp[i].addr = (uint64_t)((uintptr_t)sw_ring[i]->buf_physaddr + - RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr)); + RTE_PKTMBUF_HEADROOM - rxvq->hw->vtnet_hdr_size); start_dp[i].len = sw_ring[i]->buf_len - - RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr); + RTE_PKTMBUF_HEADROOM + rxvq->hw->vtnet_hdr_size; } rxvq->vq_avail_idx += RTE_VIRTIO_VPMD_RX_REARM_THRESH; @@ -175,8 +175,8 @@ virtio_recv_pkts_vec(void *rx_queue, struct rte_mbuf **rx_pkts, len_adjust = _mm_set_epi16( 0, 0, 0, - (uint16_t) -sizeof(struct virtio_net_hdr), - 0, (uint16_t) -sizeof(struct virtio_net_hdr), + (uint16_t) -rxvq->hw->vtnet_hdr_size, + 0, (uint16_t) -rxvq->hw->vtnet_hdr_size, 0, 0); if (unlikely(nb_pkts < RTE_VIRTIO_DESC_PER_LOOP)) -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v4 6/8] eal: pci: export pci_[un]map_device 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (4 preceding siblings ...) 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu @ 2016-01-15 4:36 ` Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support Yuanhan Liu ` (3 subsequent siblings) 9 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-15 4:36 UTC (permalink / raw) To: dev Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will invoke pci_map_device internally for us. From that point view, there is no need to export pci_map_device. However, for virtio pmd driver, which is designed to work without binding UIO (or something similar first), pci_map_device() will fail, which ends up with virtio pmd driver being skipped. Therefore, we can not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver. Therefore, this patch exports pci_map_device, and let virtio pmd call it when necessary. Cc: David Marchand <david.marchand@6wind.com> Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> Tested-By: Santosh Shukla <sshukla@mvista.com> --- v3: - export pci_unmap_device as well - Add few more comments about rte_eal_pci_map_device(). --- lib/librte_eal/bsdapp/eal/eal_pci.c | 4 ++-- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 7 +++++++ lib/librte_eal/common/eal_common_pci.c | 4 ++-- lib/librte_eal/common/eal_private.h | 18 ----------------- lib/librte_eal/common/include/rte_pci.h | 27 +++++++++++++++++++++++++ lib/librte_eal/linuxapp/eal/eal_pci.c | 4 ++-- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +++++++ 7 files changed, 47 insertions(+), 24 deletions(-) diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c index 6c21fbd..95c32c1 100644 --- a/lib/librte_eal/bsdapp/eal/eal_pci.c +++ b/lib/librte_eal/bsdapp/eal/eal_pci.c @@ -93,7 +93,7 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused) /* Map pci device */ int -pci_map_device(struct rte_pci_device *dev) +rte_eal_pci_map_device(struct rte_pci_device *dev) { int ret = -1; @@ -115,7 +115,7 @@ pci_map_device(struct rte_pci_device *dev) /* Unmap pci device */ void -pci_unmap_device(struct rte_pci_device *dev) +rte_eal_pci_unmap_device(struct rte_pci_device *dev) { /* try unmapping the NIC resources */ switch (dev->kdrv) { diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map index 9d7adf1..1b28170 100644 --- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map +++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map @@ -135,3 +135,10 @@ DPDK_2.2 { rte_xen_dom0_supported; } DPDK_2.1; + +DPDK_2.3 { + global: + + rte_eal_pci_map_device; + rte_eal_pci_unmap_device; +} DPDK_2.2; diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c index dcfe947..96d5113 100644 --- a/lib/librte_eal/common/eal_common_pci.c +++ b/lib/librte_eal/common/eal_common_pci.c @@ -188,7 +188,7 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d pci_config_space_set(dev); #endif /* map resources for devices that use igb_uio */ - ret = pci_map_device(dev); + ret = rte_eal_pci_map_device(dev); if (ret != 0) return ret; } else if (dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND && @@ -254,7 +254,7 @@ rte_eal_pci_detach_dev(struct rte_pci_driver *dr, if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING) /* unmap resources for devices that use igb_uio */ - pci_unmap_device(dev); + rte_eal_pci_unmap_device(dev); return 0; } diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h index 072e672..2342fa1 100644 --- a/lib/librte_eal/common/eal_private.h +++ b/lib/librte_eal/common/eal_private.h @@ -165,24 +165,6 @@ struct rte_pci_device; int pci_unbind_kernel_driver(struct rte_pci_device *dev); /** - * Map this device - * - * This function is private to EAL. - * - * @return - * 0 on success, negative on error and positive if no driver - * is found for the device. - */ -int pci_map_device(struct rte_pci_device *dev); - -/** - * Unmap this device - * - * This function is private to EAL. - */ -void pci_unmap_device(struct rte_pci_device *dev); - -/** * Map the PCI resource of a PCI device in virtual memory * * This function is private to EAL. diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h index 334c12e..2224109 100644 --- a/lib/librte_eal/common/include/rte_pci.h +++ b/lib/librte_eal/common/include/rte_pci.h @@ -485,6 +485,33 @@ int rte_eal_pci_read_config(const struct rte_pci_device *device, */ int rte_eal_pci_write_config(const struct rte_pci_device *device, const void *buf, size_t len, off_t offset); +/** + * Map the PCI device resources in user space virtual memory address + * + * Note that driver should not call this function when flag + * RTE_PCI_DRV_NEED_MAPPING is set, as EAL will do that for + * you when it's on. + * + * @param dev + * A pointer to a rte_pci_device structure describing the device + * to use + * + * @return + * 0 on success, negative on error and positive if no driver + * is found for the device. + */ +int rte_eal_pci_map_device(struct rte_pci_device *dev); + +/** + * Unmap this device + * + * @param dev + * A pointer to a rte_pci_device structure describing the device + * to use + */ +void rte_eal_pci_unmap_device(struct rte_pci_device *dev); + + #ifdef RTE_PCI_CONFIG /** diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c index bc5b5be..db947da 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c @@ -124,7 +124,7 @@ pci_get_kernel_driver_by_path(const char *filename, char *dri_name) /* Map pci device */ int -pci_map_device(struct rte_pci_device *dev) +rte_eal_pci_map_device(struct rte_pci_device *dev) { int ret = -1; @@ -153,7 +153,7 @@ pci_map_device(struct rte_pci_device *dev) /* Unmap pci device */ void -pci_unmap_device(struct rte_pci_device *dev) +rte_eal_pci_unmap_device(struct rte_pci_device *dev) { /* try unmapping the NIC resources using VFIO if it exists */ switch (dev->kdrv) { diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map index cbe175f..b9937c4 100644 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map @@ -138,3 +138,10 @@ DPDK_2.2 { rte_xen_dom0_supported; } DPDK_2.1; + +DPDK_2.3 { + global: + + rte_eal_pci_map_device; + rte_eal_pci_unmap_device; +} DPDK_2.2; -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (5 preceding siblings ...) 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 6/8] eal: pci: export pci_[un]map_device Yuanhan Liu @ 2016-01-15 4:36 ` Yuanhan Liu 2016-01-18 16:38 ` Xie, Huawei ` (2 more replies) 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu ` (2 subsequent siblings) 9 siblings, 3 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-15 4:36 UTC (permalink / raw) To: dev Modern (v1.0) virtio pci device defines several pci capabilities. Each cap has a configure structure corresponding to it, and the cap.bar and cap.offset fields tell us where to find it. Firstly, we map the pci resources by rte_eal_pci_map_device(). We then could easily locate a cfg structure by: cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset; Therefore, the entrance of enabling modern (v1.0) pci device support is to iterate the pci capability lists, and to locate some configs we care; and they are: - common cfg For generic virtio and virtqueue configuration, such as setting/getting features, enabling a specific queue, and so on. - nofity cfg Combining with `queue_notify_off' from common cfg, we could use it to notify a specific virt queue. - device cfg Where virtio_net_config structure is located. - isr cfg Where to read isr (interrupt status). If any of above cap is not found, we fallback to the legacy virtio handling. If succeed, hw->vtpci_ops is assigned to modern_ops, where all operations are implemented by reading/writing a (or few) specific configuration space from above 4 cfg structures. And that's basically how this patch works. Besides those changes, virtio 1.0 introduces a new status field: FEATURES_OK, which is set after features negotiation is done. Last, set the VIRTIO_F_VERSION_1 feature flag. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- v2: - re-read status after setting FEATURES_OK to make sure status is set correctly. - Add isr reading and config irq setting support. - Define some pci macro on our own to not get the dependency of linux/pci_regs.h, as there should be no such file at non-Linux platform v3: - invoke rte_eal_pci_unmap_device() at uninit stage v4: - remove unnessary inline, and likely/unlikely - mark "src" arg as const for write_dev_cfg operation --- doc/guides/rel_notes/release_2_3.rst | 3 + drivers/net/virtio/virtio_ethdev.c | 25 ++- drivers/net/virtio/virtio_ethdev.h | 3 +- drivers/net/virtio/virtio_pci.c | 335 ++++++++++++++++++++++++++++++++++- drivers/net/virtio/virtio_pci.h | 67 +++++++ drivers/net/virtio/virtqueue.h | 2 + 6 files changed, 430 insertions(+), 5 deletions(-) diff --git a/doc/guides/rel_notes/release_2_3.rst b/doc/guides/rel_notes/release_2_3.rst index 99de186..c390d97 100644 --- a/doc/guides/rel_notes/release_2_3.rst +++ b/doc/guides/rel_notes/release_2_3.rst @@ -4,6 +4,9 @@ DPDK Release 2.3 New Features ------------ +* **Virtio 1.0 support.** + + Enabled virtio 1.0 support for virtio pmd driver. Resolved Issues --------------- diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 94e0c4a..deb0382 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) return virtio_send_command(hw->cvq, &ctrl, &len, 1); } -static void +static int virtio_negotiate_features(struct virtio_hw *hw) { uint64_t host_features; @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw) hw->guest_features = vtpci_negotiate_features(hw, host_features); PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, hw->guest_features); + + if (hw->modern) { + if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) { + PMD_INIT_LOG(ERR, + "VIRTIO_F_VERSION_1 features is not enabled."); + return -1; + } + vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK); + if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) { + PMD_INIT_LOG(ERR, + "failed to set FEATURES_OK status!"); + return -1; + } + } + + return 0; } /* @@ -1032,7 +1048,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev) /* Tell the host we've known how to drive the device. */ vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER); - virtio_negotiate_features(hw); + if (virtio_negotiate_features(hw) < 0) + return -1; /* If host does not support status then disable LSC */ if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) @@ -1043,7 +1060,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev) rx_func_get(eth_dev); /* Setting up rx_header size for the device */ - if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) + if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) || + vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); else hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr); @@ -1159,6 +1177,7 @@ eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev) rte_intr_callback_unregister(&pci_dev->intr_handle, virtio_interrupt_handler, eth_dev); + rte_eal_pci_unmap_device(pci_dev); PMD_INIT_LOG(DEBUG, "dev_uninit completed"); diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h index ae2d47d..fed9571 100644 --- a/drivers/net/virtio/virtio_ethdev.h +++ b/drivers/net/virtio/virtio_ethdev.h @@ -64,7 +64,8 @@ 1u << VIRTIO_NET_F_CTRL_VQ | \ 1u << VIRTIO_NET_F_CTRL_RX | \ 1u << VIRTIO_NET_F_CTRL_VLAN | \ - 1u << VIRTIO_NET_F_MRG_RXBUF) + 1u << VIRTIO_NET_F_MRG_RXBUF | \ + 1ULL << VIRTIO_F_VERSION_1) /* * CQ function prototype diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index a903316..fe8d6a2 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -41,6 +41,14 @@ #include "virtio_logs.h" #include "virtqueue.h" +/* + * Following macros are derieved from linux/pci_regs.h, however, + * we can't simply include that header here, as there is no such + * file for non-Linux platform. + */ +#define PCI_CAPABILITY_LIST 0x34 +#define PCI_CAP_ID_VNDR 0x09 + static void legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset, void *dst, int length) @@ -442,6 +450,204 @@ static const struct virtio_pci_ops legacy_ops = { }; +#define MODERN_READ_DEF(nr_bits, type) \ +static inline type \ +io_read##nr_bits(type *addr) \ +{ \ + return *(volatile type *)addr; \ +} + +#define MODERN_WRITE_DEF(nr_bits, type) \ +static inline void \ +io_write##nr_bits(type val, type *addr) \ +{ \ + *(volatile type *)addr = val; \ +} + +MODERN_READ_DEF (8, uint8_t) +MODERN_WRITE_DEF(8, uint8_t) + +MODERN_READ_DEF (16, uint16_t) +MODERN_WRITE_DEF(16, uint16_t) + +MODERN_READ_DEF (32, uint32_t) +MODERN_WRITE_DEF(32, uint32_t) + +static inline void +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) +{ + io_write32((uint32_t)val, lo); + io_write32(val >> 32, hi); +} + +static void +modern_read_dev_config(struct virtio_hw *hw, uint64_t offset, + void *dst, int length) +{ + int i; + uint8_t *p; + uint8_t old_gen, new_gen; + + do { + old_gen = io_read8(&hw->common_cfg->config_generation); + + p = dst; + for (i = 0; i < length; i++) + *p++ = io_read8((uint8_t *)hw->dev_cfg + offset + i); + + new_gen = io_read8(&hw->common_cfg->config_generation); + } while (old_gen != new_gen); +} + +static void +modern_write_dev_config(struct virtio_hw *hw, uint64_t offset, + const void *src, int length) +{ + int i; + const uint8_t *p = src; + + for (i = 0; i < length; i++) + io_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i); +} + +static uint64_t +modern_get_features(struct virtio_hw *hw) +{ + uint32_t features_lo, features_hi; + + io_write32(0, &hw->common_cfg->device_feature_select); + features_lo = io_read32(&hw->common_cfg->device_feature); + + io_write32(1, &hw->common_cfg->device_feature_select); + features_hi = io_read32(&hw->common_cfg->device_feature); + + return ((uint64_t)(features_hi) << 32) | features_lo; +} + +static void +modern_set_features(struct virtio_hw *hw, uint64_t features) +{ + io_write32(0, &hw->common_cfg->guest_feature_select); + io_write32(features & ((1ULL << 32) - 1), + &hw->common_cfg->guest_feature); + + io_write32(1, &hw->common_cfg->guest_feature_select); + io_write32(features >> 32, + &hw->common_cfg->guest_feature); +} + +static uint8_t +modern_get_status(struct virtio_hw *hw) +{ + return io_read8(&hw->common_cfg->device_status); +} + +static void +modern_set_status(struct virtio_hw *hw, uint8_t status) +{ + io_write8(status, &hw->common_cfg->device_status); +} + +static void +modern_reset(struct virtio_hw *hw) +{ + modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); + modern_get_status(hw); +} + +static uint8_t +modern_get_isr(struct virtio_hw *hw) +{ + return io_read8(hw->isr); +} + +static uint16_t +modern_set_config_irq(struct virtio_hw *hw, uint16_t vec) +{ + io_write16(vec, &hw->common_cfg->msix_config); + return io_read16(&hw->common_cfg->msix_config); +} + +static uint16_t +modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) +{ + io_write16(queue_id, &hw->common_cfg->queue_select); + return io_read16(&hw->common_cfg->queue_size); +} + +static void +modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + uint64_t desc_addr, avail_addr, used_addr; + uint16_t notify_off; + + desc_addr = vq->mz->phys_addr; + avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc); + used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail, + ring[vq->vq_nentries]), + VIRTIO_PCI_VRING_ALIGN); + + io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); + + io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + notify_off = io_read16(&hw->common_cfg->queue_notify_off); + vq->notify_addr = (void *)((uint8_t *)hw->notify_base + + notify_off * hw->notify_off_multiplier); + + io_write16(1, &hw->common_cfg->queue_enable); + + PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index); + PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr); + PMD_INIT_LOG(DEBUG, "\t aval_addr: %"PRIx64, avail_addr); + PMD_INIT_LOG(DEBUG, "\t used_addr: %"PRIx64, used_addr); + PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)", + vq->notify_addr, notify_off); +} + +static void +modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); + + io_write64_twopart(0, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + io_write64_twopart(0, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + io_write64_twopart(0, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + io_write16(0, &hw->common_cfg->queue_enable); +} + +static void +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) +{ + io_write16(1, vq->notify_addr); +} + +static const struct virtio_pci_ops modern_ops = { + .read_dev_cfg = modern_read_dev_config, + .write_dev_cfg = modern_write_dev_config, + .reset = modern_reset, + .get_status = modern_get_status, + .set_status = modern_set_status, + .get_features = modern_get_features, + .set_features = modern_set_features, + .get_isr = modern_get_isr, + .set_config_irq = modern_set_config_irq, + .get_queue_num = modern_get_queue_num, + .setup_queue = modern_setup_queue, + .del_queue = modern_del_queue, + .notify_queue = modern_notify_queue, +}; + + void vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset, void *dst, int length) @@ -495,6 +701,12 @@ vtpci_set_status(struct virtio_hw *hw, uint8_t status) } uint8_t +vtpci_get_status(struct virtio_hw *hw) +{ + return hw->vtpci_ops->get_status(hw); +} + +uint8_t vtpci_isr(struct virtio_hw *hw) { return hw->vtpci_ops->get_isr(hw); @@ -508,15 +720,136 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) return hw->vtpci_ops->set_config_irq(hw, vec); } +static void * +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) +{ + uint8_t bar = cap->bar; + uint32_t length = cap->length; + uint32_t offset = cap->offset; + uint8_t *base; + + if (bar > 5) { + PMD_INIT_LOG(ERR, "invalid bar: %u", bar); + return NULL; + } + + if (offset + length > dev->mem_resource[bar].len) { + PMD_INIT_LOG(ERR, + "invalid cap: overflows bar space: %u > %"PRIu64, + offset + length, dev->mem_resource[bar].len); + return NULL; + } + + base = dev->mem_resource[bar].addr; + if (base == NULL) { + PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar); + return NULL; + } + + return base + offset; +} + +static int +virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw) +{ + uint8_t pos; + struct virtio_pci_cap cap; + int ret; + + if (rte_eal_pci_map_device(dev) < 0) { + PMD_INIT_LOG(DEBUG, "failed to map pci device!"); + return -1; + } + + ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST); + if (ret < 0) { + PMD_INIT_LOG(DEBUG, "failed to read pci capability list"); + return -1; + } + + while (pos) { + ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos); + if (ret < 0) { + PMD_INIT_LOG(ERR, + "failed to read pci cap at pos: %x", pos); + break; + } + + if (cap.cap_vndr != PCI_CAP_ID_VNDR) { + PMD_INIT_LOG(DEBUG, + "[%2x] skipping non VNDR cap id: %02x", + pos, cap.cap_vndr); + goto next; + } + + PMD_INIT_LOG(DEBUG, + "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u", + pos, cap.cfg_type, cap.bar, cap.offset, cap.length); + + switch (cap.cfg_type) { + case VIRTIO_PCI_CAP_COMMON_CFG: + hw->common_cfg = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_NOTIFY_CFG: + rte_eal_pci_read_config(dev, &hw->notify_off_multiplier, + 4, pos + sizeof(cap)); + hw->notify_base = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_DEVICE_CFG: + hw->dev_cfg = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_ISR_CFG: + hw->isr = get_cfg_addr(dev, &cap); + break; + } + + next: + pos = cap.cap_next; + } + + if (hw->common_cfg == NULL || hw->notify_base == NULL || + hw->dev_cfg == NULL || hw->isr == NULL) { + PMD_INIT_LOG(INFO, "no modern virtio pci device found."); + return -1; + } + + PMD_INIT_LOG(INFO, "found modern virtio pci device."); + + PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg); + PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg); + PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr); + PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u", + hw->notify_base, hw->notify_off_multiplier); + + return 0; +} + int vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) { - hw->vtpci_ops = &legacy_ops; + hw->dev = dev; + + /* + * Try if we can succeed reading virtio pci caps, which exists + * only on modern pci device. If failed, we fallback to legacy + * virtio handling. + */ + if (virtio_read_caps(dev, hw) == 0) { + PMD_INIT_LOG(INFO, "modern virtio pci detected."); + hw->vtpci_ops = &modern_ops; + hw->modern = 1; + dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; + return 0; + } + PMD_INIT_LOG(INFO, "trying with legacy virtio pci."); if (legacy_virtio_resource_init(dev) < 0) return -1; + + hw->vtpci_ops = &legacy_ops; hw->use_msix = legacy_virtio_has_msix(&dev->addr); hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr; + hw->modern = 0; return 0; } diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index 17312f6..8174245 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -93,6 +93,7 @@ struct virtqueue; #define VIRTIO_CONFIG_STATUS_ACK 0x01 #define VIRTIO_CONFIG_STATUS_DRIVER 0x02 #define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04 +#define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08 #define VIRTIO_CONFIG_STATUS_FAILED 0x80 /* @@ -141,6 +142,8 @@ struct virtqueue; /* We support indirect buffer descriptors */ #define VIRTIO_RING_F_INDIRECT_DESC 28 +#define VIRTIO_F_VERSION_1 32 + /* * Some VirtIO feature bits (currently bits 28 through 31) are * reserved for the transport being used (eg. virtio_ring), the @@ -163,6 +166,60 @@ struct virtqueue; */ #define VIRTIO_MAX_VIRTQUEUES 8 +/* Common configuration */ +#define VIRTIO_PCI_CAP_COMMON_CFG 1 +/* Notifications */ +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 +/* ISR Status */ +#define VIRTIO_PCI_CAP_ISR_CFG 3 +/* Device specific configuration */ +#define VIRTIO_PCI_CAP_DEVICE_CFG 4 +/* PCI configuration access */ +#define VIRTIO_PCI_CAP_PCI_CFG 5 + +/* This is the PCI capability header: */ +struct virtio_pci_cap { + uint8_t cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */ + uint8_t cap_next; /* Generic PCI field: next ptr. */ + uint8_t cap_len; /* Generic PCI field: capability length */ + uint8_t cfg_type; /* Identifies the structure. */ + uint8_t bar; /* Where to find it. */ + uint8_t padding[3]; /* Pad to full dword. */ + uint32_t offset; /* Offset within bar. */ + uint32_t length; /* Length of the structure, in bytes. */ +}; + +struct virtio_pci_notify_cap { + struct virtio_pci_cap cap; + uint32_t notify_off_multiplier; /* Multiplier for queue_notify_off. */ +}; + +/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */ +struct virtio_pci_common_cfg { + /* About the whole device. */ + uint32_t device_feature_select; /* read-write */ + uint32_t device_feature; /* read-only */ + uint32_t guest_feature_select; /* read-write */ + uint32_t guest_feature; /* read-write */ + uint16_t msix_config; /* read-write */ + uint16_t num_queues; /* read-only */ + uint8_t device_status; /* read-write */ + uint8_t config_generation; /* read-only */ + + /* About a specific virtqueue. */ + uint16_t queue_select; /* read-write */ + uint16_t queue_size; /* read-write, power of 2. */ + uint16_t queue_msix_vector; /* read-write */ + uint16_t queue_enable; /* read-write */ + uint16_t queue_notify_off; /* read-only */ + uint32_t queue_desc_lo; /* read-write */ + uint32_t queue_desc_hi; /* read-write */ + uint32_t queue_avail_lo; /* read-write */ + uint32_t queue_avail_hi; /* read-write */ + uint32_t queue_used_lo; /* read-write */ + uint32_t queue_used_hi; /* read-write */ +}; + struct virtio_hw; struct virtio_pci_ops { @@ -188,6 +245,8 @@ struct virtio_pci_ops { void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq); }; +struct virtio_net_config; + struct virtio_hw { struct virtqueue *cvq; uint32_t io_base; @@ -198,7 +257,14 @@ struct virtio_hw { uint8_t vlan_strip; uint8_t use_msix; uint8_t started; + uint8_t modern; uint8_t mac_addr[ETHER_ADDR_LEN]; + uint32_t notify_off_multiplier; + uint8_t *isr; + uint16_t *notify_base; + struct rte_pci_device *dev; + struct virtio_pci_common_cfg *common_cfg; + struct virtio_net_config *dev_cfg; const struct virtio_pci_ops *vtpci_ops; }; @@ -284,6 +350,7 @@ void vtpci_reset(struct virtio_hw *); void vtpci_reinit_complete(struct virtio_hw *); +uint8_t vtpci_get_status(struct virtio_hw *); void vtpci_set_status(struct virtio_hw *, uint8_t); uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t); diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h index d7fb450..99d4fa9 100644 --- a/drivers/net/virtio/virtqueue.h +++ b/drivers/net/virtio/virtqueue.h @@ -202,6 +202,8 @@ struct virtqueue { /* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */ uint64_t size_bins[8]; + uint16_t *notify_addr; + struct vq_desc_extra { void *cookie; uint16_t ndescs; -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support Yuanhan Liu @ 2016-01-18 16:38 ` Xie, Huawei 2016-01-18 16:50 ` Xie, Huawei 2016-01-18 17:07 ` Xie, Huawei 2 siblings, 0 replies; 122+ messages in thread From: Xie, Huawei @ 2016-01-18 16:38 UTC (permalink / raw) To: Yuanhan Liu, dev On 1/15/2016 12:34 PM, Yuanhan Liu wrote: > Modern (v1.0) virtio pci device defines several pci capabilities. > Each cap has a configure structure corresponding to it, and the > cap.bar and cap.offset fields tell us where to find it. > [snip] > > +static void * > +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) > +{ > + uint8_t bar = cap->bar; > + uint32_t length = cap->length; > + uint32_t offset = cap->offset; > + uint8_t *base; > + > + if (bar > 5) { > + PMD_INIT_LOG(ERR, "invalid bar: %u", bar); > + return NULL; > + } > + > + if (offset + length > dev->mem_resource[bar].len) { offset + length could overflow 32bit limit > + PMD_INIT_LOG(ERR, > + "invalid cap: overflows bar space: %u > %"PRIu64, > + offset + length, dev->mem_resource[bar].len); > + return NULL; > + } > + > + [snip] ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support Yuanhan Liu 2016-01-18 16:38 ` Xie, Huawei @ 2016-01-18 16:50 ` Xie, Huawei 2016-01-19 5:55 ` Yuanhan Liu 2016-01-18 17:07 ` Xie, Huawei 2 siblings, 1 reply; 122+ messages in thread From: Xie, Huawei @ 2016-01-18 16:50 UTC (permalink / raw) To: Yuanhan Liu, dev On 1/15/2016 12:34 PM, Yuanhan Liu wrote: > -static void > +static int > virtio_negotiate_features(struct virtio_hw *hw) > { > uint64_t host_features; > @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw) > hw->guest_features = vtpci_negotiate_features(hw, host_features); Here if we are not modern device, we should remove VIRTIO_F_VERSION_1 in guest features. > PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, > hw->guest_features); > + > + if (hw->modern) { > + if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) { > + PMD_INIT_LOG(ERR, > + "VIRTIO_F_VERSION_1 features is not enabled."); > + return -1; > + } > + vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK); > + if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) { > + PMD_INIT_LOG(ERR, > + "failed to set FEATURES_OK status!"); > + return -1; > + } > + } > + > + return 0; > } ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support 2016-01-18 16:50 ` Xie, Huawei @ 2016-01-19 5:55 ` Yuanhan Liu 2016-01-19 7:44 ` Xie, Huawei 0 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2016-01-19 5:55 UTC (permalink / raw) To: Xie, Huawei; +Cc: dev On Mon, Jan 18, 2016 at 04:50:16PM +0000, Xie, Huawei wrote: > On 1/15/2016 12:34 PM, Yuanhan Liu wrote: > > -static void > > +static int > > virtio_negotiate_features(struct virtio_hw *hw) > > { > > uint64_t host_features; > > @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw) > > hw->guest_features = vtpci_negotiate_features(hw, host_features); > > Here if we are not modern device, we should remove VIRTIO_F_VERSION_1 in > guest features. VIRTIO_F_VERSION_1 should not be set for legacy virtio device at all. --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support 2016-01-19 5:55 ` Yuanhan Liu @ 2016-01-19 7:44 ` Xie, Huawei 2016-01-19 7:54 ` Yuanhan Liu 2016-01-19 8:02 ` Xie, Huawei 0 siblings, 2 replies; 122+ messages in thread From: Xie, Huawei @ 2016-01-19 7:44 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev On 1/19/2016 1:53 PM, Yuanhan Liu wrote: > On Mon, Jan 18, 2016 at 04:50:16PM +0000, Xie, Huawei wrote: >> On 1/15/2016 12:34 PM, Yuanhan Liu wrote: >>> -static void >>> +static int >>> virtio_negotiate_features(struct virtio_hw *hw) >>> { >>> uint64_t host_features; >>> @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw) >>> hw->guest_features = vtpci_negotiate_features(hw, host_features); >> Here if we are not modern device, we should remove VIRTIO_F_VERSION_1 in >> guest features. > VIRTIO_F_VERSION_1 should not be set for legacy virtio device at all. Yes, but here this patch sets this VIRTIO_F_VERSION_1 feature even for legacy virtio device. It doesn't cause issues, but better remove it for legacy virtio device. > > --yliu > ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support 2016-01-19 7:44 ` Xie, Huawei @ 2016-01-19 7:54 ` Yuanhan Liu 2016-01-19 8:02 ` Xie, Huawei 1 sibling, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-19 7:54 UTC (permalink / raw) To: Xie, Huawei; +Cc: dev On Tue, Jan 19, 2016 at 07:44:04AM +0000, Xie, Huawei wrote: > On 1/19/2016 1:53 PM, Yuanhan Liu wrote: > > On Mon, Jan 18, 2016 at 04:50:16PM +0000, Xie, Huawei wrote: > >> On 1/15/2016 12:34 PM, Yuanhan Liu wrote: > >>> -static void > >>> +static int > >>> virtio_negotiate_features(struct virtio_hw *hw) > >>> { > >>> uint64_t host_features; > >>> @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw) > >>> hw->guest_features = vtpci_negotiate_features(hw, host_features); > >> Here if we are not modern device, we should remove VIRTIO_F_VERSION_1 in > >> guest features. > > VIRTIO_F_VERSION_1 should not be set for legacy virtio device at all. > > Yes, but here this patch sets this VIRTIO_F_VERSION_1 feature even for > legacy virtio device. > It doesn't cause issues, but better remove it for legacy virtio device. It's not set for legacy virtio device (at hw->guest_features), how could you remove it then??? --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support 2016-01-19 7:44 ` Xie, Huawei 2016-01-19 7:54 ` Yuanhan Liu @ 2016-01-19 8:02 ` Xie, Huawei 1 sibling, 0 replies; 122+ messages in thread From: Xie, Huawei @ 2016-01-19 8:02 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev On 1/19/2016 3:44 PM, Xie, Huawei wrote: > On 1/19/2016 1:53 PM, Yuanhan Liu wrote: >> On Mon, Jan 18, 2016 at 04:50:16PM +0000, Xie, Huawei wrote: >>> On 1/15/2016 12:34 PM, Yuanhan Liu wrote: >>>> -static void >>>> +static int >>>> virtio_negotiate_features(struct virtio_hw *hw) >>>> { >>>> uint64_t host_features; >>>> @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw) >>>> hw->guest_features = vtpci_negotiate_features(hw, host_features); >>> Here if we are not modern device, we should remove VIRTIO_F_VERSION_1 in >>> guest features. >> VIRTIO_F_VERSION_1 should not be set for legacy virtio device at all. > Yes, but here this patch sets this VIRTIO_F_VERSION_1 feature even for > legacy virtio device. > It doesn't cause issues, but better remove it for legacy virtio device. OK, I see the legacy_get_features return a 32bit value which masks the higher bits which contains the host VIRTIO_F_VERSION_1 feature. This is very implict. >> --yliu >> > ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support Yuanhan Liu 2016-01-18 16:38 ` Xie, Huawei 2016-01-18 16:50 ` Xie, Huawei @ 2016-01-18 17:07 ` Xie, Huawei 2016-01-19 1:36 ` Yuanhan Liu 2 siblings, 1 reply; 122+ messages in thread From: Xie, Huawei @ 2016-01-18 17:07 UTC (permalink / raw) To: Yuanhan Liu, dev .On 1/15/2016 12:34 PM, Yuanhan Liu wrote: > Modern (v1.0) virtio pci device defines several pci capabilities. > Each cap has a configure structure corresponding to it, and the > cap.bar and cap.offset fields tell us where to find it. > [snip] > + > +static inline void > +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) > +{ > + io_write32((uint32_t)val, lo); > + io_write32(val >> 32, hi); Firstly your second iowrite32 doesn't do the conversion. The conversion is duplicated. > +} > + > +static void > +modern_read_dev_config(struct virtio_hw *hw, uint64_t offset, here and there, size_t is more accurate for offset as we get it from offsetof. > + void *dst, int length) > +{ > + int i; > + uint8_t *p; > + uint8_t old_gen, new_gen; > + > + do { > + old_gen = io_read8(&hw->common_cfg->config_generation); > + > + p = dst; > + for (i = 0; i < length; i++) > + *p++ = io_read8((uint8_t *)hw->dev_cfg + offset + i); > + > + new_gen = io_read8(&hw->common_cfg->config_generation); > + } while (old_gen != new_gen); > +} > + > +static void > +modern_write_dev_config(struct virtio_hw *hw, uint64_t offset, > + const void *src, int length) > +{ > + int i; > + const uint8_t *p = src; > + > + for (i = 0; i < length; i++) > + io_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i); > +} > + > +static uint64_t > +modern_get_features(struct virtio_hw *hw) > +{ > + uint32_t features_lo, features_hi; > + > + io_write32(0, &hw->common_cfg->device_feature_select); > + features_lo = io_read32(&hw->common_cfg->device_feature); > + > + io_write32(1, &hw->common_cfg->device_feature_select); > + features_hi = io_read32(&hw->common_cfg->device_feature); > + > + return ((uint64_t)(features_hi) << 32) | features_lo; > +} > + > +static void > +modern_set_features(struct virtio_hw *hw, uint64_t features) > +{ > + io_write32(0, &hw->common_cfg->guest_feature_select); > + io_write32(features & ((1ULL << 32) - 1), again, duplicated conversion > + &hw->common_cfg->guest_feature); > + > + io_write32(1, &hw->common_cfg->guest_feature_select); [snip] ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support 2016-01-18 17:07 ` Xie, Huawei @ 2016-01-19 1:36 ` Yuanhan Liu 2016-01-19 1:51 ` Xie, Huawei 0 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2016-01-19 1:36 UTC (permalink / raw) To: Xie, Huawei; +Cc: dev On Mon, Jan 18, 2016 at 05:07:51PM +0000, Xie, Huawei wrote: > .On 1/15/2016 12:34 PM, Yuanhan Liu wrote: > > Modern (v1.0) virtio pci device defines several pci capabilities. > > Each cap has a configure structure corresponding to it, and the > > cap.bar and cap.offset fields tell us where to find it. > > > [snip] > > + > > +static inline void > > +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) > > +{ > > + io_write32((uint32_t)val, lo); > > + io_write32(val >> 32, hi); > > Firstly your second iowrite32 doesn't do the conversion. Because it's not necessary. The first one is for retrieving the low 32 bits. > The conversion is duplicated. What do you mean by "duplicated". --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support 2016-01-19 1:36 ` Yuanhan Liu @ 2016-01-19 1:51 ` Xie, Huawei 2016-01-19 2:46 ` Yuanhan Liu 0 siblings, 1 reply; 122+ messages in thread From: Xie, Huawei @ 2016-01-19 1:51 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev On 1/19/2016 9:34 AM, Yuanhan Liu wrote: > On Mon, Jan 18, 2016 at 05:07:51PM +0000, Xie, Huawei wrote: >> .On 1/15/2016 12:34 PM, Yuanhan Liu wrote: >>> Modern (v1.0) virtio pci device defines several pci capabilities. >>> Each cap has a configure structure corresponding to it, and the >>> cap.bar and cap.offset fields tell us where to find it. >>> >> [snip] >>> + >>> +static inline void >>> +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) >>> +{ >>> + io_write32((uint32_t)val, lo); >>> + io_write32(val >> 32, hi); >> Firstly your second iowrite32 doesn't do the conversion. > Because it's not necessary. The first one is for retrieving the low 32 > bits. I don't mean the shift operation, but the conversion from 64bit to 32bit. Same applied to below. > >> The conversion is duplicated. > What do you mean by "duplicated". > > --yliu > ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support 2016-01-19 1:51 ` Xie, Huawei @ 2016-01-19 2:46 ` Yuanhan Liu 2016-01-19 2:48 ` Xie, Huawei 0 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2016-01-19 2:46 UTC (permalink / raw) To: Xie, Huawei; +Cc: dev On Tue, Jan 19, 2016 at 01:51:30AM +0000, Xie, Huawei wrote: > On 1/19/2016 9:34 AM, Yuanhan Liu wrote: > > On Mon, Jan 18, 2016 at 05:07:51PM +0000, Xie, Huawei wrote: > >> .On 1/15/2016 12:34 PM, Yuanhan Liu wrote: > >>> Modern (v1.0) virtio pci device defines several pci capabilities. > >>> Each cap has a configure structure corresponding to it, and the > >>> cap.bar and cap.offset fields tell us where to find it. > >>> > >> [snip] > >>> + > >>> +static inline void > >>> +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) > >>> +{ > >>> + io_write32((uint32_t)val, lo); > >>> + io_write32(val >> 32, hi); > >> Firstly your second iowrite32 doesn't do the conversion. > > Because it's not necessary. The first one is for retrieving the low 32 > > bits. > > I don't mean the shift operation, but the conversion from 64bit to 32bit. > Same applied to below. It's more than a casting here: it's same as "val & (1<<32 - 1)", as stated above, to retrieve the low 32 bits. I know it still could work without it, but, hey, what's wrong to make it explicit? --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support 2016-01-19 2:46 ` Yuanhan Liu @ 2016-01-19 2:48 ` Xie, Huawei 2016-01-19 5:54 ` Yuanhan Liu 0 siblings, 1 reply; 122+ messages in thread From: Xie, Huawei @ 2016-01-19 2:48 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev On 1/19/2016 10:44 AM, Yuanhan Liu wrote: > On Tue, Jan 19, 2016 at 01:51:30AM +0000, Xie, Huawei wrote: >> On 1/19/2016 9:34 AM, Yuanhan Liu wrote: >>> On Mon, Jan 18, 2016 at 05:07:51PM +0000, Xie, Huawei wrote: >>>> .On 1/15/2016 12:34 PM, Yuanhan Liu wrote: >>>>> Modern (v1.0) virtio pci device defines several pci capabilities. >>>>> Each cap has a configure structure corresponding to it, and the >>>>> cap.bar and cap.offset fields tell us where to find it. >>>>> >>>> [snip] >>>>> + >>>>> +static inline void >>>>> +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) >>>>> +{ >>>>> + io_write32((uint32_t)val, lo); >>>>> + io_write32(val >> 32, hi); >>>> Firstly your second iowrite32 doesn't do the conversion. >>> Because it's not necessary. The first one is for retrieving the low 32 >>> bits. >> I don't mean the shift operation, but the conversion from 64bit to 32bit. >> Same applied to below. > It's more than a casting here: it's same as "val & (1<<32 - 1)", as > stated above, to retrieve the low 32 bits. > > I know it still could work without it, but, hey, what's wrong to make > it explicit? Say x = val, y = val >> 32, both with (uint32_t) or both not. Be consistent and simple. > > --yliu > ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support 2016-01-19 2:48 ` Xie, Huawei @ 2016-01-19 5:54 ` Yuanhan Liu 0 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-19 5:54 UTC (permalink / raw) To: Xie, Huawei; +Cc: dev On Tue, Jan 19, 2016 at 02:48:39AM +0000, Xie, Huawei wrote: > On 1/19/2016 10:44 AM, Yuanhan Liu wrote: > > On Tue, Jan 19, 2016 at 01:51:30AM +0000, Xie, Huawei wrote: > >> On 1/19/2016 9:34 AM, Yuanhan Liu wrote: > >>> On Mon, Jan 18, 2016 at 05:07:51PM +0000, Xie, Huawei wrote: > >>>> .On 1/15/2016 12:34 PM, Yuanhan Liu wrote: > >>>>> Modern (v1.0) virtio pci device defines several pci capabilities. > >>>>> Each cap has a configure structure corresponding to it, and the > >>>>> cap.bar and cap.offset fields tell us where to find it. > >>>>> > >>>> [snip] > >>>>> + > >>>>> +static inline void > >>>>> +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) > >>>>> +{ > >>>>> + io_write32((uint32_t)val, lo); > >>>>> + io_write32(val >> 32, hi); > >>>> Firstly your second iowrite32 doesn't do the conversion. > >>> Because it's not necessary. The first one is for retrieving the low 32 > >>> bits. > >> I don't mean the shift operation, but the conversion from 64bit to 32bit. > >> Same applied to below. > > It's more than a casting here: it's same as "val & (1<<32 - 1)", as > > stated above, to retrieve the low 32 bits. > > > > I know it still could work without it, but, hey, what's wrong to make > > it explicit? > > Say x = val, y = val >> 32, both with (uint32_t) or both not. Be > consistent and simple. fine. --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v4 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (6 preceding siblings ...) 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support Yuanhan Liu @ 2016-01-15 4:36 ` Yuanhan Liu 2016-01-15 8:57 ` Xu, Qian Q 2016-01-18 8:04 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Tetsuya Mukawa 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu 9 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2016-01-15 4:36 UTC (permalink / raw) To: dev virtio_pci.c is the only file references those macros; move them there. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_pci.c | 19 +++++++++++++++++++ drivers/net/virtio/virtio_pci.h | 18 ------------------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index fe8d6a2..a9f179f 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -49,6 +49,25 @@ #define PCI_CAPABILITY_LIST 0x34 #define PCI_CAP_ID_VNDR 0x09 + +#define VIRTIO_PCI_REG_ADDR(hw, reg) \ + (unsigned short)((hw)->io_base + (reg)) + +#define VIRTIO_READ_REG_1(hw, reg) \ + inb((VIRTIO_PCI_REG_ADDR((hw), (reg)))) +#define VIRTIO_WRITE_REG_1(hw, reg, value) \ + outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + +#define VIRTIO_READ_REG_2(hw, reg) \ + inw((VIRTIO_PCI_REG_ADDR((hw), (reg)))) +#define VIRTIO_WRITE_REG_2(hw, reg, value) \ + outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + +#define VIRTIO_READ_REG_4(hw, reg) \ + inl((VIRTIO_PCI_REG_ADDR((hw), (reg)))) +#define VIRTIO_WRITE_REG_4(hw, reg, value) \ + outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + static void legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset, void *dst, int length) diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index 8174245..99572a0 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -318,24 +318,6 @@ outl_p(unsigned int data, unsigned int port) } #endif -#define VIRTIO_PCI_REG_ADDR(hw, reg) \ - (unsigned short)((hw)->io_base + (reg)) - -#define VIRTIO_READ_REG_1(hw, reg) \ - inb((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_1(hw, reg, value) \ - outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - -#define VIRTIO_READ_REG_2(hw, reg) \ - inw((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_2(hw, reg, value) \ - outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - -#define VIRTIO_READ_REG_4(hw, reg) \ - inl((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_4(hw, reg, value) \ - outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - static inline int vtpci_with_feature(struct virtio_hw *hw, uint64_t bit) { -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v4 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu @ 2016-01-15 8:57 ` Xu, Qian Q 0 siblings, 0 replies; 122+ messages in thread From: Xu, Qian Q @ 2016-01-15 8:57 UTC (permalink / raw) To: Yuanhan Liu, dev Tested-by: Qian Xu <qian.q.xu@intel.com> - Test Commit: ad66a85dce9a707748cb4d9592c13022ae77c067 - OS/Kernel: Fedora 21/4.1.13 - GCC: gcc (GCC) 4.9.2 20141101 (Red Hat 4.9.2-1) - CPU: Intel(R) Xeon(R) CPU E5-2695 v4 @ 2.10 - NIC: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection (rev 01) - Target: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection (rev 01) - Total 2 cases, 2 passed, 0 failed. Test Case1: test_func_vhost_user_virtio1.0-pmd with different txqflags ====================================================================== Note: For virtio1.0 usage, we need use qemu version >2.4, such as 2.4.1 or 2.5.0. 1. Launch the Vhost sample by below commands, socket-mem is set for the vhost sample to use, need ensure that the PCI port located socket has the memory. In our case, the PCI BDF is 81:00.0, so we need assign memory for socket1.:: taskset -c 18-20 ./examples/vhost/build/vhost-switch -c 0x1c0000 -n 4 --huge-dir /mnt/huge --socket-mem 0,2048 -- -p 1 --mergeable 0 --zero-copy 0 --vm2vm 0 2. Start VM with 1 virtio, note: we need add "disable-modern=false" to enable virtio 1.0. taskset -c 22-23 \ /root/qemu-versions/qemu-2.5.0/x86_64-softmmu/qemu-system-x86_64 -name us-vhost-vm1 \ -cpu host -enable-kvm -m 2048 -object memory-backend-file,id=mem,size=2048M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc \ -smp cores=2,sockets=1 -drive file=/home/img/vm1.img \ -chardev socket,id=char0,path=/home/qxu10/virtio-1.0/dpdk/vhost-net -netdev type=vhost-user,id=mynet1,chardev=char0,vhostforce \ -device virtio-net-pci,mac=52:54:00:00:00:01,netdev=mynet1,disable-modern=false \ -netdev tap,id=ipvm1,ifname=tap3,script=/etc/qemu-ifup -device rtl8139,netdev=ipvm1,id=net0,mac=00:00:00:00:10:01 -nographic 3. In the VM, change the config file--common_linuxapp, "CONFIG_RTE_LIBRTE_VIRTIO_DEBUG_INIT=y"; Run dpdk testpmd in VM:: ./<dpdk_folder>/tools/dpdk_nic_bind.py --bind igb_uio 00:03.0 ./<dpdk_folder>/x86_64-native-linuxapp-gcc/app/test-pmd/testpmd -c 0x3 -n 4 -- -i --txqflags 0x0f00 --disable-hw-vlan $ >set fwd mac $ >start tx_first We expect similar output as below, and see modern virtio pci detected. PMD: virtio_read_caps(): [98] skipping non VNDR cap id: 11 PMD: virtio_read_caps(): [84] cfg type: 5, bar: 0, offset: 0000, len: 0 PMD: virtio_read_caps(): [70] cfg type: 2, bar: 4, offset: 3000, len: 4194304 PMD: virtio_read_caps(): [60] cfg type: 4, bar: 4, offset: 2000, len: 4096 PMD: virtio_read_caps(): [50] cfg type: 3, bar: 4, offset: 1000, len: 4096 PMD: virtio_read_caps(): [40] cfg type: 1, bar: 4, offset: 0000, len: 4096 PMD: virtio_read_caps(): found modern virtio pci device. PMD: virtio_read_caps(): common cfg mapped at: 0x7f2c61a83000 PMD: virtio_read_caps(): device cfg mapped at: 0x7f2c61a85000 PMD: virtio_read_caps(): isr cfg mapped at: 0x7f2c61a84000 PMD: virtio_read_caps(): notify base: 0x7f2c61a86000, notify off multiplier: 409 6 PMD: vtpci_init(): modern virtio pci detected. 4. Send traffic to virtio1(MAC1=52:54:00:00:00:01) with VLAN ID=1000. Check if virtio packet can be RX/TX and also check the TX packet size is same as the RX packet size. 5. Also run the dpdk testpmd in VM with txqflags=0xf01 for the virtio pmd optimization usage:: ./<dpdk_folder>/tools/dpdk_nic_bind.py --bind igb_uio 00:03.0 ./<dpdk_folder>/x86_64-native-linuxapp-gcc/app/test-pmd/testpmd -c 0x3 -n 4 -- -i --txqflags=0x0f01 --disable-hw-vlan $ >set fwd mac $ >start tx_first 6. Send traffic to virtio1(MAC1=52:54:00:00:00:01) and VLAN ID=1000. Check if virtio packet can be RX/TX and also check the TX packet size is same as the RX packet size. Check the packet content is correct. Test Case2: test_func_vhost_user_one-vm-virtio1.0-one-vm-virtio0.95 =================================================================== 1. Launch the Vhost sample by below commands, socket-mem is set for the vhost sample to use, need ensure that the PCI port located socket has the memory. In our case, the PCI BDF is 81:00.0, so we need assign memory for socket1.:: taskset -c 18-20 ./examples/vhost/build/vhost-switch -c 0x1c0000 -n 4 --huge-dir /mnt/huge --socket-mem 0,2048 -- -p 1 --mergeable 0 --zero-copy 0 --vm2vm 1 2. Start VM1 with 1 virtio, note: we need add "disable-modern=false" to enable virtio 1.0. taskset -c 22-23 \ /root/qemu-versions/qemu-2.5.0/x86_64-softmmu/qemu-system-x86_64 -name us-vhost-vm1 \ -cpu host -enable-kvm -m 2048 -object memory-backend-file,id=mem,size=2048M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc \ -smp cores=2,sockets=1 -drive file=/home/img/vm1.img \ -chardev socket,id=char0,path=/home/qxu10/virtio-1.0/dpdk/vhost-net -netdev type=vhost-user,id=mynet1,chardev=char0,vhostforce \ -device virtio-net-pci,mac=52:54:00:00:00:01,netdev=mynet1,disable-modern=false \ -netdev tap,id=ipvm1,ifname=tap3,script=/etc/qemu-ifup -device rtl8139,netdev=ipvm1,id=net0,mac=00:00:00:00:10:01 -nographic 3. Start VM2 with 1 virtio, note: taskset -c 24-25 \ /root/qemu-versions/qemu-2.5.0/x86_64-softmmu/qemu-system-x86_64 -name us-vhost-vm1 \ -cpu host -enable-kvm -m 2048 -object memory-backend-file,id=mem,size=2048M,mem-path=/mnt/huge,share=on -numa node,memdev=mem -mem-prealloc \ -smp cores=2,sockets=1 -drive file=/home/img/vm2.img \ -chardev socket,id=char0,path=/home/qxu10/virtio-1.0/dpdk/vhost-net -netdev type=vhost-user,id=mynet2,chardev=char0,vhostforce \ -device virtio-net-pci,mac=52:54:00:00:00:02,netdev=mynet2,disable-modern=true \ -netdev tap,id=ipvm2,ifname=tap4,script=/etc/qemu-ifup -device rtl8139,netdev=ipvm2,id=net1,mac=00:00:00:00:10:02 -nographic 3. Run dpdk testpmd in VM1 and VM2:: VM1: ./<dpdk_folder>/tools/dpdk_nic_bind.py --bind igb_uio 00:03.0 ./<dpdk_folder>/x86_64-native-linuxapp-gcc/app/test-pmd/testpmd -c 0x3 -n 4 -- -i --txqflags 0x0f00 --disable-hw-vlan --eth-peer=0,52:54:00:00:00:02 $ >set fwd mac $ >start tx_first VM2: ./<dpdk_folder>/tools/dpdk_nic_bind.py --bind igb_uio 00:03.0 ./<dpdk_folder>/x86_64-native-linuxapp-gcc/app/test-pmd/testpmd -c 0x3 -n 4 -- -i --txqflags 0x0f00 --disable-hw-vlan $ >set fwd mac $ >start tx_first 4. Send 100 packets at low rate to virtio1, and the expected flow is ixia-->NIC-->VHOST-->Virtio1-->Virtio2-->Vhost-->NIC->ixia port. Check the packet back at ixia port is content correct, no size change and payload change. Thanks Qian -----Original Message----- From: Yuanhan Liu [mailto:yuanhan.liu@linux.intel.com] Sent: Friday, January 15, 2016 12:36 PM To: dev@dpdk.org Cc: Xie, Huawei; Tetsuya Mukawa; Tan, Jianfeng; Xu, Qian Q; Yuanhan Liu Subject: [PATCH v4 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c virtio_pci.c is the only file references those macros; move them there. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> --- drivers/net/virtio/virtio_pci.c | 19 +++++++++++++++++++ drivers/net/virtio/virtio_pci.h | 18 ------------------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index fe8d6a2..a9f179f 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -49,6 +49,25 @@ #define PCI_CAPABILITY_LIST 0x34 #define PCI_CAP_ID_VNDR 0x09 + +#define VIRTIO_PCI_REG_ADDR(hw, reg) \ + (unsigned short)((hw)->io_base + (reg)) + +#define VIRTIO_READ_REG_1(hw, reg) \ + inb((VIRTIO_PCI_REG_ADDR((hw), (reg)))) #define VIRTIO_WRITE_REG_1(hw, +reg, value) \ + outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + +#define VIRTIO_READ_REG_2(hw, reg) \ + inw((VIRTIO_PCI_REG_ADDR((hw), (reg)))) #define VIRTIO_WRITE_REG_2(hw, +reg, value) \ + outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + +#define VIRTIO_READ_REG_4(hw, reg) \ + inl((VIRTIO_PCI_REG_ADDR((hw), (reg)))) #define VIRTIO_WRITE_REG_4(hw, +reg, value) \ + outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + static void legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset, void *dst, int length) diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index 8174245..99572a0 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -318,24 +318,6 @@ outl_p(unsigned int data, unsigned int port) } #endif -#define VIRTIO_PCI_REG_ADDR(hw, reg) \ - (unsigned short)((hw)->io_base + (reg)) - -#define VIRTIO_READ_REG_1(hw, reg) \ - inb((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_1(hw, reg, value) \ - outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - -#define VIRTIO_READ_REG_2(hw, reg) \ - inw((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_2(hw, reg, value) \ - outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - -#define VIRTIO_READ_REG_4(hw, reg) \ - inl((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_4(hw, reg, value) \ - outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - static inline int vtpci_with_feature(struct virtio_hw *hw, uint64_t bit) { -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (7 preceding siblings ...) 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu @ 2016-01-18 8:04 ` Tetsuya Mukawa 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu 9 siblings, 0 replies; 122+ messages in thread From: Tetsuya Mukawa @ 2016-01-18 8:04 UTC (permalink / raw) To: Yuanhan Liu, dev On 2016/01/15 13:36, Yuanhan Liu wrote: > v4: - mark "src" arg as const for write_dev_cfg operation > > - remove unnessary inline, and likely/unlikely > > v3: - export pci_unmap_device as well; and invoke it at virtio > uninit stage. > > - fixed same data corruption bug reported by Qian in simple > rxtx code path. > > - move VIRTIO_READ/WRITE_REG_X to virtio_pci.c > > v2: - fix a data corruption reported by Qian, due to hdr size mismatch. > check detailes at ptach 5. > > - Add missing config_irq and isr reading support from v1. > > - fix comments from v1. > > Almost all difference comes from virtio 1.0 are the PCI layout change: > the major configuration structures are stored at bar space, and their > location is stored at corresponding pci cap structure. Reading/parsing > them is one of the major work of patch 7. > > To make handling virtio v1.0 and v0.95 co-exist well, this patch set > introduces a virtio_pci_ops structure, to add another layer so that > we could keep those vtpci_foo_bar "APIs". With that, we could do the > minimum change to add virtio 1.0 support. > > > Rough test guide > ================ > > Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add > option "disable-modern=false" to qemu virtio-net-pci device to enable > virtio 1.0 (which is disabled by default). > > And if you see something like following from 'lspci -v', it means virtio > 1.0 is indeed enabled: > > 00:04.0 Ethernet controller: Red Hat, Inc Virtio network device > Subsystem: Red Hat, Inc Device 0001 > Physical Slot: 4 > Flags: bus master, fast devsel, latency 0, IRQ 11 > I/O ports at c040 [size=64] > Memory at febf1000 (32-bit, non-prefetchable) [size=4K] > Memory at fe000000 (64-bit, prefetchable) [size=8M] > Expansion ROM at feb80000 [disabled] [size=256K] > Capabilities: [98] MSI-X: Enable+ Count=6 Masked- > ==> Capabilities: [84] Vendor Specific Information: Len=14 <?> > ==> Capabilities: [70] Vendor Specific Information: Len=14 <?> > ==> Capabilities: [60] Vendor Specific Information: Len=10 <?> > ==> Capabilities: [50] Vendor Specific Information: Len=10 <?> > ==> Capabilities: [40] Vendor Specific Information: Len=10 <?> > Kernel driver in use: virtio-pci > Kernel modules: virtio_pci > > After that, there wasn't anything speical comparing to the old virtio > 0.95 pmd driver. > > > --- > Yuanhan Liu (8): > virtio: don't set vring address again at queue startup > virtio: introduce struct virtio_pci_ops > virtio: move left pci stuff to virtio_pci.c > viritio: switch to 64 bit features > virtio: retrieve hdr_size from hw->vtnet_hdr_size > eal: pci: export pci_[un]map_device > virtio: add 1.0 support > virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c > > doc/guides/rel_notes/release_2_3.rst | 3 + > drivers/net/virtio/virtio_ethdev.c | 302 +-------- > drivers/net/virtio/virtio_ethdev.h | 3 +- > drivers/net/virtio/virtio_pci.c | 793 +++++++++++++++++++++++- > drivers/net/virtio/virtio_pci.h | 120 +++- > drivers/net/virtio/virtio_rxtx.c | 21 +- > drivers/net/virtio/virtio_rxtx_simple.c | 12 +- > drivers/net/virtio/virtqueue.h | 4 +- > lib/librte_eal/bsdapp/eal/eal_pci.c | 4 +- > lib/librte_eal/bsdapp/eal/rte_eal_version.map | 7 + > lib/librte_eal/common/eal_common_pci.c | 4 +- > lib/librte_eal/common/eal_private.h | 18 - > lib/librte_eal/common/include/rte_pci.h | 27 + > lib/librte_eal/linuxapp/eal/eal_pci.c | 4 +- > lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 + > 15 files changed, 949 insertions(+), 380 deletions(-) > Reviewed-by: Tetsuya Mukawa <mukawa@igel.co.jp> Tested-by: Tetsuya Mukawa <mukawa@igel.co.jp> ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v5 0/9] virtio 1.0 enabling for virtio pmd driver 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu ` (8 preceding siblings ...) 2016-01-18 8:04 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Tetsuya Mukawa @ 2016-01-19 8:11 ` Yuanhan Liu 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu ` (10 more replies) 9 siblings, 11 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-19 8:11 UTC (permalink / raw) To: dev v5: minor fixes: - fix wrong type of arg "offset" of read/write_dev_config(): patch 2 is newly added for that. - check "offset + length" overflow Almost all difference comes from virtio 1.0 are the PCI layout change: the major configuration structures are stored at bar space, and their location is stored at corresponding pci cap structure. Reading/parsing them is one of the major work of patch 8. To make handling virtio v1.0 and v0.95 co-exist well, this patch set introduces a virtio_pci_ops structure, to add another layer so that we could keep those vtpci_foo_bar "APIs". With that, we could do the minimum change to add virtio 1.0 support. Rough test guide ================ Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add option "disable-modern=false" to qemu virtio-net-pci device to enable virtio 1.0 (which is disabled by default). And if you see something like following from 'lspci -v', it means virtio 1.0 is indeed enabled: 00:04.0 Ethernet controller: Red Hat, Inc Virtio network device Subsystem: Red Hat, Inc Device 0001 Physical Slot: 4 Flags: bus master, fast devsel, latency 0, IRQ 11 I/O ports at c040 [size=64] Memory at febf1000 (32-bit, non-prefetchable) [size=4K] Memory at fe000000 (64-bit, prefetchable) [size=8M] Expansion ROM at feb80000 [disabled] [size=256K] Capabilities: [98] MSI-X: Enable+ Count=6 Masked- ==> Capabilities: [84] Vendor Specific Information: Len=14 <?> ==> Capabilities: [70] Vendor Specific Information: Len=14 <?> ==> Capabilities: [60] Vendor Specific Information: Len=10 <?> ==> Capabilities: [50] Vendor Specific Information: Len=10 <?> ==> Capabilities: [40] Vendor Specific Information: Len=10 <?> Kernel driver in use: virtio-pci Kernel modules: virtio_pci After that, there wasn't anything speical comparing to the old virtio 0.95 pmd driver. --- Yuanhan Liu (9): virtio: don't set vring address again at queue startup virtio: define offset as size_t type virtio: introduce struct virtio_pci_ops virtio: move left pci stuff to virtio_pci.c viritio: switch to 64 bit features virtio: retrieve hdr_size from hw->vtnet_hdr_size eal: pci: export pci_[un]map_device virtio: add 1.0 support virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c doc/guides/rel_notes/release_2_3.rst | 3 + drivers/net/virtio/virtio_ethdev.c | 302 +-------- drivers/net/virtio/virtio_ethdev.h | 3 +- drivers/net/virtio/virtio_pci.c | 799 +++++++++++++++++++++++- drivers/net/virtio/virtio_pci.h | 124 +++- drivers/net/virtio/virtio_rxtx.c | 21 +- drivers/net/virtio/virtio_rxtx_simple.c | 12 +- drivers/net/virtio/virtqueue.h | 4 +- lib/librte_eal/bsdapp/eal/eal_pci.c | 4 +- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 7 + lib/librte_eal/common/eal_common_pci.c | 4 +- lib/librte_eal/common/eal_private.h | 18 - lib/librte_eal/common/include/rte_pci.h | 27 + lib/librte_eal/linuxapp/eal/eal_pci.c | 4 +- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 + 15 files changed, 957 insertions(+), 382 deletions(-) -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v5 1/9] virtio: don't set vring address again at queue startup 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu @ 2016-01-19 8:11 ` Yuanhan Liu 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 2/9] virtio: define offset as size_t type Yuanhan Liu ` (9 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-19 8:11 UTC (permalink / raw) To: dev As we have already set up it at virtio_dev_queue_setup(), and a vq restart will not reset the settings. 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> --- drivers/net/virtio/virtio_rxtx.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c index 74b39ef..b7267c0 100644 --- a/drivers/net/virtio/virtio_rxtx.c +++ b/drivers/net/virtio/virtio_rxtx.c @@ -339,11 +339,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type) vq_update_avail_idx(vq); PMD_INIT_LOG(DEBUG, "Allocated %d bufs", nbufs); - - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); } else if (queue_type == VTNET_TQ) { if (use_simple_rxtx) { int mid_idx = vq->vq_nentries >> 1; @@ -362,16 +357,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type) for (i = mid_idx; i < vq->vq_nentries; i++) vq->vq_ring.avail->ring[i] = i; } - - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); - } else { - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); } } -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v5 2/9] virtio: define offset as size_t type 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu @ 2016-01-19 8:11 ` Yuanhan Liu 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu ` (8 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-19 8:11 UTC (permalink / raw) To: dev offset arg of vtpci_read/write_dev_config is derived from offsetof(), which is of size_t type, instead of uint64_t. So, define it as size_t type. 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> --- drivers/net/virtio/virtio_pci.c | 4 ++-- drivers/net/virtio/virtio_pci.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 2245bec..b34b59e 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -38,7 +38,7 @@ static uint8_t vtpci_get_status(struct virtio_hw *); void -vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset, +vtpci_read_dev_config(struct virtio_hw *hw, size_t offset, void *dst, int length) { uint64_t off; @@ -61,7 +61,7 @@ vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset, } void -vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset, +vtpci_write_dev_config(struct virtio_hw *hw, size_t offset, void *src, int length) { uint64_t off; diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index 47f722a..fe89c21 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -261,9 +261,9 @@ 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 *, uint64_t, void *, int); +void vtpci_write_dev_config(struct virtio_hw *, size_t, void *, int); -void vtpci_read_dev_config(struct virtio_hw *, uint64_t, void *, int); +void vtpci_read_dev_config(struct virtio_hw *, size_t, void *, int); uint8_t vtpci_isr(struct virtio_hw *); -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v5 3/9] virtio: introduce struct virtio_pci_ops 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 2/9] virtio: define offset as size_t type Yuanhan Liu @ 2016-01-19 8:11 ` Yuanhan Liu 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu ` (7 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-19 8:11 UTC (permalink / raw) To: dev 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> --- 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 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v5 4/9] virtio: move left pci stuff to virtio_pci.c 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu ` (2 preceding siblings ...) 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu @ 2016-01-19 8:12 ` Yuanhan Liu 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 5/9] viritio: switch to 64 bit features Yuanhan Liu ` (6 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-19 8:12 UTC (permalink / raw) To: dev virtio_pci.c is a more proper place for pci stuff; virtio_ethdev is not. 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> --- drivers/net/virtio/virtio_ethdev.c | 265 +----------------------------------- drivers/net/virtio/virtio_pci.c | 270 ++++++++++++++++++++++++++++++++++++- 2 files changed, 270 insertions(+), 265 deletions(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 6c1d3a0..b57224d 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -36,10 +36,6 @@ #include <stdio.h> #include <errno.h> #include <unistd.h> -#ifdef RTE_EXEC_ENV_LINUXAPP -#include <dirent.h> -#include <fcntl.h> -#endif #include <rte_ethdev.h> #include <rte_memcpy.h> @@ -955,260 +951,6 @@ virtio_negotiate_features(struct virtio_hw *hw) hw->guest_features); } -#ifdef RTE_EXEC_ENV_LINUXAPP -static int -parse_sysfs_value(const char *filename, unsigned long *val) -{ - FILE *f; - char buf[BUFSIZ]; - char *end = NULL; - - f = fopen(filename, "r"); - if (f == NULL) { - PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s", - __func__, filename); - return -1; - } - - if (fgets(buf, sizeof(buf), f) == NULL) { - PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s", - __func__, filename); - fclose(f); - return -1; - } - *val = strtoul(buf, &end, 0); - if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { - PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s", - __func__, filename); - fclose(f); - return -1; - } - fclose(f); - return 0; -} - -static int get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen, - unsigned int *uio_num) -{ - struct dirent *e; - DIR *dir; - char dirname[PATH_MAX]; - - /* depending on kernel version, uio can be located in uio/uioX - * or uio:uioX */ - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", - loc->domain, loc->bus, loc->devid, loc->function); - dir = opendir(dirname); - if (dir == NULL) { - /* retry with the parent directory */ - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, - loc->domain, loc->bus, loc->devid, loc->function); - dir = opendir(dirname); - - if (dir == NULL) { - PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname); - return -1; - } - } - - /* take the first file starting with "uio" */ - while ((e = readdir(dir)) != NULL) { - /* format could be uio%d ...*/ - int shortprefix_len = sizeof("uio") - 1; - /* ... or uio:uio%d */ - int longprefix_len = sizeof("uio:uio") - 1; - char *endptr; - - if (strncmp(e->d_name, "uio", 3) != 0) - continue; - - /* first try uio%d */ - errno = 0; - *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); - if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { - snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num); - break; - } - - /* then try uio:uio%d */ - errno = 0; - *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); - if (errno == 0 && endptr != (e->d_name + longprefix_len)) { - snprintf(buf, buflen, "%s/uio:uio%u", dirname, - *uio_num); - break; - } - } - closedir(dir); - - /* No uio resource found */ - if (e == NULL) { - PMD_INIT_LOG(ERR, "Could not find uio resource"); - return -1; - } - - return 0; -} - -static int -virtio_has_msix(const struct rte_pci_addr *loc) -{ - DIR *d; - char dirname[PATH_MAX]; - - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs", - loc->domain, loc->bus, loc->devid, loc->function); - - d = opendir(dirname); - if (d) - closedir(d); - - return (d != NULL); -} - -/* Extract I/O port numbers from sysfs */ -static int virtio_resource_init_by_uio(struct rte_pci_device *pci_dev) -{ - char dirname[PATH_MAX]; - char filename[PATH_MAX]; - unsigned long start, size; - unsigned int uio_num; - - if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0) - return -1; - - /* get portio size */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/size", dirname); - if (parse_sysfs_value(filename, &size) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse size", - __func__); - return -1; - } - - /* get portio start */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/start", dirname); - if (parse_sysfs_value(filename, &start) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", - __func__); - return -1; - } - pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; - pci_dev->mem_resource[0].len = (uint64_t)size; - PMD_INIT_LOG(DEBUG, - "PCI Port IO found start=0x%lx with size=0x%lx", - start, size); - - /* save fd */ - memset(dirname, 0, sizeof(dirname)); - snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num); - pci_dev->intr_handle.fd = open(dirname, O_RDWR); - if (pci_dev->intr_handle.fd < 0) { - PMD_INIT_LOG(ERR, "Cannot open %s: %s\n", - dirname, strerror(errno)); - return -1; - } - - pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO; - pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; - - return 0; -} - -/* Extract port I/O numbers from proc/ioports */ -static int virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev) -{ - uint16_t start, end; - int size; - FILE *fp; - char *line = NULL; - char pci_id[16]; - int found = 0; - size_t linesz; - - snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, - pci_dev->addr.domain, - pci_dev->addr.bus, - pci_dev->addr.devid, - pci_dev->addr.function); - - fp = fopen("/proc/ioports", "r"); - if (fp == NULL) { - PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__); - return -1; - } - - while (getdelim(&line, &linesz, '\n', fp) > 0) { - char *ptr = line; - char *left; - int n; - - n = strcspn(ptr, ":"); - ptr[n] = 0; - left = &ptr[n+1]; - - while (*left && isspace(*left)) - left++; - - if (!strncmp(left, pci_id, strlen(pci_id))) { - found = 1; - - while (*ptr && isspace(*ptr)) - ptr++; - - sscanf(ptr, "%04hx-%04hx", &start, &end); - size = end - start + 1; - - break; - } - } - - free(line); - fclose(fp); - - if (!found) - return -1; - - pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start; - pci_dev->mem_resource[0].len = (uint64_t)size; - PMD_INIT_LOG(DEBUG, - "PCI Port IO found start=0x%x with size=0x%x", - start, size); - - /* can't support lsc interrupt without uio */ - pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; - - return 0; -} - -/* Extract I/O port numbers from sysfs */ -static int virtio_resource_init(struct rte_pci_device *pci_dev) -{ - if (virtio_resource_init_by_uio(pci_dev) == 0) - return 0; - else - return virtio_resource_init_by_ioports(pci_dev); -} - -#else -static int -virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) -{ - /* nic_uio does not enable interrupts, return 0 (false). */ - return 0; -} - -static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) -{ - /* no setup required */ - return 0; -} -#endif - /* * Process Virtio Config changed interrupt and call the callback * if link state changed. @@ -1279,14 +1021,9 @@ 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) + if (vtpci_init(pci_dev, hw) < 0) return -1; - hw->use_msix = virtio_has_msix(&pci_dev->addr); - hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr; - /* Reset the device although not necessary at startup */ vtpci_reset(hw); diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 8d001e8..16485fa 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -32,6 +32,11 @@ */ #include <stdint.h> +#ifdef RTE_EXEC_ENV_LINUXAPP + #include <dirent.h> + #include <fcntl.h> +#endif + #include "virtio_pci.h" #include "virtio_logs.h" #include "virtqueue.h" @@ -156,6 +161,264 @@ legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq) VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index); } +#ifdef RTE_EXEC_ENV_LINUXAPP +static int +parse_sysfs_value(const char *filename, unsigned long *val) +{ + FILE *f; + char buf[BUFSIZ]; + char *end = NULL; + + f = fopen(filename, "r"); + if (f == NULL) { + PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s", + __func__, filename); + return -1; + } + + if (fgets(buf, sizeof(buf), f) == NULL) { + PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s", + __func__, filename); + fclose(f); + return -1; + } + *val = strtoul(buf, &end, 0); + if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { + PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s", + __func__, filename); + fclose(f); + return -1; + } + fclose(f); + return 0; +} + +static int +get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen, + unsigned int *uio_num) +{ + struct dirent *e; + DIR *dir; + char dirname[PATH_MAX]; + + /* depending on kernel version, uio can be located in uio/uioX + * or uio:uioX */ + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", + loc->domain, loc->bus, loc->devid, loc->function); + dir = opendir(dirname); + if (dir == NULL) { + /* retry with the parent directory */ + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, + loc->domain, loc->bus, loc->devid, loc->function); + dir = opendir(dirname); + + if (dir == NULL) { + PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname); + return -1; + } + } + + /* take the first file starting with "uio" */ + while ((e = readdir(dir)) != NULL) { + /* format could be uio%d ...*/ + int shortprefix_len = sizeof("uio") - 1; + /* ... or uio:uio%d */ + int longprefix_len = sizeof("uio:uio") - 1; + char *endptr; + + if (strncmp(e->d_name, "uio", 3) != 0) + continue; + + /* first try uio%d */ + errno = 0; + *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); + if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { + snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num); + break; + } + + /* then try uio:uio%d */ + errno = 0; + *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); + if (errno == 0 && endptr != (e->d_name + longprefix_len)) { + snprintf(buf, buflen, "%s/uio:uio%u", dirname, + *uio_num); + break; + } + } + closedir(dir); + + /* No uio resource found */ + if (e == NULL) { + PMD_INIT_LOG(ERR, "Could not find uio resource"); + return -1; + } + + return 0; +} + +static int +legacy_virtio_has_msix(const struct rte_pci_addr *loc) +{ + DIR *d; + char dirname[PATH_MAX]; + + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs", + loc->domain, loc->bus, loc->devid, loc->function); + + d = opendir(dirname); + if (d) + closedir(d); + + return (d != NULL); +} + +/* Extract I/O port numbers from sysfs */ +static int +virtio_resource_init_by_uio(struct rte_pci_device *pci_dev) +{ + char dirname[PATH_MAX]; + char filename[PATH_MAX]; + unsigned long start, size; + unsigned int uio_num; + + if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0) + return -1; + + /* get portio size */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/size", dirname); + if (parse_sysfs_value(filename, &size) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse size", + __func__); + return -1; + } + + /* get portio start */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/start", dirname); + if (parse_sysfs_value(filename, &start) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", + __func__); + return -1; + } + pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; + pci_dev->mem_resource[0].len = (uint64_t)size; + PMD_INIT_LOG(DEBUG, + "PCI Port IO found start=0x%lx with size=0x%lx", + start, size); + + /* save fd */ + memset(dirname, 0, sizeof(dirname)); + snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num); + pci_dev->intr_handle.fd = open(dirname, O_RDWR); + if (pci_dev->intr_handle.fd < 0) { + PMD_INIT_LOG(ERR, "Cannot open %s: %s\n", + dirname, strerror(errno)); + return -1; + } + + pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO; + pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; + + return 0; +} + +/* Extract port I/O numbers from proc/ioports */ +static int +virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev) +{ + uint16_t start, end; + int size; + FILE *fp; + char *line = NULL; + char pci_id[16]; + int found = 0; + size_t linesz; + + snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, + pci_dev->addr.domain, + pci_dev->addr.bus, + pci_dev->addr.devid, + pci_dev->addr.function); + + fp = fopen("/proc/ioports", "r"); + if (fp == NULL) { + PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__); + return -1; + } + + while (getdelim(&line, &linesz, '\n', fp) > 0) { + char *ptr = line; + char *left; + int n; + + n = strcspn(ptr, ":"); + ptr[n] = 0; + left = &ptr[n+1]; + + while (*left && isspace(*left)) + left++; + + if (!strncmp(left, pci_id, strlen(pci_id))) { + found = 1; + + while (*ptr && isspace(*ptr)) + ptr++; + + sscanf(ptr, "%04hx-%04hx", &start, &end); + size = end - start + 1; + + break; + } + } + + free(line); + fclose(fp); + + if (!found) + return -1; + + pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start; + pci_dev->mem_resource[0].len = (uint64_t)size; + PMD_INIT_LOG(DEBUG, + "PCI Port IO found start=0x%x with size=0x%x", + start, size); + + /* can't support lsc interrupt without uio */ + pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; + + return 0; +} + +/* Extract I/O port numbers from sysfs */ +static int +legacy_virtio_resource_init(struct rte_pci_device *pci_dev) +{ + if (virtio_resource_init_by_uio(pci_dev) == 0) + return 0; + else + return virtio_resource_init_by_ioports(pci_dev); +} + +#else +static int +legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) +{ + /* nic_uio does not enable interrupts, return 0 (false). */ + return 0; +} + +static int +legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) +{ + /* no setup required */ + return 0; +} +#endif static const struct virtio_pci_ops legacy_ops = { .read_dev_cfg = legacy_read_dev_config, @@ -241,9 +504,14 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) } int -vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw) +vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) { hw->vtpci_ops = &legacy_ops; + if (legacy_virtio_resource_init(dev) < 0) + return -1; + hw->use_msix = legacy_virtio_has_msix(&dev->addr); + hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr; + return 0; } -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v5 5/9] viritio: switch to 64 bit features 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu ` (3 preceding siblings ...) 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu @ 2016-01-19 8:12 ` Yuanhan Liu 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu ` (5 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-19 8:12 UTC (permalink / raw) To: dev Switch to 64 bit features, which virtio 1.0 supports. While legacy virtio only supports 32 bit features, it complains aloud and quit when trying to setting > 32 bit features. 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> --- drivers/net/virtio/virtio_ethdev.c | 8 ++++---- drivers/net/virtio/virtio_pci.c | 15 ++++++++++----- drivers/net/virtio/virtio_pci.h | 12 ++++++------ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index b57224d..94e0c4a 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -930,16 +930,16 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) static void virtio_negotiate_features(struct virtio_hw *hw) { - uint32_t host_features; + uint64_t host_features; /* Prepare guest_features: feature that driver wants to support */ hw->guest_features = VIRTIO_PMD_GUEST_FEATURES; - PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %x", + PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %"PRIx64, hw->guest_features); /* Read device(host) feature bits */ host_features = hw->vtpci_ops->get_features(hw); - PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x", + PMD_INIT_LOG(DEBUG, "host_features before negotiate = %"PRIx64, host_features); /* @@ -947,7 +947,7 @@ virtio_negotiate_features(struct virtio_hw *hw) * guest feature bits. */ hw->guest_features = vtpci_negotiate_features(hw, host_features); - PMD_INIT_LOG(DEBUG, "features after negotiate = %x", + PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, hw->guest_features); } diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 16485fa..5e1c55f 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -87,15 +87,20 @@ legacy_write_dev_config(struct virtio_hw *hw, size_t offset, } } -static uint32_t +static uint64_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) +legacy_set_features(struct virtio_hw *hw, uint64_t features) { + if ((features >> 32) != 0) { + PMD_DRV_LOG(ERR, + "only 32 bit features are allowed for legacy virtio!"); + return; + } VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features); } @@ -451,10 +456,10 @@ vtpci_write_dev_config(struct virtio_hw *hw, size_t offset, hw->vtpci_ops->write_dev_cfg(hw, offset, src, length); } -uint32_t -vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features) +uint64_t +vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features) { - uint32_t features; + uint64_t features; /* * Limit negotiated features to what the driver, virtqueue, and diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index e8e7509..d7bc6bb 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -175,8 +175,8 @@ struct virtio_pci_ops { 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); + uint64_t (*get_features)(struct virtio_hw *hw); + void (*set_features)(struct virtio_hw *hw, uint64_t features); uint8_t (*get_isr)(struct virtio_hw *hw); @@ -191,7 +191,7 @@ struct virtio_pci_ops { struct virtio_hw { struct virtqueue *cvq; uint32_t io_base; - uint32_t guest_features; + uint64_t guest_features; uint32_t max_tx_queues; uint32_t max_rx_queues; uint16_t vtnet_hdr_size; @@ -271,9 +271,9 @@ outl_p(unsigned int data, unsigned int port) outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) static inline int -vtpci_with_feature(struct virtio_hw *hw, uint32_t bit) +vtpci_with_feature(struct virtio_hw *hw, uint64_t bit) { - return (hw->guest_features & (1u << bit)) != 0; + return (hw->guest_features & (1ULL << bit)) != 0; } /* @@ -286,7 +286,7 @@ void vtpci_reinit_complete(struct virtio_hw *); void vtpci_set_status(struct virtio_hw *, uint8_t); -uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t); +uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t); void vtpci_write_dev_config(struct virtio_hw *, size_t, const void *, int); -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v5 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu ` (4 preceding siblings ...) 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 5/9] viritio: switch to 64 bit features Yuanhan Liu @ 2016-01-19 8:12 ` Yuanhan Liu 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu ` (4 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-19 8:12 UTC (permalink / raw) To: dev The mergeable virtio net hdr format has been the standard and the only virtio net hdr format since virtio 1.0. Therefore, we can not hardcode hdr_size to "sizeof(struct virtio_net_hdr)" any more at virtio_recv_pkts(), otherwise, there would be a mismatch of hdr size from rte_vhost_enqueue_burst() and virtio_recv_pkts(), leading a packet corruption. Instead, we should retrieve it from hw->vtnet_hdr_size; we will do proper settings at eth_virtio_dev_init() in later patches. 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> --- --- drivers/net/virtio/virtio_rxtx.c | 6 ++++-- drivers/net/virtio/virtio_rxtx_simple.c | 12 ++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c index b7267c0..41a1366 100644 --- a/drivers/net/virtio/virtio_rxtx.c +++ b/drivers/net/virtio/virtio_rxtx.c @@ -560,7 +560,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ]; int error; uint32_t i, nb_enqueued; - const uint32_t hdr_size = sizeof(struct virtio_net_hdr); + uint32_t hdr_size; nb_used = VIRTQUEUE_NUSED(rxvq); @@ -580,6 +580,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) hw = rxvq->hw; nb_rx = 0; nb_enqueued = 0; + hdr_size = hw->vtnet_hdr_size; for (i = 0; i < num ; i++) { rxm = rcv_pkts[i]; @@ -664,7 +665,7 @@ virtio_recv_mergeable_pkts(void *rx_queue, uint32_t seg_num; uint16_t extra_idx; uint32_t seg_res; - const uint32_t hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); + uint32_t hdr_size; nb_used = VIRTQUEUE_NUSED(rxvq); @@ -682,6 +683,7 @@ virtio_recv_mergeable_pkts(void *rx_queue, seg_num = 0; extra_idx = 0; seg_res = 0; + hdr_size = hw->vtnet_hdr_size; while (i < nb_used) { struct virtio_net_hdr_mrg_rxbuf *header; diff --git a/drivers/net/virtio/virtio_rxtx_simple.c b/drivers/net/virtio/virtio_rxtx_simple.c index ff3c11a..3e66e8b 100644 --- a/drivers/net/virtio/virtio_rxtx_simple.c +++ b/drivers/net/virtio/virtio_rxtx_simple.c @@ -81,9 +81,9 @@ virtqueue_enqueue_recv_refill_simple(struct virtqueue *vq, start_dp = vq->vq_ring.desc; start_dp[desc_idx].addr = (uint64_t)((uintptr_t)cookie->buf_physaddr + - RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr)); + RTE_PKTMBUF_HEADROOM - vq->hw->vtnet_hdr_size); start_dp[desc_idx].len = cookie->buf_len - - RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr); + RTE_PKTMBUF_HEADROOM + vq->hw->vtnet_hdr_size; vq->vq_free_cnt--; vq->vq_avail_idx++; @@ -120,9 +120,9 @@ virtio_rxq_rearm_vec(struct virtqueue *rxvq) start_dp[i].addr = (uint64_t)((uintptr_t)sw_ring[i]->buf_physaddr + - RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr)); + RTE_PKTMBUF_HEADROOM - rxvq->hw->vtnet_hdr_size); start_dp[i].len = sw_ring[i]->buf_len - - RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr); + RTE_PKTMBUF_HEADROOM + rxvq->hw->vtnet_hdr_size; } rxvq->vq_avail_idx += RTE_VIRTIO_VPMD_RX_REARM_THRESH; @@ -175,8 +175,8 @@ virtio_recv_pkts_vec(void *rx_queue, struct rte_mbuf **rx_pkts, len_adjust = _mm_set_epi16( 0, 0, 0, - (uint16_t) -sizeof(struct virtio_net_hdr), - 0, (uint16_t) -sizeof(struct virtio_net_hdr), + (uint16_t) -rxvq->hw->vtnet_hdr_size, + 0, (uint16_t) -rxvq->hw->vtnet_hdr_size, 0, 0); if (unlikely(nb_pkts < RTE_VIRTIO_DESC_PER_LOOP)) -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v5 7/9] eal: pci: export pci_[un]map_device 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu ` (5 preceding siblings ...) 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu @ 2016-01-19 8:12 ` Yuanhan Liu 2016-01-19 8:17 ` David Marchand 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support Yuanhan Liu ` (3 subsequent siblings) 10 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2016-01-19 8:12 UTC (permalink / raw) To: dev Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will invoke pci_map_device internally for us. From that point view, there is no need to export pci_map_device. However, for virtio pmd driver, which is designed to work without binding UIO (or something similar first), pci_map_device() will fail, which ends up with virtio pmd driver being skipped. Therefore, we can not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver. Therefore, this patch exports pci_map_device, and let virtio pmd call it when necessary. Cc: David Marchand <david.marchand@6wind.com> Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> Tested-By: Santosh Shukla <sshukla@mvista.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> --- lib/librte_eal/bsdapp/eal/eal_pci.c | 4 ++-- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 7 +++++++ lib/librte_eal/common/eal_common_pci.c | 4 ++-- lib/librte_eal/common/eal_private.h | 18 ----------------- lib/librte_eal/common/include/rte_pci.h | 27 +++++++++++++++++++++++++ lib/librte_eal/linuxapp/eal/eal_pci.c | 4 ++-- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +++++++ 7 files changed, 47 insertions(+), 24 deletions(-) diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c index 6c21fbd..95c32c1 100644 --- a/lib/librte_eal/bsdapp/eal/eal_pci.c +++ b/lib/librte_eal/bsdapp/eal/eal_pci.c @@ -93,7 +93,7 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused) /* Map pci device */ int -pci_map_device(struct rte_pci_device *dev) +rte_eal_pci_map_device(struct rte_pci_device *dev) { int ret = -1; @@ -115,7 +115,7 @@ pci_map_device(struct rte_pci_device *dev) /* Unmap pci device */ void -pci_unmap_device(struct rte_pci_device *dev) +rte_eal_pci_unmap_device(struct rte_pci_device *dev) { /* try unmapping the NIC resources */ switch (dev->kdrv) { diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map index 9d7adf1..1b28170 100644 --- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map +++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map @@ -135,3 +135,10 @@ DPDK_2.2 { rte_xen_dom0_supported; } DPDK_2.1; + +DPDK_2.3 { + global: + + rte_eal_pci_map_device; + rte_eal_pci_unmap_device; +} DPDK_2.2; diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c index dcfe947..96d5113 100644 --- a/lib/librte_eal/common/eal_common_pci.c +++ b/lib/librte_eal/common/eal_common_pci.c @@ -188,7 +188,7 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d pci_config_space_set(dev); #endif /* map resources for devices that use igb_uio */ - ret = pci_map_device(dev); + ret = rte_eal_pci_map_device(dev); if (ret != 0) return ret; } else if (dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND && @@ -254,7 +254,7 @@ rte_eal_pci_detach_dev(struct rte_pci_driver *dr, if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING) /* unmap resources for devices that use igb_uio */ - pci_unmap_device(dev); + rte_eal_pci_unmap_device(dev); return 0; } diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h index 072e672..2342fa1 100644 --- a/lib/librte_eal/common/eal_private.h +++ b/lib/librte_eal/common/eal_private.h @@ -165,24 +165,6 @@ struct rte_pci_device; int pci_unbind_kernel_driver(struct rte_pci_device *dev); /** - * Map this device - * - * This function is private to EAL. - * - * @return - * 0 on success, negative on error and positive if no driver - * is found for the device. - */ -int pci_map_device(struct rte_pci_device *dev); - -/** - * Unmap this device - * - * This function is private to EAL. - */ -void pci_unmap_device(struct rte_pci_device *dev); - -/** * Map the PCI resource of a PCI device in virtual memory * * This function is private to EAL. diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h index 334c12e..2224109 100644 --- a/lib/librte_eal/common/include/rte_pci.h +++ b/lib/librte_eal/common/include/rte_pci.h @@ -485,6 +485,33 @@ int rte_eal_pci_read_config(const struct rte_pci_device *device, */ int rte_eal_pci_write_config(const struct rte_pci_device *device, const void *buf, size_t len, off_t offset); +/** + * Map the PCI device resources in user space virtual memory address + * + * Note that driver should not call this function when flag + * RTE_PCI_DRV_NEED_MAPPING is set, as EAL will do that for + * you when it's on. + * + * @param dev + * A pointer to a rte_pci_device structure describing the device + * to use + * + * @return + * 0 on success, negative on error and positive if no driver + * is found for the device. + */ +int rte_eal_pci_map_device(struct rte_pci_device *dev); + +/** + * Unmap this device + * + * @param dev + * A pointer to a rte_pci_device structure describing the device + * to use + */ +void rte_eal_pci_unmap_device(struct rte_pci_device *dev); + + #ifdef RTE_PCI_CONFIG /** diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c index bc5b5be..db947da 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c @@ -124,7 +124,7 @@ pci_get_kernel_driver_by_path(const char *filename, char *dri_name) /* Map pci device */ int -pci_map_device(struct rte_pci_device *dev) +rte_eal_pci_map_device(struct rte_pci_device *dev) { int ret = -1; @@ -153,7 +153,7 @@ pci_map_device(struct rte_pci_device *dev) /* Unmap pci device */ void -pci_unmap_device(struct rte_pci_device *dev) +rte_eal_pci_unmap_device(struct rte_pci_device *dev) { /* try unmapping the NIC resources using VFIO if it exists */ switch (dev->kdrv) { diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map index cbe175f..b9937c4 100644 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map @@ -138,3 +138,10 @@ DPDK_2.2 { rte_xen_dom0_supported; } DPDK_2.1; + +DPDK_2.3 { + global: + + rte_eal_pci_map_device; + rte_eal_pci_unmap_device; +} DPDK_2.2; -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v5 7/9] eal: pci: export pci_[un]map_device 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu @ 2016-01-19 8:17 ` David Marchand 0 siblings, 0 replies; 122+ messages in thread From: David Marchand @ 2016-01-19 8:17 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev On Tue, Jan 19, 2016 at 9:12 AM, Yuanhan Liu <yuanhan.liu@linux.intel.com> wrote: > Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will > invoke pci_map_device internally for us. From that point view, there > is no need to export pci_map_device. > > However, for virtio pmd driver, which is designed to work without > binding UIO (or something similar first), pci_map_device() will fail, > which ends up with virtio pmd driver being skipped. Therefore, we can > not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver. > > Therefore, this patch exports pci_map_device, and let virtio pmd > call it when necessary. > > Cc: David Marchand <david.marchand@6wind.com> > Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> > Tested-By: Santosh Shukla <sshukla@mvista.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> lgtm Acked-by: David Marchand <david.marchand@6wind.com> -- David Marchand ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu ` (6 preceding siblings ...) 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu @ 2016-01-19 8:12 ` Yuanhan Liu 2016-01-21 11:37 ` Thomas Monjalon 2016-01-21 11:49 ` Thomas Monjalon 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu ` (2 subsequent siblings) 10 siblings, 2 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-19 8:12 UTC (permalink / raw) To: dev Modern (v1.0) virtio pci device defines several pci capabilities. Each cap has a configure structure corresponding to it, and the cap.bar and cap.offset fields tell us where to find it. Firstly, we map the pci resources by rte_eal_pci_map_device(). We then could easily locate a cfg structure by: cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset; Therefore, the entrance of enabling modern (v1.0) pci device support is to iterate the pci capability lists, and to locate some configs we care; and they are: - common cfg For generic virtio and virtqueue configuration, such as setting/getting features, enabling a specific queue, and so on. - nofity cfg Combining with `queue_notify_off' from common cfg, we could use it to notify a specific virt queue. - device cfg Where virtio_net_config structure is located. - isr cfg Where to read isr (interrupt status). If any of above cap is not found, we fallback to the legacy virtio handling. If succeed, hw->vtpci_ops is assigned to modern_ops, where all operations are implemented by reading/writing a (or few) specific configuration space from above 4 cfg structures. And that's basically how this patch works. Besides those changes, virtio 1.0 introduces a new status field: FEATURES_OK, which is set after features negotiation is done. Last, set the VIRTIO_F_VERSION_1 feature flag. 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> --- v5: - rename MODERN_READ/WRITE_DEF macro name to IO_READ/WRITE_DEF - check offset + length overflow --- doc/guides/rel_notes/release_2_3.rst | 3 + drivers/net/virtio/virtio_ethdev.c | 25 ++- drivers/net/virtio/virtio_ethdev.h | 3 +- drivers/net/virtio/virtio_pci.c | 341 ++++++++++++++++++++++++++++++++++- drivers/net/virtio/virtio_pci.h | 67 +++++++ drivers/net/virtio/virtqueue.h | 2 + 6 files changed, 436 insertions(+), 5 deletions(-) diff --git a/doc/guides/rel_notes/release_2_3.rst b/doc/guides/rel_notes/release_2_3.rst index 99de186..c390d97 100644 --- a/doc/guides/rel_notes/release_2_3.rst +++ b/doc/guides/rel_notes/release_2_3.rst @@ -4,6 +4,9 @@ DPDK Release 2.3 New Features ------------ +* **Virtio 1.0 support.** + + Enabled virtio 1.0 support for virtio pmd driver. Resolved Issues --------------- diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 94e0c4a..deb0382 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) return virtio_send_command(hw->cvq, &ctrl, &len, 1); } -static void +static int virtio_negotiate_features(struct virtio_hw *hw) { uint64_t host_features; @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw) hw->guest_features = vtpci_negotiate_features(hw, host_features); PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, hw->guest_features); + + if (hw->modern) { + if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) { + PMD_INIT_LOG(ERR, + "VIRTIO_F_VERSION_1 features is not enabled."); + return -1; + } + vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK); + if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) { + PMD_INIT_LOG(ERR, + "failed to set FEATURES_OK status!"); + return -1; + } + } + + return 0; } /* @@ -1032,7 +1048,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev) /* Tell the host we've known how to drive the device. */ vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER); - virtio_negotiate_features(hw); + if (virtio_negotiate_features(hw) < 0) + return -1; /* If host does not support status then disable LSC */ if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) @@ -1043,7 +1060,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev) rx_func_get(eth_dev); /* Setting up rx_header size for the device */ - if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) + if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) || + vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); else hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr); @@ -1159,6 +1177,7 @@ eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev) rte_intr_callback_unregister(&pci_dev->intr_handle, virtio_interrupt_handler, eth_dev); + rte_eal_pci_unmap_device(pci_dev); PMD_INIT_LOG(DEBUG, "dev_uninit completed"); diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h index ae2d47d..fed9571 100644 --- a/drivers/net/virtio/virtio_ethdev.h +++ b/drivers/net/virtio/virtio_ethdev.h @@ -64,7 +64,8 @@ 1u << VIRTIO_NET_F_CTRL_VQ | \ 1u << VIRTIO_NET_F_CTRL_RX | \ 1u << VIRTIO_NET_F_CTRL_VLAN | \ - 1u << VIRTIO_NET_F_MRG_RXBUF) + 1u << VIRTIO_NET_F_MRG_RXBUF | \ + 1ULL << VIRTIO_F_VERSION_1) /* * CQ function prototype diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 5e1c55f..d7a453f 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -41,6 +41,14 @@ #include "virtio_logs.h" #include "virtqueue.h" +/* + * Following macros are derieved from linux/pci_regs.h, however, + * we can't simply include that header here, as there is no such + * file for non-Linux platform. + */ +#define PCI_CAPABILITY_LIST 0x34 +#define PCI_CAP_ID_VNDR 0x09 + static void legacy_read_dev_config(struct virtio_hw *hw, size_t offset, void *dst, int length) @@ -442,6 +450,204 @@ static const struct virtio_pci_ops legacy_ops = { }; +#define IO_READ_DEF(nr_bits, type) \ +static inline type \ +io_read##nr_bits(type *addr) \ +{ \ + return *(volatile type *)addr; \ +} + +#define IO_WRITE_DEF(nr_bits, type) \ +static inline void \ +io_write##nr_bits(type val, type *addr) \ +{ \ + *(volatile type *)addr = val; \ +} + +IO_READ_DEF (8, uint8_t) +IO_WRITE_DEF(8, uint8_t) + +IO_READ_DEF (16, uint16_t) +IO_WRITE_DEF(16, uint16_t) + +IO_READ_DEF (32, uint32_t) +IO_WRITE_DEF(32, uint32_t) + +static inline void +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) +{ + io_write32(val & ((1ULL << 32) - 1), lo); + io_write32(val >> 32, hi); +} + +static void +modern_read_dev_config(struct virtio_hw *hw, size_t offset, + void *dst, int length) +{ + int i; + uint8_t *p; + uint8_t old_gen, new_gen; + + do { + old_gen = io_read8(&hw->common_cfg->config_generation); + + p = dst; + for (i = 0; i < length; i++) + *p++ = io_read8((uint8_t *)hw->dev_cfg + offset + i); + + new_gen = io_read8(&hw->common_cfg->config_generation); + } while (old_gen != new_gen); +} + +static void +modern_write_dev_config(struct virtio_hw *hw, size_t offset, + const void *src, int length) +{ + int i; + const uint8_t *p = src; + + for (i = 0; i < length; i++) + io_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i); +} + +static uint64_t +modern_get_features(struct virtio_hw *hw) +{ + uint32_t features_lo, features_hi; + + io_write32(0, &hw->common_cfg->device_feature_select); + features_lo = io_read32(&hw->common_cfg->device_feature); + + io_write32(1, &hw->common_cfg->device_feature_select); + features_hi = io_read32(&hw->common_cfg->device_feature); + + return ((uint64_t)features_hi << 32) | features_lo; +} + +static void +modern_set_features(struct virtio_hw *hw, uint64_t features) +{ + io_write32(0, &hw->common_cfg->guest_feature_select); + io_write32(features & ((1ULL << 32) - 1), + &hw->common_cfg->guest_feature); + + io_write32(1, &hw->common_cfg->guest_feature_select); + io_write32(features >> 32, + &hw->common_cfg->guest_feature); +} + +static uint8_t +modern_get_status(struct virtio_hw *hw) +{ + return io_read8(&hw->common_cfg->device_status); +} + +static void +modern_set_status(struct virtio_hw *hw, uint8_t status) +{ + io_write8(status, &hw->common_cfg->device_status); +} + +static void +modern_reset(struct virtio_hw *hw) +{ + modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); + modern_get_status(hw); +} + +static uint8_t +modern_get_isr(struct virtio_hw *hw) +{ + return io_read8(hw->isr); +} + +static uint16_t +modern_set_config_irq(struct virtio_hw *hw, uint16_t vec) +{ + io_write16(vec, &hw->common_cfg->msix_config); + return io_read16(&hw->common_cfg->msix_config); +} + +static uint16_t +modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) +{ + io_write16(queue_id, &hw->common_cfg->queue_select); + return io_read16(&hw->common_cfg->queue_size); +} + +static void +modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + uint64_t desc_addr, avail_addr, used_addr; + uint16_t notify_off; + + desc_addr = vq->mz->phys_addr; + avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc); + used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail, + ring[vq->vq_nentries]), + VIRTIO_PCI_VRING_ALIGN); + + io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); + + io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + notify_off = io_read16(&hw->common_cfg->queue_notify_off); + vq->notify_addr = (void *)((uint8_t *)hw->notify_base + + notify_off * hw->notify_off_multiplier); + + io_write16(1, &hw->common_cfg->queue_enable); + + PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index); + PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr); + PMD_INIT_LOG(DEBUG, "\t aval_addr: %"PRIx64, avail_addr); + PMD_INIT_LOG(DEBUG, "\t used_addr: %"PRIx64, used_addr); + PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)", + vq->notify_addr, notify_off); +} + +static void +modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); + + io_write64_twopart(0, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + io_write64_twopart(0, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + io_write64_twopart(0, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + io_write16(0, &hw->common_cfg->queue_enable); +} + +static void +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) +{ + io_write16(1, vq->notify_addr); +} + +static const struct virtio_pci_ops modern_ops = { + .read_dev_cfg = modern_read_dev_config, + .write_dev_cfg = modern_write_dev_config, + .reset = modern_reset, + .get_status = modern_get_status, + .set_status = modern_set_status, + .get_features = modern_get_features, + .set_features = modern_set_features, + .get_isr = modern_get_isr, + .set_config_irq = modern_set_config_irq, + .get_queue_num = modern_get_queue_num, + .setup_queue = modern_setup_queue, + .del_queue = modern_del_queue, + .notify_queue = modern_notify_queue, +}; + + void vtpci_read_dev_config(struct virtio_hw *hw, size_t offset, void *dst, int length) @@ -495,6 +701,12 @@ vtpci_set_status(struct virtio_hw *hw, uint8_t status) } uint8_t +vtpci_get_status(struct virtio_hw *hw) +{ + return hw->vtpci_ops->get_status(hw); +} + +uint8_t vtpci_isr(struct virtio_hw *hw) { return hw->vtpci_ops->get_isr(hw); @@ -508,15 +720,142 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) return hw->vtpci_ops->set_config_irq(hw, vec); } +static void * +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) +{ + uint8_t bar = cap->bar; + uint32_t length = cap->length; + uint32_t offset = cap->offset; + uint8_t *base; + + if (bar > 5) { + PMD_INIT_LOG(ERR, "invalid bar: %u", bar); + return NULL; + } + + if (offset + length < offset) { + PMD_INIT_LOG(ERR, "offset(%u) + lenght(%u) overflows", + offset, length); + return NULL; + } + + if (offset + length > dev->mem_resource[bar].len) { + PMD_INIT_LOG(ERR, + "invalid cap: overflows bar space: %u > %"PRIu64, + offset + length, dev->mem_resource[bar].len); + return NULL; + } + + base = dev->mem_resource[bar].addr; + if (base == NULL) { + PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar); + return NULL; + } + + return base + offset; +} + +static int +virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw) +{ + uint8_t pos; + struct virtio_pci_cap cap; + int ret; + + if (rte_eal_pci_map_device(dev) < 0) { + PMD_INIT_LOG(DEBUG, "failed to map pci device!"); + return -1; + } + + ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST); + if (ret < 0) { + PMD_INIT_LOG(DEBUG, "failed to read pci capability list"); + return -1; + } + + while (pos) { + ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos); + if (ret < 0) { + PMD_INIT_LOG(ERR, + "failed to read pci cap at pos: %x", pos); + break; + } + + if (cap.cap_vndr != PCI_CAP_ID_VNDR) { + PMD_INIT_LOG(DEBUG, + "[%2x] skipping non VNDR cap id: %02x", + pos, cap.cap_vndr); + goto next; + } + + PMD_INIT_LOG(DEBUG, + "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u", + pos, cap.cfg_type, cap.bar, cap.offset, cap.length); + + switch (cap.cfg_type) { + case VIRTIO_PCI_CAP_COMMON_CFG: + hw->common_cfg = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_NOTIFY_CFG: + rte_eal_pci_read_config(dev, &hw->notify_off_multiplier, + 4, pos + sizeof(cap)); + hw->notify_base = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_DEVICE_CFG: + hw->dev_cfg = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_ISR_CFG: + hw->isr = get_cfg_addr(dev, &cap); + break; + } + + next: + pos = cap.cap_next; + } + + if (hw->common_cfg == NULL || hw->notify_base == NULL || + hw->dev_cfg == NULL || hw->isr == NULL) { + PMD_INIT_LOG(INFO, "no modern virtio pci device found."); + return -1; + } + + PMD_INIT_LOG(INFO, "found modern virtio pci device."); + + PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg); + PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg); + PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr); + PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u", + hw->notify_base, hw->notify_off_multiplier); + + return 0; +} + int vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) { - hw->vtpci_ops = &legacy_ops; + hw->dev = dev; + + /* + * Try if we can succeed reading virtio pci caps, which exists + * only on modern pci device. If failed, we fallback to legacy + * virtio handling. + */ + if (virtio_read_caps(dev, hw) == 0) { + PMD_INIT_LOG(INFO, "modern virtio pci detected."); + hw->vtpci_ops = &modern_ops; + hw->modern = 1; + dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; + return 0; + } + PMD_INIT_LOG(INFO, "trying with legacy virtio pci."); if (legacy_virtio_resource_init(dev) < 0) return -1; + + hw->vtpci_ops = &legacy_ops; hw->use_msix = legacy_virtio_has_msix(&dev->addr); hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr; + hw->modern = 0; return 0; } diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index d7bc6bb..fcac660 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -93,6 +93,7 @@ struct virtqueue; #define VIRTIO_CONFIG_STATUS_ACK 0x01 #define VIRTIO_CONFIG_STATUS_DRIVER 0x02 #define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04 +#define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08 #define VIRTIO_CONFIG_STATUS_FAILED 0x80 /* @@ -141,6 +142,8 @@ struct virtqueue; /* We support indirect buffer descriptors */ #define VIRTIO_RING_F_INDIRECT_DESC 28 +#define VIRTIO_F_VERSION_1 32 + /* * Some VirtIO feature bits (currently bits 28 through 31) are * reserved for the transport being used (eg. virtio_ring), the @@ -163,6 +166,60 @@ struct virtqueue; */ #define VIRTIO_MAX_VIRTQUEUES 8 +/* Common configuration */ +#define VIRTIO_PCI_CAP_COMMON_CFG 1 +/* Notifications */ +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 +/* ISR Status */ +#define VIRTIO_PCI_CAP_ISR_CFG 3 +/* Device specific configuration */ +#define VIRTIO_PCI_CAP_DEVICE_CFG 4 +/* PCI configuration access */ +#define VIRTIO_PCI_CAP_PCI_CFG 5 + +/* This is the PCI capability header: */ +struct virtio_pci_cap { + uint8_t cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */ + uint8_t cap_next; /* Generic PCI field: next ptr. */ + uint8_t cap_len; /* Generic PCI field: capability length */ + uint8_t cfg_type; /* Identifies the structure. */ + uint8_t bar; /* Where to find it. */ + uint8_t padding[3]; /* Pad to full dword. */ + uint32_t offset; /* Offset within bar. */ + uint32_t length; /* Length of the structure, in bytes. */ +}; + +struct virtio_pci_notify_cap { + struct virtio_pci_cap cap; + uint32_t notify_off_multiplier; /* Multiplier for queue_notify_off. */ +}; + +/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */ +struct virtio_pci_common_cfg { + /* About the whole device. */ + uint32_t device_feature_select; /* read-write */ + uint32_t device_feature; /* read-only */ + uint32_t guest_feature_select; /* read-write */ + uint32_t guest_feature; /* read-write */ + uint16_t msix_config; /* read-write */ + uint16_t num_queues; /* read-only */ + uint8_t device_status; /* read-write */ + uint8_t config_generation; /* read-only */ + + /* About a specific virtqueue. */ + uint16_t queue_select; /* read-write */ + uint16_t queue_size; /* read-write, power of 2. */ + uint16_t queue_msix_vector; /* read-write */ + uint16_t queue_enable; /* read-write */ + uint16_t queue_notify_off; /* read-only */ + uint32_t queue_desc_lo; /* read-write */ + uint32_t queue_desc_hi; /* read-write */ + uint32_t queue_avail_lo; /* read-write */ + uint32_t queue_avail_hi; /* read-write */ + uint32_t queue_used_lo; /* read-write */ + uint32_t queue_used_hi; /* read-write */ +}; + struct virtio_hw; struct virtio_pci_ops { @@ -188,6 +245,8 @@ struct virtio_pci_ops { void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq); }; +struct virtio_net_config; + struct virtio_hw { struct virtqueue *cvq; uint32_t io_base; @@ -198,7 +257,14 @@ struct virtio_hw { uint8_t vlan_strip; uint8_t use_msix; uint8_t started; + uint8_t modern; uint8_t mac_addr[ETHER_ADDR_LEN]; + uint32_t notify_off_multiplier; + uint8_t *isr; + uint16_t *notify_base; + struct rte_pci_device *dev; + struct virtio_pci_common_cfg *common_cfg; + struct virtio_net_config *dev_cfg; const struct virtio_pci_ops *vtpci_ops; }; @@ -284,6 +350,7 @@ void vtpci_reset(struct virtio_hw *); void vtpci_reinit_complete(struct virtio_hw *); +uint8_t vtpci_get_status(struct virtio_hw *); void vtpci_set_status(struct virtio_hw *, uint8_t); uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t); diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h index d7fb450..99d4fa9 100644 --- a/drivers/net/virtio/virtqueue.h +++ b/drivers/net/virtio/virtqueue.h @@ -202,6 +202,8 @@ struct virtqueue { /* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */ uint64_t size_bins[8]; + uint16_t *notify_addr; + struct vq_desc_extra { void *cookie; uint16_t ndescs; -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support Yuanhan Liu @ 2016-01-21 11:37 ` Thomas Monjalon 2016-01-27 3:49 ` Yuanhan Liu 2016-01-21 11:49 ` Thomas Monjalon 1 sibling, 1 reply; 122+ messages in thread From: Thomas Monjalon @ 2016-01-21 11:37 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev 2016-01-19 16:12, Yuanhan Liu: > +#define IO_READ_DEF(nr_bits, type) \ > +static inline type \ > +io_read##nr_bits(type *addr) \ > +{ \ > + return *(volatile type *)addr; \ > +} > + > +#define IO_WRITE_DEF(nr_bits, type) \ > +static inline void \ > +io_write##nr_bits(type val, type *addr) \ > +{ \ > + *(volatile type *)addr = val; \ > +} > + > +IO_READ_DEF (8, uint8_t) > +IO_WRITE_DEF(8, uint8_t) > + > +IO_READ_DEF (16, uint16_t) > +IO_WRITE_DEF(16, uint16_t) > + > +IO_READ_DEF (32, uint32_t) > +IO_WRITE_DEF(32, uint32_t) Yes you can do this. But not sure you should. > +static inline void > +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) > +{ > + io_write32(val & ((1ULL << 32) - 1), lo); > + io_write32(val >> 32, hi); > +} When debugging this code, how GDB behave? How to find the definition of io_write32() with grep or simple editors? ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support 2016-01-21 11:37 ` Thomas Monjalon @ 2016-01-27 3:49 ` Yuanhan Liu 0 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-27 3:49 UTC (permalink / raw) To: Thomas Monjalon; +Cc: dev On Thu, Jan 21, 2016 at 12:37:42PM +0100, Thomas Monjalon wrote: > 2016-01-19 16:12, Yuanhan Liu: > > +#define IO_READ_DEF(nr_bits, type) \ > > +static inline type \ > > +io_read##nr_bits(type *addr) \ > > +{ \ > > + return *(volatile type *)addr; \ > > +} > > + > > +#define IO_WRITE_DEF(nr_bits, type) \ > > +static inline void \ > > +io_write##nr_bits(type val, type *addr) \ > > +{ \ > > + *(volatile type *)addr = val; \ > > +} > > + > > +IO_READ_DEF (8, uint8_t) > > +IO_WRITE_DEF(8, uint8_t) > > + > > +IO_READ_DEF (16, uint16_t) > > +IO_WRITE_DEF(16, uint16_t) > > + > > +IO_READ_DEF (32, uint32_t) > > +IO_WRITE_DEF(32, uint32_t) > > Yes you can do this. > But not sure you should. > > > +static inline void > > +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) > > +{ > > + io_write32(val & ((1ULL << 32) - 1), lo); > > + io_write32(val >> 32, hi); > > +} > > When debugging this code, how GDB behave? > How to find the definition of io_write32() with grep or simple editors? Okay, I will unfold them. --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support Yuanhan Liu 2016-01-21 11:37 ` Thomas Monjalon @ 2016-01-21 11:49 ` Thomas Monjalon 2016-01-27 3:46 ` Yuanhan Liu 1 sibling, 1 reply; 122+ messages in thread From: Thomas Monjalon @ 2016-01-21 11:49 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev 2016-01-19 16:12, Yuanhan Liu: > int > vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) > { > - hw->vtpci_ops = &legacy_ops; > + hw->dev = dev; > + > + /* > + * Try if we can succeed reading virtio pci caps, which exists > + * only on modern pci device. If failed, we fallback to legacy > + * virtio handling. > + */ > + if (virtio_read_caps(dev, hw) == 0) { > + PMD_INIT_LOG(INFO, "modern virtio pci detected."); > + hw->vtpci_ops = &modern_ops; > + hw->modern = 1; > + dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; > + return 0; > + } RTE_PCI_DRV_INTR_LSC is already set by virtio_resource_init_by_uio(). Do you mean interrupt was not supported with legacy virtio? ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support 2016-01-21 11:49 ` Thomas Monjalon @ 2016-01-27 3:46 ` Yuanhan Liu 2016-01-27 8:11 ` Thomas Monjalon 0 siblings, 1 reply; 122+ messages in thread From: Yuanhan Liu @ 2016-01-27 3:46 UTC (permalink / raw) To: Thomas Monjalon; +Cc: dev On Thu, Jan 21, 2016 at 12:49:10PM +0100, Thomas Monjalon wrote: > 2016-01-19 16:12, Yuanhan Liu: > > int > > vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) > > { > > - hw->vtpci_ops = &legacy_ops; > > + hw->dev = dev; > > + > > + /* > > + * Try if we can succeed reading virtio pci caps, which exists > > + * only on modern pci device. If failed, we fallback to legacy > > + * virtio handling. > > + */ > > + if (virtio_read_caps(dev, hw) == 0) { > > + PMD_INIT_LOG(INFO, "modern virtio pci detected."); > > + hw->vtpci_ops = &modern_ops; > > + hw->modern = 1; > > + dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; > > + return 0; > > + } > > RTE_PCI_DRV_INTR_LSC is already set by virtio_resource_init_by_uio(). We don't go that far here. Here we just detect if it's a modern virtio device. And if yes, we do some modern initiations, and return. virtio_resource_init_by_uio() is invoked when virtio_read_caps() fails. > Do you mean interrupt was not supported with legacy virtio? Nope. this patch set changes nothing on legacy virtio support. --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support 2016-01-27 3:46 ` Yuanhan Liu @ 2016-01-27 8:11 ` Thomas Monjalon 0 siblings, 0 replies; 122+ messages in thread From: Thomas Monjalon @ 2016-01-27 8:11 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev 2016-01-27 11:46, Yuanhan Liu: > On Thu, Jan 21, 2016 at 12:49:10PM +0100, Thomas Monjalon wrote: > > 2016-01-19 16:12, Yuanhan Liu: > > > int > > > vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) > > > { > > > - hw->vtpci_ops = &legacy_ops; > > > + hw->dev = dev; > > > + > > > + /* > > > + * Try if we can succeed reading virtio pci caps, which exists > > > + * only on modern pci device. If failed, we fallback to legacy > > > + * virtio handling. > > > + */ > > > + if (virtio_read_caps(dev, hw) == 0) { > > > + PMD_INIT_LOG(INFO, "modern virtio pci detected."); > > > + hw->vtpci_ops = &modern_ops; > > > + hw->modern = 1; > > > + dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; > > > + return 0; > > > + } > > > > RTE_PCI_DRV_INTR_LSC is already set by virtio_resource_init_by_uio(). > > We don't go that far here. Here we just detect if it's a modern virtio > device. And if yes, we do some modern initiations, and return. > > virtio_resource_init_by_uio() is invoked when virtio_read_caps() fails. > > > Do you mean interrupt was not supported with legacy virtio? > > Nope. this patch set changes nothing on legacy virtio support. Oh yes. I guess I had not seen the return. ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v5 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu ` (7 preceding siblings ...) 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support Yuanhan Liu @ 2016-01-19 8:12 ` Yuanhan Liu 2016-01-19 8:55 ` [dpdk-dev] [PATCH v5 0/9] virtio 1.0 enabling for virtio pmd driver Xie, Huawei 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 " Yuanhan Liu 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-19 8:12 UTC (permalink / raw) To: dev virtio_pci.c is the only file references those macros; move them there. 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> --- drivers/net/virtio/virtio_pci.c | 19 +++++++++++++++++++ drivers/net/virtio/virtio_pci.h | 18 ------------------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index d7a453f..6b87429 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -49,6 +49,25 @@ #define PCI_CAPABILITY_LIST 0x34 #define PCI_CAP_ID_VNDR 0x09 + +#define VIRTIO_PCI_REG_ADDR(hw, reg) \ + (unsigned short)((hw)->io_base + (reg)) + +#define VIRTIO_READ_REG_1(hw, reg) \ + inb((VIRTIO_PCI_REG_ADDR((hw), (reg)))) +#define VIRTIO_WRITE_REG_1(hw, reg, value) \ + outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + +#define VIRTIO_READ_REG_2(hw, reg) \ + inw((VIRTIO_PCI_REG_ADDR((hw), (reg)))) +#define VIRTIO_WRITE_REG_2(hw, reg, value) \ + outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + +#define VIRTIO_READ_REG_4(hw, reg) \ + inl((VIRTIO_PCI_REG_ADDR((hw), (reg)))) +#define VIRTIO_WRITE_REG_4(hw, reg, value) \ + outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + static void legacy_read_dev_config(struct virtio_hw *hw, size_t offset, void *dst, int length) diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index fcac660..0544a07 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -318,24 +318,6 @@ outl_p(unsigned int data, unsigned int port) } #endif -#define VIRTIO_PCI_REG_ADDR(hw, reg) \ - (unsigned short)((hw)->io_base + (reg)) - -#define VIRTIO_READ_REG_1(hw, reg) \ - inb((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_1(hw, reg, value) \ - outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - -#define VIRTIO_READ_REG_2(hw, reg) \ - inw((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_2(hw, reg, value) \ - outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - -#define VIRTIO_READ_REG_4(hw, reg) \ - inl((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_4(hw, reg, value) \ - outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - static inline int vtpci_with_feature(struct virtio_hw *hw, uint64_t bit) { -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v5 0/9] virtio 1.0 enabling for virtio pmd driver 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu ` (8 preceding siblings ...) 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu @ 2016-01-19 8:55 ` Xie, Huawei 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 " Yuanhan Liu 10 siblings, 0 replies; 122+ messages in thread From: Xie, Huawei @ 2016-01-19 8:55 UTC (permalink / raw) To: Yuanhan Liu, dev On 1/19/2016 4:10 PM, Yuanhan Liu wrote: > v5: minor fixes: > > - fix wrong type of arg "offset" of read/write_dev_config(): patch 2 > is newly added for that. > > - check "offset + length" overflow > > Almost all difference comes from virtio 1.0 are the PCI layout change: > the major configuration structures are stored at bar space, and their > location is stored at corresponding pci cap structure. Reading/parsing > them is one of the major work of patch 8. > > To make handling virtio v1.0 and v0.95 co-exist well, this patch set > introduces a virtio_pci_ops structure, to add another layer so that > we could keep those vtpci_foo_bar "APIs". With that, we could do the > minimum change to add virtio 1.0 support. > > > Rough test guide > ================ > > Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add > option "disable-modern=false" to qemu virtio-net-pci device to enable > virtio 1.0 (which is disabled by default). > > And if you see something like following from 'lspci -v', it means virtio > 1.0 is indeed enabled: > > 00:04.0 Ethernet controller: Red Hat, Inc Virtio network device > Subsystem: Red Hat, Inc Device 0001 > Physical Slot: 4 > Flags: bus master, fast devsel, latency 0, IRQ 11 > I/O ports at c040 [size=64] > Memory at febf1000 (32-bit, non-prefetchable) [size=4K] > Memory at fe000000 (64-bit, prefetchable) [size=8M] > Expansion ROM at feb80000 [disabled] [size=256K] > Capabilities: [98] MSI-X: Enable+ Count=6 Masked- > ==> Capabilities: [84] Vendor Specific Information: Len=14 <?> > ==> Capabilities: [70] Vendor Specific Information: Len=14 <?> > ==> Capabilities: [60] Vendor Specific Information: Len=10 <?> > ==> Capabilities: [50] Vendor Specific Information: Len=10 <?> > ==> Capabilities: [40] Vendor Specific Information: Len=10 <?> > Kernel driver in use: virtio-pci > Kernel modules: virtio_pci > > After that, there wasn't anything speical comparing to the old virtio > 0.95 pmd driver. > > > > --- > Yuanhan Liu (9): > virtio: don't set vring address again at queue startup > virtio: define offset as size_t type > virtio: introduce struct virtio_pci_ops > virtio: move left pci stuff to virtio_pci.c > viritio: switch to 64 bit features > virtio: retrieve hdr_size from hw->vtnet_hdr_size > eal: pci: export pci_[un]map_device > virtio: add 1.0 support > virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c > > doc/guides/rel_notes/release_2_3.rst | 3 + > drivers/net/virtio/virtio_ethdev.c | 302 +-------- > drivers/net/virtio/virtio_ethdev.h | 3 +- > drivers/net/virtio/virtio_pci.c | 799 +++++++++++++++++++++++- > drivers/net/virtio/virtio_pci.h | 124 +++- > drivers/net/virtio/virtio_rxtx.c | 21 +- > drivers/net/virtio/virtio_rxtx_simple.c | 12 +- > drivers/net/virtio/virtqueue.h | 4 +- > lib/librte_eal/bsdapp/eal/eal_pci.c | 4 +- > lib/librte_eal/bsdapp/eal/rte_eal_version.map | 7 + > lib/librte_eal/common/eal_common_pci.c | 4 +- > lib/librte_eal/common/eal_private.h | 18 - > lib/librte_eal/common/include/rte_pci.h | 27 + > lib/librte_eal/linuxapp/eal/eal_pci.c | 4 +- > lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 + > 15 files changed, 957 insertions(+), 382 deletions(-) > Acked-by: Huawei Xie <huawei.xie@intel.com> Next time, please include all the changes made in the change notice. ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v6 0/9] virtio 1.0 enabling for virtio pmd driver 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu ` (9 preceding siblings ...) 2016-01-19 8:55 ` [dpdk-dev] [PATCH v5 0/9] virtio 1.0 enabling for virtio pmd driver Xie, Huawei @ 2016-01-28 7:54 ` Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu ` (10 more replies) 10 siblings, 11 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-28 7:54 UTC (permalink / raw) To: dev v6: unfold IO_READ/WRITE_DEF macro v5: minor fixes: - fix wrong type of arg "offset" of read/write_dev_config(): patch 2 is newly added for that. - check "offset + length" overflow Almost all difference comes from virtio 1.0 are the PCI layout change: the major configuration structures are stored at bar space, and their location is stored at corresponding pci cap structure. Reading/parsing them is one of the major work of patch 8. To make handling virtio v1.0 and v0.95 co-exist well, this patch set introduces a virtio_pci_ops structure, to add another layer so that we could keep those vtpci_foo_bar "APIs". With that, we could do the minimum change to add virtio 1.0 support. Rough test guide ================ Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add option "disable-modern=false" to qemu virtio-net-pci device to enable virtio 1.0 (which is disabled by default). And if you see something like following from 'lspci -v', it means virtio 1.0 is indeed enabled: 00:04.0 Ethernet controller: Red Hat, Inc Virtio network device Subsystem: Red Hat, Inc Device 0001 Physical Slot: 4 Flags: bus master, fast devsel, latency 0, IRQ 11 I/O ports at c040 [size=64] Memory at febf1000 (32-bit, non-prefetchable) [size=4K] Memory at fe000000 (64-bit, prefetchable) [size=8M] Expansion ROM at feb80000 [disabled] [size=256K] Capabilities: [98] MSI-X: Enable+ Count=6 Masked- ==> Capabilities: [84] Vendor Specific Information: Len=14 <?> ==> Capabilities: [70] Vendor Specific Information: Len=14 <?> ==> Capabilities: [60] Vendor Specific Information: Len=10 <?> ==> Capabilities: [50] Vendor Specific Information: Len=10 <?> ==> Capabilities: [40] Vendor Specific Information: Len=10 <?> Kernel driver in use: virtio-pci Kernel modules: virtio_pci After that, there wasn't anything speical comparing to the old virtio 0.95 pmd driver. --- Yuanhan Liu (9): virtio: don't set vring address again at queue startup virtio: define offset as size_t type virtio: introduce struct virtio_pci_ops virtio: move left pci stuff to virtio_pci.c viritio: switch to 64 bit features virtio: retrieve hdr_size from hw->vtnet_hdr_size eal: pci: export pci_[un]map_device virtio: add 1.0 support virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c doc/guides/rel_notes/release_2_3.rst | 3 + drivers/net/virtio/virtio_ethdev.c | 302 +-------- drivers/net/virtio/virtio_ethdev.h | 3 +- drivers/net/virtio/virtio_pci.c | 813 +++++++++++++++++++++++- drivers/net/virtio/virtio_pci.h | 124 +++- drivers/net/virtio/virtio_rxtx.c | 21 +- drivers/net/virtio/virtio_rxtx_simple.c | 12 +- drivers/net/virtio/virtqueue.h | 4 +- lib/librte_eal/bsdapp/eal/eal_pci.c | 4 +- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 7 + lib/librte_eal/common/eal_common_pci.c | 4 +- lib/librte_eal/common/eal_private.h | 18 - lib/librte_eal/common/include/rte_pci.h | 27 + lib/librte_eal/linuxapp/eal/eal_pci.c | 4 +- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 + 15 files changed, 971 insertions(+), 382 deletions(-) -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v6 1/9] virtio: don't set vring address again at queue startup 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 " Yuanhan Liu @ 2016-01-28 7:54 ` Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 2/9] virtio: define offset as size_t type Yuanhan Liu ` (9 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-28 7:54 UTC (permalink / raw) To: dev As we have already set up it at virtio_dev_queue_setup(), and a vq restart will not reset the settings. 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_rxtx.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c index 74b39ef..b7267c0 100644 --- a/drivers/net/virtio/virtio_rxtx.c +++ b/drivers/net/virtio/virtio_rxtx.c @@ -339,11 +339,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type) vq_update_avail_idx(vq); PMD_INIT_LOG(DEBUG, "Allocated %d bufs", nbufs); - - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); } else if (queue_type == VTNET_TQ) { if (use_simple_rxtx) { int mid_idx = vq->vq_nentries >> 1; @@ -362,16 +357,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type) for (i = mid_idx; i < vq->vq_nentries; i++) vq->vq_ring.avail->ring[i] = i; } - - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); - } else { - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); } } -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v6 2/9] virtio: define offset as size_t type 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 " Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu @ 2016-01-28 7:54 ` Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu ` (8 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-28 7:54 UTC (permalink / raw) To: dev offset arg of vtpci_read/write_dev_config is derived from offsetof(), which is of size_t type, instead of uint64_t. So, define it as size_t type. 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_pci.c | 4 ++-- drivers/net/virtio/virtio_pci.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 2245bec..b34b59e 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -38,7 +38,7 @@ static uint8_t vtpci_get_status(struct virtio_hw *); void -vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset, +vtpci_read_dev_config(struct virtio_hw *hw, size_t offset, void *dst, int length) { uint64_t off; @@ -61,7 +61,7 @@ vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset, } void -vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset, +vtpci_write_dev_config(struct virtio_hw *hw, size_t offset, void *src, int length) { uint64_t off; diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index 47f722a..fe89c21 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -261,9 +261,9 @@ 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 *, uint64_t, void *, int); +void vtpci_write_dev_config(struct virtio_hw *, size_t, void *, int); -void vtpci_read_dev_config(struct virtio_hw *, uint64_t, void *, int); +void vtpci_read_dev_config(struct virtio_hw *, size_t, void *, int); uint8_t vtpci_isr(struct virtio_hw *); -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v6 3/9] virtio: introduce struct virtio_pci_ops 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 " Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 2/9] virtio: define offset as size_t type Yuanhan Liu @ 2016-01-28 7:54 ` Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu ` (7 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-28 7:54 UTC (permalink / raw) To: dev 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> --- 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 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v6 4/9] virtio: move left pci stuff to virtio_pci.c 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 " Yuanhan Liu ` (2 preceding siblings ...) 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu @ 2016-01-28 7:54 ` Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 5/9] viritio: switch to 64 bit features Yuanhan Liu ` (6 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-28 7:54 UTC (permalink / raw) To: dev virtio_pci.c is a more proper place for pci stuff; virtio_ethdev is not. 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 | 265 +----------------------------------- drivers/net/virtio/virtio_pci.c | 270 ++++++++++++++++++++++++++++++++++++- 2 files changed, 270 insertions(+), 265 deletions(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 6c1d3a0..b57224d 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -36,10 +36,6 @@ #include <stdio.h> #include <errno.h> #include <unistd.h> -#ifdef RTE_EXEC_ENV_LINUXAPP -#include <dirent.h> -#include <fcntl.h> -#endif #include <rte_ethdev.h> #include <rte_memcpy.h> @@ -955,260 +951,6 @@ virtio_negotiate_features(struct virtio_hw *hw) hw->guest_features); } -#ifdef RTE_EXEC_ENV_LINUXAPP -static int -parse_sysfs_value(const char *filename, unsigned long *val) -{ - FILE *f; - char buf[BUFSIZ]; - char *end = NULL; - - f = fopen(filename, "r"); - if (f == NULL) { - PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s", - __func__, filename); - return -1; - } - - if (fgets(buf, sizeof(buf), f) == NULL) { - PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s", - __func__, filename); - fclose(f); - return -1; - } - *val = strtoul(buf, &end, 0); - if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { - PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s", - __func__, filename); - fclose(f); - return -1; - } - fclose(f); - return 0; -} - -static int get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen, - unsigned int *uio_num) -{ - struct dirent *e; - DIR *dir; - char dirname[PATH_MAX]; - - /* depending on kernel version, uio can be located in uio/uioX - * or uio:uioX */ - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", - loc->domain, loc->bus, loc->devid, loc->function); - dir = opendir(dirname); - if (dir == NULL) { - /* retry with the parent directory */ - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, - loc->domain, loc->bus, loc->devid, loc->function); - dir = opendir(dirname); - - if (dir == NULL) { - PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname); - return -1; - } - } - - /* take the first file starting with "uio" */ - while ((e = readdir(dir)) != NULL) { - /* format could be uio%d ...*/ - int shortprefix_len = sizeof("uio") - 1; - /* ... or uio:uio%d */ - int longprefix_len = sizeof("uio:uio") - 1; - char *endptr; - - if (strncmp(e->d_name, "uio", 3) != 0) - continue; - - /* first try uio%d */ - errno = 0; - *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); - if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { - snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num); - break; - } - - /* then try uio:uio%d */ - errno = 0; - *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); - if (errno == 0 && endptr != (e->d_name + longprefix_len)) { - snprintf(buf, buflen, "%s/uio:uio%u", dirname, - *uio_num); - break; - } - } - closedir(dir); - - /* No uio resource found */ - if (e == NULL) { - PMD_INIT_LOG(ERR, "Could not find uio resource"); - return -1; - } - - return 0; -} - -static int -virtio_has_msix(const struct rte_pci_addr *loc) -{ - DIR *d; - char dirname[PATH_MAX]; - - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs", - loc->domain, loc->bus, loc->devid, loc->function); - - d = opendir(dirname); - if (d) - closedir(d); - - return (d != NULL); -} - -/* Extract I/O port numbers from sysfs */ -static int virtio_resource_init_by_uio(struct rte_pci_device *pci_dev) -{ - char dirname[PATH_MAX]; - char filename[PATH_MAX]; - unsigned long start, size; - unsigned int uio_num; - - if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0) - return -1; - - /* get portio size */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/size", dirname); - if (parse_sysfs_value(filename, &size) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse size", - __func__); - return -1; - } - - /* get portio start */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/start", dirname); - if (parse_sysfs_value(filename, &start) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", - __func__); - return -1; - } - pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; - pci_dev->mem_resource[0].len = (uint64_t)size; - PMD_INIT_LOG(DEBUG, - "PCI Port IO found start=0x%lx with size=0x%lx", - start, size); - - /* save fd */ - memset(dirname, 0, sizeof(dirname)); - snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num); - pci_dev->intr_handle.fd = open(dirname, O_RDWR); - if (pci_dev->intr_handle.fd < 0) { - PMD_INIT_LOG(ERR, "Cannot open %s: %s\n", - dirname, strerror(errno)); - return -1; - } - - pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO; - pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; - - return 0; -} - -/* Extract port I/O numbers from proc/ioports */ -static int virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev) -{ - uint16_t start, end; - int size; - FILE *fp; - char *line = NULL; - char pci_id[16]; - int found = 0; - size_t linesz; - - snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, - pci_dev->addr.domain, - pci_dev->addr.bus, - pci_dev->addr.devid, - pci_dev->addr.function); - - fp = fopen("/proc/ioports", "r"); - if (fp == NULL) { - PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__); - return -1; - } - - while (getdelim(&line, &linesz, '\n', fp) > 0) { - char *ptr = line; - char *left; - int n; - - n = strcspn(ptr, ":"); - ptr[n] = 0; - left = &ptr[n+1]; - - while (*left && isspace(*left)) - left++; - - if (!strncmp(left, pci_id, strlen(pci_id))) { - found = 1; - - while (*ptr && isspace(*ptr)) - ptr++; - - sscanf(ptr, "%04hx-%04hx", &start, &end); - size = end - start + 1; - - break; - } - } - - free(line); - fclose(fp); - - if (!found) - return -1; - - pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start; - pci_dev->mem_resource[0].len = (uint64_t)size; - PMD_INIT_LOG(DEBUG, - "PCI Port IO found start=0x%x with size=0x%x", - start, size); - - /* can't support lsc interrupt without uio */ - pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; - - return 0; -} - -/* Extract I/O port numbers from sysfs */ -static int virtio_resource_init(struct rte_pci_device *pci_dev) -{ - if (virtio_resource_init_by_uio(pci_dev) == 0) - return 0; - else - return virtio_resource_init_by_ioports(pci_dev); -} - -#else -static int -virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) -{ - /* nic_uio does not enable interrupts, return 0 (false). */ - return 0; -} - -static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) -{ - /* no setup required */ - return 0; -} -#endif - /* * Process Virtio Config changed interrupt and call the callback * if link state changed. @@ -1279,14 +1021,9 @@ 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) + if (vtpci_init(pci_dev, hw) < 0) return -1; - hw->use_msix = virtio_has_msix(&pci_dev->addr); - hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr; - /* Reset the device although not necessary at startup */ vtpci_reset(hw); diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 8d001e8..16485fa 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -32,6 +32,11 @@ */ #include <stdint.h> +#ifdef RTE_EXEC_ENV_LINUXAPP + #include <dirent.h> + #include <fcntl.h> +#endif + #include "virtio_pci.h" #include "virtio_logs.h" #include "virtqueue.h" @@ -156,6 +161,264 @@ legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq) VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index); } +#ifdef RTE_EXEC_ENV_LINUXAPP +static int +parse_sysfs_value(const char *filename, unsigned long *val) +{ + FILE *f; + char buf[BUFSIZ]; + char *end = NULL; + + f = fopen(filename, "r"); + if (f == NULL) { + PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s", + __func__, filename); + return -1; + } + + if (fgets(buf, sizeof(buf), f) == NULL) { + PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s", + __func__, filename); + fclose(f); + return -1; + } + *val = strtoul(buf, &end, 0); + if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { + PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s", + __func__, filename); + fclose(f); + return -1; + } + fclose(f); + return 0; +} + +static int +get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen, + unsigned int *uio_num) +{ + struct dirent *e; + DIR *dir; + char dirname[PATH_MAX]; + + /* depending on kernel version, uio can be located in uio/uioX + * or uio:uioX */ + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", + loc->domain, loc->bus, loc->devid, loc->function); + dir = opendir(dirname); + if (dir == NULL) { + /* retry with the parent directory */ + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, + loc->domain, loc->bus, loc->devid, loc->function); + dir = opendir(dirname); + + if (dir == NULL) { + PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname); + return -1; + } + } + + /* take the first file starting with "uio" */ + while ((e = readdir(dir)) != NULL) { + /* format could be uio%d ...*/ + int shortprefix_len = sizeof("uio") - 1; + /* ... or uio:uio%d */ + int longprefix_len = sizeof("uio:uio") - 1; + char *endptr; + + if (strncmp(e->d_name, "uio", 3) != 0) + continue; + + /* first try uio%d */ + errno = 0; + *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); + if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { + snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num); + break; + } + + /* then try uio:uio%d */ + errno = 0; + *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); + if (errno == 0 && endptr != (e->d_name + longprefix_len)) { + snprintf(buf, buflen, "%s/uio:uio%u", dirname, + *uio_num); + break; + } + } + closedir(dir); + + /* No uio resource found */ + if (e == NULL) { + PMD_INIT_LOG(ERR, "Could not find uio resource"); + return -1; + } + + return 0; +} + +static int +legacy_virtio_has_msix(const struct rte_pci_addr *loc) +{ + DIR *d; + char dirname[PATH_MAX]; + + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs", + loc->domain, loc->bus, loc->devid, loc->function); + + d = opendir(dirname); + if (d) + closedir(d); + + return (d != NULL); +} + +/* Extract I/O port numbers from sysfs */ +static int +virtio_resource_init_by_uio(struct rte_pci_device *pci_dev) +{ + char dirname[PATH_MAX]; + char filename[PATH_MAX]; + unsigned long start, size; + unsigned int uio_num; + + if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0) + return -1; + + /* get portio size */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/size", dirname); + if (parse_sysfs_value(filename, &size) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse size", + __func__); + return -1; + } + + /* get portio start */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/start", dirname); + if (parse_sysfs_value(filename, &start) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", + __func__); + return -1; + } + pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; + pci_dev->mem_resource[0].len = (uint64_t)size; + PMD_INIT_LOG(DEBUG, + "PCI Port IO found start=0x%lx with size=0x%lx", + start, size); + + /* save fd */ + memset(dirname, 0, sizeof(dirname)); + snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num); + pci_dev->intr_handle.fd = open(dirname, O_RDWR); + if (pci_dev->intr_handle.fd < 0) { + PMD_INIT_LOG(ERR, "Cannot open %s: %s\n", + dirname, strerror(errno)); + return -1; + } + + pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO; + pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; + + return 0; +} + +/* Extract port I/O numbers from proc/ioports */ +static int +virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev) +{ + uint16_t start, end; + int size; + FILE *fp; + char *line = NULL; + char pci_id[16]; + int found = 0; + size_t linesz; + + snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, + pci_dev->addr.domain, + pci_dev->addr.bus, + pci_dev->addr.devid, + pci_dev->addr.function); + + fp = fopen("/proc/ioports", "r"); + if (fp == NULL) { + PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__); + return -1; + } + + while (getdelim(&line, &linesz, '\n', fp) > 0) { + char *ptr = line; + char *left; + int n; + + n = strcspn(ptr, ":"); + ptr[n] = 0; + left = &ptr[n+1]; + + while (*left && isspace(*left)) + left++; + + if (!strncmp(left, pci_id, strlen(pci_id))) { + found = 1; + + while (*ptr && isspace(*ptr)) + ptr++; + + sscanf(ptr, "%04hx-%04hx", &start, &end); + size = end - start + 1; + + break; + } + } + + free(line); + fclose(fp); + + if (!found) + return -1; + + pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start; + pci_dev->mem_resource[0].len = (uint64_t)size; + PMD_INIT_LOG(DEBUG, + "PCI Port IO found start=0x%x with size=0x%x", + start, size); + + /* can't support lsc interrupt without uio */ + pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; + + return 0; +} + +/* Extract I/O port numbers from sysfs */ +static int +legacy_virtio_resource_init(struct rte_pci_device *pci_dev) +{ + if (virtio_resource_init_by_uio(pci_dev) == 0) + return 0; + else + return virtio_resource_init_by_ioports(pci_dev); +} + +#else +static int +legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) +{ + /* nic_uio does not enable interrupts, return 0 (false). */ + return 0; +} + +static int +legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) +{ + /* no setup required */ + return 0; +} +#endif static const struct virtio_pci_ops legacy_ops = { .read_dev_cfg = legacy_read_dev_config, @@ -241,9 +504,14 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) } int -vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw) +vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) { hw->vtpci_ops = &legacy_ops; + if (legacy_virtio_resource_init(dev) < 0) + return -1; + hw->use_msix = legacy_virtio_has_msix(&dev->addr); + hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr; + return 0; } -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v6 5/9] viritio: switch to 64 bit features 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 " Yuanhan Liu ` (3 preceding siblings ...) 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu @ 2016-01-28 7:54 ` Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu ` (5 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-28 7:54 UTC (permalink / raw) To: dev Switch to 64 bit features, which virtio 1.0 supports. While legacy virtio only supports 32 bit features, it complains aloud and quit when trying to setting > 32 bit features. 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 | 8 ++++---- drivers/net/virtio/virtio_pci.c | 15 ++++++++++----- drivers/net/virtio/virtio_pci.h | 12 ++++++------ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index b57224d..94e0c4a 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -930,16 +930,16 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) static void virtio_negotiate_features(struct virtio_hw *hw) { - uint32_t host_features; + uint64_t host_features; /* Prepare guest_features: feature that driver wants to support */ hw->guest_features = VIRTIO_PMD_GUEST_FEATURES; - PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %x", + PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %"PRIx64, hw->guest_features); /* Read device(host) feature bits */ host_features = hw->vtpci_ops->get_features(hw); - PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x", + PMD_INIT_LOG(DEBUG, "host_features before negotiate = %"PRIx64, host_features); /* @@ -947,7 +947,7 @@ virtio_negotiate_features(struct virtio_hw *hw) * guest feature bits. */ hw->guest_features = vtpci_negotiate_features(hw, host_features); - PMD_INIT_LOG(DEBUG, "features after negotiate = %x", + PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, hw->guest_features); } diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 16485fa..5e1c55f 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -87,15 +87,20 @@ legacy_write_dev_config(struct virtio_hw *hw, size_t offset, } } -static uint32_t +static uint64_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) +legacy_set_features(struct virtio_hw *hw, uint64_t features) { + if ((features >> 32) != 0) { + PMD_DRV_LOG(ERR, + "only 32 bit features are allowed for legacy virtio!"); + return; + } VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features); } @@ -451,10 +456,10 @@ vtpci_write_dev_config(struct virtio_hw *hw, size_t offset, hw->vtpci_ops->write_dev_cfg(hw, offset, src, length); } -uint32_t -vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features) +uint64_t +vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features) { - uint32_t features; + uint64_t features; /* * Limit negotiated features to what the driver, virtqueue, and diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index e8e7509..d7bc6bb 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -175,8 +175,8 @@ struct virtio_pci_ops { 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); + uint64_t (*get_features)(struct virtio_hw *hw); + void (*set_features)(struct virtio_hw *hw, uint64_t features); uint8_t (*get_isr)(struct virtio_hw *hw); @@ -191,7 +191,7 @@ struct virtio_pci_ops { struct virtio_hw { struct virtqueue *cvq; uint32_t io_base; - uint32_t guest_features; + uint64_t guest_features; uint32_t max_tx_queues; uint32_t max_rx_queues; uint16_t vtnet_hdr_size; @@ -271,9 +271,9 @@ outl_p(unsigned int data, unsigned int port) outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) static inline int -vtpci_with_feature(struct virtio_hw *hw, uint32_t bit) +vtpci_with_feature(struct virtio_hw *hw, uint64_t bit) { - return (hw->guest_features & (1u << bit)) != 0; + return (hw->guest_features & (1ULL << bit)) != 0; } /* @@ -286,7 +286,7 @@ void vtpci_reinit_complete(struct virtio_hw *); void vtpci_set_status(struct virtio_hw *, uint8_t); -uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t); +uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t); void vtpci_write_dev_config(struct virtio_hw *, size_t, const void *, int); -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v6 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 " Yuanhan Liu ` (4 preceding siblings ...) 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 5/9] viritio: switch to 64 bit features Yuanhan Liu @ 2016-01-28 7:54 ` Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu ` (4 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-28 7:54 UTC (permalink / raw) To: dev The mergeable virtio net hdr format has been the standard and the only virtio net hdr format since virtio 1.0. Therefore, we can not hardcode hdr_size to "sizeof(struct virtio_net_hdr)" any more at virtio_recv_pkts(), otherwise, there would be a mismatch of hdr size from rte_vhost_enqueue_burst() and virtio_recv_pkts(), leading a packet corruption. Instead, we should retrieve it from hw->vtnet_hdr_size; we will do proper settings at eth_virtio_dev_init() in later patches. 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_rxtx.c | 6 ++++-- drivers/net/virtio/virtio_rxtx_simple.c | 12 ++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c index b7267c0..41a1366 100644 --- a/drivers/net/virtio/virtio_rxtx.c +++ b/drivers/net/virtio/virtio_rxtx.c @@ -560,7 +560,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ]; int error; uint32_t i, nb_enqueued; - const uint32_t hdr_size = sizeof(struct virtio_net_hdr); + uint32_t hdr_size; nb_used = VIRTQUEUE_NUSED(rxvq); @@ -580,6 +580,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) hw = rxvq->hw; nb_rx = 0; nb_enqueued = 0; + hdr_size = hw->vtnet_hdr_size; for (i = 0; i < num ; i++) { rxm = rcv_pkts[i]; @@ -664,7 +665,7 @@ virtio_recv_mergeable_pkts(void *rx_queue, uint32_t seg_num; uint16_t extra_idx; uint32_t seg_res; - const uint32_t hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); + uint32_t hdr_size; nb_used = VIRTQUEUE_NUSED(rxvq); @@ -682,6 +683,7 @@ virtio_recv_mergeable_pkts(void *rx_queue, seg_num = 0; extra_idx = 0; seg_res = 0; + hdr_size = hw->vtnet_hdr_size; while (i < nb_used) { struct virtio_net_hdr_mrg_rxbuf *header; diff --git a/drivers/net/virtio/virtio_rxtx_simple.c b/drivers/net/virtio/virtio_rxtx_simple.c index ff3c11a..3e66e8b 100644 --- a/drivers/net/virtio/virtio_rxtx_simple.c +++ b/drivers/net/virtio/virtio_rxtx_simple.c @@ -81,9 +81,9 @@ virtqueue_enqueue_recv_refill_simple(struct virtqueue *vq, start_dp = vq->vq_ring.desc; start_dp[desc_idx].addr = (uint64_t)((uintptr_t)cookie->buf_physaddr + - RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr)); + RTE_PKTMBUF_HEADROOM - vq->hw->vtnet_hdr_size); start_dp[desc_idx].len = cookie->buf_len - - RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr); + RTE_PKTMBUF_HEADROOM + vq->hw->vtnet_hdr_size; vq->vq_free_cnt--; vq->vq_avail_idx++; @@ -120,9 +120,9 @@ virtio_rxq_rearm_vec(struct virtqueue *rxvq) start_dp[i].addr = (uint64_t)((uintptr_t)sw_ring[i]->buf_physaddr + - RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr)); + RTE_PKTMBUF_HEADROOM - rxvq->hw->vtnet_hdr_size); start_dp[i].len = sw_ring[i]->buf_len - - RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr); + RTE_PKTMBUF_HEADROOM + rxvq->hw->vtnet_hdr_size; } rxvq->vq_avail_idx += RTE_VIRTIO_VPMD_RX_REARM_THRESH; @@ -175,8 +175,8 @@ virtio_recv_pkts_vec(void *rx_queue, struct rte_mbuf **rx_pkts, len_adjust = _mm_set_epi16( 0, 0, 0, - (uint16_t) -sizeof(struct virtio_net_hdr), - 0, (uint16_t) -sizeof(struct virtio_net_hdr), + (uint16_t) -rxvq->hw->vtnet_hdr_size, + 0, (uint16_t) -rxvq->hw->vtnet_hdr_size, 0, 0); if (unlikely(nb_pkts < RTE_VIRTIO_DESC_PER_LOOP)) -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v6 7/9] eal: pci: export pci_[un]map_device 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 " Yuanhan Liu ` (5 preceding siblings ...) 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu @ 2016-01-28 7:54 ` Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 8/9] virtio: add 1.0 support Yuanhan Liu ` (3 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-28 7:54 UTC (permalink / raw) To: dev Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will invoke pci_map_device internally for us. From that point view, there is no need to export pci_map_device. However, for virtio pmd driver, which is designed to work without binding UIO (or something similar first), pci_map_device() will fail, which ends up with virtio pmd driver being skipped. Therefore, we can not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver. Therefore, this patch exports pci_map_device, and let virtio pmd call it when necessary. Cc: David Marchand <david.marchand@6wind.com> Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> Tested-By: Santosh Shukla <sshukla@mvista.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: David Marchand <david.marchand@6wind.com> Acked-by: Huawei Xie <huawei.xie@intel.com> --- lib/librte_eal/bsdapp/eal/eal_pci.c | 4 ++-- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 7 +++++++ lib/librte_eal/common/eal_common_pci.c | 4 ++-- lib/librte_eal/common/eal_private.h | 18 ----------------- lib/librte_eal/common/include/rte_pci.h | 27 +++++++++++++++++++++++++ lib/librte_eal/linuxapp/eal/eal_pci.c | 4 ++-- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 7 +++++++ 7 files changed, 47 insertions(+), 24 deletions(-) diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c index 6c21fbd..95c32c1 100644 --- a/lib/librte_eal/bsdapp/eal/eal_pci.c +++ b/lib/librte_eal/bsdapp/eal/eal_pci.c @@ -93,7 +93,7 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused) /* Map pci device */ int -pci_map_device(struct rte_pci_device *dev) +rte_eal_pci_map_device(struct rte_pci_device *dev) { int ret = -1; @@ -115,7 +115,7 @@ pci_map_device(struct rte_pci_device *dev) /* Unmap pci device */ void -pci_unmap_device(struct rte_pci_device *dev) +rte_eal_pci_unmap_device(struct rte_pci_device *dev) { /* try unmapping the NIC resources */ switch (dev->kdrv) { diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map index 9d7adf1..1b28170 100644 --- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map +++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map @@ -135,3 +135,10 @@ DPDK_2.2 { rte_xen_dom0_supported; } DPDK_2.1; + +DPDK_2.3 { + global: + + rte_eal_pci_map_device; + rte_eal_pci_unmap_device; +} DPDK_2.2; diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c index dcfe947..96d5113 100644 --- a/lib/librte_eal/common/eal_common_pci.c +++ b/lib/librte_eal/common/eal_common_pci.c @@ -188,7 +188,7 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d pci_config_space_set(dev); #endif /* map resources for devices that use igb_uio */ - ret = pci_map_device(dev); + ret = rte_eal_pci_map_device(dev); if (ret != 0) return ret; } else if (dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND && @@ -254,7 +254,7 @@ rte_eal_pci_detach_dev(struct rte_pci_driver *dr, if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING) /* unmap resources for devices that use igb_uio */ - pci_unmap_device(dev); + rte_eal_pci_unmap_device(dev); return 0; } diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h index 072e672..2342fa1 100644 --- a/lib/librte_eal/common/eal_private.h +++ b/lib/librte_eal/common/eal_private.h @@ -165,24 +165,6 @@ struct rte_pci_device; int pci_unbind_kernel_driver(struct rte_pci_device *dev); /** - * Map this device - * - * This function is private to EAL. - * - * @return - * 0 on success, negative on error and positive if no driver - * is found for the device. - */ -int pci_map_device(struct rte_pci_device *dev); - -/** - * Unmap this device - * - * This function is private to EAL. - */ -void pci_unmap_device(struct rte_pci_device *dev); - -/** * Map the PCI resource of a PCI device in virtual memory * * This function is private to EAL. diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h index 334c12e..2224109 100644 --- a/lib/librte_eal/common/include/rte_pci.h +++ b/lib/librte_eal/common/include/rte_pci.h @@ -485,6 +485,33 @@ int rte_eal_pci_read_config(const struct rte_pci_device *device, */ int rte_eal_pci_write_config(const struct rte_pci_device *device, const void *buf, size_t len, off_t offset); +/** + * Map the PCI device resources in user space virtual memory address + * + * Note that driver should not call this function when flag + * RTE_PCI_DRV_NEED_MAPPING is set, as EAL will do that for + * you when it's on. + * + * @param dev + * A pointer to a rte_pci_device structure describing the device + * to use + * + * @return + * 0 on success, negative on error and positive if no driver + * is found for the device. + */ +int rte_eal_pci_map_device(struct rte_pci_device *dev); + +/** + * Unmap this device + * + * @param dev + * A pointer to a rte_pci_device structure describing the device + * to use + */ +void rte_eal_pci_unmap_device(struct rte_pci_device *dev); + + #ifdef RTE_PCI_CONFIG /** diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c index bc5b5be..db947da 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c @@ -124,7 +124,7 @@ pci_get_kernel_driver_by_path(const char *filename, char *dri_name) /* Map pci device */ int -pci_map_device(struct rte_pci_device *dev) +rte_eal_pci_map_device(struct rte_pci_device *dev) { int ret = -1; @@ -153,7 +153,7 @@ pci_map_device(struct rte_pci_device *dev) /* Unmap pci device */ void -pci_unmap_device(struct rte_pci_device *dev) +rte_eal_pci_unmap_device(struct rte_pci_device *dev) { /* try unmapping the NIC resources using VFIO if it exists */ switch (dev->kdrv) { diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map index cbe175f..b9937c4 100644 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map @@ -138,3 +138,10 @@ DPDK_2.2 { rte_xen_dom0_supported; } DPDK_2.1; + +DPDK_2.3 { + global: + + rte_eal_pci_map_device; + rte_eal_pci_unmap_device; +} DPDK_2.2; -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v6 8/9] virtio: add 1.0 support 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 " Yuanhan Liu ` (6 preceding siblings ...) 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu @ 2016-01-28 7:54 ` Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu ` (2 subsequent siblings) 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-28 7:54 UTC (permalink / raw) To: dev Modern (v1.0) virtio pci device defines several pci capabilities. Each cap has a configure structure corresponding to it, and the cap.bar and cap.offset fields tell us where to find it. Firstly, we map the pci resources by rte_eal_pci_map_device(). We then could easily locate a cfg structure by: cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset; Therefore, the entrance of enabling modern (v1.0) pci device support is to iterate the pci capability lists, and to locate some configs we care; and they are: - common cfg For generic virtio and virtqueue configuration, such as setting/getting features, enabling a specific queue, and so on. - nofity cfg Combining with `queue_notify_off' from common cfg, we could use it to notify a specific virt queue. - device cfg Where virtio_net_config structure is located. - isr cfg Where to read isr (interrupt status). If any of above cap is not found, we fallback to the legacy virtio handling. If succeed, hw->vtpci_ops is assigned to modern_ops, where all operations are implemented by reading/writing a (or few) specific configuration space from above 4 cfg structures. And that's basically how this patch works. Besides those changes, virtio 1.0 introduces a new status field: FEATURES_OK, which is set after features negotiation is done. Last, set the VIRTIO_F_VERSION_1 feature flag. 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> --- v6: - unfold DEF_IO_READ/WRITE macros v5: - rename MODERN_READ/WRITE_DEF macro name to IO_READ/WRITE_DEF - check offset + length overflow --- doc/guides/rel_notes/release_2_3.rst | 3 + drivers/net/virtio/virtio_ethdev.c | 25 ++- drivers/net/virtio/virtio_ethdev.h | 3 +- drivers/net/virtio/virtio_pci.c | 355 ++++++++++++++++++++++++++++++++++- drivers/net/virtio/virtio_pci.h | 67 +++++++ drivers/net/virtio/virtqueue.h | 2 + 6 files changed, 450 insertions(+), 5 deletions(-) diff --git a/doc/guides/rel_notes/release_2_3.rst b/doc/guides/rel_notes/release_2_3.rst index 99de186..c390d97 100644 --- a/doc/guides/rel_notes/release_2_3.rst +++ b/doc/guides/rel_notes/release_2_3.rst @@ -4,6 +4,9 @@ DPDK Release 2.3 New Features ------------ +* **Virtio 1.0 support.** + + Enabled virtio 1.0 support for virtio pmd driver. Resolved Issues --------------- diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 94e0c4a..deb0382 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) return virtio_send_command(hw->cvq, &ctrl, &len, 1); } -static void +static int virtio_negotiate_features(struct virtio_hw *hw) { uint64_t host_features; @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw) hw->guest_features = vtpci_negotiate_features(hw, host_features); PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, hw->guest_features); + + if (hw->modern) { + if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) { + PMD_INIT_LOG(ERR, + "VIRTIO_F_VERSION_1 features is not enabled."); + return -1; + } + vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK); + if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) { + PMD_INIT_LOG(ERR, + "failed to set FEATURES_OK status!"); + return -1; + } + } + + return 0; } /* @@ -1032,7 +1048,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev) /* Tell the host we've known how to drive the device. */ vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER); - virtio_negotiate_features(hw); + if (virtio_negotiate_features(hw) < 0) + return -1; /* If host does not support status then disable LSC */ if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) @@ -1043,7 +1060,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev) rx_func_get(eth_dev); /* Setting up rx_header size for the device */ - if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) + if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) || + vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); else hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr); @@ -1159,6 +1177,7 @@ eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev) rte_intr_callback_unregister(&pci_dev->intr_handle, virtio_interrupt_handler, eth_dev); + rte_eal_pci_unmap_device(pci_dev); PMD_INIT_LOG(DEBUG, "dev_uninit completed"); diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h index ae2d47d..fed9571 100644 --- a/drivers/net/virtio/virtio_ethdev.h +++ b/drivers/net/virtio/virtio_ethdev.h @@ -64,7 +64,8 @@ 1u << VIRTIO_NET_F_CTRL_VQ | \ 1u << VIRTIO_NET_F_CTRL_RX | \ 1u << VIRTIO_NET_F_CTRL_VLAN | \ - 1u << VIRTIO_NET_F_MRG_RXBUF) + 1u << VIRTIO_NET_F_MRG_RXBUF | \ + 1ULL << VIRTIO_F_VERSION_1) /* * CQ function prototype diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 5e1c55f..2d3143b 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -41,6 +41,14 @@ #include "virtio_logs.h" #include "virtqueue.h" +/* + * Following macros are derieved from linux/pci_regs.h, however, + * we can't simply include that header here, as there is no such + * file for non-Linux platform. + */ +#define PCI_CAPABILITY_LIST 0x34 +#define PCI_CAP_ID_VNDR 0x09 + static void legacy_read_dev_config(struct virtio_hw *hw, size_t offset, void *dst, int length) @@ -442,6 +450,218 @@ static const struct virtio_pci_ops legacy_ops = { }; + +static inline uint8_t +io_read8(uint8_t *addr) +{ + return *(volatile uint8_t *)addr; +} + +static inline void +io_write8(uint8_t val, uint8_t *addr) +{ + *(volatile uint8_t *)addr = val; +} + +static inline uint16_t +io_read16(uint16_t *addr) +{ + return *(volatile uint16_t *)addr; +} + +static inline void +io_write16(uint16_t val, uint16_t *addr) +{ + *(volatile uint16_t *)addr = val; +} + +static inline uint32_t +io_read32(uint32_t *addr) +{ + return *(volatile uint32_t *)addr; +} + +static inline void +io_write32(uint32_t val, uint32_t *addr) +{ + *(volatile uint32_t *)addr = val; +} + +static inline void +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) +{ + io_write32(val & ((1ULL << 32) - 1), lo); + io_write32(val >> 32, hi); +} + +static void +modern_read_dev_config(struct virtio_hw *hw, size_t offset, + void *dst, int length) +{ + int i; + uint8_t *p; + uint8_t old_gen, new_gen; + + do { + old_gen = io_read8(&hw->common_cfg->config_generation); + + p = dst; + for (i = 0; i < length; i++) + *p++ = io_read8((uint8_t *)hw->dev_cfg + offset + i); + + new_gen = io_read8(&hw->common_cfg->config_generation); + } while (old_gen != new_gen); +} + +static void +modern_write_dev_config(struct virtio_hw *hw, size_t offset, + const void *src, int length) +{ + int i; + const uint8_t *p = src; + + for (i = 0; i < length; i++) + io_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i); +} + +static uint64_t +modern_get_features(struct virtio_hw *hw) +{ + uint32_t features_lo, features_hi; + + io_write32(0, &hw->common_cfg->device_feature_select); + features_lo = io_read32(&hw->common_cfg->device_feature); + + io_write32(1, &hw->common_cfg->device_feature_select); + features_hi = io_read32(&hw->common_cfg->device_feature); + + return ((uint64_t)features_hi << 32) | features_lo; +} + +static void +modern_set_features(struct virtio_hw *hw, uint64_t features) +{ + io_write32(0, &hw->common_cfg->guest_feature_select); + io_write32(features & ((1ULL << 32) - 1), + &hw->common_cfg->guest_feature); + + io_write32(1, &hw->common_cfg->guest_feature_select); + io_write32(features >> 32, + &hw->common_cfg->guest_feature); +} + +static uint8_t +modern_get_status(struct virtio_hw *hw) +{ + return io_read8(&hw->common_cfg->device_status); +} + +static void +modern_set_status(struct virtio_hw *hw, uint8_t status) +{ + io_write8(status, &hw->common_cfg->device_status); +} + +static void +modern_reset(struct virtio_hw *hw) +{ + modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); + modern_get_status(hw); +} + +static uint8_t +modern_get_isr(struct virtio_hw *hw) +{ + return io_read8(hw->isr); +} + +static uint16_t +modern_set_config_irq(struct virtio_hw *hw, uint16_t vec) +{ + io_write16(vec, &hw->common_cfg->msix_config); + return io_read16(&hw->common_cfg->msix_config); +} + +static uint16_t +modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) +{ + io_write16(queue_id, &hw->common_cfg->queue_select); + return io_read16(&hw->common_cfg->queue_size); +} + +static void +modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + uint64_t desc_addr, avail_addr, used_addr; + uint16_t notify_off; + + desc_addr = vq->mz->phys_addr; + avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc); + used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail, + ring[vq->vq_nentries]), + VIRTIO_PCI_VRING_ALIGN); + + io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); + + io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + notify_off = io_read16(&hw->common_cfg->queue_notify_off); + vq->notify_addr = (void *)((uint8_t *)hw->notify_base + + notify_off * hw->notify_off_multiplier); + + io_write16(1, &hw->common_cfg->queue_enable); + + PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index); + PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr); + PMD_INIT_LOG(DEBUG, "\t aval_addr: %"PRIx64, avail_addr); + PMD_INIT_LOG(DEBUG, "\t used_addr: %"PRIx64, used_addr); + PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)", + vq->notify_addr, notify_off); +} + +static void +modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); + + io_write64_twopart(0, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + io_write64_twopart(0, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + io_write64_twopart(0, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + io_write16(0, &hw->common_cfg->queue_enable); +} + +static void +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) +{ + io_write16(1, vq->notify_addr); +} + +static const struct virtio_pci_ops modern_ops = { + .read_dev_cfg = modern_read_dev_config, + .write_dev_cfg = modern_write_dev_config, + .reset = modern_reset, + .get_status = modern_get_status, + .set_status = modern_set_status, + .get_features = modern_get_features, + .set_features = modern_set_features, + .get_isr = modern_get_isr, + .set_config_irq = modern_set_config_irq, + .get_queue_num = modern_get_queue_num, + .setup_queue = modern_setup_queue, + .del_queue = modern_del_queue, + .notify_queue = modern_notify_queue, +}; + + void vtpci_read_dev_config(struct virtio_hw *hw, size_t offset, void *dst, int length) @@ -495,6 +715,12 @@ vtpci_set_status(struct virtio_hw *hw, uint8_t status) } uint8_t +vtpci_get_status(struct virtio_hw *hw) +{ + return hw->vtpci_ops->get_status(hw); +} + +uint8_t vtpci_isr(struct virtio_hw *hw) { return hw->vtpci_ops->get_isr(hw); @@ -508,15 +734,142 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) return hw->vtpci_ops->set_config_irq(hw, vec); } +static void * +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) +{ + uint8_t bar = cap->bar; + uint32_t length = cap->length; + uint32_t offset = cap->offset; + uint8_t *base; + + if (bar > 5) { + PMD_INIT_LOG(ERR, "invalid bar: %u", bar); + return NULL; + } + + if (offset + length < offset) { + PMD_INIT_LOG(ERR, "offset(%u) + lenght(%u) overflows", + offset, length); + return NULL; + } + + if (offset + length > dev->mem_resource[bar].len) { + PMD_INIT_LOG(ERR, + "invalid cap: overflows bar space: %u > %"PRIu64, + offset + length, dev->mem_resource[bar].len); + return NULL; + } + + base = dev->mem_resource[bar].addr; + if (base == NULL) { + PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar); + return NULL; + } + + return base + offset; +} + +static int +virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw) +{ + uint8_t pos; + struct virtio_pci_cap cap; + int ret; + + if (rte_eal_pci_map_device(dev) < 0) { + PMD_INIT_LOG(DEBUG, "failed to map pci device!"); + return -1; + } + + ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST); + if (ret < 0) { + PMD_INIT_LOG(DEBUG, "failed to read pci capability list"); + return -1; + } + + while (pos) { + ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos); + if (ret < 0) { + PMD_INIT_LOG(ERR, + "failed to read pci cap at pos: %x", pos); + break; + } + + if (cap.cap_vndr != PCI_CAP_ID_VNDR) { + PMD_INIT_LOG(DEBUG, + "[%2x] skipping non VNDR cap id: %02x", + pos, cap.cap_vndr); + goto next; + } + + PMD_INIT_LOG(DEBUG, + "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u", + pos, cap.cfg_type, cap.bar, cap.offset, cap.length); + + switch (cap.cfg_type) { + case VIRTIO_PCI_CAP_COMMON_CFG: + hw->common_cfg = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_NOTIFY_CFG: + rte_eal_pci_read_config(dev, &hw->notify_off_multiplier, + 4, pos + sizeof(cap)); + hw->notify_base = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_DEVICE_CFG: + hw->dev_cfg = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_ISR_CFG: + hw->isr = get_cfg_addr(dev, &cap); + break; + } + + next: + pos = cap.cap_next; + } + + if (hw->common_cfg == NULL || hw->notify_base == NULL || + hw->dev_cfg == NULL || hw->isr == NULL) { + PMD_INIT_LOG(INFO, "no modern virtio pci device found."); + return -1; + } + + PMD_INIT_LOG(INFO, "found modern virtio pci device."); + + PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg); + PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg); + PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr); + PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u", + hw->notify_base, hw->notify_off_multiplier); + + return 0; +} + int vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) { - hw->vtpci_ops = &legacy_ops; + hw->dev = dev; + /* + * Try if we can succeed reading virtio pci caps, which exists + * only on modern pci device. If failed, we fallback to legacy + * virtio handling. + */ + if (virtio_read_caps(dev, hw) == 0) { + PMD_INIT_LOG(INFO, "modern virtio pci detected."); + hw->vtpci_ops = &modern_ops; + hw->modern = 1; + dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; + return 0; + } + + PMD_INIT_LOG(INFO, "trying with legacy virtio pci."); if (legacy_virtio_resource_init(dev) < 0) return -1; + + hw->vtpci_ops = &legacy_ops; hw->use_msix = legacy_virtio_has_msix(&dev->addr); hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr; + hw->modern = 0; return 0; } diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index d7bc6bb..fcac660 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -93,6 +93,7 @@ struct virtqueue; #define VIRTIO_CONFIG_STATUS_ACK 0x01 #define VIRTIO_CONFIG_STATUS_DRIVER 0x02 #define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04 +#define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08 #define VIRTIO_CONFIG_STATUS_FAILED 0x80 /* @@ -141,6 +142,8 @@ struct virtqueue; /* We support indirect buffer descriptors */ #define VIRTIO_RING_F_INDIRECT_DESC 28 +#define VIRTIO_F_VERSION_1 32 + /* * Some VirtIO feature bits (currently bits 28 through 31) are * reserved for the transport being used (eg. virtio_ring), the @@ -163,6 +166,60 @@ struct virtqueue; */ #define VIRTIO_MAX_VIRTQUEUES 8 +/* Common configuration */ +#define VIRTIO_PCI_CAP_COMMON_CFG 1 +/* Notifications */ +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 +/* ISR Status */ +#define VIRTIO_PCI_CAP_ISR_CFG 3 +/* Device specific configuration */ +#define VIRTIO_PCI_CAP_DEVICE_CFG 4 +/* PCI configuration access */ +#define VIRTIO_PCI_CAP_PCI_CFG 5 + +/* This is the PCI capability header: */ +struct virtio_pci_cap { + uint8_t cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */ + uint8_t cap_next; /* Generic PCI field: next ptr. */ + uint8_t cap_len; /* Generic PCI field: capability length */ + uint8_t cfg_type; /* Identifies the structure. */ + uint8_t bar; /* Where to find it. */ + uint8_t padding[3]; /* Pad to full dword. */ + uint32_t offset; /* Offset within bar. */ + uint32_t length; /* Length of the structure, in bytes. */ +}; + +struct virtio_pci_notify_cap { + struct virtio_pci_cap cap; + uint32_t notify_off_multiplier; /* Multiplier for queue_notify_off. */ +}; + +/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */ +struct virtio_pci_common_cfg { + /* About the whole device. */ + uint32_t device_feature_select; /* read-write */ + uint32_t device_feature; /* read-only */ + uint32_t guest_feature_select; /* read-write */ + uint32_t guest_feature; /* read-write */ + uint16_t msix_config; /* read-write */ + uint16_t num_queues; /* read-only */ + uint8_t device_status; /* read-write */ + uint8_t config_generation; /* read-only */ + + /* About a specific virtqueue. */ + uint16_t queue_select; /* read-write */ + uint16_t queue_size; /* read-write, power of 2. */ + uint16_t queue_msix_vector; /* read-write */ + uint16_t queue_enable; /* read-write */ + uint16_t queue_notify_off; /* read-only */ + uint32_t queue_desc_lo; /* read-write */ + uint32_t queue_desc_hi; /* read-write */ + uint32_t queue_avail_lo; /* read-write */ + uint32_t queue_avail_hi; /* read-write */ + uint32_t queue_used_lo; /* read-write */ + uint32_t queue_used_hi; /* read-write */ +}; + struct virtio_hw; struct virtio_pci_ops { @@ -188,6 +245,8 @@ struct virtio_pci_ops { void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq); }; +struct virtio_net_config; + struct virtio_hw { struct virtqueue *cvq; uint32_t io_base; @@ -198,7 +257,14 @@ struct virtio_hw { uint8_t vlan_strip; uint8_t use_msix; uint8_t started; + uint8_t modern; uint8_t mac_addr[ETHER_ADDR_LEN]; + uint32_t notify_off_multiplier; + uint8_t *isr; + uint16_t *notify_base; + struct rte_pci_device *dev; + struct virtio_pci_common_cfg *common_cfg; + struct virtio_net_config *dev_cfg; const struct virtio_pci_ops *vtpci_ops; }; @@ -284,6 +350,7 @@ void vtpci_reset(struct virtio_hw *); void vtpci_reinit_complete(struct virtio_hw *); +uint8_t vtpci_get_status(struct virtio_hw *); void vtpci_set_status(struct virtio_hw *, uint8_t); uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t); diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h index d7fb450..99d4fa9 100644 --- a/drivers/net/virtio/virtqueue.h +++ b/drivers/net/virtio/virtqueue.h @@ -202,6 +202,8 @@ struct virtqueue { /* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */ uint64_t size_bins[8]; + uint16_t *notify_addr; + struct vq_desc_extra { void *cookie; uint16_t ndescs; -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v6 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 " Yuanhan Liu ` (7 preceding siblings ...) 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 8/9] virtio: add 1.0 support Yuanhan Liu @ 2016-01-28 7:54 ` Yuanhan Liu 2016-02-02 10:46 ` [dpdk-dev] [PATCH v6 0/9] virtio 1.0 enabling for virtio pmd driver Thomas Monjalon 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 " Yuanhan Liu 10 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-01-28 7:54 UTC (permalink / raw) To: dev virtio_pci.c is the only file references those macros; move them there. 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_pci.c | 19 +++++++++++++++++++ drivers/net/virtio/virtio_pci.h | 18 ------------------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 2d3143b..e16104e 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -49,6 +49,25 @@ #define PCI_CAPABILITY_LIST 0x34 #define PCI_CAP_ID_VNDR 0x09 + +#define VIRTIO_PCI_REG_ADDR(hw, reg) \ + (unsigned short)((hw)->io_base + (reg)) + +#define VIRTIO_READ_REG_1(hw, reg) \ + inb((VIRTIO_PCI_REG_ADDR((hw), (reg)))) +#define VIRTIO_WRITE_REG_1(hw, reg, value) \ + outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + +#define VIRTIO_READ_REG_2(hw, reg) \ + inw((VIRTIO_PCI_REG_ADDR((hw), (reg)))) +#define VIRTIO_WRITE_REG_2(hw, reg, value) \ + outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + +#define VIRTIO_READ_REG_4(hw, reg) \ + inl((VIRTIO_PCI_REG_ADDR((hw), (reg)))) +#define VIRTIO_WRITE_REG_4(hw, reg, value) \ + outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + static void legacy_read_dev_config(struct virtio_hw *hw, size_t offset, void *dst, int length) diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index fcac660..0544a07 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -318,24 +318,6 @@ outl_p(unsigned int data, unsigned int port) } #endif -#define VIRTIO_PCI_REG_ADDR(hw, reg) \ - (unsigned short)((hw)->io_base + (reg)) - -#define VIRTIO_READ_REG_1(hw, reg) \ - inb((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_1(hw, reg, value) \ - outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - -#define VIRTIO_READ_REG_2(hw, reg) \ - inw((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_2(hw, reg, value) \ - outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - -#define VIRTIO_READ_REG_4(hw, reg) \ - inl((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_4(hw, reg, value) \ - outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - static inline int vtpci_with_feature(struct virtio_hw *hw, uint64_t bit) { -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v6 0/9] virtio 1.0 enabling for virtio pmd driver 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 " Yuanhan Liu ` (8 preceding siblings ...) 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu @ 2016-02-02 10:46 ` Thomas Monjalon 2016-02-02 13:00 ` Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 " Yuanhan Liu 10 siblings, 1 reply; 122+ messages in thread From: Thomas Monjalon @ 2016-02-02 10:46 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev Hi Yuanhan, I wanted to apply these patches but I see few checkpatch warnings, inluding a typo. Sometimes I fix them myself but I guess you would prefer checking it. ### PATCH v6 4_9 CHECK:SPACING: spaces preferred around that '+' (ctx:VxV) #571: FILE: drivers/net/virtio/virtio_pci.c:361: + left = &ptr[n+1]; ^ WARNING:NAKED_SSCANF: unchecked sscanf return value #582: FILE: drivers/net/virtio/virtio_pci.c:372: + sscanf(ptr, "%04hx-%04hx", &start, &end); ### PATCH v6 5_9 CHECK:CONCATENATED_STRING: Concatenated strings should use spaces between elements #79: FILE: drivers/net/virtio/virtio_ethdev.c:937: + PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %"PRIx64, CHECK:CONCATENATED_STRING: Concatenated strings should use spaces between elements #85: FILE: drivers/net/virtio/virtio_ethdev.c:942: + PMD_INIT_LOG(DEBUG, "host_features before negotiate = %"PRIx64, CHECK:CONCATENATED_STRING: Concatenated strings should use spaces between elements #94: FILE: drivers/net/virtio/virtio_ethdev.c:950: + PMD_INIT_LOG(DEBUG, "features after negotiate = %"PRIx64, ### PATCH v6 7_9 WARNING:BAD_SIGN_OFF: 'Tested-by:' is the preferred signature form #63: Tested-By: Santosh Shukla <sshukla@mvista.com> ### PATCH v6 8_9 CHECK:CAMELCASE: Avoid CamelCase: <PRIx64> #396: FILE: drivers/net/virtio/virtio_pci.c:620: + PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr); CHECK:CONCATENATED_STRING: Concatenated strings should use spaces between elements #396: FILE: drivers/net/virtio/virtio_pci.c:620: + PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr); CHECK:CONCATENATED_STRING: Concatenated strings should use spaces between elements #397: FILE: drivers/net/virtio/virtio_pci.c:621: + PMD_INIT_LOG(DEBUG, "\t aval_addr: %"PRIx64, avail_addr); CHECK:CONCATENATED_STRING: Concatenated strings should use spaces between elements #398: FILE: drivers/net/virtio/virtio_pci.c:622: + PMD_INIT_LOG(DEBUG, "\t used_addr: %"PRIx64, used_addr); WARNING:TYPO_SPELLING: 'lenght' may be misspelled - perhaps 'length'? #475: FILE: drivers/net/virtio/virtio_pci.c:751: + PMD_INIT_LOG(ERR, "offset(%u) + lenght(%u) overflows", CHECK:CAMELCASE: Avoid CamelCase: <PRIu64> #482: FILE: drivers/net/virtio/virtio_pci.c:758: + "invalid cap: overflows bar space: %u > %"PRIu64, CHECK:CONCATENATED_STRING: Concatenated strings should use spaces between elements #482: FILE: drivers/net/virtio/virtio_pci.c:758: + "invalid cap: overflows bar space: %u > %"PRIu64, WARNING:INDENTED_LABEL: labels should not be indented #550: FILE: drivers/net/virtio/virtio_pci.c:826: + next: ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v6 0/9] virtio 1.0 enabling for virtio pmd driver 2016-02-02 10:46 ` [dpdk-dev] [PATCH v6 0/9] virtio 1.0 enabling for virtio pmd driver Thomas Monjalon @ 2016-02-02 13:00 ` Yuanhan Liu 0 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-02-02 13:00 UTC (permalink / raw) To: Thomas Monjalon; +Cc: dev On Tue, Feb 02, 2016 at 11:46:54AM +0100, Thomas Monjalon wrote: > Hi Yuanhan, > > I wanted to apply these patches but I see few checkpatch warnings, > inluding a typo. > Sometimes I fix them myself but I guess you would prefer checking it. Okay; I will fix them all. --yliu ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v7 0/9] virtio 1.0 enabling for virtio pmd driver 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 " Yuanhan Liu ` (9 preceding siblings ...) 2016-02-02 10:46 ` [dpdk-dev] [PATCH v6 0/9] virtio 1.0 enabling for virtio pmd driver Thomas Monjalon @ 2016-02-02 13:48 ` Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu ` (9 more replies) 10 siblings, 10 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw) To: dev v7: - make checkpatch a bit happier; few (false) warnings still left. - rebase to latest code: fixed a conflict. v6: unfold IO_READ/WRITE_DEF macro v5: minor fixes: - fix wrong type of arg "offset" of read/write_dev_config(): patch 2 is newly added for that. - check "offset + length" overflow Almost all difference comes from virtio 1.0 are the PCI layout change: the major configuration structures are stored at bar space, and their location is stored at corresponding pci cap structure. Reading/parsing them is one of the major work of patch 8. To make handling virtio v1.0 and v0.95 co-exist well, this patch set introduces a virtio_pci_ops structure, to add another layer so that we could keep those vtpci_foo_bar "APIs". With that, we could do the minimum change to add virtio 1.0 support. Rough test guide ================ Firstly, you need get a virtio 1.0 supported QEMU (say, v2.5), then add option "disable-modern=false" to qemu virtio-net-pci device to enable virtio 1.0 (which is disabled by default). And if you see something like following from 'lspci -v', it means virtio 1.0 is indeed enabled: 00:04.0 Ethernet controller: Red Hat, Inc Virtio network device Subsystem: Red Hat, Inc Device 0001 Physical Slot: 4 Flags: bus master, fast devsel, latency 0, IRQ 11 I/O ports at c040 [size=64] Memory at febf1000 (32-bit, non-prefetchable) [size=4K] Memory at fe000000 (64-bit, prefetchable) [size=8M] Expansion ROM at feb80000 [disabled] [size=256K] Capabilities: [98] MSI-X: Enable+ Count=6 Masked- ==> Capabilities: [84] Vendor Specific Information: Len=14 <?> ==> Capabilities: [70] Vendor Specific Information: Len=14 <?> ==> Capabilities: [60] Vendor Specific Information: Len=10 <?> ==> Capabilities: [50] Vendor Specific Information: Len=10 <?> ==> Capabilities: [40] Vendor Specific Information: Len=10 <?> Kernel driver in use: virtio-pci Kernel modules: virtio_pci After that, there wasn't anything speical comparing to the old virtio 0.95 pmd driver. --- Yuanhan Liu (9): virtio: don't set vring address again at queue startup virtio: define offset as size_t type virtio: introduce struct virtio_pci_ops virtio: move left pci stuff to virtio_pci.c viritio: switch to 64 bit features virtio: retrieve hdr_size from hw->vtnet_hdr_size eal: pci: export pci_[un]map_device virtio: add 1.0 support virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c doc/guides/rel_notes/release_2_3.rst | 3 + drivers/net/virtio/virtio_ethdev.c | 302 +-------- drivers/net/virtio/virtio_ethdev.h | 3 +- drivers/net/virtio/virtio_pci.c | 815 +++++++++++++++++++++++- drivers/net/virtio/virtio_pci.h | 124 +++- drivers/net/virtio/virtio_rxtx.c | 21 +- drivers/net/virtio/virtio_rxtx_simple.c | 12 +- drivers/net/virtio/virtqueue.h | 4 +- lib/librte_eal/bsdapp/eal/eal_pci.c | 4 +- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 2 + lib/librte_eal/common/eal_common_pci.c | 4 +- lib/librte_eal/common/eal_private.h | 18 - lib/librte_eal/common/include/rte_pci.h | 27 + lib/librte_eal/linuxapp/eal/eal_pci.c | 4 +- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 3 + 15 files changed, 964 insertions(+), 382 deletions(-) -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v7 1/9] virtio: don't set vring address again at queue startup 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 " Yuanhan Liu @ 2016-02-02 13:48 ` Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 2/9] virtio: define offset as size_t type Yuanhan Liu ` (8 subsequent siblings) 9 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw) To: dev As we have already set up it at virtio_dev_queue_setup(), and a vq restart will not reset the settings. 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_rxtx.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c index 74b39ef..b7267c0 100644 --- a/drivers/net/virtio/virtio_rxtx.c +++ b/drivers/net/virtio/virtio_rxtx.c @@ -339,11 +339,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type) vq_update_avail_idx(vq); PMD_INIT_LOG(DEBUG, "Allocated %d bufs", nbufs); - - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); } else if (queue_type == VTNET_TQ) { if (use_simple_rxtx) { int mid_idx = vq->vq_nentries >> 1; @@ -362,16 +357,6 @@ virtio_dev_vring_start(struct virtqueue *vq, int queue_type) for (i = mid_idx; i < vq->vq_nentries; i++) vq->vq_ring.avail->ring[i] = i; } - - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); - } else { - VIRTIO_WRITE_REG_2(vq->hw, VIRTIO_PCI_QUEUE_SEL, - vq->vq_queue_index); - VIRTIO_WRITE_REG_4(vq->hw, VIRTIO_PCI_QUEUE_PFN, - vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); } } -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v7 2/9] virtio: define offset as size_t type 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 " Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu @ 2016-02-02 13:48 ` Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu ` (7 subsequent siblings) 9 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw) To: dev offset arg of vtpci_read/write_dev_config is derived from offsetof(), which is of size_t type, instead of uint64_t. So, define it as size_t type. 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_pci.c | 4 ++-- drivers/net/virtio/virtio_pci.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 2245bec..b34b59e 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -38,7 +38,7 @@ static uint8_t vtpci_get_status(struct virtio_hw *); void -vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset, +vtpci_read_dev_config(struct virtio_hw *hw, size_t offset, void *dst, int length) { uint64_t off; @@ -61,7 +61,7 @@ vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset, } void -vtpci_write_dev_config(struct virtio_hw *hw, uint64_t offset, +vtpci_write_dev_config(struct virtio_hw *hw, size_t offset, void *src, int length) { uint64_t off; diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index 47f722a..fe89c21 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -261,9 +261,9 @@ 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 *, uint64_t, void *, int); +void vtpci_write_dev_config(struct virtio_hw *, size_t, void *, int); -void vtpci_read_dev_config(struct virtio_hw *, uint64_t, void *, int); +void vtpci_read_dev_config(struct virtio_hw *, size_t, void *, int); uint8_t vtpci_isr(struct virtio_hw *); -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v7 3/9] virtio: introduce struct virtio_pci_ops 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 " Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 2/9] virtio: define offset as size_t type Yuanhan Liu @ 2016-02-02 13:48 ` Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu ` (6 subsequent siblings) 9 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw) To: dev 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> --- 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 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v7 4/9] virtio: move left pci stuff to virtio_pci.c 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 " Yuanhan Liu ` (2 preceding siblings ...) 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu @ 2016-02-02 13:48 ` Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 5/9] viritio: switch to 64 bit features Yuanhan Liu ` (5 subsequent siblings) 9 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw) To: dev virtio_pci.c is a more proper place for pci stuff; virtio_ethdev is not. 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 | 265 +----------------------------------- drivers/net/virtio/virtio_pci.c | 272 ++++++++++++++++++++++++++++++++++++- 2 files changed, 272 insertions(+), 265 deletions(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 6c1d3a0..b57224d 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -36,10 +36,6 @@ #include <stdio.h> #include <errno.h> #include <unistd.h> -#ifdef RTE_EXEC_ENV_LINUXAPP -#include <dirent.h> -#include <fcntl.h> -#endif #include <rte_ethdev.h> #include <rte_memcpy.h> @@ -955,260 +951,6 @@ virtio_negotiate_features(struct virtio_hw *hw) hw->guest_features); } -#ifdef RTE_EXEC_ENV_LINUXAPP -static int -parse_sysfs_value(const char *filename, unsigned long *val) -{ - FILE *f; - char buf[BUFSIZ]; - char *end = NULL; - - f = fopen(filename, "r"); - if (f == NULL) { - PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s", - __func__, filename); - return -1; - } - - if (fgets(buf, sizeof(buf), f) == NULL) { - PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s", - __func__, filename); - fclose(f); - return -1; - } - *val = strtoul(buf, &end, 0); - if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { - PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s", - __func__, filename); - fclose(f); - return -1; - } - fclose(f); - return 0; -} - -static int get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen, - unsigned int *uio_num) -{ - struct dirent *e; - DIR *dir; - char dirname[PATH_MAX]; - - /* depending on kernel version, uio can be located in uio/uioX - * or uio:uioX */ - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", - loc->domain, loc->bus, loc->devid, loc->function); - dir = opendir(dirname); - if (dir == NULL) { - /* retry with the parent directory */ - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, - loc->domain, loc->bus, loc->devid, loc->function); - dir = opendir(dirname); - - if (dir == NULL) { - PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname); - return -1; - } - } - - /* take the first file starting with "uio" */ - while ((e = readdir(dir)) != NULL) { - /* format could be uio%d ...*/ - int shortprefix_len = sizeof("uio") - 1; - /* ... or uio:uio%d */ - int longprefix_len = sizeof("uio:uio") - 1; - char *endptr; - - if (strncmp(e->d_name, "uio", 3) != 0) - continue; - - /* first try uio%d */ - errno = 0; - *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); - if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { - snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num); - break; - } - - /* then try uio:uio%d */ - errno = 0; - *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); - if (errno == 0 && endptr != (e->d_name + longprefix_len)) { - snprintf(buf, buflen, "%s/uio:uio%u", dirname, - *uio_num); - break; - } - } - closedir(dir); - - /* No uio resource found */ - if (e == NULL) { - PMD_INIT_LOG(ERR, "Could not find uio resource"); - return -1; - } - - return 0; -} - -static int -virtio_has_msix(const struct rte_pci_addr *loc) -{ - DIR *d; - char dirname[PATH_MAX]; - - snprintf(dirname, sizeof(dirname), - SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs", - loc->domain, loc->bus, loc->devid, loc->function); - - d = opendir(dirname); - if (d) - closedir(d); - - return (d != NULL); -} - -/* Extract I/O port numbers from sysfs */ -static int virtio_resource_init_by_uio(struct rte_pci_device *pci_dev) -{ - char dirname[PATH_MAX]; - char filename[PATH_MAX]; - unsigned long start, size; - unsigned int uio_num; - - if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0) - return -1; - - /* get portio size */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/size", dirname); - if (parse_sysfs_value(filename, &size) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse size", - __func__); - return -1; - } - - /* get portio start */ - snprintf(filename, sizeof(filename), - "%s/portio/port0/start", dirname); - if (parse_sysfs_value(filename, &start) < 0) { - PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", - __func__); - return -1; - } - pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; - pci_dev->mem_resource[0].len = (uint64_t)size; - PMD_INIT_LOG(DEBUG, - "PCI Port IO found start=0x%lx with size=0x%lx", - start, size); - - /* save fd */ - memset(dirname, 0, sizeof(dirname)); - snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num); - pci_dev->intr_handle.fd = open(dirname, O_RDWR); - if (pci_dev->intr_handle.fd < 0) { - PMD_INIT_LOG(ERR, "Cannot open %s: %s\n", - dirname, strerror(errno)); - return -1; - } - - pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO; - pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; - - return 0; -} - -/* Extract port I/O numbers from proc/ioports */ -static int virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev) -{ - uint16_t start, end; - int size; - FILE *fp; - char *line = NULL; - char pci_id[16]; - int found = 0; - size_t linesz; - - snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, - pci_dev->addr.domain, - pci_dev->addr.bus, - pci_dev->addr.devid, - pci_dev->addr.function); - - fp = fopen("/proc/ioports", "r"); - if (fp == NULL) { - PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__); - return -1; - } - - while (getdelim(&line, &linesz, '\n', fp) > 0) { - char *ptr = line; - char *left; - int n; - - n = strcspn(ptr, ":"); - ptr[n] = 0; - left = &ptr[n+1]; - - while (*left && isspace(*left)) - left++; - - if (!strncmp(left, pci_id, strlen(pci_id))) { - found = 1; - - while (*ptr && isspace(*ptr)) - ptr++; - - sscanf(ptr, "%04hx-%04hx", &start, &end); - size = end - start + 1; - - break; - } - } - - free(line); - fclose(fp); - - if (!found) - return -1; - - pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start; - pci_dev->mem_resource[0].len = (uint64_t)size; - PMD_INIT_LOG(DEBUG, - "PCI Port IO found start=0x%x with size=0x%x", - start, size); - - /* can't support lsc interrupt without uio */ - pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; - - return 0; -} - -/* Extract I/O port numbers from sysfs */ -static int virtio_resource_init(struct rte_pci_device *pci_dev) -{ - if (virtio_resource_init_by_uio(pci_dev) == 0) - return 0; - else - return virtio_resource_init_by_ioports(pci_dev); -} - -#else -static int -virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) -{ - /* nic_uio does not enable interrupts, return 0 (false). */ - return 0; -} - -static int virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) -{ - /* no setup required */ - return 0; -} -#endif - /* * Process Virtio Config changed interrupt and call the callback * if link state changed. @@ -1279,14 +1021,9 @@ 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) + if (vtpci_init(pci_dev, hw) < 0) return -1; - hw->use_msix = virtio_has_msix(&pci_dev->addr); - hw->io_base = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr; - /* Reset the device although not necessary at startup */ vtpci_reset(hw); diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 8d001e8..e89a044 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -32,6 +32,11 @@ */ #include <stdint.h> +#ifdef RTE_EXEC_ENV_LINUXAPP + #include <dirent.h> + #include <fcntl.h> +#endif + #include "virtio_pci.h" #include "virtio_logs.h" #include "virtqueue.h" @@ -156,6 +161,266 @@ legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq) VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index); } +#ifdef RTE_EXEC_ENV_LINUXAPP +static int +parse_sysfs_value(const char *filename, unsigned long *val) +{ + FILE *f; + char buf[BUFSIZ]; + char *end = NULL; + + f = fopen(filename, "r"); + if (f == NULL) { + PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s", + __func__, filename); + return -1; + } + + if (fgets(buf, sizeof(buf), f) == NULL) { + PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s", + __func__, filename); + fclose(f); + return -1; + } + *val = strtoul(buf, &end, 0); + if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { + PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s", + __func__, filename); + fclose(f); + return -1; + } + fclose(f); + return 0; +} + +static int +get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen, + unsigned int *uio_num) +{ + struct dirent *e; + DIR *dir; + char dirname[PATH_MAX]; + + /* + * depending on kernel version, uio can be located in uio/uioX + * or uio:uioX + */ + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio", + loc->domain, loc->bus, loc->devid, loc->function); + dir = opendir(dirname); + if (dir == NULL) { + /* retry with the parent directory */ + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT, + loc->domain, loc->bus, loc->devid, loc->function); + dir = opendir(dirname); + + if (dir == NULL) { + PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname); + return -1; + } + } + + /* take the first file starting with "uio" */ + while ((e = readdir(dir)) != NULL) { + /* format could be uio%d ...*/ + int shortprefix_len = sizeof("uio") - 1; + /* ... or uio:uio%d */ + int longprefix_len = sizeof("uio:uio") - 1; + char *endptr; + + if (strncmp(e->d_name, "uio", 3) != 0) + continue; + + /* first try uio%d */ + errno = 0; + *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10); + if (errno == 0 && endptr != (e->d_name + shortprefix_len)) { + snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num); + break; + } + + /* then try uio:uio%d */ + errno = 0; + *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10); + if (errno == 0 && endptr != (e->d_name + longprefix_len)) { + snprintf(buf, buflen, "%s/uio:uio%u", dirname, + *uio_num); + break; + } + } + closedir(dir); + + /* No uio resource found */ + if (e == NULL) { + PMD_INIT_LOG(ERR, "Could not find uio resource"); + return -1; + } + + return 0; +} + +static int +legacy_virtio_has_msix(const struct rte_pci_addr *loc) +{ + DIR *d; + char dirname[PATH_MAX]; + + snprintf(dirname, sizeof(dirname), + SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs", + loc->domain, loc->bus, loc->devid, loc->function); + + d = opendir(dirname); + if (d) + closedir(d); + + return (d != NULL); +} + +/* Extract I/O port numbers from sysfs */ +static int +virtio_resource_init_by_uio(struct rte_pci_device *pci_dev) +{ + char dirname[PATH_MAX]; + char filename[PATH_MAX]; + unsigned long start, size; + unsigned int uio_num; + + if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0) + return -1; + + /* get portio size */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/size", dirname); + if (parse_sysfs_value(filename, &size) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse size", + __func__); + return -1; + } + + /* get portio start */ + snprintf(filename, sizeof(filename), + "%s/portio/port0/start", dirname); + if (parse_sysfs_value(filename, &start) < 0) { + PMD_INIT_LOG(ERR, "%s(): cannot parse portio start", + __func__); + return -1; + } + pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start; + pci_dev->mem_resource[0].len = (uint64_t)size; + PMD_INIT_LOG(DEBUG, + "PCI Port IO found start=0x%lx with size=0x%lx", + start, size); + + /* save fd */ + memset(dirname, 0, sizeof(dirname)); + snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num); + pci_dev->intr_handle.fd = open(dirname, O_RDWR); + if (pci_dev->intr_handle.fd < 0) { + PMD_INIT_LOG(ERR, "Cannot open %s: %s\n", + dirname, strerror(errno)); + return -1; + } + + pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO; + pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; + + return 0; +} + +/* Extract port I/O numbers from proc/ioports */ +static int +virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev) +{ + uint16_t start, end; + int size; + FILE *fp; + char *line = NULL; + char pci_id[16]; + int found = 0; + size_t linesz; + + snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT, + pci_dev->addr.domain, + pci_dev->addr.bus, + pci_dev->addr.devid, + pci_dev->addr.function); + + fp = fopen("/proc/ioports", "r"); + if (fp == NULL) { + PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__); + return -1; + } + + while (getdelim(&line, &linesz, '\n', fp) > 0) { + char *ptr = line; + char *left; + int n; + + n = strcspn(ptr, ":"); + ptr[n] = 0; + left = &ptr[n + 1]; + + while (*left && isspace(*left)) + left++; + + if (!strncmp(left, pci_id, strlen(pci_id))) { + found = 1; + + while (*ptr && isspace(*ptr)) + ptr++; + + sscanf(ptr, "%04hx-%04hx", &start, &end); + size = end - start + 1; + + break; + } + } + + free(line); + fclose(fp); + + if (!found) + return -1; + + pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start; + pci_dev->mem_resource[0].len = (uint64_t)size; + PMD_INIT_LOG(DEBUG, + "PCI Port IO found start=0x%x with size=0x%x", + start, size); + + /* can't support lsc interrupt without uio */ + pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC; + + return 0; +} + +/* Extract I/O port numbers from sysfs */ +static int +legacy_virtio_resource_init(struct rte_pci_device *pci_dev) +{ + if (virtio_resource_init_by_uio(pci_dev) == 0) + return 0; + else + return virtio_resource_init_by_ioports(pci_dev); +} + +#else +static int +legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused) +{ + /* nic_uio does not enable interrupts, return 0 (false). */ + return 0; +} + +static int +legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused) +{ + /* no setup required */ + return 0; +} +#endif static const struct virtio_pci_ops legacy_ops = { .read_dev_cfg = legacy_read_dev_config, @@ -241,9 +506,14 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) } int -vtpci_init(struct rte_pci_device *dev __rte_unused, struct virtio_hw *hw) +vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) { hw->vtpci_ops = &legacy_ops; + if (legacy_virtio_resource_init(dev) < 0) + return -1; + hw->use_msix = legacy_virtio_has_msix(&dev->addr); + hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr; + return 0; } -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v7 5/9] viritio: switch to 64 bit features 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 " Yuanhan Liu ` (3 preceding siblings ...) 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu @ 2016-02-02 13:48 ` Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu ` (4 subsequent siblings) 9 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw) To: dev Switch to 64 bit features, which virtio 1.0 supports. While legacy virtio only supports 32 bit features, it complains aloud and quit when trying to setting > 32 bit features. 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 | 8 ++++---- drivers/net/virtio/virtio_pci.c | 15 ++++++++++----- drivers/net/virtio/virtio_pci.h | 12 ++++++------ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index b57224d..4f84757 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -930,16 +930,16 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) static void virtio_negotiate_features(struct virtio_hw *hw) { - uint32_t host_features; + uint64_t host_features; /* Prepare guest_features: feature that driver wants to support */ hw->guest_features = VIRTIO_PMD_GUEST_FEATURES; - PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %x", + PMD_INIT_LOG(DEBUG, "guest_features before negotiate = %" PRIx64, hw->guest_features); /* Read device(host) feature bits */ host_features = hw->vtpci_ops->get_features(hw); - PMD_INIT_LOG(DEBUG, "host_features before negotiate = %x", + PMD_INIT_LOG(DEBUG, "host_features before negotiate = %" PRIx64, host_features); /* @@ -947,7 +947,7 @@ virtio_negotiate_features(struct virtio_hw *hw) * guest feature bits. */ hw->guest_features = vtpci_negotiate_features(hw, host_features); - PMD_INIT_LOG(DEBUG, "features after negotiate = %x", + PMD_INIT_LOG(DEBUG, "features after negotiate = %" PRIx64, hw->guest_features); } diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index e89a044..3961077 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -87,15 +87,20 @@ legacy_write_dev_config(struct virtio_hw *hw, size_t offset, } } -static uint32_t +static uint64_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) +legacy_set_features(struct virtio_hw *hw, uint64_t features) { + if ((features >> 32) != 0) { + PMD_DRV_LOG(ERR, + "only 32 bit features are allowed for legacy virtio!"); + return; + } VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features); } @@ -453,10 +458,10 @@ vtpci_write_dev_config(struct virtio_hw *hw, size_t offset, hw->vtpci_ops->write_dev_cfg(hw, offset, src, length); } -uint32_t -vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features) +uint64_t +vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features) { - uint32_t features; + uint64_t features; /* * Limit negotiated features to what the driver, virtqueue, and diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index e8e7509..d7bc6bb 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -175,8 +175,8 @@ struct virtio_pci_ops { 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); + uint64_t (*get_features)(struct virtio_hw *hw); + void (*set_features)(struct virtio_hw *hw, uint64_t features); uint8_t (*get_isr)(struct virtio_hw *hw); @@ -191,7 +191,7 @@ struct virtio_pci_ops { struct virtio_hw { struct virtqueue *cvq; uint32_t io_base; - uint32_t guest_features; + uint64_t guest_features; uint32_t max_tx_queues; uint32_t max_rx_queues; uint16_t vtnet_hdr_size; @@ -271,9 +271,9 @@ outl_p(unsigned int data, unsigned int port) outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) static inline int -vtpci_with_feature(struct virtio_hw *hw, uint32_t bit) +vtpci_with_feature(struct virtio_hw *hw, uint64_t bit) { - return (hw->guest_features & (1u << bit)) != 0; + return (hw->guest_features & (1ULL << bit)) != 0; } /* @@ -286,7 +286,7 @@ void vtpci_reinit_complete(struct virtio_hw *); void vtpci_set_status(struct virtio_hw *, uint8_t); -uint32_t vtpci_negotiate_features(struct virtio_hw *, uint32_t); +uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t); void vtpci_write_dev_config(struct virtio_hw *, size_t, const void *, int); -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v7 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 " Yuanhan Liu ` (4 preceding siblings ...) 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 5/9] viritio: switch to 64 bit features Yuanhan Liu @ 2016-02-02 13:48 ` Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu ` (3 subsequent siblings) 9 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw) To: dev The mergeable virtio net hdr format has been the standard and the only virtio net hdr format since virtio 1.0. Therefore, we can not hardcode hdr_size to "sizeof(struct virtio_net_hdr)" any more at virtio_recv_pkts(), otherwise, there would be a mismatch of hdr size from rte_vhost_enqueue_burst() and virtio_recv_pkts(), leading a packet corruption. Instead, we should retrieve it from hw->vtnet_hdr_size; we will do proper settings at eth_virtio_dev_init() in later patches. 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_rxtx.c | 6 ++++-- drivers/net/virtio/virtio_rxtx_simple.c | 12 ++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c index b7267c0..41a1366 100644 --- a/drivers/net/virtio/virtio_rxtx.c +++ b/drivers/net/virtio/virtio_rxtx.c @@ -560,7 +560,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ]; int error; uint32_t i, nb_enqueued; - const uint32_t hdr_size = sizeof(struct virtio_net_hdr); + uint32_t hdr_size; nb_used = VIRTQUEUE_NUSED(rxvq); @@ -580,6 +580,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) hw = rxvq->hw; nb_rx = 0; nb_enqueued = 0; + hdr_size = hw->vtnet_hdr_size; for (i = 0; i < num ; i++) { rxm = rcv_pkts[i]; @@ -664,7 +665,7 @@ virtio_recv_mergeable_pkts(void *rx_queue, uint32_t seg_num; uint16_t extra_idx; uint32_t seg_res; - const uint32_t hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); + uint32_t hdr_size; nb_used = VIRTQUEUE_NUSED(rxvq); @@ -682,6 +683,7 @@ virtio_recv_mergeable_pkts(void *rx_queue, seg_num = 0; extra_idx = 0; seg_res = 0; + hdr_size = hw->vtnet_hdr_size; while (i < nb_used) { struct virtio_net_hdr_mrg_rxbuf *header; diff --git a/drivers/net/virtio/virtio_rxtx_simple.c b/drivers/net/virtio/virtio_rxtx_simple.c index ff3c11a..3a1de9d 100644 --- a/drivers/net/virtio/virtio_rxtx_simple.c +++ b/drivers/net/virtio/virtio_rxtx_simple.c @@ -81,9 +81,9 @@ virtqueue_enqueue_recv_refill_simple(struct virtqueue *vq, start_dp = vq->vq_ring.desc; start_dp[desc_idx].addr = (uint64_t)((uintptr_t)cookie->buf_physaddr + - RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr)); + RTE_PKTMBUF_HEADROOM - vq->hw->vtnet_hdr_size); start_dp[desc_idx].len = cookie->buf_len - - RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr); + RTE_PKTMBUF_HEADROOM + vq->hw->vtnet_hdr_size; vq->vq_free_cnt--; vq->vq_avail_idx++; @@ -120,9 +120,9 @@ virtio_rxq_rearm_vec(struct virtqueue *rxvq) start_dp[i].addr = (uint64_t)((uintptr_t)sw_ring[i]->buf_physaddr + - RTE_PKTMBUF_HEADROOM - sizeof(struct virtio_net_hdr)); + RTE_PKTMBUF_HEADROOM - rxvq->hw->vtnet_hdr_size); start_dp[i].len = sw_ring[i]->buf_len - - RTE_PKTMBUF_HEADROOM + sizeof(struct virtio_net_hdr); + RTE_PKTMBUF_HEADROOM + rxvq->hw->vtnet_hdr_size; } rxvq->vq_avail_idx += RTE_VIRTIO_VPMD_RX_REARM_THRESH; @@ -175,8 +175,8 @@ virtio_recv_pkts_vec(void *rx_queue, struct rte_mbuf **rx_pkts, len_adjust = _mm_set_epi16( 0, 0, 0, - (uint16_t) -sizeof(struct virtio_net_hdr), - 0, (uint16_t) -sizeof(struct virtio_net_hdr), + (uint16_t)-rxvq->hw->vtnet_hdr_size, + 0, (uint16_t)-rxvq->hw->vtnet_hdr_size, 0, 0); if (unlikely(nb_pkts < RTE_VIRTIO_DESC_PER_LOOP)) -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v7 7/9] eal: pci: export pci_[un]map_device 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 " Yuanhan Liu ` (5 preceding siblings ...) 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu @ 2016-02-02 13:48 ` Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 8/9] virtio: add 1.0 support Yuanhan Liu ` (2 subsequent siblings) 9 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw) To: dev Normally we could set RTE_PCI_DRV_NEED_MAPPING flag so that eal will invoke pci_map_device internally for us. From that point view, there is no need to export pci_map_device. However, for virtio pmd driver, which is designed to work without binding UIO (or something similar first), pci_map_device() will fail, which ends up with virtio pmd driver being skipped. Therefore, we can not set RTE_PCI_DRV_NEED_MAPPING blindly at virtio pmd driver. Therefore, this patch exports pci_map_device, and let virtio pmd call it when necessary. Cc: David Marchand <david.marchand@6wind.com> Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> Tested-by: Santosh Shukla <sshukla@mvista.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: David Marchand <david.marchand@6wind.com> Acked-by: Huawei Xie <huawei.xie@intel.com> --- lib/librte_eal/bsdapp/eal/eal_pci.c | 4 ++-- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 2 ++ lib/librte_eal/common/eal_common_pci.c | 4 ++-- lib/librte_eal/common/eal_private.h | 18 ----------------- lib/librte_eal/common/include/rte_pci.h | 27 +++++++++++++++++++++++++ lib/librte_eal/linuxapp/eal/eal_pci.c | 4 ++-- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 3 +++ 7 files changed, 38 insertions(+), 24 deletions(-) diff --git a/lib/librte_eal/bsdapp/eal/eal_pci.c b/lib/librte_eal/bsdapp/eal/eal_pci.c index 6c21fbd..95c32c1 100644 --- a/lib/librte_eal/bsdapp/eal/eal_pci.c +++ b/lib/librte_eal/bsdapp/eal/eal_pci.c @@ -93,7 +93,7 @@ pci_unbind_kernel_driver(struct rte_pci_device *dev __rte_unused) /* Map pci device */ int -pci_map_device(struct rte_pci_device *dev) +rte_eal_pci_map_device(struct rte_pci_device *dev) { int ret = -1; @@ -115,7 +115,7 @@ pci_map_device(struct rte_pci_device *dev) /* Unmap pci device */ void -pci_unmap_device(struct rte_pci_device *dev) +rte_eal_pci_unmap_device(struct rte_pci_device *dev) { /* try unmapping the NIC resources */ switch (dev->kdrv) { diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map index 6fa9c67..d8ac7f7 100644 --- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map +++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map @@ -139,6 +139,8 @@ DPDK_2.2 { DPDK_2.3 { global: + rte_eal_pci_map_device; + rte_eal_pci_unmap_device; rte_cpu_feature_table; } DPDK_2.2; diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c index dcfe947..96d5113 100644 --- a/lib/librte_eal/common/eal_common_pci.c +++ b/lib/librte_eal/common/eal_common_pci.c @@ -188,7 +188,7 @@ rte_eal_pci_probe_one_driver(struct rte_pci_driver *dr, struct rte_pci_device *d pci_config_space_set(dev); #endif /* map resources for devices that use igb_uio */ - ret = pci_map_device(dev); + ret = rte_eal_pci_map_device(dev); if (ret != 0) return ret; } else if (dr->drv_flags & RTE_PCI_DRV_FORCE_UNBIND && @@ -254,7 +254,7 @@ rte_eal_pci_detach_dev(struct rte_pci_driver *dr, if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING) /* unmap resources for devices that use igb_uio */ - pci_unmap_device(dev); + rte_eal_pci_unmap_device(dev); return 0; } diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h index 072e672..2342fa1 100644 --- a/lib/librte_eal/common/eal_private.h +++ b/lib/librte_eal/common/eal_private.h @@ -165,24 +165,6 @@ struct rte_pci_device; int pci_unbind_kernel_driver(struct rte_pci_device *dev); /** - * Map this device - * - * This function is private to EAL. - * - * @return - * 0 on success, negative on error and positive if no driver - * is found for the device. - */ -int pci_map_device(struct rte_pci_device *dev); - -/** - * Unmap this device - * - * This function is private to EAL. - */ -void pci_unmap_device(struct rte_pci_device *dev); - -/** * Map the PCI resource of a PCI device in virtual memory * * This function is private to EAL. diff --git a/lib/librte_eal/common/include/rte_pci.h b/lib/librte_eal/common/include/rte_pci.h index 334c12e..2224109 100644 --- a/lib/librte_eal/common/include/rte_pci.h +++ b/lib/librte_eal/common/include/rte_pci.h @@ -485,6 +485,33 @@ int rte_eal_pci_read_config(const struct rte_pci_device *device, */ int rte_eal_pci_write_config(const struct rte_pci_device *device, const void *buf, size_t len, off_t offset); +/** + * Map the PCI device resources in user space virtual memory address + * + * Note that driver should not call this function when flag + * RTE_PCI_DRV_NEED_MAPPING is set, as EAL will do that for + * you when it's on. + * + * @param dev + * A pointer to a rte_pci_device structure describing the device + * to use + * + * @return + * 0 on success, negative on error and positive if no driver + * is found for the device. + */ +int rte_eal_pci_map_device(struct rte_pci_device *dev); + +/** + * Unmap this device + * + * @param dev + * A pointer to a rte_pci_device structure describing the device + * to use + */ +void rte_eal_pci_unmap_device(struct rte_pci_device *dev); + + #ifdef RTE_PCI_CONFIG /** diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c index bc5b5be..db947da 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c @@ -124,7 +124,7 @@ pci_get_kernel_driver_by_path(const char *filename, char *dri_name) /* Map pci device */ int -pci_map_device(struct rte_pci_device *dev) +rte_eal_pci_map_device(struct rte_pci_device *dev) { int ret = -1; @@ -153,7 +153,7 @@ pci_map_device(struct rte_pci_device *dev) /* Unmap pci device */ void -pci_unmap_device(struct rte_pci_device *dev) +rte_eal_pci_unmap_device(struct rte_pci_device *dev) { /* try unmapping the NIC resources using VFIO if it exists */ switch (dev->kdrv) { diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map index aa4fcbd..4c09c0b 100644 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map @@ -142,5 +142,8 @@ DPDK_2.2 { DPDK_2.3 { global: + rte_eal_pci_map_device; + rte_eal_pci_unmap_device; rte_cpu_feature_table; + } DPDK_2.2; -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v7 8/9] virtio: add 1.0 support 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 " Yuanhan Liu ` (6 preceding siblings ...) 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu @ 2016-02-02 13:48 ` Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu 2016-02-03 15:09 ` [dpdk-dev] [PATCH v7 0/9] virtio 1.0 enabling for virtio pmd driver Thomas Monjalon 9 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw) To: dev Modern (v1.0) virtio pci device defines several pci capabilities. Each cap has a configure structure corresponding to it, and the cap.bar and cap.offset fields tell us where to find it. Firstly, we map the pci resources by rte_eal_pci_map_device(). We then could easily locate a cfg structure by: cfg_addr = dev->mem_resources[cap.bar].addr + cap.offset; Therefore, the entrance of enabling modern (v1.0) pci device support is to iterate the pci capability lists, and to locate some configs we care; and they are: - common cfg For generic virtio and virtqueue configuration, such as setting/getting features, enabling a specific queue, and so on. - nofity cfg Combining with `queue_notify_off' from common cfg, we could use it to notify a specific virt queue. - device cfg Where virtio_net_config structure is located. - isr cfg Where to read isr (interrupt status). If any of above cap is not found, we fallback to the legacy virtio handling. If succeed, hw->vtpci_ops is assigned to modern_ops, where all operations are implemented by reading/writing a (or few) specific configuration space from above 4 cfg structures. And that's basically how this patch works. Besides those changes, virtio 1.0 introduces a new status field: FEATURES_OK, which is set after features negotiation is done. Last, set the VIRTIO_F_VERSION_1 feature flag. 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> --- v6: - unfold DEF_IO_READ/WRITE macros v5: - rename MODERN_READ/WRITE_DEF macro name to IO_READ/WRITE_DEF - check offset + length overflow --- doc/guides/rel_notes/release_2_3.rst | 3 + drivers/net/virtio/virtio_ethdev.c | 25 ++- drivers/net/virtio/virtio_ethdev.h | 3 +- drivers/net/virtio/virtio_pci.c | 355 ++++++++++++++++++++++++++++++++++- drivers/net/virtio/virtio_pci.h | 67 +++++++ drivers/net/virtio/virtqueue.h | 2 + 6 files changed, 450 insertions(+), 5 deletions(-) diff --git a/doc/guides/rel_notes/release_2_3.rst b/doc/guides/rel_notes/release_2_3.rst index 99de186..c390d97 100644 --- a/doc/guides/rel_notes/release_2_3.rst +++ b/doc/guides/rel_notes/release_2_3.rst @@ -4,6 +4,9 @@ DPDK Release 2.3 New Features ------------ +* **Virtio 1.0 support.** + + Enabled virtio 1.0 support for virtio pmd driver. Resolved Issues --------------- diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c index 4f84757..755503d 100644 --- a/drivers/net/virtio/virtio_ethdev.c +++ b/drivers/net/virtio/virtio_ethdev.c @@ -927,7 +927,7 @@ virtio_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) return virtio_send_command(hw->cvq, &ctrl, &len, 1); } -static void +static int virtio_negotiate_features(struct virtio_hw *hw) { uint64_t host_features; @@ -949,6 +949,22 @@ virtio_negotiate_features(struct virtio_hw *hw) hw->guest_features = vtpci_negotiate_features(hw, host_features); PMD_INIT_LOG(DEBUG, "features after negotiate = %" PRIx64, hw->guest_features); + + if (hw->modern) { + if (!vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) { + PMD_INIT_LOG(ERR, + "VIRTIO_F_VERSION_1 features is not enabled."); + return -1; + } + vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK); + if (!(vtpci_get_status(hw) & VIRTIO_CONFIG_STATUS_FEATURES_OK)) { + PMD_INIT_LOG(ERR, + "failed to set FEATURES_OK status!"); + return -1; + } + } + + return 0; } /* @@ -1032,7 +1048,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev) /* Tell the host we've known how to drive the device. */ vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER); - virtio_negotiate_features(hw); + if (virtio_negotiate_features(hw) < 0) + return -1; /* If host does not support status then disable LSC */ if (!vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) @@ -1043,7 +1060,8 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev) rx_func_get(eth_dev); /* Setting up rx_header size for the device */ - if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) + if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) || + vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr_mrg_rxbuf); else hw->vtnet_hdr_size = sizeof(struct virtio_net_hdr); @@ -1159,6 +1177,7 @@ eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev) rte_intr_callback_unregister(&pci_dev->intr_handle, virtio_interrupt_handler, eth_dev); + rte_eal_pci_unmap_device(pci_dev); PMD_INIT_LOG(DEBUG, "dev_uninit completed"); diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h index ae2d47d..fed9571 100644 --- a/drivers/net/virtio/virtio_ethdev.h +++ b/drivers/net/virtio/virtio_ethdev.h @@ -64,7 +64,8 @@ 1u << VIRTIO_NET_F_CTRL_VQ | \ 1u << VIRTIO_NET_F_CTRL_RX | \ 1u << VIRTIO_NET_F_CTRL_VLAN | \ - 1u << VIRTIO_NET_F_MRG_RXBUF) + 1u << VIRTIO_NET_F_MRG_RXBUF | \ + 1ULL << VIRTIO_F_VERSION_1) /* * CQ function prototype diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 3961077..4cdecea 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -41,6 +41,14 @@ #include "virtio_logs.h" #include "virtqueue.h" +/* + * Following macros are derieved from linux/pci_regs.h, however, + * we can't simply include that header here, as there is no such + * file for non-Linux platform. + */ +#define PCI_CAPABILITY_LIST 0x34 +#define PCI_CAP_ID_VNDR 0x09 + static void legacy_read_dev_config(struct virtio_hw *hw, size_t offset, void *dst, int length) @@ -444,6 +452,218 @@ static const struct virtio_pci_ops legacy_ops = { }; + +static inline uint8_t +io_read8(uint8_t *addr) +{ + return *(volatile uint8_t *)addr; +} + +static inline void +io_write8(uint8_t val, uint8_t *addr) +{ + *(volatile uint8_t *)addr = val; +} + +static inline uint16_t +io_read16(uint16_t *addr) +{ + return *(volatile uint16_t *)addr; +} + +static inline void +io_write16(uint16_t val, uint16_t *addr) +{ + *(volatile uint16_t *)addr = val; +} + +static inline uint32_t +io_read32(uint32_t *addr) +{ + return *(volatile uint32_t *)addr; +} + +static inline void +io_write32(uint32_t val, uint32_t *addr) +{ + *(volatile uint32_t *)addr = val; +} + +static inline void +io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi) +{ + io_write32(val & ((1ULL << 32) - 1), lo); + io_write32(val >> 32, hi); +} + +static void +modern_read_dev_config(struct virtio_hw *hw, size_t offset, + void *dst, int length) +{ + int i; + uint8_t *p; + uint8_t old_gen, new_gen; + + do { + old_gen = io_read8(&hw->common_cfg->config_generation); + + p = dst; + for (i = 0; i < length; i++) + *p++ = io_read8((uint8_t *)hw->dev_cfg + offset + i); + + new_gen = io_read8(&hw->common_cfg->config_generation); + } while (old_gen != new_gen); +} + +static void +modern_write_dev_config(struct virtio_hw *hw, size_t offset, + const void *src, int length) +{ + int i; + const uint8_t *p = src; + + for (i = 0; i < length; i++) + io_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i); +} + +static uint64_t +modern_get_features(struct virtio_hw *hw) +{ + uint32_t features_lo, features_hi; + + io_write32(0, &hw->common_cfg->device_feature_select); + features_lo = io_read32(&hw->common_cfg->device_feature); + + io_write32(1, &hw->common_cfg->device_feature_select); + features_hi = io_read32(&hw->common_cfg->device_feature); + + return ((uint64_t)features_hi << 32) | features_lo; +} + +static void +modern_set_features(struct virtio_hw *hw, uint64_t features) +{ + io_write32(0, &hw->common_cfg->guest_feature_select); + io_write32(features & ((1ULL << 32) - 1), + &hw->common_cfg->guest_feature); + + io_write32(1, &hw->common_cfg->guest_feature_select); + io_write32(features >> 32, + &hw->common_cfg->guest_feature); +} + +static uint8_t +modern_get_status(struct virtio_hw *hw) +{ + return io_read8(&hw->common_cfg->device_status); +} + +static void +modern_set_status(struct virtio_hw *hw, uint8_t status) +{ + io_write8(status, &hw->common_cfg->device_status); +} + +static void +modern_reset(struct virtio_hw *hw) +{ + modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET); + modern_get_status(hw); +} + +static uint8_t +modern_get_isr(struct virtio_hw *hw) +{ + return io_read8(hw->isr); +} + +static uint16_t +modern_set_config_irq(struct virtio_hw *hw, uint16_t vec) +{ + io_write16(vec, &hw->common_cfg->msix_config); + return io_read16(&hw->common_cfg->msix_config); +} + +static uint16_t +modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id) +{ + io_write16(queue_id, &hw->common_cfg->queue_select); + return io_read16(&hw->common_cfg->queue_size); +} + +static void +modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + uint64_t desc_addr, avail_addr, used_addr; + uint16_t notify_off; + + desc_addr = vq->mz->phys_addr; + avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc); + used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail, + ring[vq->vq_nentries]), + VIRTIO_PCI_VRING_ALIGN); + + io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); + + io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + notify_off = io_read16(&hw->common_cfg->queue_notify_off); + vq->notify_addr = (void *)((uint8_t *)hw->notify_base + + notify_off * hw->notify_off_multiplier); + + io_write16(1, &hw->common_cfg->queue_enable); + + PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index); + PMD_INIT_LOG(DEBUG, "\t desc_addr: %" PRIx64, desc_addr); + PMD_INIT_LOG(DEBUG, "\t aval_addr: %" PRIx64, avail_addr); + PMD_INIT_LOG(DEBUG, "\t used_addr: %" PRIx64, used_addr); + PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)", + vq->notify_addr, notify_off); +} + +static void +modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select); + + io_write64_twopart(0, &hw->common_cfg->queue_desc_lo, + &hw->common_cfg->queue_desc_hi); + io_write64_twopart(0, &hw->common_cfg->queue_avail_lo, + &hw->common_cfg->queue_avail_hi); + io_write64_twopart(0, &hw->common_cfg->queue_used_lo, + &hw->common_cfg->queue_used_hi); + + io_write16(0, &hw->common_cfg->queue_enable); +} + +static void +modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq) +{ + io_write16(1, vq->notify_addr); +} + +static const struct virtio_pci_ops modern_ops = { + .read_dev_cfg = modern_read_dev_config, + .write_dev_cfg = modern_write_dev_config, + .reset = modern_reset, + .get_status = modern_get_status, + .set_status = modern_set_status, + .get_features = modern_get_features, + .set_features = modern_set_features, + .get_isr = modern_get_isr, + .set_config_irq = modern_set_config_irq, + .get_queue_num = modern_get_queue_num, + .setup_queue = modern_setup_queue, + .del_queue = modern_del_queue, + .notify_queue = modern_notify_queue, +}; + + void vtpci_read_dev_config(struct virtio_hw *hw, size_t offset, void *dst, int length) @@ -497,6 +717,12 @@ vtpci_set_status(struct virtio_hw *hw, uint8_t status) } uint8_t +vtpci_get_status(struct virtio_hw *hw) +{ + return hw->vtpci_ops->get_status(hw); +} + +uint8_t vtpci_isr(struct virtio_hw *hw) { return hw->vtpci_ops->get_isr(hw); @@ -510,15 +736,142 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec) return hw->vtpci_ops->set_config_irq(hw, vec); } +static void * +get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap) +{ + uint8_t bar = cap->bar; + uint32_t length = cap->length; + uint32_t offset = cap->offset; + uint8_t *base; + + if (bar > 5) { + PMD_INIT_LOG(ERR, "invalid bar: %u", bar); + return NULL; + } + + if (offset + length < offset) { + PMD_INIT_LOG(ERR, "offset(%u) + length(%u) overflows", + offset, length); + return NULL; + } + + if (offset + length > dev->mem_resource[bar].len) { + PMD_INIT_LOG(ERR, + "invalid cap: overflows bar space: %u > %" PRIu64, + offset + length, dev->mem_resource[bar].len); + return NULL; + } + + base = dev->mem_resource[bar].addr; + if (base == NULL) { + PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar); + return NULL; + } + + return base + offset; +} + +static int +virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw) +{ + uint8_t pos; + struct virtio_pci_cap cap; + int ret; + + if (rte_eal_pci_map_device(dev) < 0) { + PMD_INIT_LOG(DEBUG, "failed to map pci device!"); + return -1; + } + + ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST); + if (ret < 0) { + PMD_INIT_LOG(DEBUG, "failed to read pci capability list"); + return -1; + } + + while (pos) { + ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos); + if (ret < 0) { + PMD_INIT_LOG(ERR, + "failed to read pci cap at pos: %x", pos); + break; + } + + if (cap.cap_vndr != PCI_CAP_ID_VNDR) { + PMD_INIT_LOG(DEBUG, + "[%2x] skipping non VNDR cap id: %02x", + pos, cap.cap_vndr); + goto next; + } + + PMD_INIT_LOG(DEBUG, + "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u", + pos, cap.cfg_type, cap.bar, cap.offset, cap.length); + + switch (cap.cfg_type) { + case VIRTIO_PCI_CAP_COMMON_CFG: + hw->common_cfg = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_NOTIFY_CFG: + rte_eal_pci_read_config(dev, &hw->notify_off_multiplier, + 4, pos + sizeof(cap)); + hw->notify_base = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_DEVICE_CFG: + hw->dev_cfg = get_cfg_addr(dev, &cap); + break; + case VIRTIO_PCI_CAP_ISR_CFG: + hw->isr = get_cfg_addr(dev, &cap); + break; + } + +next: + pos = cap.cap_next; + } + + if (hw->common_cfg == NULL || hw->notify_base == NULL || + hw->dev_cfg == NULL || hw->isr == NULL) { + PMD_INIT_LOG(INFO, "no modern virtio pci device found."); + return -1; + } + + PMD_INIT_LOG(INFO, "found modern virtio pci device."); + + PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg); + PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg); + PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr); + PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u", + hw->notify_base, hw->notify_off_multiplier); + + return 0; +} + int vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw) { - hw->vtpci_ops = &legacy_ops; + hw->dev = dev; + /* + * Try if we can succeed reading virtio pci caps, which exists + * only on modern pci device. If failed, we fallback to legacy + * virtio handling. + */ + if (virtio_read_caps(dev, hw) == 0) { + PMD_INIT_LOG(INFO, "modern virtio pci detected."); + hw->vtpci_ops = &modern_ops; + hw->modern = 1; + dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC; + return 0; + } + + PMD_INIT_LOG(INFO, "trying with legacy virtio pci."); if (legacy_virtio_resource_init(dev) < 0) return -1; + + hw->vtpci_ops = &legacy_ops; hw->use_msix = legacy_virtio_has_msix(&dev->addr); hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr; + hw->modern = 0; return 0; } diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index d7bc6bb..fcac660 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -93,6 +93,7 @@ struct virtqueue; #define VIRTIO_CONFIG_STATUS_ACK 0x01 #define VIRTIO_CONFIG_STATUS_DRIVER 0x02 #define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04 +#define VIRTIO_CONFIG_STATUS_FEATURES_OK 0x08 #define VIRTIO_CONFIG_STATUS_FAILED 0x80 /* @@ -141,6 +142,8 @@ struct virtqueue; /* We support indirect buffer descriptors */ #define VIRTIO_RING_F_INDIRECT_DESC 28 +#define VIRTIO_F_VERSION_1 32 + /* * Some VirtIO feature bits (currently bits 28 through 31) are * reserved for the transport being used (eg. virtio_ring), the @@ -163,6 +166,60 @@ struct virtqueue; */ #define VIRTIO_MAX_VIRTQUEUES 8 +/* Common configuration */ +#define VIRTIO_PCI_CAP_COMMON_CFG 1 +/* Notifications */ +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 +/* ISR Status */ +#define VIRTIO_PCI_CAP_ISR_CFG 3 +/* Device specific configuration */ +#define VIRTIO_PCI_CAP_DEVICE_CFG 4 +/* PCI configuration access */ +#define VIRTIO_PCI_CAP_PCI_CFG 5 + +/* This is the PCI capability header: */ +struct virtio_pci_cap { + uint8_t cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */ + uint8_t cap_next; /* Generic PCI field: next ptr. */ + uint8_t cap_len; /* Generic PCI field: capability length */ + uint8_t cfg_type; /* Identifies the structure. */ + uint8_t bar; /* Where to find it. */ + uint8_t padding[3]; /* Pad to full dword. */ + uint32_t offset; /* Offset within bar. */ + uint32_t length; /* Length of the structure, in bytes. */ +}; + +struct virtio_pci_notify_cap { + struct virtio_pci_cap cap; + uint32_t notify_off_multiplier; /* Multiplier for queue_notify_off. */ +}; + +/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */ +struct virtio_pci_common_cfg { + /* About the whole device. */ + uint32_t device_feature_select; /* read-write */ + uint32_t device_feature; /* read-only */ + uint32_t guest_feature_select; /* read-write */ + uint32_t guest_feature; /* read-write */ + uint16_t msix_config; /* read-write */ + uint16_t num_queues; /* read-only */ + uint8_t device_status; /* read-write */ + uint8_t config_generation; /* read-only */ + + /* About a specific virtqueue. */ + uint16_t queue_select; /* read-write */ + uint16_t queue_size; /* read-write, power of 2. */ + uint16_t queue_msix_vector; /* read-write */ + uint16_t queue_enable; /* read-write */ + uint16_t queue_notify_off; /* read-only */ + uint32_t queue_desc_lo; /* read-write */ + uint32_t queue_desc_hi; /* read-write */ + uint32_t queue_avail_lo; /* read-write */ + uint32_t queue_avail_hi; /* read-write */ + uint32_t queue_used_lo; /* read-write */ + uint32_t queue_used_hi; /* read-write */ +}; + struct virtio_hw; struct virtio_pci_ops { @@ -188,6 +245,8 @@ struct virtio_pci_ops { void (*notify_queue)(struct virtio_hw *hw, struct virtqueue *vq); }; +struct virtio_net_config; + struct virtio_hw { struct virtqueue *cvq; uint32_t io_base; @@ -198,7 +257,14 @@ struct virtio_hw { uint8_t vlan_strip; uint8_t use_msix; uint8_t started; + uint8_t modern; uint8_t mac_addr[ETHER_ADDR_LEN]; + uint32_t notify_off_multiplier; + uint8_t *isr; + uint16_t *notify_base; + struct rte_pci_device *dev; + struct virtio_pci_common_cfg *common_cfg; + struct virtio_net_config *dev_cfg; const struct virtio_pci_ops *vtpci_ops; }; @@ -284,6 +350,7 @@ void vtpci_reset(struct virtio_hw *); void vtpci_reinit_complete(struct virtio_hw *); +uint8_t vtpci_get_status(struct virtio_hw *); void vtpci_set_status(struct virtio_hw *, uint8_t); uint64_t vtpci_negotiate_features(struct virtio_hw *, uint64_t); diff --git a/drivers/net/virtio/virtqueue.h b/drivers/net/virtio/virtqueue.h index d7fb450..99d4fa9 100644 --- a/drivers/net/virtio/virtqueue.h +++ b/drivers/net/virtio/virtqueue.h @@ -202,6 +202,8 @@ struct virtqueue { /* Size bins in array as RFC 2819, undersized [0], 64 [1], etc */ uint64_t size_bins[8]; + uint16_t *notify_addr; + struct vq_desc_extra { void *cookie; uint16_t ndescs; -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* [dpdk-dev] [PATCH v7 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 " Yuanhan Liu ` (7 preceding siblings ...) 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 8/9] virtio: add 1.0 support Yuanhan Liu @ 2016-02-02 13:48 ` Yuanhan Liu 2016-02-03 15:09 ` [dpdk-dev] [PATCH v7 0/9] virtio 1.0 enabling for virtio pmd driver Thomas Monjalon 9 siblings, 0 replies; 122+ messages in thread From: Yuanhan Liu @ 2016-02-02 13:48 UTC (permalink / raw) To: dev virtio_pci.c is the only file references those macros; move them there. 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_pci.c | 19 +++++++++++++++++++ drivers/net/virtio/virtio_pci.h | 18 ------------------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c index 4cdecea..9fbc2f5 100644 --- a/drivers/net/virtio/virtio_pci.c +++ b/drivers/net/virtio/virtio_pci.c @@ -49,6 +49,25 @@ #define PCI_CAPABILITY_LIST 0x34 #define PCI_CAP_ID_VNDR 0x09 + +#define VIRTIO_PCI_REG_ADDR(hw, reg) \ + (unsigned short)((hw)->io_base + (reg)) + +#define VIRTIO_READ_REG_1(hw, reg) \ + inb((VIRTIO_PCI_REG_ADDR((hw), (reg)))) +#define VIRTIO_WRITE_REG_1(hw, reg, value) \ + outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + +#define VIRTIO_READ_REG_2(hw, reg) \ + inw((VIRTIO_PCI_REG_ADDR((hw), (reg)))) +#define VIRTIO_WRITE_REG_2(hw, reg, value) \ + outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + +#define VIRTIO_READ_REG_4(hw, reg) \ + inl((VIRTIO_PCI_REG_ADDR((hw), (reg)))) +#define VIRTIO_WRITE_REG_4(hw, reg, value) \ + outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) + static void legacy_read_dev_config(struct virtio_hw *hw, size_t offset, void *dst, int length) diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h index fcac660..0544a07 100644 --- a/drivers/net/virtio/virtio_pci.h +++ b/drivers/net/virtio/virtio_pci.h @@ -318,24 +318,6 @@ outl_p(unsigned int data, unsigned int port) } #endif -#define VIRTIO_PCI_REG_ADDR(hw, reg) \ - (unsigned short)((hw)->io_base + (reg)) - -#define VIRTIO_READ_REG_1(hw, reg) \ - inb((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_1(hw, reg, value) \ - outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - -#define VIRTIO_READ_REG_2(hw, reg) \ - inw((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_2(hw, reg, value) \ - outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - -#define VIRTIO_READ_REG_4(hw, reg) \ - inl((VIRTIO_PCI_REG_ADDR((hw), (reg)))) -#define VIRTIO_WRITE_REG_4(hw, reg, value) \ - outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg)))) - static inline int vtpci_with_feature(struct virtio_hw *hw, uint64_t bit) { -- 1.9.0 ^ permalink raw reply [flat|nested] 122+ messages in thread
* Re: [dpdk-dev] [PATCH v7 0/9] virtio 1.0 enabling for virtio pmd driver 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 " Yuanhan Liu ` (8 preceding siblings ...) 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu @ 2016-02-03 15:09 ` Thomas Monjalon 9 siblings, 0 replies; 122+ messages in thread From: Thomas Monjalon @ 2016-02-03 15:09 UTC (permalink / raw) To: Yuanhan Liu; +Cc: dev 2016-02-02 21:48, Yuanhan Liu: > v7: - make checkpatch a bit happier; few (false) warnings still left. > > - rebase to latest code: fixed a conflict. > > v6: unfold IO_READ/WRITE_DEF macro > > v5: minor fixes: > > - fix wrong type of arg "offset" of read/write_dev_config(): patch 2 > is newly added for that. > > - check "offset + length" overflow > > Almost all difference comes from virtio 1.0 are the PCI layout change: > the major configuration structures are stored at bar space, and their > location is stored at corresponding pci cap structure. Reading/parsing > them is one of the major work of patch 8. > > To make handling virtio v1.0 and v0.95 co-exist well, this patch set > introduces a virtio_pci_ops structure, to add another layer so that > we could keep those vtpci_foo_bar "APIs". With that, we could do the > minimum change to add virtio 1.0 support. Applied, thanks ^ permalink raw reply [flat|nested] 122+ messages in thread
end of thread, other threads:[~2016-02-03 15:10 UTC | newest] Thread overview: 122+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2015-12-10 3:54 [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu 2015-12-10 3:54 ` [dpdk-dev] [PATCH 1/6] virtio: don't set vring address again at queue startup Yuanhan Liu 2015-12-10 3:54 ` [dpdk-dev] [PATCH 2/6] virtio: introduce struct virtio_pci_ops Yuanhan Liu 2015-12-29 11:31 ` Tan, Jianfeng 2015-12-30 3:45 ` Yuanhan Liu 2015-12-10 3:54 ` [dpdk-dev] [PATCH 3/6] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu 2015-12-10 3:54 ` [dpdk-dev] [PATCH 4/6] viritio: switch to 64 bit features Yuanhan Liu 2015-12-10 3:54 ` [dpdk-dev] [PATCH 5/6] virtio: set RTE_PCI_DRV_NEED_MAPPING flag Yuanhan Liu 2015-12-10 3:54 ` [dpdk-dev] [PATCH 6/6] virtio: add virtio v1.0 support Yuanhan Liu 2015-12-29 11:39 ` Tan, Jianfeng 2015-12-30 3:40 ` Yuanhan Liu 2015-12-10 3:58 ` [dpdk-dev] [PATCH 0/6 for 2.3] initial virtio 1.0 enabling Yuanhan Liu 2015-12-29 11:19 ` Tan, Jianfeng 2015-12-30 3:53 ` Yuanhan Liu 2016-01-04 3:55 ` Xu, Qian Q 2016-01-04 4:16 ` Yuanhan Liu 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 1/7] virtio: don't set vring address again at queue startup Yuanhan Liu 2016-01-12 6:58 ` [dpdk-dev] [PATCH v2 2/7] virtio: introduce struct virtio_pci_ops Yuanhan Liu 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 3/7] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 4/7] viritio: switch to 64 bit features Yuanhan Liu 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 5/7] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 6/7] eal: pci: export pci_map_device Yuanhan Liu 2016-01-12 8:31 ` David Marchand 2016-01-12 8:40 ` Yuanhan Liu 2016-01-12 9:05 ` Yuanhan Liu 2016-01-13 14:44 ` Santosh Shukla 2016-01-12 6:59 ` [dpdk-dev] [PATCH v2 7/7] virtio: add 1.0 support Yuanhan Liu 2016-01-13 3:31 ` Tetsuya Mukawa 2016-01-13 9:38 ` Yuanhan Liu 2016-01-14 7:47 ` Xie, Huawei 2016-01-14 7:50 ` Yuanhan Liu 2016-01-14 7:51 ` Xie, Huawei 2016-01-14 7:58 ` Yuanhan Liu 2016-01-14 8:08 ` Xie, Huawei 2016-01-14 8:22 ` Yuanhan Liu 2016-01-14 8:28 ` Xie, Huawei 2016-01-14 7:50 ` Xie, Huawei 2016-01-14 8:38 ` Yuanhan Liu 2016-01-12 7:07 ` [dpdk-dev] [PATCH v2 0/7] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu 2016-01-14 4:27 ` Tetsuya Mukawa 2016-01-14 5:59 ` Yuanhan Liu 2016-01-14 6:09 ` Tan, Jianfeng 2016-01-14 6:41 ` Tetsuya Mukawa 2016-01-18 9:04 ` Tetsuya Mukawa 2016-01-14 6:45 ` Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 0/8] " Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 2/8] virtio: introduce struct virtio_pci_ops Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 3/8] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 4/8] viritio: switch to 64 bit features Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 6/8] eal: pci: export pci_[un]map_device Yuanhan Liu 2016-01-14 7:45 ` Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 7/8] virtio: add 1.0 support Yuanhan Liu 2016-01-14 7:42 ` [dpdk-dev] [PATCH v3 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu 2016-01-16 10:08 ` Santosh Shukla 2016-01-17 14:07 ` Santosh Shukla 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 1/8] virtio: don't set vring address again at queue startup Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 2/8] virtio: introduce struct virtio_pci_ops Yuanhan Liu 2016-01-18 17:21 ` Xie, Huawei 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 3/8] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 4/8] viritio: switch to 64 bit features Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 5/8] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 6/8] eal: pci: export pci_[un]map_device Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 7/8] virtio: add 1.0 support Yuanhan Liu 2016-01-18 16:38 ` Xie, Huawei 2016-01-18 16:50 ` Xie, Huawei 2016-01-19 5:55 ` Yuanhan Liu 2016-01-19 7:44 ` Xie, Huawei 2016-01-19 7:54 ` Yuanhan Liu 2016-01-19 8:02 ` Xie, Huawei 2016-01-18 17:07 ` Xie, Huawei 2016-01-19 1:36 ` Yuanhan Liu 2016-01-19 1:51 ` Xie, Huawei 2016-01-19 2:46 ` Yuanhan Liu 2016-01-19 2:48 ` Xie, Huawei 2016-01-19 5:54 ` Yuanhan Liu 2016-01-15 4:36 ` [dpdk-dev] [PATCH v4 8/8] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu 2016-01-15 8:57 ` Xu, Qian Q 2016-01-18 8:04 ` [dpdk-dev] [PATCH v4 0/8] virtio 1.0 enabling for virtio pmd driver Tetsuya Mukawa 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 0/9] " Yuanhan Liu 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 2/9] virtio: define offset as size_t type Yuanhan Liu 2016-01-19 8:11 ` [dpdk-dev] [PATCH v5 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 5/9] viritio: switch to 64 bit features Yuanhan Liu 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu 2016-01-19 8:17 ` David Marchand 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 8/9] virtio: add 1.0 support Yuanhan Liu 2016-01-21 11:37 ` Thomas Monjalon 2016-01-27 3:49 ` Yuanhan Liu 2016-01-21 11:49 ` Thomas Monjalon 2016-01-27 3:46 ` Yuanhan Liu 2016-01-27 8:11 ` Thomas Monjalon 2016-01-19 8:12 ` [dpdk-dev] [PATCH v5 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu 2016-01-19 8:55 ` [dpdk-dev] [PATCH v5 0/9] virtio 1.0 enabling for virtio pmd driver Xie, Huawei 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 " Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 2/9] virtio: define offset as size_t type Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 5/9] viritio: switch to 64 bit features Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 8/9] virtio: add 1.0 support Yuanhan Liu 2016-01-28 7:54 ` [dpdk-dev] [PATCH v6 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu 2016-02-02 10:46 ` [dpdk-dev] [PATCH v6 0/9] virtio 1.0 enabling for virtio pmd driver Thomas Monjalon 2016-02-02 13:00 ` Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 " Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 1/9] virtio: don't set vring address again at queue startup Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 2/9] virtio: define offset as size_t type Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 3/9] virtio: introduce struct virtio_pci_ops Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 4/9] virtio: move left pci stuff to virtio_pci.c Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 5/9] viritio: switch to 64 bit features Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 6/9] virtio: retrieve hdr_size from hw->vtnet_hdr_size Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 7/9] eal: pci: export pci_[un]map_device Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 8/9] virtio: add 1.0 support Yuanhan Liu 2016-02-02 13:48 ` [dpdk-dev] [PATCH v7 9/9] virtio: move VIRTIO_READ/WRITE_REG_X into virtio_pci.c Yuanhan Liu 2016-02-03 15:09 ` [dpdk-dev] [PATCH v7 0/9] virtio 1.0 enabling for virtio pmd driver Thomas Monjalon
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).