diff options
| -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 | /* |
