aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/s390/kvm/kvm_virtio.c22
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 */
300static void kvm_extint_handler(u16 code) 300static 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/*