From 24bfa207efb9b9d591552eefc1f414ff33ef0eac Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 4 Jun 2015 23:05:58 -0400 Subject: vhost: put log correctly in vhost_dev_start() We allocate an dummy log even if the size is zero. So we should put it unconditionally too. Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 01f1e04..3a52a4d 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1111,9 +1111,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) return 0; fail_log: - if (hdev->log_size) { - vhost_log_put(hdev, false); - } + vhost_log_put(hdev, false); fail_vq: while (--i >= 0) { vhost_virtqueue_stop(hdev, -- cgit v1.1 From 3c185597c86b8cd0a07c46e7a5bd5aac28bb7200 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 4 Jun 2015 12:34:11 +0200 Subject: virtio: endianness checks for virtio 1.0 devices Add code that checks for the VERSION_1 feature bit in order to make decisions about the device's endianness. This allows us to support transitional devices. Signed-off-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 8ac6156..d37d27b 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -903,7 +903,11 @@ static bool virtio_device_endian_needed(void *opaque) VirtIODevice *vdev = opaque; assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); - return vdev->device_endian != virtio_default_endian(); + if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { + return vdev->device_endian != virtio_default_endian(); + } + /* Devices conforming to VIRTIO 1.0 or later are always LE. */ + return vdev->device_endian != VIRTIO_DEVICE_ENDIAN_LITTLE; } static bool virtio_64bit_features_needed(void *opaque) -- cgit v1.1 From ab223c9518e8c7eb542ef3133de1a34475b69790 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 4 Jun 2015 12:34:12 +0200 Subject: virtio: allow virtio-1 queue layout For virtio-1 devices, we allow a more complex queue layout that doesn't require descriptor table and rings on a physically-contigous memory area: add virtio_queue_set_rings() to allow transports to set this up. Signed-off-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio-mmio.c | 3 +++ hw/virtio/virtio.c | 53 +++++++++++++++++++++++++++++++------------------ 2 files changed, 37 insertions(+), 19 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index c8f7294..18660b0 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -333,8 +333,11 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value, case VIRTIO_MMIO_QUEUENUM: DPRINTF("mmio_queue write %d max %d\n", (int)value, VIRTQUEUE_MAX_SIZE); virtio_queue_set_num(vdev, vdev->queue_sel, value); + /* Note: only call this function for legacy devices */ + virtio_queue_update_rings(vdev, vdev->queue_sel); break; case VIRTIO_MMIO_QUEUEALIGN: + /* Note: this is only valid for legacy devices */ virtio_queue_set_align(vdev, vdev->queue_sel, value); break; case VIRTIO_MMIO_QUEUEPFN: diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index d37d27b..c27e975 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -69,7 +69,6 @@ typedef struct VRing struct VirtQueue { VRing vring; - hwaddr pa; uint16_t last_avail_idx; /* Last used index value we have signalled on */ uint16_t signalled_used; @@ -93,15 +92,18 @@ struct VirtQueue }; /* virt queue functions */ -static void virtqueue_init(VirtQueue *vq) +void virtio_queue_update_rings(VirtIODevice *vdev, int n) { - hwaddr pa = vq->pa; + VRing *vring = &vdev->vq[n].vring; - vq->vring.desc = pa; - vq->vring.avail = pa + vq->vring.num * sizeof(VRingDesc); - vq->vring.used = vring_align(vq->vring.avail + - offsetof(VRingAvail, ring[vq->vring.num]), - vq->vring.align); + if (!vring->desc) { + /* not yet setup -> nothing to do */ + return; + } + vring->avail = vring->desc + vring->num * sizeof(VRingDesc); + vring->used = vring_align(vring->avail + + offsetof(VRingAvail, ring[vring->num]), + vring->align); } static inline uint64_t vring_desc_addr(VirtIODevice *vdev, hwaddr desc_pa, @@ -605,7 +607,6 @@ void virtio_reset(void *opaque) vdev->vq[i].vring.avail = 0; vdev->vq[i].vring.used = 0; vdev->vq[i].last_avail_idx = 0; - vdev->vq[i].pa = 0; virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR); vdev->vq[i].signalled_used = 0; vdev->vq[i].signalled_used_valid = false; @@ -708,13 +709,21 @@ void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data) void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr) { - vdev->vq[n].pa = addr; - virtqueue_init(&vdev->vq[n]); + vdev->vq[n].vring.desc = addr; + virtio_queue_update_rings(vdev, n); } hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n) { - return vdev->vq[n].pa; + return vdev->vq[n].vring.desc; +} + +void virtio_queue_set_rings(VirtIODevice *vdev, int n, hwaddr desc, + hwaddr avail, hwaddr used) +{ + vdev->vq[n].vring.desc = desc; + vdev->vq[n].vring.avail = avail; + vdev->vq[n].vring.used = used; } void virtio_queue_set_num(VirtIODevice *vdev, int n, int num) @@ -728,7 +737,6 @@ void virtio_queue_set_num(VirtIODevice *vdev, int n, int num) return; } vdev->vq[n].vring.num = num; - virtqueue_init(&vdev->vq[n]); } VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector) @@ -771,6 +779,11 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align) BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + /* virtio-1 compliant devices cannot change the alignment */ + if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { + error_report("tried to modify queue alignment for virtio-1 device"); + return; + } /* Check that the transport told us it was going to do this * (so a buggy transport will immediately assert rather than * silently failing to migrate this state) @@ -778,7 +791,7 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align) assert(k->has_variable_vring_alignment); vdev->vq[n].vring.align = align; - virtqueue_init(&vdev->vq[n]); + virtio_queue_update_rings(vdev, n); } void virtio_queue_notify_vq(VirtQueue *vq) @@ -992,7 +1005,8 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) if (k->has_variable_vring_alignment) { qemu_put_be32(f, vdev->vq[i].vring.align); } - qemu_put_be64(f, vdev->vq[i].pa); + /* XXX virtio-1 devices */ + qemu_put_be64(f, vdev->vq[i].vring.desc); qemu_put_be16s(f, &vdev->vq[i].last_avail_idx); if (k->save_queue) { k->save_queue(qbus->parent, i, f); @@ -1076,13 +1090,14 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) if (k->has_variable_vring_alignment) { vdev->vq[i].vring.align = qemu_get_be32(f); } - vdev->vq[i].pa = qemu_get_be64(f); + vdev->vq[i].vring.desc = qemu_get_be64(f); qemu_get_be16s(f, &vdev->vq[i].last_avail_idx); vdev->vq[i].signalled_used_valid = false; vdev->vq[i].notification = true; - if (vdev->vq[i].pa) { - virtqueue_init(&vdev->vq[i]); + if (vdev->vq[i].vring.desc) { + /* XXX virtio-1 devices */ + virtio_queue_update_rings(vdev, i); } else if (vdev->vq[i].last_avail_idx) { error_report("VQ %d address 0x0 " "inconsistent with Host index 0x%x", @@ -1138,7 +1153,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) } for (i = 0; i < num; i++) { - if (vdev->vq[i].pa) { + if (vdev->vq[i].vring.desc) { uint16_t nheads; nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx; /* Check it isn't doing strange things with descriptor numbers. */ -- cgit v1.1 From f5a5628cf0b65b223fa0c9031714578dfac4cf04 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 4 Jun 2015 12:34:13 +0200 Subject: dataplane: allow virtio-1 devices Handle endianness conversion for virtio-1 virtqueues correctly. Note that dataplane now needs to be built per-target. Signed-off-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/virtio/dataplane/vring.c | 47 +++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 21 deletions(-) (limited to 'hw') diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c index 5c7b8c2..fabb810 100644 --- a/hw/virtio/dataplane/vring.c +++ b/hw/virtio/dataplane/vring.c @@ -157,15 +157,18 @@ bool vring_should_notify(VirtIODevice *vdev, Vring *vring) } -static int get_desc(Vring *vring, VirtQueueElement *elem, +static int get_desc(VirtIODevice *vdev, Vring *vring, VirtQueueElement *elem, struct vring_desc *desc) { unsigned *num; struct iovec *iov; hwaddr *addr; MemoryRegion *mr; + int is_write = virtio_tswap16(vdev, desc->flags) & VRING_DESC_F_WRITE; + uint32_t len = virtio_tswap32(vdev, desc->len); + uint64_t desc_addr = virtio_tswap64(vdev, desc->addr); - if (desc->flags & VRING_DESC_F_WRITE) { + if (is_write) { num = &elem->in_num; iov = &elem->in_sg[*num]; addr = &elem->in_addr[*num]; @@ -189,18 +192,17 @@ static int get_desc(Vring *vring, VirtQueueElement *elem, } /* TODO handle non-contiguous memory across region boundaries */ - iov->iov_base = vring_map(&mr, desc->addr, desc->len, - desc->flags & VRING_DESC_F_WRITE); + iov->iov_base = vring_map(&mr, desc_addr, len, is_write); if (!iov->iov_base) { error_report("Failed to map descriptor addr %#" PRIx64 " len %u", - (uint64_t)desc->addr, desc->len); + (uint64_t)desc_addr, len); return -EFAULT; } /* The MemoryRegion is looked up again and unref'ed later, leave the * ref in place. */ - iov->iov_len = desc->len; - *addr = desc->addr; + iov->iov_len = len; + *addr = desc_addr; *num += 1; return 0; } @@ -222,21 +224,23 @@ static int get_indirect(VirtIODevice *vdev, Vring *vring, struct vring_desc desc; unsigned int i = 0, count, found = 0; int ret; + uint32_t len = virtio_tswap32(vdev, indirect->len); + uint64_t addr = virtio_tswap64(vdev, indirect->addr); /* Sanity check */ - if (unlikely(indirect->len % sizeof(desc))) { + if (unlikely(len % sizeof(desc))) { error_report("Invalid length in indirect descriptor: " "len %#x not multiple of %#zx", - indirect->len, sizeof(desc)); + len, sizeof(desc)); vring->broken = true; return -EFAULT; } - count = indirect->len / sizeof(desc); + count = len / sizeof(desc); /* Buffers are chained via a 16 bit next field, so * we can have at most 2^16 of these. */ if (unlikely(count > USHRT_MAX + 1)) { - error_report("Indirect buffer length too big: %d", indirect->len); + error_report("Indirect buffer length too big: %d", len); vring->broken = true; return -EFAULT; } @@ -247,12 +251,12 @@ static int get_indirect(VirtIODevice *vdev, Vring *vring, /* Translate indirect descriptor */ desc_ptr = vring_map(&mr, - indirect->addr + found * sizeof(desc), + addr + found * sizeof(desc), sizeof(desc), false); if (!desc_ptr) { error_report("Failed to map indirect descriptor " "addr %#" PRIx64 " len %zu", - (uint64_t)indirect->addr + found * sizeof(desc), + (uint64_t)addr + found * sizeof(desc), sizeof(desc)); vring->broken = true; return -EFAULT; @@ -270,19 +274,20 @@ static int get_indirect(VirtIODevice *vdev, Vring *vring, return -EFAULT; } - if (unlikely(desc.flags & VRING_DESC_F_INDIRECT)) { + if (unlikely(virtio_tswap16(vdev, desc.flags) + & VRING_DESC_F_INDIRECT)) { error_report("Nested indirect descriptor"); vring->broken = true; return -EFAULT; } - ret = get_desc(vring, elem, &desc); + ret = get_desc(vdev, vring, elem, &desc); if (ret < 0) { vring->broken |= (ret == -EFAULT); return ret; } - i = desc.next; - } while (desc.flags & VRING_DESC_F_NEXT); + i = virtio_tswap16(vdev, desc.next); + } while (virtio_tswap16(vdev, desc.flags) & VRING_DESC_F_NEXT); return 0; } @@ -383,7 +388,7 @@ int vring_pop(VirtIODevice *vdev, Vring *vring, /* Ensure descriptor is loaded before accessing fields */ barrier(); - if (desc.flags & VRING_DESC_F_INDIRECT) { + if (virtio_tswap16(vdev, desc.flags) & VRING_DESC_F_INDIRECT) { ret = get_indirect(vdev, vring, elem, &desc); if (ret < 0) { goto out; @@ -391,13 +396,13 @@ int vring_pop(VirtIODevice *vdev, Vring *vring, continue; } - ret = get_desc(vring, elem, &desc); + ret = get_desc(vdev, vring, elem, &desc); if (ret < 0) { goto out; } - i = desc.next; - } while (desc.flags & VRING_DESC_F_NEXT); + i = virtio_tswap16(vdev, desc.next); + } while (virtio_tswap16(vdev, desc.flags) & VRING_DESC_F_NEXT); /* On success, increment avail index. */ vring->last_avail_idx++; -- cgit v1.1 From 6c0196d702e8482a17638ee79f45ce27cdd1ef5d Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 4 Jun 2015 12:34:14 +0200 Subject: virtio: disallow late feature changes for virtio-1 For virtio-1 devices, the driver must not attempt to set feature bits after it set FEATURES_OK in the device status. Simply reject it in that case. Signed-off-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index c27e975..3367100 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1021,7 +1021,7 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) vmstate_save_state(f, &vmstate_virtio, vdev, NULL); } -int virtio_set_features(VirtIODevice *vdev, uint64_t val) +static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val) { VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); bool bad = (val & ~(vdev->host_features)) != 0; @@ -1034,6 +1034,18 @@ int virtio_set_features(VirtIODevice *vdev, uint64_t val) return bad ? -1 : 0; } +int virtio_set_features(VirtIODevice *vdev, uint64_t val) +{ + /* + * The driver must not attempt to set features after feature negotiation + * has finished. + */ + if (vdev->status & VIRTIO_CONFIG_S_FEATURES_OK) { + return -EINVAL; + } + return virtio_set_features_nocheck(vdev, val); +} + int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) { int i, ret; @@ -1137,14 +1149,14 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) * host_features. */ uint64_t features64 = vdev->guest_features; - if (virtio_set_features(vdev, features64) < 0) { + if (virtio_set_features_nocheck(vdev, features64) < 0) { error_report("Features 0x%" PRIx64 " unsupported. " "Allowed features: 0x%" PRIx64, features64, vdev->host_features); return -1; } } else { - if (virtio_set_features(vdev, features) < 0) { + if (virtio_set_features_nocheck(vdev, features) < 0) { error_report("Features 0x%x unsupported. " "Allowed features: 0x%" PRIx64, features, vdev->host_features); -- cgit v1.1 From 0b352fd680e1ca7827ddea47b5e9b603320913b6 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 4 Jun 2015 12:34:15 +0200 Subject: virtio: allow to fail setting status virtio-1 allow setting of the FEATURES_OK status bit to fail if the negotiated feature bits are inconsistent: let's fail virtio_set_status() in that case and update virtio-ccw to post an error to the guest. Signed-off-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/s390x/virtio-ccw.c | 20 ++++++++++++-------- hw/virtio/virtio.c | 24 +++++++++++++++++++++++- 2 files changed, 35 insertions(+), 9 deletions(-) (limited to 'hw') diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index ef90fed..3ef0055 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -497,15 +497,19 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) { virtio_ccw_stop_ioeventfd(dev); } - virtio_set_status(vdev, status); - if (vdev->status == 0) { - virtio_reset(vdev); - } - if (status & VIRTIO_CONFIG_S_DRIVER_OK) { - virtio_ccw_start_ioeventfd(dev); + if (virtio_set_status(vdev, status) == 0) { + if (vdev->status == 0) { + virtio_reset(vdev); + } + if (status & VIRTIO_CONFIG_S_DRIVER_OK) { + virtio_ccw_start_ioeventfd(dev); + } + sch->curr_status.scsw.count = ccw.count - sizeof(status); + ret = 0; + } else { + /* Trigger a command reject. */ + ret = -ENOSYS; } - sch->curr_status.scsw.count = ccw.count - sizeof(status); - ret = 0; } break; case CCW_CMD_SET_IND: diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 3367100..8a6ebae 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -544,15 +544,37 @@ void virtio_update_irq(VirtIODevice *vdev) virtio_notify_vector(vdev, VIRTIO_NO_VECTOR); } -void virtio_set_status(VirtIODevice *vdev, uint8_t val) +static int virtio_validate_features(VirtIODevice *vdev) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + + if (k->validate_features) { + return k->validate_features(vdev); + } else { + return 0; + } +} + +int virtio_set_status(VirtIODevice *vdev, uint8_t val) { VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); trace_virtio_set_status(vdev, val); + if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { + if (!(vdev->status & VIRTIO_CONFIG_S_FEATURES_OK) && + val & VIRTIO_CONFIG_S_FEATURES_OK) { + int ret = virtio_validate_features(vdev); + + if (ret) { + return ret; + } + } + } if (k->set_status) { k->set_status(vdev, val); } vdev->status = val; + return 0; } bool target_words_bigendian(void); -- cgit v1.1 From b6a3cddb22d3f0f729e267d45f350ae31bdebbcf Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 4 Jun 2015 12:34:16 +0200 Subject: virtio-net: no writeable mac for virtio-1 Devices operating as virtio 1.0 may not allow writes to the mac address in config space. Signed-off-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 1 + 1 file changed, 1 insertion(+) (limited to 'hw') diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 0d3bf0f..e2d2ab5 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -87,6 +87,7 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) memcpy(&netcfg, config, n->config_size); if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR) && + !virtio_has_feature(vdev, VIRTIO_F_VERSION_1) && memcmp(netcfg.mac, n->mac, ETH_ALEN)) { memcpy(n->mac, netcfg.mac, ETH_ALEN); qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac); -- cgit v1.1 From bb9d17f831fa8e70494eab8421d83a542e3d8508 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 4 Jun 2015 12:34:17 +0200 Subject: virtio-net: support longer header virtio-1 devices always use num_buffers in the header, even if mergeable rx buffers have not been negotiated. Signed-off-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index e2d2ab5..a01c4d1 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -367,15 +367,21 @@ static int peer_has_ufo(VirtIONet *n) return n->has_ufo; } -static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs) +static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs, + int version_1) { int i; NetClientState *nc; n->mergeable_rx_bufs = mergeable_rx_bufs; - n->guest_hdr_len = n->mergeable_rx_bufs ? - sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr); + if (version_1) { + n->guest_hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); + } else { + n->guest_hdr_len = n->mergeable_rx_bufs ? + sizeof(struct virtio_net_hdr_mrg_rxbuf) : + sizeof(struct virtio_net_hdr); + } for (i = 0; i < n->max_queues; i++) { nc = qemu_get_subqueue(n->nic, i); @@ -522,7 +528,9 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) virtio_net_set_mrg_rx_bufs(n, __virtio_has_feature(features, - VIRTIO_NET_F_MRG_RXBUF)); + VIRTIO_NET_F_MRG_RXBUF), + __virtio_has_feature(features, + VIRTIO_F_VERSION_1)); if (n->has_vnet_hdr) { n->curr_guest_offloads = @@ -1375,7 +1383,8 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f, qemu_get_buffer(f, n->mac, ETH_ALEN); n->vqs[0].tx_waiting = qemu_get_be32(f); - virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f)); + virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f), + virtio_has_feature(vdev, VIRTIO_F_VERSION_1)); if (version_id >= 3) n->status = qemu_get_be16(f); @@ -1627,7 +1636,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) n->vqs[0].tx_waiting = 0; n->tx_burst = n->net_conf.txburst; - virtio_net_set_mrg_rx_bufs(n, 0); + virtio_net_set_mrg_rx_bufs(n, 0, 0); n->promisc = 1; /* for compatibility */ n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN); -- cgit v1.1 From df91055db5c9cee93d70ca8c08d72119a240b987 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 4 Jun 2015 12:34:18 +0200 Subject: virtio-net: enable virtio 1.0 virtio-net (non-vhost) now should have everything in place to support virtio 1.0: let's enable the feature bit for it. Note that VIRTIO_F_VERSION_1 is technically a transport feature; once every device is ready for virtio 1.0, we can move setting this feature bit out of the individual devices. Signed-off-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 1 + 1 file changed, 1 insertion(+) (limited to 'hw') diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index a01c4d1..49fa13f 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -470,6 +470,7 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features) } if (!get_vhost_net(nc->peer)) { + virtio_add_feature(&features, VIRTIO_F_VERSION_1); return features; } return vhost_net_get_features(get_vhost_net(nc->peer), features); -- cgit v1.1 From b1506132001eee6b11cf23b5968cd66ec141a9ed Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 4 Jun 2015 12:34:19 +0200 Subject: vhost_net: add version_1 feature Add VERSION_1 to list of features that we should test at the backend. Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/net/vhost_net.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'hw') diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 426b23e..dc48ece 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -52,6 +52,7 @@ static const int kernel_feature_bits[] = { VIRTIO_RING_F_INDIRECT_DESC, VIRTIO_RING_F_EVENT_IDX, VIRTIO_NET_F_MRG_RXBUF, + VIRTIO_F_VERSION_1, VHOST_INVALID_FEATURE_BIT }; @@ -62,6 +63,7 @@ static const int user_feature_bits[] = { VIRTIO_RING_F_EVENT_IDX, VIRTIO_F_ANY_LAYOUT, + VIRTIO_F_VERSION_1, VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_GSO, -- cgit v1.1 From 9a2ba82302bea7faf3b9579f9168b89c73ae34ad Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 4 Jun 2015 12:34:20 +0200 Subject: vhost: 64 bit features Make sure that all vhost interfaces use 64 bit features, as the virtio core does, and make sure to use ULL everywhere possible to be on the safe side. Signed-off-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/net/vhost_net.c | 12 ++++++------ hw/virtio/vhost.c | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'hw') diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index dc48ece..1c55517 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -109,13 +109,13 @@ static const int *vhost_net_get_feature_bits(struct vhost_net *net) return feature_bits; } -unsigned vhost_net_get_features(struct vhost_net *net, unsigned features) +uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features) { return vhost_get_features(&net->dev, vhost_net_get_feature_bits(net), features); } -void vhost_net_ack_features(struct vhost_net *net, unsigned features) +void vhost_net_ack_features(struct vhost_net *net, uint64_t features) { net->dev.acked_features = net->dev.backend_features; vhost_ack_features(&net->dev, vhost_net_get_feature_bits(net), features); @@ -149,7 +149,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) goto fail; } net->dev.backend_features = qemu_has_vnet_hdr(options->net_backend) - ? 0 : (1 << VHOST_NET_F_VIRTIO_NET_HDR); + ? 0 : (1ULL << VHOST_NET_F_VIRTIO_NET_HDR); net->backend = r; } else { net->dev.backend_features = 0; @@ -169,7 +169,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) if (backend_kernel) { if (!qemu_has_vnet_hdr_len(options->net_backend, sizeof(struct virtio_net_hdr_mrg_rxbuf))) { - net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF); + net->dev.features &= ~(1ULL << VIRTIO_NET_F_MRG_RXBUF); } if (~net->dev.features & net->dev.backend_features) { fprintf(stderr, "vhost lacks feature mask %" PRIu64 @@ -433,11 +433,11 @@ void vhost_net_cleanup(struct vhost_net *net) { } -unsigned vhost_net_get_features(struct vhost_net *net, unsigned features) +uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features) { return features; } -void vhost_net_ack_features(struct vhost_net *net, unsigned features) +void vhost_net_ack_features(struct vhost_net *net, uint64_t features) { } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 3a52a4d..7908255 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -590,7 +590,7 @@ static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log) uint64_t features = dev->acked_features; int r; if (enable_log) { - features |= 0x1 << VHOST_F_LOG_ALL; + features |= 0x1ULL << VHOST_F_LOG_ALL; } r = dev->vhost_ops->vhost_call(dev, VHOST_SET_FEATURES, &features); return r < 0 ? -errno : 0; @@ -899,7 +899,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, .priority = 10 }; hdev->migration_blocker = NULL; - if (!(hdev->features & (0x1 << VHOST_F_LOG_ALL))) { + if (!(hdev->features & (0x1ULL << VHOST_F_LOG_ALL))) { error_setg(&hdev->migration_blocker, "Migration disabled: vhost lacks VHOST_F_LOG_ALL feature."); migrate_add_blocker(hdev->migration_blocker); @@ -1042,12 +1042,12 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, assert(r >= 0); } -unsigned vhost_get_features(struct vhost_dev *hdev, const int *feature_bits, - unsigned features) +uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits, + uint64_t features) { const int *bit = feature_bits; while (*bit != VHOST_INVALID_FEATURE_BIT) { - unsigned bit_mask = (1 << *bit); + uint64_t bit_mask = (1ULL << *bit); if (!(hdev->features & bit_mask)) { features &= ~bit_mask; } @@ -1057,11 +1057,11 @@ unsigned vhost_get_features(struct vhost_dev *hdev, const int *feature_bits, } void vhost_ack_features(struct vhost_dev *hdev, const int *feature_bits, - unsigned features) + uint64_t features) { const int *bit = feature_bits; while (*bit != VHOST_INVALID_FEATURE_BIT) { - unsigned bit_mask = (1 << *bit); + uint64_t bit_mask = (1ULL << *bit); if (features & bit_mask) { hdev->acked_features |= bit_mask; } -- cgit v1.1 From c17bef33601737e24a3d53259ddb6db28ac4d6d2 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 4 Jun 2015 12:34:21 +0200 Subject: linux-headers: add virtio_pci Easier than duplicating code. Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 6d4f64e..8dca87c 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -38,6 +38,8 @@ #define VIRTIO_PCI_REGION_SIZE(dev) VIRTIO_PCI_CONFIG_OFF(msix_present(dev)) +#undef VIRTIO_PCI_CONFIG + /* The remaining space is defined by each driver as the per-driver * configuration space */ #define VIRTIO_PCI_CONFIG_SIZE(dev) VIRTIO_PCI_CONFIG_OFF(msix_enabled(dev)) -- cgit v1.1 From dfb8e184db758bff275f94f7aa634300886cfe21 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 4 Jun 2015 12:34:22 +0200 Subject: virtio-pci: initial virtio 1.0 support 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 To: virtualization@lists.linux-foundation.org, qemu-devel@nongnu.org Cc: rusty@rustcorp.com.au, thuth@linux.vnet.ibm.com, mst@redhat.com, Cornelia Huck Subject: [PATCH RFC v6 00/20] qemu: towards virtio-1 host support Message-Id: <1418304322-7546-1-git-send-email-cornelia.huck@de.ibm.com> which is itself still missing some core bits. Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 379 +++++++++++++++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-pci.h | 16 +++ 2 files changed, 395 insertions(+) (limited to 'hw') 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)) { + 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); 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; -- cgit v1.1 From b8f059081d93f1802480059d1d49fe5c1d32f60c Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 4 Jun 2015 12:34:23 +0200 Subject: virtio: generation counter support Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 2 +- hw/virtio/virtio.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 8fc3c4e..7805bdd 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -977,7 +977,7 @@ static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr, val = vdev->status; break; case VIRTIO_PCI_COMMON_CFGGENERATION: - val = 0; /* TODO */ + val = vdev->generation; break; case VIRTIO_PCI_COMMON_Q_SELECT: val = vdev->queue_sel; diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 8a6ebae..cae5eca 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -930,6 +930,7 @@ void virtio_notify_config(VirtIODevice *vdev) return; vdev->isr |= 0x03; + vdev->generation++; virtio_notify_vector(vdev, vdev->config_vector); } -- cgit v1.1 From adfb743c90c7aa5e92907ce875e4f35747ee1963 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 4 Jun 2015 12:34:24 +0200 Subject: virtio: add modern config accessors virtio 1.0 defines config space as LE, as opposed to pre-1.0 which was native endian. Add API for transports to execute word/dword accesses in little endian format - will be useful for mmio and pci (byte access is also wrapped, for completeness). For simplicity, we still keep config in host native endian format, byteswap to LE on guest access. Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) (limited to 'hw') diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index cae5eca..fb49ffc 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -729,6 +729,102 @@ void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data) } } +uint32_t virtio_config_modern_readb(VirtIODevice *vdev, uint32_t addr) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint8_t val; + + if (addr + sizeof(val) > vdev->config_len) { + return (uint32_t)-1; + } + + k->get_config(vdev, vdev->config); + + val = ldub_p(vdev->config + addr); + return val; +} + +uint32_t virtio_config_modern_readw(VirtIODevice *vdev, uint32_t addr) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint16_t val; + + if (addr + sizeof(val) > vdev->config_len) { + return (uint32_t)-1; + } + + k->get_config(vdev, vdev->config); + + val = lduw_le_p(vdev->config + addr); + return val; +} + +uint32_t virtio_config_modern_readl(VirtIODevice *vdev, uint32_t addr) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint32_t val; + + if (addr + sizeof(val) > vdev->config_len) { + return (uint32_t)-1; + } + + k->get_config(vdev, vdev->config); + + val = ldl_le_p(vdev->config + addr); + return val; +} + +void virtio_config_modern_writeb(VirtIODevice *vdev, + uint32_t addr, uint32_t data) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint8_t val = data; + + if (addr + sizeof(val) > vdev->config_len) { + return; + } + + stb_p(vdev->config + addr, val); + + if (k->set_config) { + k->set_config(vdev, vdev->config); + } +} + +void virtio_config_modern_writew(VirtIODevice *vdev, + uint32_t addr, uint32_t data) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint16_t val = data; + + if (addr + sizeof(val) > vdev->config_len) { + return; + } + + stw_le_p(vdev->config + addr, val); + + if (k->set_config) { + k->set_config(vdev, vdev->config); + } +} + +void virtio_config_modern_writel(VirtIODevice *vdev, + uint32_t addr, uint32_t data) +{ + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + uint32_t val = data; + + if (addr + sizeof(val) > vdev->config_len) { + return; + } + + stl_le_p(vdev->config + addr, val); + + if (k->set_config) { + k->set_config(vdev, vdev->config); + } +} + void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr) { vdev->vq[n].vring.desc = addr; -- cgit v1.1 From 54c720d49d3f9741b52ac95c65a5cc990254a5d8 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 4 Jun 2015 12:34:25 +0200 Subject: virtio-pci: switch to modern accessors for 1.0 virtio 1.0 config space is in LE format for all devices, use modern wrappers when accessed through the 1.0 BAR. Reported-by: Rusty Russell Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 7805bdd..d6d7668 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1162,13 +1162,13 @@ static uint64_t virtio_pci_device_read(void *opaque, hwaddr addr, switch (size) { case 1: - val = virtio_config_readb(vdev, addr); + val = virtio_config_modern_readb(vdev, addr); break; case 2: - val = virtio_config_readw(vdev, addr); + val = virtio_config_modern_readw(vdev, addr); break; case 4: - val = virtio_config_readl(vdev, addr); + val = virtio_config_modern_readl(vdev, addr); break; } return val; @@ -1180,13 +1180,13 @@ static void virtio_pci_device_write(void *opaque, hwaddr addr, VirtIODevice *vdev = opaque; switch (size) { case 1: - virtio_config_writeb(vdev, addr, val); + virtio_config_modern_writeb(vdev, addr, val); break; case 2: - virtio_config_writew(vdev, addr, val); + virtio_config_modern_writew(vdev, addr, val); break; case 4: - virtio_config_writel(vdev, addr, val); + virtio_config_modern_writel(vdev, addr, val); break; } } -- cgit v1.1 From e266d421490e0ae83044bbebb209b2d3650c0ba6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 4 Jun 2015 12:34:26 +0200 Subject: virtio-pci: add flags to enable/disable legacy/modern Add VIRTIO_PCI_FLAG_DISABLE_LEGACY and VIRTIO_PCI_FLAG_DISABLE_MODERN for VirtIOPCIProxy->flags. Also add properties for them. They can be used to disable modern (virtio 1.0) or legacy (virtio 0.9) modes. By default only legacy is advertized, modern will be turned on by default once all remaining spec compilance issues are addressed. Signed-off-by: Gerd Hoffmann Acked-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 46 +++++++++++++++++++++++++++++++++------------- hw/virtio/virtio-pci.h | 6 ++++++ 2 files changed, 39 insertions(+), 13 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index d6d7668..37c4533 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1197,6 +1197,8 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) { VirtIOPCIProxy *proxy = VIRTIO_PCI(d); VirtioBusState *bus = &proxy->bus; + bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY); + bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN); uint8_t *config; uint32_t size; VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); @@ -1205,13 +1207,24 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) if (proxy->class_code) { pci_config_set_class(config, proxy->class_code); } - pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID, - pci_get_word(config + PCI_VENDOR_ID)); - pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus)); + + if (legacy) { + /* legacy and transitional */ + pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID, + pci_get_word(config + PCI_VENDOR_ID)); + pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus)); + } else { + /* pure virtio-1.0 */ + pci_set_word(config + PCI_VENDOR_ID, + PCI_VENDOR_ID_REDHAT_QUMRANET); + pci_set_word(config + PCI_DEVICE_ID, + 0x1040 + virtio_bus_get_vdev_id(bus)); + pci_config_set_revision(config, 1); + } config[PCI_INTERRUPT_PIN] = 1; - if (1) { /* TODO: Make this optional, dependent on virtio 1.0 */ + if (modern) { struct virtio_pci_cap common = { .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG, .cap_len = sizeof common, @@ -1325,17 +1338,20 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) proxy->pci_dev.config_write = virtio_write_config; - size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) - + virtio_bus_get_vdev_config_len(bus); - if (size & (size - 1)) { - size = 1 << qemu_fls(size); - } + if (legacy) { + size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + + virtio_bus_get_vdev_config_len(bus); + if (size & (size - 1)) { + size = 1 << qemu_fls(size); + } - memory_region_init_io(&proxy->bar, OBJECT(proxy), &virtio_pci_config_ops, - proxy, "virtio-pci", size); + 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); + pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, + &proxy->bar); + } if (!kvm_has_many_ioeventfds()) { proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD; @@ -1379,6 +1395,10 @@ static void virtio_pci_reset(DeviceState *qdev) static Property virtio_pci_properties[] = { DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false), + DEFINE_PROP_BIT("disable-legacy", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT, false), + DEFINE_PROP_BIT("disable-modern", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 7a6481f..4e9b2db 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -63,6 +63,12 @@ typedef struct VirtioBusClass VirtioPCIBusClass; #define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1 #define VIRTIO_PCI_FLAG_USE_IOEVENTFD (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT) +/* virtio version flags */ +#define VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT 2 +#define VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT 3 +#define VIRTIO_PCI_FLAG_DISABLE_LEGACY (1 << VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT) +#define VIRTIO_PCI_FLAG_DISABLE_MODERN (1 << VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT) + typedef struct { MSIMessage msg; int virq; -- cgit v1.1 From 8aca0d75869f8ad0aa0032c50d8c85dcad65302f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 4 Jun 2015 12:34:27 +0200 Subject: virtio-pci: make QEMU_VIRTIO_PCI_QUEUE_MEM_MULT smaller Signed-off-by: Gerd Hoffmann Acked-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 37c4533..9481584 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -936,7 +936,7 @@ static void virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy, cap->cap_len - PCI_CAP_FLAGS); } -#define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x10000 +#define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x1000 static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr, unsigned size) -- cgit v1.1 From 23c5e3977502a1b57fa2d8cf8cf4b5c9e45f0d1f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 4 Jun 2015 12:34:28 +0200 Subject: virtio-pci: change & document virtio pci bar layout. This patch adds variables for the pci bars (to get rid of the magic numbers in the code) and moves the modern virtio bar to region 4 so regions 2+3 are kept free. virtio-vga wants use them. Signed-off-by: Gerd Hoffmann Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 9481584..16d6e69 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -926,8 +926,6 @@ static void virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy, 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); @@ -1203,6 +1201,22 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) uint32_t size; VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + /* + * virtio pci bar layout + * + * region 0 -- virtio legacy io bar + * region 1 -- msi-x bar + * region 2+3 -- not used by virtio-pci + * region 4+5 -- virtio modern memory (64bit) bar + * + * Regions 2+3 can be used by VirtIOPCIProxy subclasses. + * virtio-vga places the vga framebuffer there. + * + */ + uint32_t legacy_io_bar = 0; + uint32_t msix_bar = 1; + uint32_t modern_mem_bar = 4; + config = proxy->pci_dev.config; if (proxy->class_code) { pci_config_set_class(config, proxy->class_code); @@ -1228,24 +1242,28 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) struct virtio_pci_cap common = { .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG, .cap_len = sizeof common, + .bar = modern_mem_bar, .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, + .bar = modern_mem_bar, .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, + .bar = modern_mem_bar, .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.bar = modern_mem_bar, .cap.offset = cpu_to_le32(0x3000), .cap.length = cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * VIRTIO_QUEUE_MAX), @@ -1325,12 +1343,13 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) 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, + pci_register_bar(&proxy->pci_dev, modern_mem_bar, + PCI_BASE_ADDRESS_SPACE_MEMORY, &proxy->modern_bar); } if (proxy->nvectors && - msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1)) { + msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, msix_bar)) { error_report("unable to init msix vectors to %" PRIu32, proxy->nvectors); proxy->nvectors = 0; @@ -1349,8 +1368,8 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) &virtio_pci_config_ops, proxy, "virtio-pci", size); - pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, - &proxy->bar); + pci_register_bar(&proxy->pci_dev, legacy_io_bar, + PCI_BASE_ADDRESS_SPACE_IO, &proxy->bar); } if (!kvm_has_many_ioeventfds()) { -- cgit v1.1 From 4e93a68eb369b2f7adbef7a4f6afd7a30a0ed927 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 4 Jun 2015 12:34:29 +0200 Subject: virtio-pci: make modern bar 64bit + prefetchable Signed-off-by: Gerd Hoffmann Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 16d6e69..7804361 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1344,7 +1344,9 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) VIRTIO_QUEUE_MAX); memory_region_add_subregion(&proxy->modern_bar, 0x3000, &proxy->notify); pci_register_bar(&proxy->pci_dev, modern_mem_bar, - PCI_BASE_ADDRESS_SPACE_MEMORY, + PCI_BASE_ADDRESS_SPACE_MEMORY | + PCI_BASE_ADDRESS_MEM_PREFETCH | + PCI_BASE_ADDRESS_MEM_TYPE_64, &proxy->modern_bar); } -- cgit v1.1 From 975acc0ae6d60260859884a9235ae3c62e2969a2 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 4 Jun 2015 12:34:30 +0200 Subject: virtio-pci: correctly set host notifiers for modern bar Currently, during host notifier set. We only add eventfd for legacy bar, this is not correct since: - Non-transitional device does not have legacy bar, so qemu will crash since proxy->bar was not initialized. - Modern device uses modern bar and notify cap to notify the device, we should add eventfd for proxy->notify. So this patch fixes the above two issues by adding eventfd based on whether legacy or modern device were supported. Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 7804361..b7beddd 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -135,12 +135,21 @@ static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f) return 0; } +#define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x1000 + static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy, int n, bool assign, bool set_handler) { VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtQueue *vq = virtio_get_queue(vdev, n); EventNotifier *notifier = virtio_queue_get_host_notifier(vq); + bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY); + bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN); + MemoryRegion *modern_mr = &proxy->notify; + MemoryRegion *legacy_mr = &proxy->bar; + hwaddr modern_addr = QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * + virtio_get_queue_index(vq); + hwaddr legacy_addr = VIRTIO_PCI_QUEUE_NOTIFY; int r = 0; if (assign) { @@ -151,11 +160,23 @@ static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy, return r; } virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler); - memory_region_add_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2, - true, n, notifier); + if (modern) { + memory_region_add_eventfd(modern_mr, modern_addr, 2, + true, n, notifier); + } + if (legacy) { + memory_region_add_eventfd(legacy_mr, legacy_addr, 2, + true, n, notifier); + } } else { - memory_region_del_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2, - true, n, notifier); + if (modern) { + memory_region_del_eventfd(modern_mr, modern_addr, 2, + true, n, notifier); + } + if (legacy) { + memory_region_del_eventfd(legacy_mr, legacy_addr, 2, + true, n, notifier); + } virtio_queue_set_host_notifier_fd_handler(vq, false, false); event_notifier_cleanup(notifier); } @@ -934,8 +955,6 @@ static void virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy, cap->cap_len - PCI_CAP_FLAGS); } -#define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x1000 - static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr, unsigned size) { -- cgit v1.1 From 40de55affda76392627e68d3b1ba5a6a11c492bc Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 4 Jun 2015 12:34:32 +0200 Subject: virtio-balloon: switch to virtio_add_feature This was missed during the conversion of feature bit manipulation. Signed-off-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio-balloon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index f915c7b..78bc14f 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -312,7 +312,7 @@ static void virtio_balloon_set_config(VirtIODevice *vdev, static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f) { - f |= (1 << VIRTIO_BALLOON_F_STATS_VQ); + virtio_add_feature(&f, VIRTIO_BALLOON_F_STATS_VQ); return f; } -- cgit v1.1 From 588255ad5021f06789f438f7b045015c54e30841 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 4 Jun 2015 12:34:33 +0200 Subject: virtio-pci: add struct VirtIOPCIRegion for virtio-1 regions For now just place the MemoryRegion there, following patches will add more. Signed-off-by: Gerd Hoffmann Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 20 +++++++++++--------- hw/virtio/virtio-pci.h | 12 ++++++++---- 2 files changed, 19 insertions(+), 13 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index b7beddd..ebba2d1 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -145,7 +145,7 @@ static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy, EventNotifier *notifier = virtio_queue_get_host_notifier(vq); bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY); bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN); - MemoryRegion *modern_mr = &proxy->notify; + MemoryRegion *modern_mr = &proxy->notify.mr; MemoryRegion *legacy_mr = &proxy->bar; hwaddr modern_addr = QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * virtio_get_queue_index(vq); @@ -1340,28 +1340,30 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) 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), + memory_region_init_io(&proxy->common.mr, 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), + memory_region_add_subregion(&proxy->modern_bar, 0, &proxy->common.mr); + memory_region_init_io(&proxy->isr.mr, 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), + memory_region_add_subregion(&proxy->modern_bar, 0x1000, &proxy->isr.mr); + memory_region_init_io(&proxy->device.mr, 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), + memory_region_add_subregion(&proxy->modern_bar, 0x2000, + &proxy->device.mr); + memory_region_init_io(&proxy->notify.mr, 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); + memory_region_add_subregion(&proxy->modern_bar, 0x3000, + &proxy->notify.mr); pci_register_bar(&proxy->pci_dev, modern_mem_bar, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_PREFETCH | diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 4e9b2db..8f1fc02 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -91,13 +91,17 @@ typedef struct VirtioPCIClass { void (*realize)(VirtIOPCIProxy *vpci_dev, Error **errp); } VirtioPCIClass; +typedef struct VirtIOPCIRegion { + MemoryRegion mr; +} VirtIOPCIRegion; + struct VirtIOPCIProxy { PCIDevice pci_dev; MemoryRegion bar; - MemoryRegion common; - MemoryRegion isr; - MemoryRegion device; - MemoryRegion notify; + VirtIOPCIRegion common; + VirtIOPCIRegion isr; + VirtIOPCIRegion device; + VirtIOPCIRegion notify; MemoryRegion modern_bar; uint32_t flags; uint32_t class_code; -- cgit v1.1 From 1141ce2190c85daacfa9b874476651ed0f7dc6df Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 4 Jun 2015 12:34:34 +0200 Subject: virtio-pci: add virtio_pci_modern_regions_init() Add init function for the modern pci regions, move over the init code. Signed-off-by: Gerd Hoffmann Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 117 +++++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 58 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index ebba2d1..090e95b 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1208,6 +1208,64 @@ static void virtio_pci_device_write(void *opaque, hwaddr addr, } } +static void virtio_pci_modern_regions_init(VirtIOPCIProxy *proxy) +{ + 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, + }; + + memory_region_init_io(&proxy->common.mr, OBJECT(proxy), + &common_ops, + proxy, + "virtio-pci-common", 0x1000); + memory_region_init_io(&proxy->isr.mr, OBJECT(proxy), + &isr_ops, + proxy, + "virtio-pci-isr", 0x1000); + memory_region_init_io(&proxy->device.mr, OBJECT(proxy), + &device_ops, + virtio_bus_get_device(&proxy->bus), + "virtio-pci-device", 0x1000); + memory_region_init_io(&proxy->notify.mr, OBJECT(proxy), + ¬ify_ops, + virtio_bus_get_device(&proxy->bus), + "virtio-pci-notify", + QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * + VIRTIO_QUEUE_MAX); +} /* This is called by virtio-bus just after the device is plugged. */ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) @@ -1290,46 +1348,6 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) 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); @@ -1340,28 +1358,11 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) 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.mr, OBJECT(proxy), - &common_ops, - proxy, - "virtio-pci-common", 0x1000); + virtio_pci_modern_regions_init(proxy); memory_region_add_subregion(&proxy->modern_bar, 0, &proxy->common.mr); - memory_region_init_io(&proxy->isr.mr, OBJECT(proxy), - &isr_ops, - proxy, - "virtio-pci-isr", 0x1000); memory_region_add_subregion(&proxy->modern_bar, 0x1000, &proxy->isr.mr); - memory_region_init_io(&proxy->device.mr, OBJECT(proxy), - &device_ops, - virtio_bus_get_device(&proxy->bus), - "virtio-pci-device", 0x1000); memory_region_add_subregion(&proxy->modern_bar, 0x2000, &proxy->device.mr); - memory_region_init_io(&proxy->notify.mr, 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.mr); pci_register_bar(&proxy->pci_dev, modern_mem_bar, -- cgit v1.1 From a3cc2e81592aba6d818005c078b94b16ba47a02c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 4 Jun 2015 12:34:35 +0200 Subject: virtio-pci: add virtio_pci_modern_region_map() Add function to map modern virtio regions. Add offset to VirtIOPCIRegion. Signed-off-by: Gerd Hoffmann Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 25 +++++++++++++++++++------ hw/virtio/virtio-pci.h | 1 + 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 090e95b..759cfc4 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1251,20 +1251,35 @@ static void virtio_pci_modern_regions_init(VirtIOPCIProxy *proxy) &common_ops, proxy, "virtio-pci-common", 0x1000); + proxy->common.offset = 0x0; + memory_region_init_io(&proxy->isr.mr, OBJECT(proxy), &isr_ops, proxy, "virtio-pci-isr", 0x1000); + proxy->isr.offset = 0x1000; + memory_region_init_io(&proxy->device.mr, OBJECT(proxy), &device_ops, virtio_bus_get_device(&proxy->bus), "virtio-pci-device", 0x1000); + proxy->device.offset = 0x2000; + memory_region_init_io(&proxy->notify.mr, OBJECT(proxy), ¬ify_ops, virtio_bus_get_device(&proxy->bus), "virtio-pci-notify", QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * VIRTIO_QUEUE_MAX); + proxy->notify.offset = 0x3000; +} + +static void virtio_pci_modern_region_map(VirtIOPCIProxy *proxy, + VirtIOPCIRegion *region) +{ + memory_region_add_subregion(&proxy->modern_bar, + region->offset, + ®ion->mr); } /* This is called by virtio-bus just after the device is plugged. */ @@ -1359,12 +1374,10 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) 2 * QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * VIRTIO_QUEUE_MAX); virtio_pci_modern_regions_init(proxy); - memory_region_add_subregion(&proxy->modern_bar, 0, &proxy->common.mr); - memory_region_add_subregion(&proxy->modern_bar, 0x1000, &proxy->isr.mr); - memory_region_add_subregion(&proxy->modern_bar, 0x2000, - &proxy->device.mr); - memory_region_add_subregion(&proxy->modern_bar, 0x3000, - &proxy->notify.mr); + virtio_pci_modern_region_map(proxy, &proxy->common); + virtio_pci_modern_region_map(proxy, &proxy->isr); + virtio_pci_modern_region_map(proxy, &proxy->device); + virtio_pci_modern_region_map(proxy, &proxy->notify); pci_register_bar(&proxy->pci_dev, modern_mem_bar, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_PREFETCH | diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 8f1fc02..f5829b0 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -93,6 +93,7 @@ typedef struct VirtioPCIClass { typedef struct VirtIOPCIRegion { MemoryRegion mr; + uint32_t offset; } VirtIOPCIRegion; struct VirtIOPCIProxy { -- cgit v1.1 From 54790d71e4adcfaae95dac3c7019b10721e609de Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 4 Jun 2015 12:34:36 +0200 Subject: virtio-pci: move virtio_pci_add_mem_cap call to virtio_pci_modern_region_map Also fill offset and length automatically, from VirtIOPCIRegion->offset and region size. Signed-off-by: Gerd Hoffmann Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 759cfc4..f4bdd1c 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1275,11 +1275,16 @@ static void virtio_pci_modern_regions_init(VirtIOPCIProxy *proxy) } static void virtio_pci_modern_region_map(VirtIOPCIProxy *proxy, - VirtIOPCIRegion *region) + VirtIOPCIRegion *region, + struct virtio_pci_cap *cap) { memory_region_add_subregion(&proxy->modern_bar, region->offset, ®ion->mr); + + cap->offset = cpu_to_le32(region->offset); + cap->length = cpu_to_le32(memory_region_size(®ion->mr)); + virtio_pci_add_mem_cap(proxy, cap); } /* This is called by virtio-bus just after the device is plugged. */ @@ -1335,49 +1340,36 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG, .cap_len = sizeof common, .bar = modern_mem_bar, - .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, .bar = modern_mem_bar, - .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, .bar = modern_mem_bar, - .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.bar = modern_mem_bar, - .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), }; /* 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); virtio_pci_modern_regions_init(proxy); - virtio_pci_modern_region_map(proxy, &proxy->common); - virtio_pci_modern_region_map(proxy, &proxy->isr); - virtio_pci_modern_region_map(proxy, &proxy->device); - virtio_pci_modern_region_map(proxy, &proxy->notify); + virtio_pci_modern_region_map(proxy, &proxy->common, &common); + virtio_pci_modern_region_map(proxy, &proxy->isr, &isr); + virtio_pci_modern_region_map(proxy, &proxy->device, &device); + virtio_pci_modern_region_map(proxy, &proxy->notify, ¬ify.cap); pci_register_bar(&proxy->pci_dev, modern_mem_bar, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_PREFETCH | -- cgit v1.1 From fc004905c5b4b7568aad50087c156a5f4dfae1a7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 4 Jun 2015 12:34:37 +0200 Subject: virtio-pci: move cap type to VirtIOPCIRegion Signed-off-by: Gerd Hoffmann Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 9 +++++---- hw/virtio/virtio-pci.h | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index f4bdd1c..440db10 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1252,18 +1252,21 @@ static void virtio_pci_modern_regions_init(VirtIOPCIProxy *proxy) proxy, "virtio-pci-common", 0x1000); proxy->common.offset = 0x0; + proxy->common.type = VIRTIO_PCI_CAP_COMMON_CFG; memory_region_init_io(&proxy->isr.mr, OBJECT(proxy), &isr_ops, proxy, "virtio-pci-isr", 0x1000); proxy->isr.offset = 0x1000; + proxy->isr.type = VIRTIO_PCI_CAP_ISR_CFG; memory_region_init_io(&proxy->device.mr, OBJECT(proxy), &device_ops, virtio_bus_get_device(&proxy->bus), "virtio-pci-device", 0x1000); proxy->device.offset = 0x2000; + proxy->device.type = VIRTIO_PCI_CAP_DEVICE_CFG; memory_region_init_io(&proxy->notify.mr, OBJECT(proxy), ¬ify_ops, @@ -1272,6 +1275,7 @@ static void virtio_pci_modern_regions_init(VirtIOPCIProxy *proxy) QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * VIRTIO_QUEUE_MAX); proxy->notify.offset = 0x3000; + proxy->notify.type = VIRTIO_PCI_CAP_NOTIFY_CFG; } static void virtio_pci_modern_region_map(VirtIOPCIProxy *proxy, @@ -1282,6 +1286,7 @@ static void virtio_pci_modern_region_map(VirtIOPCIProxy *proxy, region->offset, ®ion->mr); + cap->cfg_type = region->type; cap->offset = cpu_to_le32(region->offset); cap->length = cpu_to_le32(memory_region_size(®ion->mr)); virtio_pci_add_mem_cap(proxy, cap); @@ -1337,22 +1342,18 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) if (modern) { struct virtio_pci_cap common = { - .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG, .cap_len = sizeof common, .bar = modern_mem_bar, }; struct virtio_pci_cap isr = { - .cfg_type = VIRTIO_PCI_CAP_ISR_CFG, .cap_len = sizeof isr, .bar = modern_mem_bar, }; struct virtio_pci_cap device = { - .cfg_type = VIRTIO_PCI_CAP_DEVICE_CFG, .cap_len = sizeof device, .bar = modern_mem_bar, }; struct virtio_pci_notify_cap notify = { - .cap.cfg_type = VIRTIO_PCI_CAP_NOTIFY_CFG, .cap.cap_len = sizeof notify, .cap.bar = modern_mem_bar, .notify_off_multiplier = diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index f5829b0..ea1343d 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -94,6 +94,7 @@ typedef struct VirtioPCIClass { typedef struct VirtIOPCIRegion { MemoryRegion mr; uint32_t offset; + uint32_t type; } VirtIOPCIRegion; struct VirtIOPCIProxy { -- cgit v1.1 From cc52ea90f835aa66d431db712b22f8b15bec2e46 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 4 Jun 2015 12:34:38 +0200 Subject: virtio-pci: drop identical virtio_pci_cap Now the three struct virtio_pci_caps are identical, lets drop two of them ;) Signed-off-by: Gerd Hoffmann Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 440db10..771bbd5 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1341,16 +1341,8 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) if (modern) { - struct virtio_pci_cap common = { - .cap_len = sizeof common, - .bar = modern_mem_bar, - }; - struct virtio_pci_cap isr = { - .cap_len = sizeof isr, - .bar = modern_mem_bar, - }; - struct virtio_pci_cap device = { - .cap_len = sizeof device, + struct virtio_pci_cap cap = { + .cap_len = sizeof cap, .bar = modern_mem_bar, }; struct virtio_pci_notify_cap notify = { @@ -1367,9 +1359,9 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) 2 * QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * VIRTIO_QUEUE_MAX); virtio_pci_modern_regions_init(proxy); - virtio_pci_modern_region_map(proxy, &proxy->common, &common); - virtio_pci_modern_region_map(proxy, &proxy->isr, &isr); - virtio_pci_modern_region_map(proxy, &proxy->device, &device); + virtio_pci_modern_region_map(proxy, &proxy->common, &cap); + virtio_pci_modern_region_map(proxy, &proxy->isr, &cap); + virtio_pci_modern_region_map(proxy, &proxy->device, &cap); virtio_pci_modern_region_map(proxy, &proxy->notify, ¬ify.cap); pci_register_bar(&proxy->pci_dev, modern_mem_bar, PCI_BASE_ADDRESS_SPACE_MEMORY | -- cgit v1.1 From b6ce27a593ab39ac28baebc3045901925046bebd Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 4 Jun 2015 12:34:39 +0200 Subject: virtio-pci: fill VirtIOPCIRegions early. Initialize the modern bar and the VirtIOPCIRegion fields early, in realize. Also add a size field to VirtIOPCIRegion and variables for pci bars to VirtIOPCIProxy. This allows virtio-pci subclasses to change things before the device_plugged callback applies them. virtio-vga will use that to arrange regions in a way that virtio-vga is compatible to both stdvga (in vga mode) and virtio-gpu-pci (in pci mode). Signed-off-by: Gerd Hoffmann Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 92 ++++++++++++++++++++++++++++---------------------- hw/virtio/virtio-pci.h | 4 +++ 2 files changed, 55 insertions(+), 41 deletions(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 771bbd5..76653a7 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1250,32 +1250,26 @@ static void virtio_pci_modern_regions_init(VirtIOPCIProxy *proxy) memory_region_init_io(&proxy->common.mr, OBJECT(proxy), &common_ops, proxy, - "virtio-pci-common", 0x1000); - proxy->common.offset = 0x0; - proxy->common.type = VIRTIO_PCI_CAP_COMMON_CFG; + "virtio-pci-common", + proxy->common.size); memory_region_init_io(&proxy->isr.mr, OBJECT(proxy), &isr_ops, proxy, - "virtio-pci-isr", 0x1000); - proxy->isr.offset = 0x1000; - proxy->isr.type = VIRTIO_PCI_CAP_ISR_CFG; + "virtio-pci-isr", + proxy->isr.size); memory_region_init_io(&proxy->device.mr, OBJECT(proxy), &device_ops, virtio_bus_get_device(&proxy->bus), - "virtio-pci-device", 0x1000); - proxy->device.offset = 0x2000; - proxy->device.type = VIRTIO_PCI_CAP_DEVICE_CFG; + "virtio-pci-device", + proxy->device.size); memory_region_init_io(&proxy->notify.mr, OBJECT(proxy), ¬ify_ops, virtio_bus_get_device(&proxy->bus), "virtio-pci-notify", - QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * - VIRTIO_QUEUE_MAX); - proxy->notify.offset = 0x3000; - proxy->notify.type = VIRTIO_PCI_CAP_NOTIFY_CFG; + proxy->notify.size); } static void virtio_pci_modern_region_map(VirtIOPCIProxy *proxy, @@ -1287,8 +1281,9 @@ static void virtio_pci_modern_region_map(VirtIOPCIProxy *proxy, ®ion->mr); cap->cfg_type = region->type; + cap->bar = proxy->modern_mem_bar; cap->offset = cpu_to_le32(region->offset); - cap->length = cpu_to_le32(memory_region_size(®ion->mr)); + cap->length = cpu_to_le32(region->size); virtio_pci_add_mem_cap(proxy, cap); } @@ -1303,22 +1298,6 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) uint32_t size; VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); - /* - * virtio pci bar layout - * - * region 0 -- virtio legacy io bar - * region 1 -- msi-x bar - * region 2+3 -- not used by virtio-pci - * region 4+5 -- virtio modern memory (64bit) bar - * - * Regions 2+3 can be used by VirtIOPCIProxy subclasses. - * virtio-vga places the vga framebuffer there. - * - */ - uint32_t legacy_io_bar = 0; - uint32_t msix_bar = 1; - uint32_t modern_mem_bar = 4; - config = proxy->pci_dev.config; if (proxy->class_code) { pci_config_set_class(config, proxy->class_code); @@ -1343,11 +1322,9 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) if (modern) { struct virtio_pci_cap cap = { .cap_len = sizeof cap, - .bar = modern_mem_bar, }; struct virtio_pci_notify_cap notify = { .cap.cap_len = sizeof notify, - .cap.bar = modern_mem_bar, .notify_off_multiplier = cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT), }; @@ -1355,15 +1332,12 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) /* TODO: add io access for speed */ 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); virtio_pci_modern_regions_init(proxy); virtio_pci_modern_region_map(proxy, &proxy->common, &cap); virtio_pci_modern_region_map(proxy, &proxy->isr, &cap); virtio_pci_modern_region_map(proxy, &proxy->device, &cap); virtio_pci_modern_region_map(proxy, &proxy->notify, ¬ify.cap); - pci_register_bar(&proxy->pci_dev, modern_mem_bar, + pci_register_bar(&proxy->pci_dev, proxy->modern_mem_bar, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_PREFETCH | PCI_BASE_ADDRESS_MEM_TYPE_64, @@ -1371,7 +1345,8 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) } if (proxy->nvectors && - msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, msix_bar)) { + msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, + proxy->msix_bar)) { error_report("unable to init msix vectors to %" PRIu32, proxy->nvectors); proxy->nvectors = 0; @@ -1390,7 +1365,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) &virtio_pci_config_ops, proxy, "virtio-pci", size); - pci_register_bar(&proxy->pci_dev, legacy_io_bar, + pci_register_bar(&proxy->pci_dev, proxy->legacy_io_bar, PCI_BASE_ADDRESS_SPACE_IO, &proxy->bar); } @@ -1410,12 +1385,47 @@ static void virtio_pci_device_unplugged(DeviceState *d) static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) { - VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev); + VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev); VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev); - virtio_pci_bus_new(&dev->bus, sizeof(dev->bus), dev); + /* + * virtio pci bar layout used by default. + * subclasses can re-arrange things if needed. + * + * region 0 -- virtio legacy io bar + * region 1 -- msi-x bar + * region 4+5 -- virtio modern memory (64bit) bar + * + */ + proxy->legacy_io_bar = 0; + proxy->msix_bar = 1; + proxy->modern_mem_bar = 4; + + proxy->common.offset = 0x0; + proxy->common.size = 0x1000; + proxy->common.type = VIRTIO_PCI_CAP_COMMON_CFG; + + proxy->isr.offset = 0x1000; + proxy->isr.size = 0x1000; + proxy->isr.type = VIRTIO_PCI_CAP_ISR_CFG; + + proxy->device.offset = 0x2000; + proxy->device.size = 0x1000; + proxy->device.type = VIRTIO_PCI_CAP_DEVICE_CFG; + + proxy->notify.offset = 0x3000; + proxy->notify.size = + QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * VIRTIO_QUEUE_MAX; + proxy->notify.type = VIRTIO_PCI_CAP_NOTIFY_CFG; + + /* subclasses can enforce modern, so do this unconditionally */ + memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci", + 2 * QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * + VIRTIO_QUEUE_MAX); + + virtio_pci_bus_new(&proxy->bus, sizeof(proxy->bus), proxy); if (k->realize) { - k->realize(dev, errp); + k->realize(proxy, errp); } } diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index ea1343d..ff5ab71 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -94,6 +94,7 @@ typedef struct VirtioPCIClass { typedef struct VirtIOPCIRegion { MemoryRegion mr; uint32_t offset; + uint32_t size; uint32_t type; } VirtIOPCIRegion; @@ -105,6 +106,9 @@ struct VirtIOPCIProxy { VirtIOPCIRegion device; VirtIOPCIRegion notify; MemoryRegion modern_bar; + uint32_t legacy_io_bar; + uint32_t msix_bar; + uint32_t modern_mem_bar; uint32_t flags; uint32_t class_code; uint32_t nvectors; -- cgit v1.1 From f958c8aa138718b8126a300d6faece522f7674b8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 4 Jun 2015 12:34:41 +0200 Subject: virtio-input: core code & base class [pci] This patch adds the virtio-pci support bits for virtio-input-device. Signed-off-by: Gerd Hoffmann Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 36 ++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-pci.h | 14 ++++++++++++++ 2 files changed, 50 insertions(+) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 76653a7..8ec741b 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -24,6 +24,7 @@ #include "hw/virtio/virtio-serial.h" #include "hw/virtio/virtio-scsi.h" #include "hw/virtio/virtio-balloon.h" +#include "hw/virtio/virtio-input.h" #include "hw/pci/pci.h" #include "qemu/error-report.h" #include "hw/pci/msi.h" @@ -1897,6 +1898,40 @@ static const TypeInfo virtio_rng_pci_info = { .class_init = virtio_rng_pci_class_init, }; +/* virtio-input-pci */ + +static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev); + DeviceState *vdev = DEVICE(&vinput->vdev); + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + /* force virtio-1.0 */ + vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN; + vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY; + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void virtio_input_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + k->realize = virtio_input_pci_realize; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + + pcidev_k->class_id = PCI_CLASS_INPUT_OTHER; +} + +static const TypeInfo virtio_input_pci_info = { + .name = TYPE_VIRTIO_INPUT_PCI, + .parent = TYPE_VIRTIO_PCI, + .instance_size = sizeof(VirtIOInputPCI), + .class_init = virtio_input_pci_class_init, + .abstract = true, +}; + /* virtio-pci-bus */ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size, @@ -1938,6 +1973,7 @@ static const TypeInfo virtio_pci_bus_info = { static void virtio_pci_register_types(void) { type_register_static(&virtio_rng_pci_info); + type_register_static(&virtio_input_pci_info); type_register_static(&virtio_pci_bus_info); type_register_static(&virtio_pci_info); #ifdef CONFIG_VIRTFS diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index ff5ab71..754971f 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -24,6 +24,7 @@ #include "hw/virtio/virtio-balloon.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-9p.h" +#include "hw/virtio/virtio-input.h" #ifdef CONFIG_VIRTFS #include "hw/9pfs/virtio-9p.h" #endif @@ -39,6 +40,7 @@ typedef struct VirtIOSerialPCI VirtIOSerialPCI; typedef struct VirtIONetPCI VirtIONetPCI; typedef struct VHostSCSIPCI VHostSCSIPCI; typedef struct VirtIORngPCI VirtIORngPCI; +typedef struct VirtIOInputPCI VirtIOInputPCI; /* virtio-pci-bus */ @@ -234,6 +236,18 @@ struct VirtIORngPCI { VirtIORNG vdev; }; +/* + * virtio-input-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci" +#define VIRTIO_INPUT_PCI(obj) \ + OBJECT_CHECK(VirtIOInputPCI, (obj), TYPE_VIRTIO_INPUT_PCI) + +struct VirtIOInputPCI { + VirtIOPCIProxy parent_obj; + VirtIOInput vdev; +}; + /* Virtio ABI version, if we increment this, we break the guest driver. */ #define VIRTIO_PCI_ABI_VERSION 0 -- cgit v1.1 From 710e2d90da1a16807f7885d37b203ce739fdc53a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 4 Jun 2015 12:34:42 +0200 Subject: virtio-input: emulated devices [pci] This patch adds virtio-pci support for the emulated virtio-input devices. Using them is as simple as adding "-device virtio-tablet-pci" to your command line. If you want add multiple devices but don't want waste a pci slot for each you can compose a multifunction device this way: qemu -device virtio-keyboard-pci,addr=0d.0,multifunction=on \ -device virtio-tablet-pci,addr=0d.1,multifunction=on Signed-off-by: Gerd Hoffmann Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-pci.h | 13 ++++++++ 2 files changed, 97 insertions(+) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 8ec741b..d7cf34c 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1900,6 +1900,12 @@ static const TypeInfo virtio_rng_pci_info = { /* virtio-input-pci */ +static Property virtio_input_hid_pci_properties[] = { + DEFINE_VIRTIO_INPUT_PROPERTIES(VirtIOInputPCI, vdev.input), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), + DEFINE_PROP_END_OF_LIST(), +}; + static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) { VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev); @@ -1924,6 +1930,49 @@ static void virtio_input_pci_class_init(ObjectClass *klass, void *data) pcidev_k->class_id = PCI_CLASS_INPUT_OTHER; } +static void virtio_input_hid_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->props = virtio_input_hid_pci_properties; +} + +static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + pcidev_k->class_id = PCI_CLASS_INPUT_KEYBOARD; +} + +static void virtio_input_hid_mouse_pci_class_init(ObjectClass *klass, + void *data) +{ + PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + + pcidev_k->class_id = PCI_CLASS_INPUT_MOUSE; +} + +static void virtio_keyboard_initfn(Object *obj) +{ + VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); + object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_KEYBOARD); + object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); +} + +static void virtio_mouse_initfn(Object *obj) +{ + VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); + object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_MOUSE); + object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); +} + +static void virtio_tablet_initfn(Object *obj) +{ + VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj); + object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_TABLET); + object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); +} + static const TypeInfo virtio_input_pci_info = { .name = TYPE_VIRTIO_INPUT_PCI, .parent = TYPE_VIRTIO_PCI, @@ -1932,6 +1981,37 @@ static const TypeInfo virtio_input_pci_info = { .abstract = true, }; +static const TypeInfo virtio_input_hid_pci_info = { + .name = TYPE_VIRTIO_INPUT_HID_PCI, + .parent = TYPE_VIRTIO_INPUT_PCI, + .instance_size = sizeof(VirtIOInputHIDPCI), + .class_init = virtio_input_hid_pci_class_init, + .abstract = true, +}; + +static const TypeInfo virtio_keyboard_pci_info = { + .name = TYPE_VIRTIO_KEYBOARD_PCI, + .parent = TYPE_VIRTIO_INPUT_HID_PCI, + .class_init = virtio_input_hid_kbd_pci_class_init, + .instance_size = sizeof(VirtIOInputHIDPCI), + .instance_init = virtio_keyboard_initfn, +}; + +static const TypeInfo virtio_mouse_pci_info = { + .name = TYPE_VIRTIO_MOUSE_PCI, + .parent = TYPE_VIRTIO_INPUT_HID_PCI, + .class_init = virtio_input_hid_mouse_pci_class_init, + .instance_size = sizeof(VirtIOInputHIDPCI), + .instance_init = virtio_mouse_initfn, +}; + +static const TypeInfo virtio_tablet_pci_info = { + .name = TYPE_VIRTIO_TABLET_PCI, + .parent = TYPE_VIRTIO_INPUT_HID_PCI, + .instance_size = sizeof(VirtIOInputHIDPCI), + .instance_init = virtio_tablet_initfn, +}; + /* virtio-pci-bus */ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size, @@ -1974,6 +2054,10 @@ static void virtio_pci_register_types(void) { type_register_static(&virtio_rng_pci_info); type_register_static(&virtio_input_pci_info); + type_register_static(&virtio_input_hid_pci_info); + type_register_static(&virtio_keyboard_pci_info); + type_register_static(&virtio_mouse_pci_info); + type_register_static(&virtio_tablet_pci_info); type_register_static(&virtio_pci_bus_info); type_register_static(&virtio_pci_info); #ifdef CONFIG_VIRTFS diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 754971f..d962125 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -41,6 +41,7 @@ typedef struct VirtIONetPCI VirtIONetPCI; typedef struct VHostSCSIPCI VHostSCSIPCI; typedef struct VirtIORngPCI VirtIORngPCI; typedef struct VirtIOInputPCI VirtIOInputPCI; +typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI; /* virtio-pci-bus */ @@ -248,6 +249,18 @@ struct VirtIOInputPCI { VirtIOInput vdev; }; +#define TYPE_VIRTIO_INPUT_HID_PCI "virtio-input-hid-pci" +#define TYPE_VIRTIO_KEYBOARD_PCI "virtio-keyboard-pci" +#define TYPE_VIRTIO_MOUSE_PCI "virtio-mouse-pci" +#define TYPE_VIRTIO_TABLET_PCI "virtio-tablet-pci" +#define VIRTIO_INPUT_HID_PCI(obj) \ + OBJECT_CHECK(VirtIOInputHIDPCI, (obj), TYPE_VIRTIO_INPUT_HID_PCI) + +struct VirtIOInputHIDPCI { + VirtIOPCIProxy parent_obj; + VirtIOInputHID vdev; +}; + /* Virtio ABI version, if we increment this, we break the guest driver. */ #define VIRTIO_PCI_ABI_VERSION 0 -- cgit v1.1 From 87108bb26ce04637980c0897caeabee8901e72c9 Mon Sep 17 00:00:00 2001 From: Shannon Zhao Date: Wed, 10 Jun 2015 23:04:30 +0800 Subject: virtio-net: move qdev properties into virtio-net.c As only one place in virtio-net.c uses DEFINE_VIRTIO_NET_FEATURES, there is no need to expose it. Inline it into virtio-net.c to avoid wrongly use. Signed-off-by: Shannon Zhao Signed-off-by: Shannon Zhao Reviewed-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 49fa13f..9281aa1 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1707,10 +1707,50 @@ static void virtio_net_instance_init(Object *obj) } static Property virtio_net_properties[] = { - DEFINE_VIRTIO_NET_FEATURES(VirtIONet, host_features), + DEFINE_PROP_BIT("any_layout", VirtIONet, host_features, + VIRTIO_F_ANY_LAYOUT, true), + DEFINE_PROP_BIT("csum", VirtIONet, host_features, VIRTIO_NET_F_CSUM, true), + DEFINE_PROP_BIT("guest_csum", VirtIONet, host_features, + VIRTIO_NET_F_GUEST_CSUM, true), + DEFINE_PROP_BIT("gso", VirtIONet, host_features, VIRTIO_NET_F_GSO, true), + DEFINE_PROP_BIT("guest_tso4", VirtIONet, host_features, + VIRTIO_NET_F_GUEST_TSO4, true), + DEFINE_PROP_BIT("guest_tso6", VirtIONet, host_features, + VIRTIO_NET_F_GUEST_TSO6, true), + DEFINE_PROP_BIT("guest_ecn", VirtIONet, host_features, + VIRTIO_NET_F_GUEST_ECN, true), + DEFINE_PROP_BIT("guest_ufo", VirtIONet, host_features, + VIRTIO_NET_F_GUEST_UFO, true), + DEFINE_PROP_BIT("guest_announce", VirtIONet, host_features, + VIRTIO_NET_F_GUEST_ANNOUNCE, true), + DEFINE_PROP_BIT("host_tso4", VirtIONet, host_features, + VIRTIO_NET_F_HOST_TSO4, true), + DEFINE_PROP_BIT("host_tso6", VirtIONet, host_features, + VIRTIO_NET_F_HOST_TSO6, true), + DEFINE_PROP_BIT("host_ecn", VirtIONet, host_features, + VIRTIO_NET_F_HOST_ECN, true), + DEFINE_PROP_BIT("host_ufo", VirtIONet, host_features, + VIRTIO_NET_F_HOST_UFO, true), + DEFINE_PROP_BIT("mrg_rxbuf", VirtIONet, host_features, + VIRTIO_NET_F_MRG_RXBUF, true), + DEFINE_PROP_BIT("status", VirtIONet, host_features, + VIRTIO_NET_F_STATUS, true), + DEFINE_PROP_BIT("ctrl_vq", VirtIONet, host_features, + VIRTIO_NET_F_CTRL_VQ, true), + DEFINE_PROP_BIT("ctrl_rx", VirtIONet, host_features, + VIRTIO_NET_F_CTRL_RX, true), + DEFINE_PROP_BIT("ctrl_vlan", VirtIONet, host_features, + VIRTIO_NET_F_CTRL_VLAN, true), + DEFINE_PROP_BIT("ctrl_rx_extra", VirtIONet, host_features, + VIRTIO_NET_F_CTRL_RX_EXTRA, true), + DEFINE_PROP_BIT("ctrl_mac_addr", VirtIONet, host_features, + VIRTIO_NET_F_CTRL_MAC_ADDR, true), + DEFINE_PROP_BIT("ctrl_guest_offloads", VirtIONet, host_features, + VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true), + DEFINE_PROP_BIT("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false), DEFINE_NIC_PROPERTIES(VirtIONet, nic_conf), DEFINE_PROP_UINT32("x-txtimer", VirtIONet, net_conf.txtimer, - TX_TIMER_INTERVAL), + TX_TIMER_INTERVAL), DEFINE_PROP_INT32("x-txburst", VirtIONet, net_conf.txburst, TX_BURST), DEFINE_PROP_STRING("tx", VirtIONet, net_conf.tx), DEFINE_PROP_END_OF_LIST(), -- cgit v1.1 From 0c63237a90f37fffe8a8016f24f61bb228653e86 Mon Sep 17 00:00:00 2001 From: Shannon Zhao Date: Wed, 10 Jun 2015 23:04:32 +0800 Subject: virtio-scsi: move qdev properties into virtio-scsi.c As only one place in virtio-scsi.c uses DEFINE_VIRTIO_SCSI_PROPERTIES and DEFINE_VIRTIO_SCSI_FEATURES, there is no need to expose them. Inline them into virtio-scsi.c to avoid wrongly use. Signed-off-by: Shannon Zhao Signed-off-by: Shannon Zhao Reviewed-by: Paolo Bonzini Acked-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/scsi/virtio-scsi.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index b0dee29..f7d3c7c 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -948,8 +948,17 @@ static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp) } static Property virtio_scsi_properties[] = { - DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSI, parent_obj.conf), - DEFINE_VIRTIO_SCSI_FEATURES(VirtIOSCSI, host_features), + DEFINE_PROP_UINT32("num_queues", VirtIOSCSI, parent_obj.conf.num_queues, 1), + DEFINE_PROP_UINT32("max_sectors", VirtIOSCSI, parent_obj.conf.max_sectors, + 0xFFFF), + DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSI, parent_obj.conf.cmd_per_lun, + 128), + DEFINE_PROP_BIT("any_layout", VirtIOSCSI, host_features, + VIRTIO_F_ANY_LAYOUT, true), + DEFINE_PROP_BIT("hotplug", VirtIOSCSI, host_features, + VIRTIO_SCSI_F_HOTPLUG, true), + DEFINE_PROP_BIT("param_change", VirtIOSCSI, host_features, + VIRTIO_SCSI_F_CHANGE, true), DEFINE_PROP_END_OF_LIST(), }; -- cgit v1.1 From fe704809b974d8dd8e020b4d3f48ede338a886fe Mon Sep 17 00:00:00 2001 From: Shannon Zhao Date: Wed, 10 Jun 2015 23:04:33 +0800 Subject: virtio-rng: move qdev properties into virtio-rng.c As only one place in virtio-rng.c uses DEFINE_VIRTIO_RNG_PROPERTIES, there is no need to expose it. Inline it into virtio-rng.c to avoid wrongly use. Signed-off-by: Shannon Zhao Signed-off-by: Shannon Zhao Reviewed-by: Paolo Bonzini Acked-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-rng.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index 420c39f..22b1d87 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -219,7 +219,13 @@ static void virtio_rng_device_unrealize(DeviceState *dev, Error **errp) } static Property virtio_rng_properties[] = { - DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORNG, conf), + /* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s. If + * you have an entropy source capable of generating more entropy than this + * and you can pass it through via virtio-rng, then hats off to you. Until + * then, this is unlimited for all practical purposes. + */ + DEFINE_PROP_UINT64("max-bytes", VirtIORNG, conf.max_bytes, INT64_MAX), + DEFINE_PROP_UINT32("period", VirtIORNG, conf.period_ms, 1 << 16), DEFINE_PROP_END_OF_LIST(), }; -- cgit v1.1 From 448777c411b80df0263eb00b9df2f829cdc7cc9b Mon Sep 17 00:00:00 2001 From: Shannon Zhao Date: Wed, 10 Jun 2015 23:04:34 +0800 Subject: virtio-serial-bus: move qdev properties into virtio-serial-bus.c As only one place in virtio-serial-bus.c uses DEFINE_VIRTIO_SERIAL_PROPERTIES, there is no need to expose it. Inline it into virtio-serial-bus.c to avoid wrongly use. Signed-off-by: Shannon Zhao Signed-off-by: Shannon Zhao Reviewed-by: Paolo Bonzini Acked-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/char/virtio-serial-bus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index f893523..d451b22 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -1083,7 +1083,8 @@ static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp) } static Property virtio_serial_properties[] = { - DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtIOSerial, serial), + DEFINE_PROP_UINT32("max_ports", VirtIOSerial, serial.max_virtserial_ports, + 31), DEFINE_PROP_END_OF_LIST(), }; -- cgit v1.1 From 83a84878da2e00b4d350bd90d6775c1f6320e7b4 Mon Sep 17 00:00:00 2001 From: Shannon Zhao Date: Wed, 10 Jun 2015 23:04:35 +0800 Subject: virtio-9p-device: move qdev properties into virtio-9p-device.c As only one place in virtio-9p-device.c uses DEFINE_VIRTIO_9P_PROPERTIES, there is no need to expose it. Inline it into virtio-9p-device.c to avoid wrongly use. Signed-off-by: Shannon Zhao Signed-off-by: Shannon Zhao Reviewed-by: Paolo Bonzini Acked-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/9pfs/virtio-9p-device.c | 3 ++- hw/9pfs/virtio-9p.h | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'hw') diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 60f9ff9..3f4c9e7 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -140,7 +140,8 @@ out: /* virtio-9p device */ static Property virtio_9p_properties[] = { - DEFINE_VIRTIO_9P_PROPERTIES(V9fsState, fsconf), + DEFINE_PROP_STRING("mount_tag", V9fsState, fsconf.tag), + DEFINE_PROP_STRING("fsdev", V9fsState, fsconf.fsdev_id), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 58dafa9..2e7d488 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -391,8 +391,4 @@ extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath, #define VIRTIO_9P(obj) \ OBJECT_CHECK(V9fsState, (obj), TYPE_VIRTIO_9P) -#define DEFINE_VIRTIO_9P_PROPERTIES(_state, _field) \ - DEFINE_PROP_STRING("mount_tag", _state, _field.tag), \ - DEFINE_PROP_STRING("fsdev", _state, _field.fsdev_id) - #endif -- cgit v1.1 From 21549a4642e1f1b438ffc31dd9dc35f134b10e5b Mon Sep 17 00:00:00 2001 From: Shannon Zhao Date: Wed, 10 Jun 2015 23:04:36 +0800 Subject: vhost-scsi: move qdev properties into vhost-scsi.c As only one place in vhost-scsi.c uses DEFINE_VHOST_SCSI_PROPERTIES, there is no need to expose it. Inline it into vhost-scsi.c to avoid wrongly use. Signed-off-by: Shannon Zhao Signed-off-by: Shannon Zhao Reviewed-by: Paolo Bonzini Acked-by: Cornelia Huck Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/scsi/vhost-scsi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 9c76486..1941aa1 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -294,7 +294,14 @@ static char *vhost_scsi_get_fw_dev_path(FWPathProvider *p, BusState *bus, } static Property vhost_scsi_properties[] = { - DEFINE_VHOST_SCSI_PROPERTIES(VHostSCSI, parent_obj.conf), + DEFINE_PROP_STRING("vhostfd", VHostSCSI, parent_obj.conf.vhostfd), + DEFINE_PROP_STRING("wwpn", VHostSCSI, parent_obj.conf.wwpn), + DEFINE_PROP_UINT32("boot_tpgt", VHostSCSI, parent_obj.conf.boot_tpgt, 0), + DEFINE_PROP_UINT32("num_queues", VHostSCSI, parent_obj.conf.num_queues, 1), + DEFINE_PROP_UINT32("max_sectors", VHostSCSI, parent_obj.conf.max_sectors, + 0xFFFF), + DEFINE_PROP_UINT32("cmd_per_lun", VHostSCSI, parent_obj.conf.cmd_per_lun, + 128), DEFINE_PROP_END_OF_LIST(), }; -- cgit v1.1 From c96d9286a6d70452e5fa4f1e3f840715e325be95 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Thu, 11 Jun 2015 02:37:58 +0200 Subject: i386/acpi-build: more traditional _UID and _HID for PXB root buses The ACPI specification permits the _HID and _UID objects to evaluate to strings. (See "6.1.5 _HID (Hardware ID)" and "6.1.12 _UID (Unique ID)" in the ACPI v6.0 spec.) With regard to related standards, the UEFI specification can also express a device address composed from string _HID and _UID identifiers, inside the Expanded ACPI Device Path Node. (See "9.3.3 ACPI Device Path", Table 49, in the UEFI v2.5 spec.) However, numeric (integer) contents for both _HID and _UID are more traditional. They are recommended by the UEFI spec for size reasons: [...] the ACPI Device Path node is smaller and should be used if possible to reduce the size of device paths that may potentially be stored in nonvolatile storage [...] External tools support them better (for example the --acpi_hid and --acpi_uid options of "efibootmgr" only take numeric identifiers). Finally, numeric _HID and _UID contents are existing practice in the QEMU source. This patch was tested with a Fedora 20 LiveCD and a preexistent Windows Server 2012 R2 guest. Using "acpidump" and "iasl" in the Fedora guest, we get, in the SSDT: > Scope (\_SB) > { > Device (PC04) > { > Name (_UID, 0x04) // _UID: Unique ID > Name (_HID, EisaId ("PNP0A03") /* PCI Bus */) // _HID: Hardware ID Cc: Marcel Apfelbaum Cc: Michael S. Tsirkin Signed-off-by: Laszlo Ersek Reviewed-by: Marcel Apfelbaum Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index db32fd1..8fae3b9 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -944,9 +944,8 @@ build_ssdt(GArray *table_data, GArray *linker, scope = aml_scope("\\_SB"); dev = aml_device("PC%.02X", bus_num); - aml_append(dev, - aml_name_decl("_UID", aml_string("PC%.02X", bus_num))); - aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A03"))); + aml_append(dev, aml_name_decl("_UID", aml_int(bus_num))); + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03"))); aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num))); if (numa_node != NUMA_NODE_UNASSIGNED) { -- cgit v1.1 From 4ebc736e9938a7e88ecc785734b17145bf802a56 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Thu, 11 Jun 2015 02:37:59 +0200 Subject: i386/acpi-build: fix PXB workarounds for unsupported BIOSes The patch apci: fix PXB behaviour if used with unsupported BIOS uses the following condition to see if a "PXB mem/IO chunk" has *not* been configured by the BIOS: (!range_base || range_base > range_limit) When this condition evaluates to true, said patch *omits* the corresponding entry from the _CRS. Later on the patch checks for the opposite condition (with the intent of *adding* entries to the _CRS if the "PXB mem/IO chunks" *have* been configured). Unfortunately, the condition was negated incorrectly: only the first ! operator was removed, which led to the nonsensical expression (range_base || range_base > range_limit) leading to bogus entries in the _CRS, and causing BSOD in Windows Server 2012 R2 when it runs on OVMF. The correct negative of the condition seen at the top is (range_base && range_base <= range_limit) Fix the expressions. Cc: Marcel Apfelbaum Cc: Michael S. Tsirkin Signed-off-by: Laszlo Ersek Reviewed-by: Marcel Apfelbaum Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 8fae3b9..8e88ade 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -832,7 +832,7 @@ static Aml *build_crs(PCIHostState *host, * Work-around for old bioses * that do not support multiple root buses */ - if (range_base || range_base > range_limit) { + if (range_base && range_base <= range_limit) { aml_append(crs, aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, AML_ENTIRE_RANGE, @@ -853,7 +853,7 @@ static Aml *build_crs(PCIHostState *host, * Work-around for old bioses * that do not support multiple root buses */ - if (range_base || range_base > range_limit) { + if (range_base && range_base <= range_limit) { aml_append(crs, aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, AML_NON_CACHEABLE, @@ -864,7 +864,7 @@ static Aml *build_crs(PCIHostState *host, 0, range_limit - range_base + 1)); crs_range_insert(mem_ranges, range_base, range_limit); - } + } range_base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); @@ -875,7 +875,7 @@ static Aml *build_crs(PCIHostState *host, * Work-around for old bioses * that do not support multiple root buses */ - if (range_base || range_base > range_limit) { + if (range_base && range_base <= range_limit) { aml_append(crs, aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, AML_NON_CACHEABLE, -- cgit v1.1