ANDROID: KVM: arm64: Add atomics-based checking refcount implementation at EL2

The current nVHE refcount implementation at EL2 uses a simple spinlock
to serialise accesses. Although this works, it forces serialisation in
places where it is not necessary, so introduce a simple atomics-based
refcount implementation instead.

Bug: 357781595
Change-Id: I238861fe1cc2880c552c239cdd707dfa8a400be2
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Fuad Tabba <tabba@google.com>
This commit is contained in:
Will Deacon
2023-06-30 17:14:17 +01:00
committed by Keir Fraser
parent 1effffa4af
commit 9d2f5a0465
@@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Atomics-based checking refcount implementation.
* Copyright (C) 2023 Google LLC
* Author: Will Deacon <will@kernel.org>
*/
#ifndef __ARM64_KVM_NVHE_REFCOUNT_H__
#define __ARM64_KVM_NVHE_REFCOUNT_H__
#include <asm/lse.h>
static inline s16 __ll_sc_refcount_fetch_add_16(u16 *refcount, s16 addend)
{
u16 new;
u32 flag;
asm volatile(
" prfm pstl1strm, %[refcount]\n"
"1: ldxrh %w[new], %[refcount]\n"
" add %w[new], %w[new], %w[addend]\n"
" stxrh %w[flag], %w[new], %[refcount]\n"
" cbnz %w[flag], 1b"
: [refcount] "+Q" (*refcount),
[new] "=&r" (new),
[flag] "=&r" (flag)
: [addend] "Ir" (addend));
return new;
}
#ifdef CONFIG_ARM64_LSE_ATOMICS
static inline s16 __lse_refcount_fetch_add_16(u16 *refcount, s16 addend)
{
s16 old;
asm volatile(__LSE_PREAMBLE
" ldaddh %w[addend], %w[old], %[refcount]"
: [refcount] "+Q" (*refcount),
[old] "=r" (old)
: [addend] "r" (addend));
return old + addend;
}
#endif /* CONFIG_ARM64_LSE_ATOMICS */
static inline u64 __hyp_refcount_fetch_add(void *refcount, const size_t size,
const s64 addend)
{
s64 new;
switch (size) {
case 2:
new = __lse_ll_sc_body(refcount_fetch_add_16, refcount, addend);
break;
default:
BUILD_BUG_ON_MSG(1, "Unsupported refcount size");
unreachable();
}
BUG_ON(new < 0);
return new;
}
#define hyp_refcount_inc(r) __hyp_refcount_fetch_add(&(r), sizeof(r), 1)
#define hyp_refcount_dec(r) __hyp_refcount_fetch_add(&(r), sizeof(r), -1)
#define hyp_refcount_get(r) READ_ONCE(r)
#define hyp_refcount_set(r, v) do { \
typeof(r) *__rp = &(r); \
WARN_ON(hyp_refcount_get(*__rp)); \
WRITE_ONCE(*__rp, v); \
} while (0)
#endif /* __ARM64_KVM_NVHE_REFCOUNT_H__ */