]> Pileus Git - ~andy/linux/blobdiff - drivers/s390/kvm/kvm_virtio.c
Merge tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[~andy/linux] / drivers / s390 / kvm / kvm_virtio.c
index 7d08fba7542dd756ea410b1afedd6eaa7d599334..6711e65764b5e7a4482564014ac6aa0e78189242 100644 (file)
@@ -421,6 +421,26 @@ static void kvm_extint_handler(struct ext_code ext_code,
        }
 }
 
+/*
+ * For s390-virtio, we expect a page above main storage containing
+ * the virtio configuration. Try to actually load from this area
+ * in order to figure out if the host provides this page.
+ */
+static int __init test_devices_support(unsigned long addr)
+{
+       int ret = -EIO;
+
+       asm volatile(
+               "0:     lura    0,%1\n"
+               "1:     xgr     %0,%0\n"
+               "2:\n"
+               EX_TABLE(0b,2b)
+               EX_TABLE(1b,2b)
+               : "+d" (ret)
+               : "a" (addr)
+               : "0", "cc");
+       return ret;
+}
 /*
  * Init function for virtio
  * devices are in a single page above top of "normal" mem
@@ -432,21 +452,23 @@ static int __init kvm_devices_init(void)
        if (!MACHINE_IS_KVM)
                return -ENODEV;
 
+       if (test_devices_support(real_memory_size) < 0)
+               return -ENODEV;
+
+       rc = vmem_add_mapping(real_memory_size, PAGE_SIZE);
+       if (rc)
+               return rc;
+
+       kvm_devices = (void *) real_memory_size;
+
        kvm_root = root_device_register("kvm_s390");
        if (IS_ERR(kvm_root)) {
                rc = PTR_ERR(kvm_root);
                printk(KERN_ERR "Could not register kvm_s390 root device");
+               vmem_remove_mapping(real_memory_size, PAGE_SIZE);
                return rc;
        }
 
-       rc = vmem_add_mapping(real_memory_size, PAGE_SIZE);
-       if (rc) {
-               root_device_unregister(kvm_root);
-               return rc;
-       }
-
-       kvm_devices = (void *) real_memory_size;
-
        INIT_WORK(&hotplug_work, hotplug_devices);
 
        service_subclass_irq_register();