diff mbox series

[v5,04/11] mips: use fallback for random_get_entropy() instead of just c0 random

Message ID 20220419111650.1582274-5-Jason@zx2c4.com (mailing list archive)
State Handled Elsewhere
Headers show
Series archs/random: fallback to best raw ktime when no cycle counter | expand

Commit Message

Jason A. Donenfeld April 19, 2022, 11:16 a.m. UTC
For situations in which we don't have a c0 counter register available,
we've been falling back to reading the c0 "random" register, which is
usually bounded by the amount of TLB entries and changes every other
cycle or so. This means it wraps extremely often. We can do better by
combining this fast-changing counter with a potentially slower-changing
counter from random_get_entropy_fallback() in the more significant bits.
This commit combines the two, taking into account that the changing bits
are in a different bit position depending on the CPU model. In addition,
we previously were falling back to 0 for ancient CPUs that Linux does
not support anyway; remove that dead path entirely.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Cc: Maciej W. Rozycki <macro@orcam.me.uk>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
ThomasB - I dropped your Ack from v4, because this is pretty different
from v4 now.

Maciej - you mentioned you had a test rig. Think you could provide a
"Tested-by" if this approach works?

 arch/mips/include/asm/timex.h | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

Comments

Maciej W. Rozycki April 21, 2022, 7:25 p.m. UTC | #1
On Tue, 19 Apr 2022, Jason A. Donenfeld wrote:

> For situations in which we don't have a c0 counter register available,
> we've been falling back to reading the c0 "random" register, which is
> usually bounded by the amount of TLB entries and changes every other
> cycle or so. This means it wraps extremely often. We can do better by
> combining this fast-changing counter with a potentially slower-changing
> counter from random_get_entropy_fallback() in the more significant bits.
> This commit combines the two, taking into account that the changing bits
> are in a different bit position depending on the CPU model. In addition,
> we previously were falling back to 0 for ancient CPUs that Linux does
> not support anyway; remove that dead path entirely.

Tested-by: Maciej W. Rozycki <macro@orcam.me.uk>

 I've pushed the algorithm through testing with a number of suitable 
systems:

- an R2000A and an R3000A with no timer of any kind, only jiffies,

- an R3400 with a chipset timer only,

- an R4400SC with a usable buggy CP0 counter and a chipset timer,

- a 5Kc with a good CP0 counter only,

with no obvious issues spotted.  Thank you for working on this!

  Maciej
Jason A. Donenfeld April 21, 2022, 8:01 p.m. UTC | #2
Hi Maciej,

On Thu, Apr 21, 2022 at 9:25 PM Maciej W. Rozycki <macro@orcam.me.uk> wrote:
>
> On Tue, 19 Apr 2022, Jason A. Donenfeld wrote:
>
> > For situations in which we don't have a c0 counter register available,
> > we've been falling back to reading the c0 "random" register, which is
> > usually bounded by the amount of TLB entries and changes every other
> > cycle or so. This means it wraps extremely often. We can do better by
> > combining this fast-changing counter with a potentially slower-changing
> > counter from random_get_entropy_fallback() in the more significant bits.
> > This commit combines the two, taking into account that the changing bits
> > are in a different bit position depending on the CPU model. In addition,
> > we previously were falling back to 0 for ancient CPUs that Linux does
> > not support anyway; remove that dead path entirely.
>
> Tested-by: Maciej W. Rozycki <macro@orcam.me.uk>
>
>  I've pushed the algorithm through testing with a number of suitable
> systems:
>
> - an R2000A and an R3000A with no timer of any kind, only jiffies,
>
> - an R3400 with a chipset timer only,
>
> - an R4400SC with a usable buggy CP0 counter and a chipset timer,
>
> - a 5Kc with a good CP0 counter only,
>
> with no obvious issues spotted.  Thank you for working on this!

Thanks for all the testing!

ThomasB - I think maybe you can re-"Acked-by" this now if you're on
board with the strategy here?

