aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorChristian Borntraeger <borntraeger@de.ibm.com>2008-11-18 16:44:13 -0500
committerRusty Russell <rusty@rustcorp.com.au>2008-12-29 17:56:11 -0500
commitbe3c5832d51174ef7f21cefd6ad612dabdcb62fd (patch)
tree320f5ed69cbbb82d211ed721294296e3eff858e7 /drivers
parentc29834584ea4eafccf2f62a0b8a32e64f792044c (diff)
kvm-s390: implement config_changed for virtio on s390
This patch implements config_changed for the s390 virtio transport. We use the least significant bit of the interrupt parameter field to decide, if this interrupt should call the virtio virtqueue callback or the config_changed callback. This method is compatible with old host and guest code. Old 64 bit guests will not check the bit and trigger a harmless additional vring_interrupt call. Old host code will never set this bit, this is also safe. This patch also takes care of a potential future 31 bit virtio transport for s390. On 31 bit _LC_PFAULT_INTPARM and __LC_EXT_PARAMS are identical. We exploit the alignment of the token and fold the change bit into the lsb of the token itself. Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers')
-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/*