summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/s390x/virtio-ccw.c18
1 files changed, 10 insertions, 8 deletions
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index c1f4bb1d33..3c988a000b 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -786,9 +786,10 @@ static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d)
static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc,
uint8_t to_be_set)
{
- uint8_t ind_old, ind_new;
+ uint8_t expected, actual;
hwaddr len = 1;
- uint8_t *ind_addr;
+ /* avoid multiple fetches */
+ uint8_t volatile *ind_addr;
ind_addr = cpu_physical_memory_map(ind_loc, &len, true);
if (!ind_addr) {
@@ -796,14 +797,15 @@ static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc,
__func__, sch->cssid, sch->ssid, sch->schid);
return -1;
}
+ actual = *ind_addr;
do {
- ind_old = *ind_addr;
- ind_new = ind_old | to_be_set;
- } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old);
- trace_virtio_ccw_set_ind(ind_loc, ind_old, ind_new);
- cpu_physical_memory_unmap(ind_addr, len, 1, len);
+ expected = actual;
+ actual = atomic_cmpxchg(ind_addr, expected, expected | to_be_set);
+ } while (actual != expected);
+ trace_virtio_ccw_set_ind(ind_loc, actual, actual | to_be_set);
+ cpu_physical_memory_unmap((void *)ind_addr, len, 1, len);
- return ind_old;
+ return actual;
}
static void virtio_ccw_notify(DeviceState *d, uint16_t vector)