]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/s390/kvm/kvm_virtio.c
virtio: Add transport feature handling stub for virtio_ring.
[linux-2.6-omap-h63xx.git] / drivers / s390 / kvm / kvm_virtio.c
index 47a7e6200b262f660c4471cc8c23bfccd32203c2..79954bd6bfa5a02b963e6c2868c9c5ad22bed5af 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/err.h>
 #include <linux/virtio.h>
 #include <linux/virtio_config.h>
+#include <linux/virtio_console.h>
 #include <linux/interrupt.h>
 #include <linux/virtio_ring.h>
 #include <linux/pfn.h>
  */
 static void *kvm_devices;
 
-/*
- * Unique numbering for kvm devices.
- */
-static unsigned int dev_index;
-
 struct kvm_device {
        struct virtio_device vdev;
        struct kvm_device_desc *desc;
@@ -78,27 +74,36 @@ static unsigned desc_size(const struct kvm_device_desc *desc)
                + desc->config_len;
 }
 
-/*
- * This tests (and acknowleges) a feature bit.
- */
-static bool kvm_feature(struct virtio_device *vdev, unsigned fbit)
+/* This gets the device's feature bits. */
+static u32 kvm_get_features(struct virtio_device *vdev)
 {
+       unsigned int i;
+       u32 features = 0;
        struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
-       u8 *features;
+       u8 *in_features = kvm_vq_features(desc);
 
-       if (fbit / 8 > desc->feature_len)
-               return false;
+       for (i = 0; i < min(desc->feature_len * 8, 32); i++)
+               if (in_features[i / 8] & (1 << (i % 8)))
+                       features |= (1 << i);
+       return features;
+}
 
-       features = kvm_vq_features(desc);
-       if (!(features[fbit / 8] & (1 << (fbit % 8))))
-               return false;
+static void kvm_finalize_features(struct virtio_device *vdev)
+{
+       unsigned int i, bits;
+       struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
+       /* Second half of bitmap is features we accept. */
+       u8 *out_features = kvm_vq_features(desc) + desc->feature_len;
 
-       /*
-        * We set the matching bit in the other half of the bitmap to tell the
-        * Host we want to use this feature.
-        */
-       features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8));
-       return true;
+       /* Give virtio_ring a chance to accept features. */
+       vring_transport_features(vdev);
+
+       memset(out_features, 0, desc->feature_len);
+       bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
+       for (i = 0; i < bits; i++) {
+               if (test_bit(i, vdev->features))
+                       out_features[i / 8] |= (1 << (i % 8));
+       }
 }
 
 /*
@@ -221,7 +226,8 @@ static void kvm_del_vq(struct virtqueue *vq)
  * The config ops structure as defined by virtio config
  */
 static struct virtio_config_ops kvm_vq_configspace_ops = {
-       .feature = kvm_feature,
+       .get_features = kvm_get_features,
+       .finalize_features = kvm_finalize_features,
        .get = kvm_get,
        .set = kvm_set,
        .get_status = kvm_get_status,
@@ -244,26 +250,25 @@ static struct device kvm_root = {
  * adds a new device and register it with virtio
  * appropriate drivers are loaded by the device model
  */
-static void add_kvm_device(struct kvm_device_desc *d)
+static void add_kvm_device(struct kvm_device_desc *d, unsigned int offset)
 {
        struct kvm_device *kdev;
 
        kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
        if (!kdev) {
-               printk(KERN_EMERG "Cannot allocate kvm dev %u\n",
-                      dev_index++);
+               printk(KERN_EMERG "Cannot allocate kvm dev %u type %u\n",
+                      offset, d->type);
                return;
        }
 
        kdev->vdev.dev.parent = &kvm_root;
-       kdev->vdev.index = dev_index++;
        kdev->vdev.id.device = d->type;
        kdev->vdev.config = &kvm_vq_configspace_ops;
        kdev->desc = d;
 
        if (register_virtio_device(&kdev->vdev) != 0) {
-               printk(KERN_ERR "Failed to register kvm device %u\n",
-                      kdev->vdev.index);
+               printk(KERN_ERR "Failed to register kvm device %u type %u\n",
+                      offset, d->type);
                kfree(kdev);
        }
 }
@@ -283,7 +288,7 @@ static void scan_devices(void)
                if (d->type == 0)
                        break;
 
-               add_kvm_device(d);
+               add_kvm_device(d, i);
        }
 }
 
@@ -333,6 +338,25 @@ static int __init kvm_devices_init(void)
        return 0;
 }
 
+/* code for early console output with virtio_console */
+static __init int early_put_chars(u32 vtermno, const char *buf, int count)
+{
+       char scratch[17];
+       unsigned int len = count;
+
+       if (len > sizeof(scratch) - 1)
+               len = sizeof(scratch) - 1;
+       scratch[len] = '\0';
+       memcpy(scratch, buf, len);
+       kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, __pa(scratch));
+       return len;
+}
+
+void s390_virtio_console_init(void)
+{
+       virtio_cons_early_init(early_put_chars);
+}
+
 /*
  * We do this after core stuff, but before the drivers.
  */