diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2012-12-14 11:02:16 -0500 |
---|---|---|
committer | Gleb Natapov <gleb@redhat.com> | 2012-12-18 07:36:38 -0500 |
commit | 55c171a6d90dc0574021f9c836127cfd1a7d2e30 (patch) | |
tree | b13fae2636784f86aecf148beeb353bc21ac2531 /drivers/s390 | |
parent | d4b06c2d4cce466e2d62163c0a954e1b2ce96f8b (diff) |
KVM: s390: Handle hosts not supporting s390-virtio.
Running under a kvm host does not necessarily imply the presence of
a page mapped above the main memory with the virtio information;
however, the code includes a hard coded access to that page.
Instead, check for the presence of the page and exit gracefully
before we hit an addressing exception if it does not exist.
Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com>
Reviewed-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
cc: stable@vger.kernel.org
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/kvm/kvm_virtio.c | 38 |
1 files changed, 30 insertions, 8 deletions
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 7dabef624da3..b846b6c4130a 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c | |||
@@ -422,6 +422,26 @@ static void kvm_extint_handler(struct ext_code ext_code, | |||
422 | } | 422 | } |
423 | 423 | ||
424 | /* | 424 | /* |
425 | * For s390-virtio, we expect a page above main storage containing | ||
426 | * the virtio configuration. Try to actually load from this area | ||
427 | * in order to figure out if the host provides this page. | ||
428 | */ | ||
429 | static int __init test_devices_support(unsigned long addr) | ||
430 | { | ||
431 | int ret = -EIO; | ||
432 | |||
433 | asm volatile( | ||
434 | "0: lura 0,%1\n" | ||
435 | "1: xgr %0,%0\n" | ||
436 | "2:\n" | ||
437 | EX_TABLE(0b,2b) | ||
438 | EX_TABLE(1b,2b) | ||
439 | : "+d" (ret) | ||
440 | : "a" (addr) | ||
441 | : "0", "cc"); | ||
442 | return ret; | ||
443 | } | ||
444 | /* | ||
425 | * Init function for virtio | 445 | * Init function for virtio |
426 | * devices are in a single page above top of "normal" mem | 446 | * devices are in a single page above top of "normal" mem |
427 | */ | 447 | */ |
@@ -432,21 +452,23 @@ static int __init kvm_devices_init(void) | |||
432 | if (!MACHINE_IS_KVM) | 452 | if (!MACHINE_IS_KVM) |
433 | return -ENODEV; | 453 | return -ENODEV; |
434 | 454 | ||
455 | if (test_devices_support(real_memory_size) < 0) | ||
456 | return -ENODEV; | ||
457 | |||
458 | rc = vmem_add_mapping(real_memory_size, PAGE_SIZE); | ||
459 | if (rc) | ||
460 | return rc; | ||
461 | |||
462 | kvm_devices = (void *) real_memory_size; | ||
463 | |||
435 | kvm_root = root_device_register("kvm_s390"); | 464 | kvm_root = root_device_register("kvm_s390"); |
436 | if (IS_ERR(kvm_root)) { | 465 | if (IS_ERR(kvm_root)) { |
437 | rc = PTR_ERR(kvm_root); | 466 | rc = PTR_ERR(kvm_root); |
438 | printk(KERN_ERR "Could not register kvm_s390 root device"); | 467 | printk(KERN_ERR "Could not register kvm_s390 root device"); |
468 | vmem_remove_mapping(real_memory_size, PAGE_SIZE); | ||
439 | return rc; | 469 | return rc; |
440 | } | 470 | } |
441 | 471 | ||
442 | rc = vmem_add_mapping(real_memory_size, PAGE_SIZE); | ||
443 | if (rc) { | ||
444 | root_device_unregister(kvm_root); | ||
445 | return rc; | ||
446 | } | ||
447 | |||
448 | kvm_devices = (void *) real_memory_size; | ||
449 | |||
450 | INIT_WORK(&hotplug_work, hotplug_devices); | 472 | INIT_WORK(&hotplug_work, hotplug_devices); |
451 | 473 | ||
452 | service_subclass_irq_register(); | 474 | service_subclass_irq_register(); |