Jason
Thomas Bogendoerfer April 21, 2022, 9:05 p.m. UTC | #3
On Tue, Apr 19, 2022 at 01:16:43PM +0200, Jason A. Donenfeld wrote:
> For situations in which we don't have a c0 counter register available,
> we've been falling back to reading the c0 "random" register, which is
> usually bounded by the amount of TLB entries and changes every other
> cycle or so. This means it wraps extremely often. We can do better by
> combining this fast-changing counter with a potentially slower-changing
> counter from random_get_entropy_fallback() in the more significant bits.
> This commit combines the two, taking into account that the changing bits
> are in a different bit position depending on the CPU model. In addition,
> we previously were falling back to 0 for ancient CPUs that Linux does
> not support anyway; remove that dead path entirely.
> 
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> Cc: Maciej W. Rozycki <macro@orcam.me.uk>
> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
> ---
> ThomasB - I dropped your Ack from v4, because this is pretty different
> from v4 now.
> 
> Maciej - you mentioned you had a test rig. Think you could provide a
> "Tested-by" if this approach works?
> 
>  arch/mips/include/asm/timex.h | 16 +++++++---------
>  1 file changed, 7 insertions(+), 9 deletions(-)
> 
> diff --git a/arch/mips/include/asm/timex.h b/arch/mips/include/asm/timex.h
> index b05bb70a2e46..e3f5460a923b 100644
> --- a/arch/mips/include/asm/timex.h
> +++ b/arch/mips/include/asm/timex.h
> @@ -80,21 +80,19 @@ static inline cycles_t get_cycles(void)
>  /*
>   * Like get_cycles - but where c0_count is not available we desperately
>   * use c0_random in an attempt to get at least a little bit of entropy.
> - *
> - * R6000 and R6000A neither have a count register nor a random register.
> - * That leaves no entropy source in the CPU itself.
>   */
>  static inline unsigned long random_get_entropy(void)
>  {
> -	unsigned int prid = read_c0_prid();
> -	unsigned int imp = prid & PRID_IMP_MASK;
> +	unsigned int c0_random;
>  
> -	if (can_use_mips_counter(prid))
> +	if (can_use_mips_counter(read_c0_prid()))
>  		return read_c0_count();
> -	else if (likely(imp != PRID_IMP_R6000 && imp != PRID_IMP_R6000A))
> -		return read_c0_random();
> +
> +	if (cpu_has_3kex)
> +		c0_random = (read_c0_random() >> 8) & 0x3f;
>  	else
> -		return 0;	/* no usable register */
> +		c0_random = read_c0_random() & 0x3f;
> +	return (random_get_entropy_fallback() << 6) | (0x3f - c0_random);
>  }
>  #define random_get_entropy random_get_entropy
>  
> -- 
> 2.35.1

Acked-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
diff mbox series

Patch

diff --git a/arch/mips/include/asm/timex.h b/arch/mips/include/asm/timex.h
index b05bb70a2e46..e3f5460a923b 100644
--- a/arch/mips/include/asm/timex.h
+++ b/arch/mips/include/asm/timex.h
@@ -80,21 +80,19 @@  static inline cycles_t get_cycles(void)
 /*
  * Like get_cycles - but where c0_count is not available we desperately
  * use c0_random in an attempt to get at least a little bit of entropy.
- *
- * R6000 and R6000A neither have a count register nor a random register.
- * That leaves no entropy source in the CPU itself.
  */
 static inline unsigned long random_get_entropy(void)
 {
-	unsigned int prid = read_c0_prid();
-	unsigned int imp = prid & PRID_IMP_MASK;
+	unsigned int c0_random;
 
-	if (can_use_mips_counter(prid))
+	if (can_use_mips_counter(read_c0_prid()))
 		return read_c0_count();
-	else if (likely(imp != PRID_IMP_R6000 && imp != PRID_IMP_R6000A))
-		return read_c0_random();
+
+	if (cpu_has_3kex)
+		c0_random = (read_c0_random() >> 8) & 0x3f;
 	else
-		return 0;	/* no usable register */
+		c0_random = read_c0_random() & 0x3f;
+	return (random_get_entropy_fallback() << 6) | (0x3f - c0_random);
 }
 #define random_get_entropy random_get_entropy