Move the config size calculation from virtio_net_init() to
virtio_common_init() so that all virtio devices can benefit. This requires
that the host_features be passed to virtio_common_init(), and the size of
the config struct will be calculated based on which feature bits are
enabled. This calculation is performed using a per-driver table that maps
each feature bit to the size of the config struct at the time that the
feature was introduced. virtio_common_init() also takes a minimum config
size to use in the case that all feature bits are disabled.

For now, each driver contains a dummy table that uses the full size of the
config struct. These dummy tables will be replaced on a per-driver basis.

Signed-off-by: Jesse Larrew <jlar...@linux.vnet.ibm.com>
---
 hw/9pfs/virtio-9p-device.c | 15 ++++++++++-----
 hw/virtio-balloon.c        | 15 ++++++++++++---
 hw/virtio-blk.c            | 14 +++++++++++---
 hw/virtio-net.c            | 11 +++--------
 hw/virtio-rng.c            |  8 +++++++-
 hw/virtio-scsi.c           | 10 +++++++++-
 hw/virtio-serial-bus.c     | 13 ++++++++++---
 hw/virtio.c                | 13 ++++++++++++-
 hw/virtio.h                |  4 +++-
 9 files changed, 77 insertions(+), 26 deletions(-)

diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 74155fb..24d033b 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -20,6 +20,12 @@
 #include "virtio-9p-xattr.h"
 #include "virtio-9p-coth.h"
 
+static VirtIOFeature feature_sizes[] = {
+    {.flags = 0xffffffff, /* dummy table -- all features included. */
+     .end = endof(struct virtio_9p_config, tag) + MAX_TAG_LEN},
+    {}
+};
+
 static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
 {
     features |= 1 << VIRTIO_9P_MOUNT_TAG;
@@ -54,11 +60,10 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf 
*conf)
     FsDriverEntry *fse;
     V9fsPath path;
 
-    s = (V9fsState *)virtio_common_init("virtio-9p",
-                                    VIRTIO_ID_9P,
-                                    sizeof(struct virtio_9p_config)+
-                                    MAX_TAG_LEN,
-                                    sizeof(V9fsState));
+    s = (V9fsState *)virtio_common_init("virtio-9p", VIRTIO_ID_9P,
+                                        host_features, feature_sizes,
+                                        sizeof(struct virtio_9p_config) +
+                                            MAX_TAG_LEN, sizeof(V9fsState));
     /* initialize pdu allocator */
     QLIST_INIT(&s->free_list);
     QLIST_INIT(&s->active_list);
diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 4574db6..81f27e9 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -29,6 +29,12 @@
 #include <sys/mman.h>
 #endif
 
