* [Qemu-devel] [PATCH RFC 2/3] virtio: misc fixes, include linux header
2014-12-30 16:28 [Qemu-devel] [PATCH RFC 0/3] virtio-pci: towards virtio 1.0 host support Michael S. Tsirkin
2014-12-30 16:28 ` [Qemu-devel] [PATCH RFC 1/3] linux-headers: add virtio_pci Michael S. Tsirkin
@ 2014-12-30 16:28 ` Michael S. Tsirkin
2014-12-30 22:25 ` Peter Maydell
2014-12-30 16:28 ` [Qemu-devel] [PATCH RFC 3/3] virtio-pci: initial virtio 1.0 support Michael S. Tsirkin
2 siblings, 1 reply; 5+ messages in thread
From: Michael S. Tsirkin @ 2014-12-30 16:28 UTC (permalink / raw)
To: qemu-devel; +Cc: cornelia.huck, Rusty Russell, Anthony Liguori
Tweak virtio core so we can use linux virtio pci header
directly without duplicating code.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
hw/net/virtio-net.c | 2 +-
hw/virtio/virtio-pci.c | 3 +++
hw/virtio/virtio.c | 13 +++++++++----
3 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index b5dd356..5fff769 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -1046,7 +1046,7 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
return -1;
error_report("virtio-net unexpected empty queue: "
"i %zd mergeable %d offset %zd, size %zd, "
- "guest hdr len %zd, host hdr len %zd guest features 0x%lx",
+ "guest hdr len %zd, host hdr len %zd guest features 0x%"PRIx64,
i, n->mergeable_rx_bufs, offset, size,
n->guest_hdr_len, n->host_hdr_len, vdev->guest_features);
exit(1);
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 7382705..bc11d3d 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -17,6 +17,7 @@
#include <inttypes.h>
+#include "linux-headers/linux/virtio_pci.h"
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-blk.h"
#include "hw/virtio/virtio-net.h"
@@ -76,6 +77,8 @@
VIRTIO_PCI_CONFIG_MSI : \
VIRTIO_PCI_CONFIG_NOMSI)
+#undef VIRTIO_PCI_CONFIG
+
/* The remaining space is defined by each driver as the per-driver
* configuration space */
#define VIRTIO_PCI_CONFIG(dev) (msix_enabled(dev) ? \
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 90eedd3..301b83f 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -1033,7 +1033,8 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
int i, ret;
int32_t config_len;
uint32_t num;
- uint32_t features;
+ uint32_t features_lo, features_hi;
+ uint64_t features;
uint64_t supported_features;
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
@@ -1057,12 +1058,16 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
if (vdev->queue_sel >= VIRTIO_PCI_QUEUE_MAX) {
return -1;
}
- qemu_get_be32s(f, &features);
+ qemu_get_be32s(f, &features_lo);
+
+ //if (features_lo & (1UL << VIRTIO_F_VERSION_1)) {
+ qemu_get_be32s(f, &features_hi);
+ //}
+ features = (((uint64_t)features_hi) << 32) | features_lo;
- /* XXX features >= 32 */
if (__virtio_set_features(vdev, features) < 0) {
supported_features = k->get_features(qbus->parent);
- error_report("Features 0x%x unsupported. Allowed features: 0x%lx",
+ error_report("Features 0x%"PRIx64" unsupported. Allowed features: 0x%"PRIx64,
features, supported_features);
return -1;
}
--
MST
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH RFC 3/3] virtio-pci: initial virtio 1.0 support
2014-12-30 16:28 [Qemu-devel] [PATCH RFC 0/3] virtio-pci: towards virtio 1.0 host support Michael S. Tsirkin
2014-12-30 16:28 ` [Qemu-devel] [PATCH RFC 1/3] linux-headers: add virtio_pci Michael S. Tsirkin
2014-12-30 16:28 ` [Qemu-devel] [PATCH RFC 2/3] virtio: misc fixes, include linux header Michael S. Tsirkin
@ 2014-12-30 16:28 ` Michael S. Tsirkin
2 siblings, 0 replies; 5+ messages in thread
From: Michael S. Tsirkin @ 2014-12-30 16:28 UTC (permalink / raw)
To: qemu-devel; +Cc: cornelia.huck, Rusty Russell, Anthony Liguori
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 <cornelia.huck@de.ibm.com>
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 <cornelia.huck@de.ibm.com>
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 <mst@redhat.com>
---
hw/virtio/virtio-pci.h | 16 +++
hw/virtio/virtio-pci.c | 375 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 391 insertions(+)
diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
index 85f102d..2cddd6a 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -88,10 +88,26 @@ 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;
uint64_t host_features;
+ 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_PCI_QUEUE_MAX];
+
bool ioeventfd_disabled;
bool ioeventfd_started;
VirtIOIRQFD *vector_irqfd;
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index bc11d3d..51c33c5 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -959,6 +959,275 @@ static const TypeInfo virtio_9p_pci_info = {
* virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
*/
+static void virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy,
+ struct virtio_pci_cap *cap)
+{
+ PCIDevice *dev = &proxy->pci_dev;
+ int offset;
+
+ cap->type_and_bar |= 2 << VIRTIO_PCI_CAP_BAR_SHIFT;
+
+ 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 = proxy->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_PCI_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_PCI_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_PCI_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)
{
@@ -976,6 +1245,111 @@ static void virtio_pci_device_plugged(DeviceState *d)
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 = {
+ .type_and_bar = VIRTIO_PCI_CAP_COMMON_CFG,
+ .cap_len = sizeof common,
+ .offset = cpu_to_le32(0x0),
+ .length = cpu_to_le32(0x1000),
+ };
+ struct virtio_pci_cap isr = {
+ .type_and_bar = VIRTIO_PCI_CAP_ISR_CFG,
+ .cap_len = sizeof isr,
+ .offset = cpu_to_le32(0x1000),
+ .length = cpu_to_le32(0x1000),
+ };
+ struct virtio_pci_cap device = {
+ .type_and_bar = 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.type_and_bar = 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_PCI_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(&proxy->host_features, VIRTIO_F_VERSION_1);
+ memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci",
+ 2 * QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
+ VIRTIO_PCI_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_PCI_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,
@@ -993,6 +1367,7 @@ static void virtio_pci_device_plugged(DeviceState *d)
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);
--
MST
^ permalink raw reply related [flat|nested] 5+ messages in thread