]> xenbits.xensource.com Git - qemu-xen.git/commitdiff
virtio: add features as qdev properties
authorMichael S. Tsirkin <mst@redhat.com>
Sun, 10 Jan 2010 11:52:53 +0000 (13:52 +0200)
committerAnthony Liguori <aliguori@us.ibm.com>
Mon, 11 Jan 2010 19:40:59 +0000 (13:40 -0600)
Add feature bits as properties to virtio. This makes it possible to e.g. define
machine without indirect buffer support, which is required for 0.10
compatibility, or without hardware checksum support, which is required for 0.11
compatibility.  Since default values for optional features are now set by qdev,
get_features callback has been modified: it sets non-optional bits, and clears
bits not supported by host.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
12 files changed:
hw/s390-virtio-bus.c
hw/s390-virtio-bus.h
hw/syborg_virtio.c
hw/virtio-balloon.c
hw/virtio-blk.c
hw/virtio-blk.h
hw/virtio-console.c
hw/virtio-net.c
hw/virtio-net.h
hw/virtio-pci.c
hw/virtio.c
hw/virtio.h

index 6c0da11f73b820ffa7491817fe6215be7d5f6bbd..980e7ebbe80545c638d01b2c43706c5cd9e59f6c 100644 (file)
@@ -101,6 +101,7 @@ static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev)
     bus->dev_offs += dev_len;
 
     virtio_bind_device(vdev, &virtio_s390_bindings, dev);
+    dev->host_features = vdev->get_features(vdev, dev->host_features);
     s390_virtio_device_sync(dev);
 
     return 0;
@@ -222,9 +223,7 @@ static void s390_virtio_device_sync(VirtIOS390Device *dev)
     cur_offs += num_vq * VIRTIO_VQCONFIG_LEN;
 
     /* Sync feature bitmap */
-    if (dev->vdev->get_features) {
-        stl_phys(cur_offs, dev->vdev->get_features(dev->vdev));
-    }
+    stl_phys(cur_offs, dev->host_features);
 
     dev->feat_offs = cur_offs + dev->feat_len;
     cur_offs += dev->feat_len * 2;
@@ -310,10 +309,17 @@ static void virtio_s390_notify(void *opaque, uint16_t vector)
     kvm_s390_virtio_irq(s390_cpu_addr2state(0), 0, token);
 }
 
+static unsigned virtio_s390_get_features(void *opaque)
+{
+    VirtIOS390Device *dev = (VirtIOS390Device*)opaque;
+    return dev->host_features;
+}
+
 /**************** S390 Virtio Bus Device Descriptions *******************/
 
 static const VirtIOBindings virtio_s390_bindings = {
     .notify = virtio_s390_notify,
+    .get_features = virtio_s390_get_features,
 };
 
 static VirtIOS390DeviceInfo s390_virtio_net = {
index ef3671421a572551ae865e7caf7ba852b3a6420f..8ae206563e512ff9f0c971204ce8baa9b57c5b53 100644 (file)
@@ -40,6 +40,7 @@ typedef struct VirtIOS390Device {
     VirtIODevice *vdev;
     DriveInfo *dinfo;
     NICConf nic;
+    uint32_t host_features;
 } VirtIOS390Device;
 
 typedef struct VirtIOS390Bus {
index fe6fc23ecd9365328f963548ccbd1810961ff961..65239a0572f1b73f0f9b11a25f2405060c003d59 100644 (file)
@@ -25,6 +25,7 @@
 #include "syborg.h"
 #include "sysbus.h"
 #include "virtio.h"
+#include "virtio-net.h"
 #include "sysemu.h"
 
 //#define DEBUG_SYBORG_VIRTIO
@@ -66,6 +67,7 @@ typedef struct {
     uint32_t int_enable;
     uint32_t id;
     NICConf nic;
+    uint32_t host_features;
 } SyborgVirtIOProxy;
 
 static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
@@ -86,8 +88,7 @@ static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
         ret = s->id;
         break;
     case SYBORG_VIRTIO_HOST_FEATURES:
-        ret = vdev->get_features(vdev);
-        ret |= vdev->binding->get_features(s);
+        ret = s->host_features;
         break;
     case SYBORG_VIRTIO_GUEST_FEATURES:
         ret = vdev->guest_features;
@@ -244,9 +245,8 @@ static void syborg_virtio_update_irq(void *opaque, uint16_t vector)
 
 static unsigned syborg_virtio_get_features(void *opaque)
 {
-    unsigned ret = 0;
-    ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
-    return ret;
+    SyborgVirtIOProxy *proxy = opaque;
+    return proxy->host_features;
 }
 
 static VirtIOBindings syborg_virtio_bindings = {
@@ -272,6 +272,8 @@ static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev)
     qemu_register_reset(virtio_reset, vdev);
 
     virtio_bind_device(vdev, &syborg_virtio_bindings, proxy);
+    proxy->host_features |= (0x1 << VIRTIO_F_NOTIFY_ON_EMPTY);
+    proxy->host_features = vdev->get_features(vdev, proxy->host_features);
     return 0;
 }
 
@@ -292,6 +294,7 @@ static SysBusDeviceInfo syborg_virtio_net_info = {
     .qdev.size  = sizeof(SyborgVirtIOProxy),
     .qdev.props = (Property[]) {
         DEFINE_NIC_PROPERTIES(SyborgVirtIOProxy, nic),
+        DEFINE_VIRTIO_NET_FEATURES(SyborgVirtIOProxy, host_features),
         DEFINE_PROP_END_OF_LIST(),
     }
 };
index cfd3b413ff4f66aebad41a73eecd7622faabb42e..e17880ff7c3a9ca0ab6feafd9e8a045cc39f85d3 100644 (file)
@@ -124,9 +124,9 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
     dev->actual = config.actual;
 }
 
