1 /* 2 * Copyright (C) 2018, Emilio G. Cota <cota@braap.org> 3 * 4 * License: GNU GPL, version 2 or later. 5 * See the COPYING file in the top-level directory. 6 */ 7 #include "qemu/osdep.h" 8 #include "qemu/atomic.h" 9 #include "qemu/thread.h" 10 11 #ifdef CONFIG_ATOMIC64 12 #error This file must only be compiled if !CONFIG_ATOMIC64 13 #endif 14 15 /* 16 * When !CONFIG_ATOMIC64, we serialize both reads and writes with spinlocks. 17 * We use an array of spinlocks, with padding computed at run-time based on 18 * the host's dcache line size. 19 * We point to the array with a void * to simplify the padding's computation. 20 * Each spinlock is located every lock_size bytes. 21 */ 22 static void *lock_array; 23 static size_t lock_size; 24 25 /* 26 * Systems without CONFIG_ATOMIC64 are unlikely to have many cores, so we use a 27 * small array of locks. 28 */ 29 #define NR_LOCKS 16 30 31 static QemuSpin *addr_to_lock(const void *addr) 32 { 33 uintptr_t a = (uintptr_t)addr; 34 uintptr_t idx; 35 36 idx = a >> qemu_dcache_linesize_log; 37 idx ^= (idx >> 8) ^ (idx >> 16); 38 idx &= NR_LOCKS - 1; 39 return lock_array + idx * lock_size; 40 } 41 42 #define GEN_READ(name, type) \ 43 type name(const type *ptr) \ 44 { \ 45 QemuSpin *lock = addr_to_lock(ptr); \ 46 type ret; \ 47 \ 48 qemu_spin_lock(lock); \ 49 ret = *ptr; \ 50 qemu_spin_unlock(lock); \ 51 return ret; \ 52 } 53 54 GEN_READ(atomic_read_i64, int64_t) 55 GEN_READ(atomic_read_u64, uint64_t) 56 #undef GEN_READ 57 58 #define GEN_SET(name, type) \ 59 void name(type *ptr, type val) \ 60 { \ 61 QemuSpin *lock = addr_to_lock(ptr); \ 62 \ 63 qemu_spin_lock(lock); \ 64 *ptr = val; \ 65 qemu_spin_unlock(lock); \ 66 } 67 68 GEN_SET(atomic_set_i64, int64_t) 69 GEN_SET(atomic_set_u64, uint64_t) 70 #undef GEN_SET 71 72 void atomic64_init(void) 73 { 74 int i; 75 76 lock_size = ROUND_UP(sizeof(QemuSpin), qemu_dcache_linesize); 77 lock_array = qemu_memalign(qemu_dcache_linesize, lock_size * NR_LOCKS); 78 for (i = 0; i < NR_LOCKS; i++) { 79 QemuSpin *lock = lock_array + i * lock_size; 80 81 qemu_spin_init(lock); 82 } 83 } 84