1*10243401SSamuel Ortiz /* SPDX-License-Identifier: GPL-2.0 */ 2*10243401SSamuel Ortiz /* 3*10243401SSamuel Ortiz * Kernel interface for the RISCV arch_random_* functions 4*10243401SSamuel Ortiz * 5*10243401SSamuel Ortiz * Copyright (c) 2023 Rivos Inc. 6*10243401SSamuel Ortiz * 7*10243401SSamuel Ortiz */ 8*10243401SSamuel Ortiz 9*10243401SSamuel Ortiz #ifndef ASM_RISCV_ARCHRANDOM_H 10*10243401SSamuel Ortiz #define ASM_RISCV_ARCHRANDOM_H 11*10243401SSamuel Ortiz 12*10243401SSamuel Ortiz #include <asm/csr.h> 13*10243401SSamuel Ortiz #include <asm/processor.h> 14*10243401SSamuel Ortiz 15*10243401SSamuel Ortiz #define SEED_RETRY_LOOPS 100 16*10243401SSamuel Ortiz csr_seed_long(unsigned long * v)17*10243401SSamuel Ortizstatic inline bool __must_check csr_seed_long(unsigned long *v) 18*10243401SSamuel Ortiz { 19*10243401SSamuel Ortiz unsigned int retry = SEED_RETRY_LOOPS, valid_seeds = 0; 20*10243401SSamuel Ortiz const int needed_seeds = sizeof(long) / sizeof(u16); 21*10243401SSamuel Ortiz u16 *entropy = (u16 *)v; 22*10243401SSamuel Ortiz 23*10243401SSamuel Ortiz do { 24*10243401SSamuel Ortiz /* 25*10243401SSamuel Ortiz * The SEED CSR must be accessed with a read-write instruction. 26*10243401SSamuel Ortiz */ 27*10243401SSamuel Ortiz unsigned long csr_seed = csr_swap(CSR_SEED, 0); 28*10243401SSamuel Ortiz unsigned long opst = csr_seed & SEED_OPST_MASK; 29*10243401SSamuel Ortiz 30*10243401SSamuel Ortiz switch (opst) { 31*10243401SSamuel Ortiz case SEED_OPST_ES16: 32*10243401SSamuel Ortiz entropy[valid_seeds++] = csr_seed & SEED_ENTROPY_MASK; 33*10243401SSamuel Ortiz if (valid_seeds == needed_seeds) 34*10243401SSamuel Ortiz return true; 35*10243401SSamuel Ortiz break; 36*10243401SSamuel Ortiz 37*10243401SSamuel Ortiz case SEED_OPST_DEAD: 38*10243401SSamuel Ortiz pr_err_once("archrandom: Unrecoverable error\n"); 39*10243401SSamuel Ortiz return false; 40*10243401SSamuel Ortiz 41*10243401SSamuel Ortiz case SEED_OPST_BIST: 42*10243401SSamuel Ortiz case SEED_OPST_WAIT: 43*10243401SSamuel Ortiz default: 44*10243401SSamuel Ortiz cpu_relax(); 45*10243401SSamuel Ortiz continue; 46*10243401SSamuel Ortiz } 47*10243401SSamuel Ortiz } while (--retry); 48*10243401SSamuel Ortiz 49*10243401SSamuel Ortiz return false; 50*10243401SSamuel Ortiz } 51*10243401SSamuel Ortiz arch_get_random_longs(unsigned long * v,size_t max_longs)52*10243401SSamuel Ortizstatic inline size_t __must_check arch_get_random_longs(unsigned long *v, size_t max_longs) 53*10243401SSamuel Ortiz { 54*10243401SSamuel Ortiz return 0; 55*10243401SSamuel Ortiz } 56*10243401SSamuel Ortiz arch_get_random_seed_longs(unsigned long * v,size_t max_longs)57*10243401SSamuel Ortizstatic inline size_t __must_check arch_get_random_seed_longs(unsigned long *v, size_t max_longs) 58*10243401SSamuel Ortiz { 59*10243401SSamuel Ortiz if (!max_longs) 60*10243401SSamuel Ortiz return 0; 61*10243401SSamuel Ortiz 62*10243401SSamuel Ortiz /* 63*10243401SSamuel Ortiz * If Zkr is supported and csr_seed_long succeeds, we return one long 64*10243401SSamuel Ortiz * worth of entropy. 65*10243401SSamuel Ortiz */ 66*10243401SSamuel Ortiz if (riscv_has_extension_likely(RISCV_ISA_EXT_ZKR) && csr_seed_long(v)) 67*10243401SSamuel Ortiz return 1; 68*10243401SSamuel Ortiz 69*10243401SSamuel Ortiz return 0; 70*10243401SSamuel Ortiz } 71*10243401SSamuel Ortiz 72*10243401SSamuel Ortiz #endif /* ASM_RISCV_ARCHRANDOM_H */ 73