-static uint32_t virtio_balloon_get_features(VirtIODevice *vdev)
+static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
 {
-    return 0;
+    return f;
 }
 
 static ram_addr_t virtio_balloon_to_target(void *opaque, ram_addr_t target)
index a2f063974ab88f7917634262128fbf6864addf39..cb1ae1f953cb90aff4ccf0673b28b41044c8a6eb 100644 (file)
@@ -432,19 +432,15 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
     memcpy(config, &blkcfg, s->config_size);
 }
 
-static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
+static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
 {
     VirtIOBlock *s = to_virtio_blk(vdev);
-    uint32_t features = 0;
 
     features |= (1 << VIRTIO_BLK_F_SEG_MAX);
     features |= (1 << VIRTIO_BLK_F_GEOMETRY);
 
     if (bdrv_enable_write_cache(s->bs))
         features |= (1 << VIRTIO_BLK_F_WCACHE);
-#ifdef __linux__
-    features |= (1 << VIRTIO_BLK_F_SCSI);
-#endif
     if (strcmp(s->serial_str, "0"))
         features |= 1 << VIRTIO_BLK_F_IDENTIFY;
     
index 23ad74caec22c5679fcb3a895249560327d7f0bc..c28f776c2eb4cd025b373820fc6aaf0806fb9e2b 100644 (file)
@@ -92,4 +92,12 @@ struct virtio_scsi_inhdr
     uint32_t residual;
 };
 
+#ifdef __linux__
+#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
+        DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \
+        DEFINE_PROP_BIT("scsi", _state, _field, VIRTIO_BLK_F_SCSI, true)
+#else
+#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
+        DEFINE_VIRTIO_COMMON_FEATURES(_state, _field)
+#endif
 #endif
index 57f8f89afaf620edb0d0076a887b38d82b7eaeea..4f18ef29cb791ba264dbc88c94cc00c754f46092 100644 (file)
@@ -51,9 +51,9 @@ static void virtio_console_handle_input(VirtIODevice *vdev, VirtQueue *vq)
 {
 }
 
-static uint32_t virtio_console_get_features(VirtIODevice *vdev)
+static uint32_t virtio_console_get_features(VirtIODevice *vdev, uint32_t f)
 {
-    return 0;
+    return f;
 }
 
 static int vcon_can_read(void *opaque)
index ab20a33e21c11c49c45ef14acf2219aec60fbdb8..c2a389ffb579487c5fa86025d4a3adb3efcfe437 100644 (file)
@@ -147,34 +147,27 @@ static int peer_has_ufo(VirtIONet *n)
     return n->has_ufo;
 }
 
-static uint32_t virtio_net_get_features(VirtIODevice *vdev)
+static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
 {
     VirtIONet *n = to_virtio_net(vdev);
-    uint32_t features = (1 << VIRTIO_NET_F_MAC) |
-                        (1 << VIRTIO_NET_F_MRG_RXBUF) |
-                        (1 << VIRTIO_NET_F_STATUS) |
-                        (1 << VIRTIO_NET_F_CTRL_VQ) |
-                        (1 << VIRTIO_NET_F_CTRL_RX) |
-                        (1 << VIRTIO_NET_F_CTRL_VLAN) |
-                        (1 << VIRTIO_NET_F_CTRL_RX_EXTRA);
 
     if (peer_has_vnet_hdr(n)) {
         tap_using_vnet_hdr(n->nic->nc.peer, 1);
+    } else {
+        features &= ~(0x1 << VIRTIO_NET_F_CSUM);
+        features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO4);
+        features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO6);
+        features &= ~(0x1 << VIRTIO_NET_F_HOST_ECN);
+
+        features &= ~(0x1 << VIRTIO_NET_F_GUEST_CSUM);
+        features &= ~(0x1 << VIRTIO_NET_F_GUEST_TSO4);
+        features &= ~(0x1 << VIRTIO_NET_F_GUEST_TSO6);
+        features &= ~(0x1 << VIRTIO_NET_F_GUEST_ECN);
+    }
 
