1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _ASM_ARCHRANDOM_H
3#define _ASM_ARCHRANDOM_H
4
5#ifdef CONFIG_ARCH_RANDOM
6
7#include <linux/bug.h>
8#include <linux/kernel.h>
9#include <asm/cpufeature.h>
10
11static inline bool __arm64_rndr(unsigned long *v)
12{
13	bool ok;
14
15	/*
16	 * Reads of RNDR set PSTATE.NZCV to 0b0000 on success,
17	 * and set PSTATE.NZCV to 0b0100 otherwise.
18	 */
19	asm volatile(
20		__mrs_s("%0", SYS_RNDR_EL0) "\n"
21	"	cset %w1, ne\n"
22	: "=r" (*v), "=r" (ok)
23	:
24	: "cc");
25
26	return ok;
27}
28
29static inline bool __must_check arch_get_random_long(unsigned long *v)
30{
31	return false;
32}
33
34static inline bool __must_check arch_get_random_int(unsigned int *v)
35{
36	return false;
37}
38
39static inline bool __must_check arch_get_random_seed_long(unsigned long *v)
40{
41	/*
42	 * Only support the generic interface after we have detected
43	 * the system wide capability, avoiding complexity with the
44	 * cpufeature code and with potential scheduling between CPUs
45	 * with and without the feature.
46	 */
47	if (!cpus_have_const_cap(ARM64_HAS_RNG))
48		return false;
49
50	return __arm64_rndr(v);
51}
52
53
54static inline bool __must_check arch_get_random_seed_int(unsigned int *v)
55{
56	unsigned long val;
57	bool ok = arch_get_random_seed_long(&val);
58
59	*v = val;
60	return ok;
61}
62
63static inline bool __init __early_cpu_has_rndr(void)
64{
65	/* Open code as we run prior to the first call to cpufeature. */
66	unsigned long ftr = read_sysreg_s(SYS_ID_AA64ISAR0_EL1);
67	return (ftr >> ID_AA64ISAR0_RNDR_SHIFT) & 0xf;
68}
69
70static inline bool __init __must_check
71arch_get_random_seed_long_early(unsigned long *v)
72{
73	WARN_ON(system_state != SYSTEM_BOOTING);
74
75	if (!__early_cpu_has_rndr())
76		return false;
77
78	return __arm64_rndr(v);
79}
80#define arch_get_random_seed_long_early arch_get_random_seed_long_early
81
82#endif /* CONFIG_ARCH_RANDOM */
83#endif /* _ASM_ARCHRANDOM_H */
84