/* SPDX-License-Identifier: GPL-2.0-only */ /* * A stand-alone ticket spinlock implementation for use by the non-VHE * KVM hypervisor code running at EL2. * * Copyright (C) 2020 Google LLC * Author: Will Deacon * * Heavily based on the implementation removed by c11090474d70 which was: * Copyright (C) 2012 ARM Ltd. */ #ifndef __ARM64_KVM_NVHE_SPINLOCK_H__ #define __ARM64_KVM_NVHE_SPINLOCK_H__ #include #include typedef union hyp_spinlock { u32 __val; struct { #ifdef __AARCH64EB__ u16 next, owner; #else u16 owner, next; #endif }; } hyp_spinlock_t; #define hyp_spin_lock_init(l) \ do { \ *(l) = (hyp_spinlock_t){ .__val = 0 }; \ } while (0) static inline void hyp_spin_lock(hyp_spinlock_t *lock) { u32 tmp; hyp_spinlock_t lockval, newval; asm volatile( /* Atomically increment the next ticket. */ ARM64_LSE_ATOMIC_INSN( /* LL/SC */ " prfm pstl1strm, %3\n" "1: ldaxr %w0, %3\n" " add %w1, %w0, #(1 << 16)\n" " stxr %w2, %w1, %3\n" " cbnz %w2, 1b\n", /* LSE atomics */ " mov %w2, #(1 << 16)\n" " ldadda %w2, %w0, %3\n" __nops(3)) /* Did we get the lock? */ " eor %w1, %w0, %w0, ror #16\n" " cbz %w1, 3f\n" /* * No: spin on the owner. Send a local event to avoid missing an * unlock before the exclusive load. */ " sevl\n" "2: wfe\n" " ldaxrh %w2, %4\n" " eor %w1, %w2, %w0, lsr #16\n" " cbnz %w1, 2b\n" /* We got the lock. Critical section starts here. */ "3:" : "=&r" (lockval), "=&r" (newval), "=&r" (tmp), "+Q" (*lock) : "Q" (lock->owner) : "memory"); } static inline void hyp_spin_unlock(hyp_spinlock_t *lock) { u64 tmp; asm volatile( ARM64_LSE_ATOMIC_INSN( /* LL/SC */ " ldrh %w1, %0\n" " add %w1, %w1, #1\n" " stlrh %w1, %0", /* LSE atomics */ " mov %w1, #1\n" " staddlh %w1, %0\n" __nops(1)) : "=Q" (lock->owner), "=&r" (tmp) : : "memory"); } #endif /* __ARM64_KVM_NVHE_SPINLOCK_H__ */