18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _ASM_ARCHRANDOM_H
38c2ecf20Sopenharmony_ci#define _ASM_ARCHRANDOM_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_RANDOM
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/bug.h>
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <asm/cpufeature.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistatic inline bool __arm64_rndr(unsigned long *v)
128c2ecf20Sopenharmony_ci{
138c2ecf20Sopenharmony_ci	bool ok;
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci	/*
168c2ecf20Sopenharmony_ci	 * Reads of RNDR set PSTATE.NZCV to 0b0000 on success,
178c2ecf20Sopenharmony_ci	 * and set PSTATE.NZCV to 0b0100 otherwise.
188c2ecf20Sopenharmony_ci	 */
198c2ecf20Sopenharmony_ci	asm volatile(
208c2ecf20Sopenharmony_ci		__mrs_s("%0", SYS_RNDR_EL0) "\n"
218c2ecf20Sopenharmony_ci	"	cset %w1, ne\n"
228c2ecf20Sopenharmony_ci	: "=r" (*v), "=r" (ok)
238c2ecf20Sopenharmony_ci	:
248c2ecf20Sopenharmony_ci	: "cc");
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	return ok;
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic inline bool __must_check arch_get_random_long(unsigned long *v)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	return false;
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic inline bool __must_check arch_get_random_int(unsigned int *v)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	return false;
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic inline bool __must_check arch_get_random_seed_long(unsigned long *v)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	/*
428c2ecf20Sopenharmony_ci	 * Only support the generic interface after we have detected
438c2ecf20Sopenharmony_ci	 * the system wide capability, avoiding complexity with the
448c2ecf20Sopenharmony_ci	 * cpufeature code and with potential scheduling between CPUs
458c2ecf20Sopenharmony_ci	 * with and without the feature.
468c2ecf20Sopenharmony_ci	 */
478c2ecf20Sopenharmony_ci	if (!cpus_have_const_cap(ARM64_HAS_RNG))
488c2ecf20Sopenharmony_ci		return false;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	return __arm64_rndr(v);
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic inline bool __must_check arch_get_random_seed_int(unsigned int *v)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	unsigned long val;
578c2ecf20Sopenharmony_ci	bool ok = arch_get_random_seed_long(&val);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	*v = val;
608c2ecf20Sopenharmony_ci	return ok;
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic inline bool __init __early_cpu_has_rndr(void)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	/* Open code as we run prior to the first call to cpufeature. */
668c2ecf20Sopenharmony_ci	unsigned long ftr = read_sysreg_s(SYS_ID_AA64ISAR0_EL1);
678c2ecf20Sopenharmony_ci	return (ftr >> ID_AA64ISAR0_RNDR_SHIFT) & 0xf;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic inline bool __init __must_check
718c2ecf20Sopenharmony_ciarch_get_random_seed_long_early(unsigned long *v)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	WARN_ON(system_state != SYSTEM_BOOTING);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (!__early_cpu_has_rndr())
768c2ecf20Sopenharmony_ci		return false;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	return __arm64_rndr(v);
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci#define arch_get_random_seed_long_early arch_get_random_seed_long_early
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci#endif /* CONFIG_ARCH_RANDOM */
838c2ecf20Sopenharmony_ci#endif /* _ASM_ARCHRANDOM_H */
84