-        features |= (1 << VIRTIO_NET_F_CSUM);
-        features |= (1 << VIRTIO_NET_F_HOST_TSO4);
-        features |= (1 << VIRTIO_NET_F_HOST_TSO6);
-        features |= (1 << VIRTIO_NET_F_HOST_ECN);
-
-        features |= (1 << VIRTIO_NET_F_GUEST_CSUM);
-        features |= (1 << VIRTIO_NET_F_GUEST_TSO4);
-        features |= (1 << VIRTIO_NET_F_GUEST_TSO6);
-        features |= (1 << VIRTIO_NET_F_GUEST_ECN);
-
-        if (peer_has_ufo(n)) {
-            features |= (1 << VIRTIO_NET_F_GUEST_UFO);
-            features |= (1 << VIRTIO_NET_F_HOST_UFO);
-        }
+    if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) {
+        features &= ~(0x1 << VIRTIO_NET_F_GUEST_UFO);
+        features &= ~(0x1 << VIRTIO_NET_F_HOST_UFO);
     }
 
     return features;
@@ -192,7 +185,7 @@ static uint32_t virtio_net_bad_features(VirtIODevice *vdev)
     features |= (1 << VIRTIO_NET_F_HOST_TSO6);
     features |= (1 << VIRTIO_NET_F_HOST_ECN);
 
-    return features & virtio_net_get_features(vdev);
+    return features;
 }
 
 static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features)
index 2085181673066dd2abac4e5ac5594cecd1bf8420..9130d75c939d98f8b8de7b60797e954cb8a77579 100644 (file)
@@ -153,4 +153,24 @@ struct virtio_net_ctrl_mac {
  #define VIRTIO_NET_CTRL_VLAN_ADD             0
  #define VIRTIO_NET_CTRL_VLAN_DEL             1
 
+#define DEFINE_VIRTIO_NET_FEATURES(_state, _field) \
+        DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \
+        DEFINE_PROP_BIT("csum", _state, _field, VIRTIO_NET_F_CSUM, true), \
+        DEFINE_PROP_BIT("guest_csum", _state, _field, VIRTIO_NET_F_GUEST_CSUM, true), \
+        DEFINE_PROP_BIT("mac", _state, _field, VIRTIO_NET_F_MAC, true), \
+        DEFINE_PROP_BIT("gso", _state, _field, VIRTIO_NET_F_GSO, true), \
+        DEFINE_PROP_BIT("guest_tso4", _state, _field, VIRTIO_NET_F_GUEST_TSO4, true), \
+        DEFINE_PROP_BIT("guest_tso6", _state, _field, VIRTIO_NET_F_GUEST_TSO6, true), \
+        DEFINE_PROP_BIT("guest_ecn", _state, _field, VIRTIO_NET_F_GUEST_ECN, true), \
+        DEFINE_PROP_BIT("guest_ufo", _state, _field, VIRTIO_NET_F_GUEST_UFO, true), \
+        DEFINE_PROP_BIT("host_tso4", _state, _field, VIRTIO_NET_F_HOST_TSO4, true), \
+        DEFINE_PROP_BIT("host_tso6", _state, _field, VIRTIO_NET_F_HOST_TSO6, true), \
+        DEFINE_PROP_BIT("host_ecn", _state, _field, VIRTIO_NET_F_HOST_ECN, true), \
+        DEFINE_PROP_BIT("host_ufo", _state, _field, VIRTIO_NET_F_HOST_UFO, true), \
+        DEFINE_PROP_BIT("mrg_rxbuf", _state, _field, VIRTIO_NET_F_MRG_RXBUF, true), \
+        DEFINE_PROP_BIT("status", _state, _field, VIRTIO_NET_F_STATUS, true), \
+        DEFINE_PROP_BIT("ctrl_vq", _state, _field, VIRTIO_NET_F_CTRL_VQ, true), \
+        DEFINE_PROP_BIT("ctrl_rx", _state, _field, VIRTIO_NET_F_CTRL_RX, true), \
+        DEFINE_PROP_BIT("ctrl_vlan", _state, _field, VIRTIO_NET_F_CTRL_VLAN, true), \
+        DEFINE_PROP_BIT("ctrl_rx_extra", _state, _field, VIRTIO_NET_F_CTRL_RX_EXTRA, true)
 #endif
index 4e1d5e196352a81c82f3ea7980fbc5a4b6a2bf6d..6d0f9dd37a02b91b1ed5fe02d065ca026ba93fc6 100644 (file)
@@ -16,6 +16,8 @@
 #include <inttypes.h>
 
 #include "virtio.h"
+#include "virtio-blk.h"
+#include "virtio-net.h"
 #include "pci.h"
 #include "sysemu.h"
 #include "msix.h"
@@ -92,6 +94,7 @@ typedef struct {
     uint32_t nvectors;
     DriveInfo *dinfo;
     NICConf nic;
+    uint32_t host_features;
 } VirtIOPCIProxy;
 
 /* virtio device */
@@ -175,7 +178,7 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
        /* Guest does not negotiate properly?  We have to assume nothing. */
        if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
            if (vdev->bad_features)
-               val = vdev->bad_features(vdev);
+               val = proxy->host_features & vdev->bad_features(vdev);
            else
                val = 0;
        }
