1782da5b2SEmilio G. Cota /* 2782da5b2SEmilio G. Cota * Copyright (C) 2018, Emilio G. Cota <cota@braap.org> 3782da5b2SEmilio G. Cota * 4782da5b2SEmilio G. Cota * License: GNU GPL, version 2 or later. 5782da5b2SEmilio G. Cota * See the COPYING file in the top-level directory. 6782da5b2SEmilio G. Cota */ 7782da5b2SEmilio G. Cota #include "qemu/osdep.h" 8782da5b2SEmilio G. Cota #include "qemu/atomic.h" 9782da5b2SEmilio G. Cota #include "qemu/thread.h" 10ad768e6fSPeter Maydell #include "qemu/cacheinfo.h" 11*5df022cfSPeter Maydell #include "qemu/memalign.h" 12782da5b2SEmilio G. Cota 13782da5b2SEmilio G. Cota #ifdef CONFIG_ATOMIC64 14782da5b2SEmilio G. Cota #error This file must only be compiled if !CONFIG_ATOMIC64 15782da5b2SEmilio G. Cota #endif 16782da5b2SEmilio G. Cota 17782da5b2SEmilio G. Cota /* 18782da5b2SEmilio G. Cota * When !CONFIG_ATOMIC64, we serialize both reads and writes with spinlocks. 19782da5b2SEmilio G. Cota * We use an array of spinlocks, with padding computed at run-time based on 20782da5b2SEmilio G. Cota * the host's dcache line size. 21782da5b2SEmilio G. Cota * We point to the array with a void * to simplify the padding's computation. 22782da5b2SEmilio G. Cota * Each spinlock is located every lock_size bytes. 23782da5b2SEmilio G. Cota */ 24782da5b2SEmilio G. Cota static void *lock_array; 25782da5b2SEmilio G. Cota static size_t lock_size; 26782da5b2SEmilio G. Cota 27782da5b2SEmilio G. Cota /* 28782da5b2SEmilio G. Cota * Systems without CONFIG_ATOMIC64 are unlikely to have many cores, so we use a 29782da5b2SEmilio G. Cota * small array of locks. 30782da5b2SEmilio G. Cota */ 31782da5b2SEmilio G. Cota #define NR_LOCKS 16 32782da5b2SEmilio G. Cota 33782da5b2SEmilio G. Cota static QemuSpin *addr_to_lock(const void *addr) 34782da5b2SEmilio G. Cota { 35782da5b2SEmilio G. Cota uintptr_t a = (uintptr_t)addr; 36782da5b2SEmilio G. Cota uintptr_t idx; 37782da5b2SEmilio G. Cota 38782da5b2SEmilio G. Cota idx = a >> qemu_dcache_linesize_log; 39782da5b2SEmilio G. Cota idx ^= (idx >> 8) ^ (idx >> 16); 40782da5b2SEmilio G. Cota idx &= NR_LOCKS - 1; 41782da5b2SEmilio G. Cota return lock_array + idx * lock_size; 42782da5b2SEmilio G. Cota } 43782da5b2SEmilio G. Cota 44782da5b2SEmilio G. Cota #define GEN_READ(name, type) \ 45782da5b2SEmilio G. Cota type name(const type *ptr) \ 46782da5b2SEmilio G. Cota { \ 47782da5b2SEmilio G. Cota QemuSpin *lock = addr_to_lock(ptr); \ 48782da5b2SEmilio G. Cota type ret; \ 49782da5b2SEmilio G. Cota \ 50782da5b2SEmilio G. Cota qemu_spin_lock(lock); \ 51782da5b2SEmilio G. Cota ret = *ptr; \ 52782da5b2SEmilio G. Cota qemu_spin_unlock(lock); \ 53782da5b2SEmilio G. Cota return ret; \ 54782da5b2SEmilio G. Cota } 55782da5b2SEmilio G. Cota 56d73415a3SStefan Hajnoczi GEN_READ(qatomic_read_i64, int64_t) 57d73415a3SStefan Hajnoczi GEN_READ(qatomic_read_u64, uint64_t) 58782da5b2SEmilio G. Cota #undef GEN_READ 59782da5b2SEmilio G. Cota 60782da5b2SEmilio G. Cota #define GEN_SET(name, type) \ 61782da5b2SEmilio G. Cota void name(type *ptr, type val) \ 62782da5b2SEmilio G. Cota { \ 63782da5b2SEmilio G. Cota QemuSpin *lock = addr_to_lock(ptr); \ 64782da5b2SEmilio G. Cota \ 65782da5b2SEmilio G. Cota qemu_spin_lock(lock); \ 66782da5b2SEmilio G. Cota *ptr = val; \ 67782da5b2SEmilio G. Cota qemu_spin_unlock(lock); \ 68782da5b2SEmilio G. Cota } 69782da5b2SEmilio G. Cota 70d73415a3SStefan Hajnoczi GEN_SET(qatomic_set_i64, int64_t) 71d73415a3SStefan Hajnoczi GEN_SET(qatomic_set_u64, uint64_t) 72782da5b2SEmilio G. Cota #undef GEN_SET 73782da5b2SEmilio G. Cota 74d73415a3SStefan Hajnoczi void qatomic64_init(void) 75782da5b2SEmilio G. Cota { 76782da5b2SEmilio G. Cota int i; 77782da5b2SEmilio G. Cota 78782da5b2SEmilio G. Cota lock_size = ROUND_UP(sizeof(QemuSpin), qemu_dcache_linesize); 79782da5b2SEmilio G. Cota lock_array = qemu_memalign(qemu_dcache_linesize, lock_size * NR_LOCKS); 80782da5b2SEmilio G. Cota for (i = 0; i < NR_LOCKS; i++) { 81782da5b2SEmilio G. Cota QemuSpin *lock = lock_array + i * lock_size; 82782da5b2SEmilio G. Cota 83782da5b2SEmilio G. Cota qemu_spin_init(lock); 84782da5b2SEmilio G. Cota } 85782da5b2SEmilio G. Cota } 86