diff options
Diffstat (limited to 'drivers/s390/kvm')
-rw-r--r-- | drivers/s390/kvm/kvm_virtio.c | 22 |
1 files changed, 19 insertions, 3 deletions
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 4e8354aa8576..28c90b89f2b4 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c | |||
@@ -299,13 +299,29 @@ static void scan_devices(void) | |||
299 | */ | 299 | */ |
300 | static void kvm_extint_handler(u16 code) | 300 | static void kvm_extint_handler(u16 code) |
301 | { | 301 | { |
302 | void *data = (void *) *(long *) __LC_PFAULT_INTPARM; | 302 | struct virtqueue *vq; |
303 | u16 subcode = S390_lowcore.cpu_addr; | 303 | u16 subcode; |
304 | int config_changed; | ||
304 | 305 | ||
306 | subcode = S390_lowcore.cpu_addr; | ||
305 | if ((subcode & 0xff00) != VIRTIO_SUBCODE_64) | 307 | if ((subcode & 0xff00) != VIRTIO_SUBCODE_64) |
306 | return; | 308 | return; |
307 | 309 | ||
308 | vring_interrupt(0, data); | 310 | /* The LSB might be overloaded, we have to mask it */ |
311 | vq = (struct virtqueue *) ((*(long *) __LC_PFAULT_INTPARM) & ~1UL); | ||
312 | |||
313 | /* We use the LSB of extparam, to decide, if this interrupt is a config | ||
314 | * change or a "standard" interrupt */ | ||
315 | config_changed = (*(int *) __LC_EXT_PARAMS & 1); | ||
316 | |||
317 | if (config_changed) { | ||
318 | struct virtio_driver *drv; | ||
319 | drv = container_of(vq->vdev->dev.driver, | ||
320 | struct virtio_driver, driver); | ||
321 | if (drv->config_changed) | ||
322 | drv->config_changed(vq->vdev); | ||
323 | } else | ||
324 | vring_interrupt(0, vq); | ||
309 | } | 325 | } |
310 | 326 | ||
311 | /* | 327 | /* |