@@ -235,8 +238,7 @@ static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
 
     switch (addr) {
     case VIRTIO_PCI_HOST_FEATURES:
-        ret = vdev->get_features(vdev);
-        ret |= vdev->binding->get_features(proxy);
+        ret = proxy->host_features;
         break;
     case VIRTIO_PCI_GUEST_FEATURES:
         ret = vdev->guest_features;
@@ -382,11 +384,8 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
 
 static unsigned virtio_pci_get_features(void *opaque)
 {
-    unsigned ret = 0;
-    ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
-    ret |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
-    ret |= (1 << VIRTIO_F_BAD_FEATURE);
-    return ret;
+    VirtIOPCIProxy *proxy = opaque;
+    return proxy->host_features;
 }
 
 static const VirtIOBindings virtio_pci_bindings = {
@@ -442,6 +441,9 @@ static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
                            virtio_map);
 
     virtio_bind_device(vdev, &virtio_pci_bindings, proxy);
+    proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
+    proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
+    proxy->host_features = vdev->get_features(vdev, proxy->host_features);
 }
 
 static int virtio_blk_init_pci(PCIDevice *pci_dev)
@@ -553,6 +555,7 @@ static PCIDeviceInfo virtio_info[] = {
             DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
             DEFINE_PROP_DRIVE("drive", VirtIOPCIProxy, dinfo),
             DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+            DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
             DEFINE_PROP_END_OF_LIST(),
         },
         .qdev.reset = virtio_pci_reset,
@@ -564,6 +567,7 @@ static PCIDeviceInfo virtio_info[] = {
         .romfile    = "pxe-virtio.bin",
         .qdev.props = (Property[]) {
             DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
+            DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
             DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
             DEFINE_PROP_END_OF_LIST(),
         },
@@ -575,6 +579,7 @@ static PCIDeviceInfo virtio_info[] = {
         .exit      = virtio_exit_pci,
         .qdev.props = (Property[]) {
             DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
+            DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
             DEFINE_PROP_END_OF_LIST(),
         },
         .qdev.reset = virtio_pci_reset,
@@ -583,6 +588,10 @@ static PCIDeviceInfo virtio_info[] = {
         .qdev.size = sizeof(VirtIOPCIProxy),
         .init      = virtio_balloon_init_pci,
         .exit      = virtio_exit_pci,
+        .qdev.props = (Property[]) {
+            DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+            DEFINE_PROP_END_OF_LIST(),
+        },
         .qdev.reset = virtio_pci_reset,
     },{
         /* end of list */
index c25a5f12bbfbffe4262b3ce2518b2fa78205daf3..fa7184ab95e4d2d37e397c92cdc9f74abb4ec975 100644 (file)
@@ -652,7 +652,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
 {
     int num, i, ret;
     uint32_t features;
-    uint32_t supported_features = vdev->get_features(vdev) |
+    uint32_t supported_features =
         vdev->binding->get_features(vdev->binding_opaque);
 
     if (vdev->binding->load_config) {
index 85ef171248a4ce96aed1b9f02c4576b7d630e960..3994cc973ff456f1280c1b2cde1c1fa865b71f65 100644 (file)
@@ -105,7 +105,7 @@ struct VirtIODevice
     void *config;
     uint16_t config_vector;
     int nvectors;
-    uint32_t (*get_features)(VirtIODevice *vdev);
+    uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features);
     uint32_t (*bad_features)(VirtIODevice *vdev);
     void (*set_features)(VirtIODevice *vdev, uint32_t val);
     void (*get_config)(VirtIODevice *vdev, uint8_t *config);
@@ -176,4 +176,9 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev);
 
 void virtio_net_exit(VirtIODevice *vdev);
 
+#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
+       DEFINE_PROP_BIT("indirect_desc", _state, _field, \
+                       VIRTIO_RING_F_INDIRECT_DESC, true)
+
+
 #endif