diff options
author | Alexander Graf <agraf@suse.de> | 2010-08-24 09:48:51 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-10-24 04:51:29 -0400 |
commit | cefa33e2f8f7852abb42f22ec25a6084a931c5ac (patch) | |
tree | 6944f5afe499955b69316cf7b3f62e7464028dd3 /drivers/s390 | |
parent | fc678d67fee1acccf21322318dd833b892a572e4 (diff) |
KVM: S390: Add virtio hotplug add support
The one big missing feature in s390-virtio was hotplugging. This is no more.
This patch implements hotplug add support, so you can on the fly add new devices
in the guest.
Keep in mind that this needs a patch for qemu to actually leverage the
functionality.
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/kvm/kvm_virtio.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 68cef4da15e8..5a46b8c5d68a 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c | |||
@@ -32,6 +32,7 @@ | |||
32 | * The pointer to our (page) of device descriptions. | 32 | * The pointer to our (page) of device descriptions. |
33 | */ | 33 | */ |
34 | static void *kvm_devices; | 34 | static void *kvm_devices; |
35 | struct work_struct hotplug_work; | ||
35 | 36 | ||
36 | struct kvm_device { | 37 | struct kvm_device { |
37 | struct virtio_device vdev; | 38 | struct virtio_device vdev; |
@@ -328,6 +329,47 @@ static void scan_devices(void) | |||
328 | } | 329 | } |
329 | 330 | ||
330 | /* | 331 | /* |
332 | * match for a kvm device with a specific desc pointer | ||
333 | */ | ||
334 | static int match_desc(struct device *dev, void *data) | ||
335 | { | ||
336 | if ((ulong)to_kvmdev(dev_to_virtio(dev))->desc == (ulong)data) | ||
337 | return 1; | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | /* | ||
343 | * hotplug_device tries to find changes in the device page. | ||
344 | */ | ||
345 | static void hotplug_devices(struct work_struct *dummy) | ||
346 | { | ||
347 | unsigned int i; | ||
348 | struct kvm_device_desc *d; | ||
349 | struct device *dev; | ||
350 | |||
351 | for (i = 0; i < PAGE_SIZE; i += desc_size(d)) { | ||
352 | d = kvm_devices + i; | ||
353 | |||
354 | /* end of list */ | ||
355 | if (d->type == 0) | ||
356 | break; | ||
357 | |||
358 | /* device already exists */ | ||
359 | dev = device_find_child(kvm_root, d, match_desc); | ||
360 | if (dev) { | ||
361 | /* XXX check for hotplug remove */ | ||
362 | put_device(dev); | ||
363 | continue; | ||
364 | } | ||
365 | |||
366 | /* new device */ | ||
367 | printk(KERN_INFO "Adding new virtio device %p\n", d); | ||
368 | add_kvm_device(d, i); | ||
369 | } | ||
370 | } | ||
371 | |||
372 | /* | ||
331 | * we emulate the request_irq behaviour on top of s390 extints | 373 | * we emulate the request_irq behaviour on top of s390 extints |
332 | */ | 374 | */ |
333 | static void kvm_extint_handler(u16 code) | 375 | static void kvm_extint_handler(u16 code) |
@@ -357,6 +399,9 @@ static void kvm_extint_handler(u16 code) | |||
357 | 399 | ||
358 | break; | 400 | break; |
359 | } | 401 | } |
402 | case VIRTIO_PARAM_DEV_ADD: | ||
403 | schedule_work(&hotplug_work); | ||
404 | break; | ||
360 | case VIRTIO_PARAM_VRING_INTERRUPT: | 405 | case VIRTIO_PARAM_VRING_INTERRUPT: |
361 | default: | 406 | default: |
362 | vring_interrupt(0, vq); | 407 | vring_interrupt(0, vq); |
@@ -390,6 +435,8 @@ static int __init kvm_devices_init(void) | |||
390 | 435 | ||
391 | kvm_devices = (void *) real_memory_size; | 436 | kvm_devices = (void *) real_memory_size; |
392 | 437 | ||
438 | INIT_WORK(&hotplug_work, hotplug_devices); | ||
439 | |||
393 | ctl_set_bit(0, 9); | 440 | ctl_set_bit(0, 9); |
394 | register_external_interrupt(0x2603, kvm_extint_handler); | 441 | register_external_interrupt(0x2603, kvm_extint_handler); |
395 | 442 | ||