+static VirtIOFeature feature_sizes[] = {
+    {.flags = 0xffffffff, /* dummy table -- all features included. */
+     .end = sizeof(struct virtio_balloon_config)},
+    {}
+};
+
 typedef struct VirtIOBalloon
 {
     VirtIODevice vdev;
@@ -278,7 +284,7 @@ static void virtio_balloon_get_config(VirtIODevice *vdev, 
uint8_t *config_data)
     config.num_pages = cpu_to_le32(dev->num_pages);
     config.actual = cpu_to_le32(dev->actual);
 
-    memcpy(config_data, &config, 8);
+    memcpy(config_data, &config, vdev->config_len);
 }
 
 static void virtio_balloon_set_config(VirtIODevice *vdev,
@@ -287,7 +293,7 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
     VirtIOBalloon *dev = to_virtio_balloon(vdev);
     struct virtio_balloon_config config;
     uint32_t oldactual = dev->actual;
-    memcpy(&config, config_data, 8);
+    memcpy(&config, config_data, vdev->config_len);
     dev->actual = le32_to_cpu(config.actual);
     if (dev->actual != oldactual) {
         qemu_balloon_changed(ram_size -
@@ -356,7 +362,10 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev, 
uint32_t host_features)
 
     s = (VirtIOBalloon *)virtio_common_init("virtio-balloon",
                                             VIRTIO_ID_BALLOON,
-                                            8, sizeof(VirtIOBalloon));
+                                            host_features, feature_sizes,
+                                            endof(struct virtio_balloon_config,
+                                                  actual),
+                                            sizeof(VirtIOBalloon));
 
     s->vdev.get_config = virtio_balloon_get_config;
     s->vdev.set_config = virtio_balloon_set_config;
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index b3ab267..788a4c7 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -25,6 +25,12 @@
 # include <scsi/sg.h>
 #endif
 
+static VirtIOFeature feature_sizes[] = {
+    {.flags = 0xffffffff, /* dummy table -- all features included */
+     .end = sizeof(struct virtio_blk_config)},
+    {}
+};
+
 typedef struct VirtIOBlock
 {
     VirtIODevice vdev;
@@ -531,7 +537,7 @@ static void virtio_blk_update_config(VirtIODevice *vdev, 
uint8_t *config)
     blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
     blkcfg.alignment_offset = 0;
     blkcfg.wce = bdrv_enable_write_cache(s->bs);
-    memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
+    memcpy(config, &blkcfg, vdev->config_len);
 }
 
 static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
@@ -539,7 +545,7 @@ static void virtio_blk_set_config(VirtIODevice *vdev, const 
uint8_t *config)
     VirtIOBlock *s = to_virtio_blk(vdev);
     struct virtio_blk_config blkcfg;
 
-    memcpy(&blkcfg, config, sizeof(blkcfg));
+    memcpy(&blkcfg, config, vdev->config_len);
     bdrv_set_enable_write_cache(s->bs, blkcfg.wce != 0);
 }
 
@@ -660,7 +666,9 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, 
VirtIOBlkConf *blk,
     }
 
     s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK,
-                                          sizeof(struct virtio_blk_config),
+                                          host_features, feature_sizes,
+                                          endof(struct virtio_blk_config,
+                                                blk_size),
                                           sizeof(VirtIOBlock));
 
     s->vdev.get_config = virtio_blk_update_config;
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 78dc97d..302e93b 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -1292,16 +1292,11 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf 
*conf,
                               virtio_net_conf *net, uint32_t host_features)
 {
     VirtIONet *n;
-    int i, config_size = 0;
-
-    for (i = 0; feature_sizes[i].flags != 0; i++) {
-        if (host_features & feature_sizes[i].flags) {
-            config_size = MAX(feature_sizes[i].end, config_size);
-        }
-    }
+    int i;
 
     n = (VirtIONet *)virtio_common_init("virtio-net", VIRTIO_ID_NET,
-                                        config_size, sizeof(VirtIONet));
+                                        host_features, feature_sizes, 0,
+                                        sizeof(VirtIONet));
 
     n->vdev.get_config = virtio_net_get_config;
     n->vdev.set_config = virtio_net_set_config;
diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c
index e063127..c53cc08 100644
--- a/hw/virtio-rng.c
+++ b/hw/virtio-rng.c
@@ -15,6 +15,12 @@
 #include "virtio-rng.h"
 #include "qemu/rng.h"
 
