[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PULL 13/42] virtio-pci: initial virtio 1.0 support
From: |
Paolo Bonzini |
Subject: |
Re: [Qemu-devel] [PULL 13/42] virtio-pci: initial virtio 1.0 support |
Date: |
Sat, 20 Jun 2015 23:08:59 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.6.0 |
On 11/06/2015 13:58, Michael S. Tsirkin wrote:
> This is somewhat functional. With this, and linux driver from my tree,
> I was able to use virtio net as virtio 1.0 device for light browsing.
>
> At the moment, dataplane and vhost code is
> still missing.
>
> Based on Cornelia's virtio 1.0 patchset:
> Date: Thu, 11 Dec 2014 14:25:02 +0100
> From: Cornelia Huck <address@hidden>
> To: address@hidden, address@hidden
> Cc: address@hidden, address@hidden, address@hidden,
> Cornelia Huck <address@hidden>
> Subject: [PATCH RFC v6 00/20] qemu: towards virtio-1 host support
> Message-Id: <address@hidden>
>
> which is itself still missing some core bits.
>
> Signed-off-by: Michael S. Tsirkin <address@hidden>
> Reviewed-by: Michael S. Tsirkin <address@hidden>
> ---
> hw/virtio/virtio-pci.h | 16 +++
> hw/virtio/virtio-pci.c | 379
> +++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 395 insertions(+)
>
> diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
> index de39468..7a6481f 100644
> --- a/hw/virtio/virtio-pci.h
> +++ b/hw/virtio/virtio-pci.h
> @@ -88,9 +88,25 @@ typedef struct VirtioPCIClass {
> struct VirtIOPCIProxy {
> PCIDevice pci_dev;
> MemoryRegion bar;
> + MemoryRegion common;
> + MemoryRegion isr;
> + MemoryRegion device;
> + MemoryRegion notify;
> + MemoryRegion modern_bar;
> uint32_t flags;
> uint32_t class_code;
> uint32_t nvectors;
> + uint32_t dfselect;
> + uint32_t gfselect;
> + uint32_t guest_features[2];
> + struct {
> + uint16_t num;
> + bool enabled;
> + uint32_t desc[2];
> + uint32_t avail[2];
> + uint32_t used[2];
> + } vqs[VIRTIO_QUEUE_MAX];
> +
> bool ioeventfd_disabled;
> bool ioeventfd_started;
> VirtIOIRQFD *vector_irqfd;
> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> index 8dca87c..8fc3c4e 100644
> --- a/hw/virtio/virtio-pci.c
> +++ b/hw/virtio/virtio-pci.c
> @@ -920,6 +920,278 @@ static int virtio_pci_query_nvectors(DeviceState *d)
> return proxy->nvectors;
> }
>
> +static void virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy,
> + struct virtio_pci_cap *cap)
> +{
> + PCIDevice *dev = &proxy->pci_dev;
> + int offset;
> +
> + cap->bar = 2;
> +
> + offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, 0, cap->cap_len);
> + assert(offset > 0);
> +
> + assert(cap->cap_len >= sizeof *cap);
> + memcpy(dev->config + offset + PCI_CAP_FLAGS, &cap->cap_len,
> + cap->cap_len - PCI_CAP_FLAGS);
> +}
> +
> +#define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x10000
> +
> +static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr,
> + unsigned size)
> +{
> + VirtIOPCIProxy *proxy = opaque;
> + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
> + uint32_t val = 0;
> + int i;
> +
> + switch (addr) {
> + case VIRTIO_PCI_COMMON_DFSELECT:
> + val = proxy->dfselect;
> + break;
> + case VIRTIO_PCI_COMMON_DF:
> + if (proxy->dfselect <= 1) {
> + val = vdev->host_features >> (32 * proxy->dfselect);
> + }
> + break;
> + case VIRTIO_PCI_COMMON_GFSELECT:
> + val = proxy->gfselect;
> + break;
> + case VIRTIO_PCI_COMMON_GF:
> + if (proxy->gfselect <= ARRAY_SIZE(proxy->guest_features)) {
Off-by-one error: < instead of <= is required here. Bonus for patching
checkpatch.pl...
Paolo
> + val = proxy->guest_features[proxy->gfselect];
> + }
> + break;
> + case VIRTIO_PCI_COMMON_MSIX:
> + val = vdev->config_vector;
> + break;
> + case VIRTIO_PCI_COMMON_NUMQ:
> + for (i = 0; i < VIRTIO_QUEUE_MAX; ++i) {
> + if (virtio_queue_get_num(vdev, i)) {
> + val = i + 1;
> + }
> + }
> + break;
> + case VIRTIO_PCI_COMMON_STATUS:
> + val = vdev->status;
> + break;
> + case VIRTIO_PCI_COMMON_CFGGENERATION:
> + val = 0; /* TODO */
> + break;
> + case VIRTIO_PCI_COMMON_Q_SELECT:
> + val = vdev->queue_sel;
> + break;
> + case VIRTIO_PCI_COMMON_Q_SIZE:
> + val = virtio_queue_get_num(vdev, vdev->queue_sel);
> + break;
> + case VIRTIO_PCI_COMMON_Q_MSIX:
> + val = virtio_queue_vector(vdev, vdev->queue_sel);
> + break;
> + case VIRTIO_PCI_COMMON_Q_ENABLE:
> + val = proxy->vqs[vdev->queue_sel].enabled;
> + break;
> + case VIRTIO_PCI_COMMON_Q_NOFF:
> + /* Simply map queues in order */
> + val = vdev->queue_sel;
> + break;
> + case VIRTIO_PCI_COMMON_Q_DESCLO:
> + val = proxy->vqs[vdev->queue_sel].desc[0];
> + break;
> + case VIRTIO_PCI_COMMON_Q_DESCHI:
> + val = proxy->vqs[vdev->queue_sel].desc[1];
> + break;
> + case VIRTIO_PCI_COMMON_Q_AVAILLO:
> + val = proxy->vqs[vdev->queue_sel].avail[0];
> + break;
> + case VIRTIO_PCI_COMMON_Q_AVAILHI:
> + val = proxy->vqs[vdev->queue_sel].avail[1];
> + break;
> + case VIRTIO_PCI_COMMON_Q_USEDLO:
> + val = proxy->vqs[vdev->queue_sel].used[0];
> + break;
> + case VIRTIO_PCI_COMMON_Q_USEDHI:
> + val = proxy->vqs[vdev->queue_sel].used[1];
> + break;
> + default:
> + val = 0;
> + }
> +
> + return val;
> +}
> +
> +static void virtio_pci_common_write(void *opaque, hwaddr addr,
> + uint64_t val, unsigned size)
> +{
> + VirtIOPCIProxy *proxy = opaque;
> + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
> +
> + switch (addr) {
> + case VIRTIO_PCI_COMMON_DFSELECT:
> + proxy->dfselect = val;
> + break;
> + case VIRTIO_PCI_COMMON_GFSELECT:
> + proxy->gfselect = val;
> + break;
> + case VIRTIO_PCI_COMMON_GF:
> + if (proxy->gfselect <= ARRAY_SIZE(proxy->guest_features)) {
> + proxy->guest_features[proxy->gfselect] = val;
> + virtio_set_features(vdev,
> + (((uint64_t)proxy->guest_features[1]) << 32)
> |
> + proxy->guest_features[0]);
> + }
> + break;
> + case VIRTIO_PCI_COMMON_MSIX:
> + msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
> + /* Make it possible for guest to discover an error took place. */
> + if (msix_vector_use(&proxy->pci_dev, val) < 0) {
> + val = VIRTIO_NO_VECTOR;
> + }
> + vdev->config_vector = val;
> + break;
> + case VIRTIO_PCI_COMMON_STATUS:
> + if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
> + virtio_pci_stop_ioeventfd(proxy);
> + }
> +
> + virtio_set_status(vdev, val & 0xFF);
> +
> + if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
> + virtio_pci_start_ioeventfd(proxy);
> + }
> +
> + if (vdev->status == 0) {
> + virtio_reset(vdev);
> + msix_unuse_all_vectors(&proxy->pci_dev);
> + }
> +
> + break;
> + case VIRTIO_PCI_COMMON_Q_SELECT:
> + if (val < VIRTIO_QUEUE_MAX) {
> + vdev->queue_sel = val;
> + }
> + break;
> + case VIRTIO_PCI_COMMON_Q_SIZE:
> + proxy->vqs[vdev->queue_sel].num = val;
> + break;
> + case VIRTIO_PCI_COMMON_Q_MSIX:
> + msix_vector_unuse(&proxy->pci_dev,
> + virtio_queue_vector(vdev, vdev->queue_sel));
> + /* Make it possible for guest to discover an error took place. */
> + if (msix_vector_use(&proxy->pci_dev, val) < 0) {
> + val = VIRTIO_NO_VECTOR;
> + }
> + virtio_queue_set_vector(vdev, vdev->queue_sel, val);
> + break;
> + case VIRTIO_PCI_COMMON_Q_ENABLE:
> + /* TODO: need a way to put num back on reset. */
> + virtio_queue_set_num(vdev, vdev->queue_sel,
> + proxy->vqs[vdev->queue_sel].num);
> + virtio_queue_set_rings(vdev, vdev->queue_sel,
> + ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32
> |
> + proxy->vqs[vdev->queue_sel].desc[0],
> + ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) <<
> 32 |
> + proxy->vqs[vdev->queue_sel].avail[0],
> + ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32
> |
> + proxy->vqs[vdev->queue_sel].used[0]);
> + break;
> + case VIRTIO_PCI_COMMON_Q_DESCLO:
> + proxy->vqs[vdev->queue_sel].desc[0] = val;
> + break;
> + case VIRTIO_PCI_COMMON_Q_DESCHI:
> + proxy->vqs[vdev->queue_sel].desc[1] = val;
> + break;
> + case VIRTIO_PCI_COMMON_Q_AVAILLO:
> + proxy->vqs[vdev->queue_sel].avail[0] = val;
> + break;
> + case VIRTIO_PCI_COMMON_Q_AVAILHI:
> + proxy->vqs[vdev->queue_sel].avail[1] = val;
> + break;
> + case VIRTIO_PCI_COMMON_Q_USEDLO:
> + proxy->vqs[vdev->queue_sel].used[0] = val;
> + break;
> + case VIRTIO_PCI_COMMON_Q_USEDHI:
> + proxy->vqs[vdev->queue_sel].used[1] = val;
> + break;
> + default:
> + break;
> + }
> +}
> +
> +
> +static uint64_t virtio_pci_notify_read(void *opaque, hwaddr addr,
> + unsigned size)
> +{
> + return 0;
> +}
> +
> +static void virtio_pci_notify_write(void *opaque, hwaddr addr,
> + uint64_t val, unsigned size)
> +{
> + VirtIODevice *vdev = opaque;
> + unsigned queue = addr / QEMU_VIRTIO_PCI_QUEUE_MEM_MULT;
> +
> + if (queue < VIRTIO_QUEUE_MAX) {
> + virtio_queue_notify(vdev, queue);
> + }
> +}
> +
> +static uint64_t virtio_pci_isr_read(void *opaque, hwaddr addr,
> + unsigned size)
> +{
> + VirtIOPCIProxy *proxy = opaque;
> + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
> + uint64_t val = vdev->isr;
> +
> + vdev->isr = 0;
> + pci_irq_deassert(&proxy->pci_dev);
> +
> + return val;
> +}
> +
> +static void virtio_pci_isr_write(void *opaque, hwaddr addr,
> + uint64_t val, unsigned size)
> +{
> +}
> +
> +static uint64_t virtio_pci_device_read(void *opaque, hwaddr addr,
> + unsigned size)
> +{
> + VirtIODevice *vdev = opaque;
> + uint64_t val = 0;
> +
> + switch (size) {
> + case 1:
> + val = virtio_config_readb(vdev, addr);
> + break;
> + case 2:
> + val = virtio_config_readw(vdev, addr);
> + break;
> + case 4:
> + val = virtio_config_readl(vdev, addr);
> + break;
> + }
> + return val;
> +}
> +
> +static void virtio_pci_device_write(void *opaque, hwaddr addr,
> + uint64_t val, unsigned size)
> +{
> + VirtIODevice *vdev = opaque;
> + switch (size) {
> + case 1:
> + virtio_config_writeb(vdev, addr, val);
> + break;
> + case 2:
> + virtio_config_writew(vdev, addr, val);
> + break;
> + case 4:
> + virtio_config_writel(vdev, addr, val);
> + break;
> + }
> +}
> +
> +
> /* This is called by virtio-bus just after the device is plugged. */
> static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
> {
> @@ -938,6 +1210,112 @@ static void virtio_pci_device_plugged(DeviceState *d,
> Error **errp)
> pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
> config[PCI_INTERRUPT_PIN] = 1;
>
> +
> + if (1) { /* TODO: Make this optional, dependent on virtio 1.0 */
> + struct virtio_pci_cap common = {
> + .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG,
> + .cap_len = sizeof common,
> + .offset = cpu_to_le32(0x0),
> + .length = cpu_to_le32(0x1000),
> + };
> + struct virtio_pci_cap isr = {
> + .cfg_type = VIRTIO_PCI_CAP_ISR_CFG,
> + .cap_len = sizeof isr,
> + .offset = cpu_to_le32(0x1000),
> + .length = cpu_to_le32(0x1000),
> + };
> + struct virtio_pci_cap device = {
> + .cfg_type = VIRTIO_PCI_CAP_DEVICE_CFG,
> + .cap_len = sizeof device,
> + .offset = cpu_to_le32(0x2000),
> + .length = cpu_to_le32(0x1000),
> + };
> + struct virtio_pci_notify_cap notify = {
> + .cap.cfg_type = VIRTIO_PCI_CAP_NOTIFY_CFG,
> + .cap.cap_len = sizeof notify,
> + .cap.offset = cpu_to_le32(0x3000),
> + .cap.length = cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
> + VIRTIO_QUEUE_MAX),
> + .notify_off_multiplier =
> + cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT),
> + };
> +
> + static const MemoryRegionOps common_ops = {
> + .read = virtio_pci_common_read,
> + .write = virtio_pci_common_write,
> + .impl = {
> + .min_access_size = 1,
> + .max_access_size = 4,
> + },
> + .endianness = DEVICE_LITTLE_ENDIAN,
> + };
> +
> + static const MemoryRegionOps isr_ops = {
> + .read = virtio_pci_isr_read,
> + .write = virtio_pci_isr_write,
> + .impl = {
> + .min_access_size = 1,
> + .max_access_size = 4,
> + },
> + .endianness = DEVICE_LITTLE_ENDIAN,
> + };
> +
> + static const MemoryRegionOps device_ops = {
> + .read = virtio_pci_device_read,
> + .write = virtio_pci_device_write,
> + .impl = {
> + .min_access_size = 1,
> + .max_access_size = 4,
> + },
> + .endianness = DEVICE_LITTLE_ENDIAN,
> + };
> +
> + static const MemoryRegionOps notify_ops = {
> + .read = virtio_pci_notify_read,
> + .write = virtio_pci_notify_write,
> + .impl = {
> + .min_access_size = 1,
> + .max_access_size = 4,
> + },
> + .endianness = DEVICE_LITTLE_ENDIAN,
> + };
> +
> + /* TODO: add io access for speed */
> + virtio_pci_add_mem_cap(proxy, &common);
> + virtio_pci_add_mem_cap(proxy, &isr);
> + virtio_pci_add_mem_cap(proxy, &device);
> + virtio_pci_add_mem_cap(proxy, ¬ify.cap);
> +
> + virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
> + memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci",
> + 2 * QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
> + VIRTIO_QUEUE_MAX);
> + memory_region_init_io(&proxy->common, OBJECT(proxy),
> + &common_ops,
> + proxy,
> + "virtio-pci-common", 0x1000);
> + memory_region_add_subregion(&proxy->modern_bar, 0, &proxy->common);
> + memory_region_init_io(&proxy->isr, OBJECT(proxy),
> + &isr_ops,
> + proxy,
> + "virtio-pci-isr", 0x1000);
> + memory_region_add_subregion(&proxy->modern_bar, 0x1000, &proxy->isr);
> + memory_region_init_io(&proxy->device, OBJECT(proxy),
> + &device_ops,
> + virtio_bus_get_device(&proxy->bus),
> + "virtio-pci-device", 0x1000);
> + memory_region_add_subregion(&proxy->modern_bar, 0x2000,
> &proxy->device);
> + memory_region_init_io(&proxy->notify, OBJECT(proxy),
> + ¬ify_ops,
> + virtio_bus_get_device(&proxy->bus),
> + "virtio-pci-notify",
> + QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
> + VIRTIO_QUEUE_MAX);
> + memory_region_add_subregion(&proxy->modern_bar, 0x3000,
> &proxy->notify);
> + pci_register_bar(&proxy->pci_dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY,
> + &proxy->modern_bar);
> + }
> +
> if (proxy->nvectors &&
> msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1)) {
> error_report("unable to init msix vectors to %" PRIu32,
> @@ -955,6 +1333,7 @@ static void virtio_pci_device_plugged(DeviceState *d,
> Error **errp)
>
> memory_region_init_io(&proxy->bar, OBJECT(proxy), &virtio_pci_config_ops,
> proxy, "virtio-pci", size);
> +
> pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
> &proxy->bar);
>
>
- [Qemu-devel] [PULL 05/42] virtio: disallow late feature changes for virtio-1, (continued)
- [Qemu-devel] [PULL 05/42] virtio: disallow late feature changes for virtio-1, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 04/42] dataplane: allow virtio-1 devices, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 06/42] virtio: allow to fail setting status, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 07/42] virtio-net: no writeable mac for virtio-1, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 08/42] virtio-net: support longer header, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 10/42] vhost_net: add version_1 feature, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 09/42] virtio-net: enable virtio 1.0, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 12/42] linux-headers: add virtio_pci, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 14/42] virtio: generation counter support, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 13/42] virtio-pci: initial virtio 1.0 support, Michael S. Tsirkin, 2015/06/11
- Re: [Qemu-devel] [PULL 13/42] virtio-pci: initial virtio 1.0 support,
Paolo Bonzini <=
- [Qemu-devel] [PULL 11/42] vhost: 64 bit features, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 15/42] virtio: add modern config accessors, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 16/42] virtio-pci: switch to modern accessors for 1.0, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 17/42] virtio-pci: add flags to enable/disable legacy/modern, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 18/42] virtio-pci: make QEMU_VIRTIO_PCI_QUEUE_MEM_MULT smaller, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 22/42] virtio_balloon: header update, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 23/42] virtio-balloon: switch to virtio_add_feature, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 24/42] virtio-pci: add struct VirtIOPCIRegion for virtio-1 regions, Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 25/42] virtio-pci: add virtio_pci_modern_regions_init(), Michael S. Tsirkin, 2015/06/11
- [Qemu-devel] [PULL 26/42] virtio-pci: add virtio_pci_modern_region_map(), Michael S. Tsirkin, 2015/06/11