s390/ipl: Fix waiting for virtio processing

The guest side must not manipulate the index for the used buffers. Instead,
remember the state of the used buffer locally and wait until it has moved.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Acked-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 49f2d29..4d6e48f 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -123,6 +123,7 @@
     /* We're running with interrupts off anyways, so don't bother */
     vr->used->flags = VRING_USED_F_NO_NOTIFY;
     vr->used->idx = 0;
+    vr->used_idx = 0;
 
     debug_print_addr("init vr", vr);
 }
@@ -150,8 +151,6 @@
     if (!(flags & VRING_DESC_F_NEXT)) {
         vr->avail->idx++;
     }
-
-    vr->used->idx = vr->next_idx;
 }
 
 static u64 get_clock(void)
@@ -180,7 +179,8 @@
     struct subchannel_id schid = vr->schid;
     int r = 0;
 
-    while (vr->used->idx == vr->next_idx) {
+    /* Wait until the used index has moved. */
+    while (vr->used->idx == vr->used_idx) {
         vring_notify(schid);
         if (timeout && (get_second() >= target_second)) {
             r = 1;
@@ -189,6 +189,7 @@
         yield();
     }
 
+    vr->used_idx = vr->used->idx;
     vr->next_idx = 0;
     vr->desc[0].len = 0;
     vr->desc[0].flags = 0;
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index 86fdd57..772a63f 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -115,6 +115,7 @@
 struct vring {
     unsigned int num;
     int next_idx;
+    int used_idx;
     struct vring_desc *desc;
     struct vring_avail *avail;
     struct vring_used *used;