+static VirtIOFeature feature_sizes[] = {
+    {.flags = 0xffffffff, /* dummy table -- all features included. */
+     .end = endof(struct VirtIORNGConf, default_backend)},
+    {}
+};
+
 typedef struct VirtIORNG {
     VirtIODevice vdev;
 
@@ -155,7 +161,7 @@ VirtIODevice *virtio_rng_init(DeviceState *dev, 
VirtIORNGConf *conf)
     VirtIODevice *vdev;
     Error *local_err = NULL;
 
-    vdev = virtio_common_init("virtio-rng", VIRTIO_ID_RNG, 0,
+    vdev = virtio_common_init("virtio-rng", VIRTIO_ID_RNG, 0, feature_sizes, 0,
                               sizeof(VirtIORNG));
 
     vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index d6db042..6c92975 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -17,6 +17,12 @@
 #include <hw/scsi.h>
 #include <hw/scsi-defs.h>
 
+static VirtIOFeature feature_sizes[] = {
+    {.flags = 0xffffffff,
+     .end = sizeof(struct VirtIOSCSIConf)},
+    {}
+};
+
 #define VIRTIO_SCSI_VQ_SIZE     128
 #define VIRTIO_SCSI_CDB_SIZE    32
 #define VIRTIO_SCSI_SENSE_SIZE  96
@@ -710,7 +716,9 @@ VirtIODevice *virtio_scsi_init(DeviceState *dev, 
VirtIOSCSIConf *proxyconf,
 
     sz = sizeof(VirtIOSCSI) + proxyconf->num_queues * sizeof(VirtQueue *);
     s = (VirtIOSCSI *)virtio_common_init("virtio-scsi", VIRTIO_ID_SCSI,
-                                         sizeof(VirtIOSCSIConfig), sz);
+                                         host_features, feature_sizes,
+                                         endof(struct VirtIOSCSIConf,
+                                             cmd_per_lun), sz);
 
     s->qdev = dev;
     s->conf = proxyconf;
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index d6b588f..9cd9fbd 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -25,6 +25,12 @@
 #include "trace.h"
 #include "virtio-serial.h"
 
+static VirtIOFeature feature_sizes[] = {
+    {.flags = 0xffffffff, /* dummy table -- all features included. */
+     .end = sizeof(struct virtio_console_config)},
+    {}
+};
+
 /* The virtio-serial bus on top of which the ports will ride as devices */
 struct VirtIOSerialBus {
     BusState qbus;
@@ -523,14 +529,14 @@ static void get_config(VirtIODevice *vdev, uint8_t 
*config_data)
     VirtIOSerial *vser;
 
     vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
-    memcpy(config_data, &vser->config, sizeof(struct virtio_console_config));
+    memcpy(config_data, &vser->config, vdev->config_len);
 }
 
 static void set_config(VirtIODevice *vdev, const uint8_t *config_data)
 {
     struct virtio_console_config config;
 
-    memcpy(&config, config_data, sizeof(config));
+    memcpy(&config, config_data, vdev->config_len);
 }
 
 static void guest_reset(VirtIOSerial *vser)
@@ -964,7 +970,8 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, 
virtio_serial_conf *conf,
     }
 
     vdev = virtio_common_init("virtio-serial", VIRTIO_ID_CONSOLE,
-                              sizeof(struct virtio_console_config),
+                              host_features, feature_sizes,
+                              endof(struct virtio_console_config, rows),
                               sizeof(VirtIOSerial));
 
     vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
diff --git a/hw/virtio.c b/hw/virtio.c
index e259348..487fdab 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -948,10 +948,21 @@ void virtio_init(VirtIODevice *vdev, const char *name,
 }
 
 VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
-                                 size_t config_size, size_t struct_size)
+                                 uint32_t host_features,
+                                 const VirtIOFeature *feature_table,
+                                 size_t min_config_size, size_t struct_size)
 {
+    int i, config_size = min_config_size;
     VirtIODevice *vdev;
+
     vdev = g_malloc0(struct_size);
+
+    for (i = 0; feature_table && feature_table[i].flags != 0; i++) {
+        if (host_features & feature_table[i].flags) {
+            config_size = MAX(feature_table[i].end, config_size);
+        }
+    }
+
     virtio_init(vdev, name, device_id, config_size);
     return vdev;
 }
diff --git a/hw/virtio.h b/hw/virtio.h
index 17ce9c8..f3b7e28 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -229,7 +229,9 @@ int virtio_queue_empty(VirtQueue *vq);
 /* Host binding interface.  */
 
 VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
-                                 size_t config_size, size_t struct_size);
+                                 uint32_t host_features,
+                                 const VirtIOFeature *feature_table,
+                                 size_t min_config_size, size_t struct_size);
 uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr);
 uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr);
 uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr);
-- 
1.7.11.7


Reply via email to