[V3,20/30] x86/microcode: Sanitize __wait_for_cpus()

Message ID 20230912065502.022650614@linutronix.de
State New
Headers
Series x86/microcode: Cleanup and late loading enhancements |

Commit Message

Thomas Gleixner Sept. 12, 2023, 7:58 a.m. UTC
  From: Thomas Gleixner <tglx@linutronix.de>

The code is too complicated for no reason:

 - The return value is pointless as this is a strict boolean.

 - It's way simpler to count down from num_online_cpus() and check for
   zero.

  - The timeout argument is pointless as this is always one second.

  - Touching the NMI watchdog every 100ns does not make any sense, neither
    does checking every 100ns. This is really not a hotpath operation.

Preload the atomic counter with the number of online CPUs and simplify the
whole timeout logic. Delay for one microsecond and touch the NMI watchdog
once per millisecond.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

---
 arch/x86/kernel/cpu/microcode/core.c |   41 ++++++++++++++---------------------
 1 file changed, 17 insertions(+), 24 deletions(-)
---
  

Comments

Borislav Petkov Sept. 22, 2023, 4:24 p.m. UTC | #1
On Tue, Sep 12, 2023 at 09:58:15AM +0200, Thomas Gleixner wrote:
> +	for (timeout = 0; timeout < USEC_PER_SEC; timeout++) {
> +		if (!atomic_read(cnt))
> +			return true;

<---- newline here.

> +		udelay(1);

And here.

Otherwise it looks too crammed.

> +		if (!(timeout % 1000))

MSEC_PER_SEC - no naked numbers pls.

> +			touch_nmi_watchdog();
>  	}
> -	return 0;
> +	/* Prevent the late comers to make progress and let them time out */

s/to make progress/from making progress/

Nice, otherwise.
  
Thomas Gleixner Sept. 26, 2023, 8:51 a.m. UTC | #2
On Fri, Sep 22 2023 at 18:24, Borislav Petkov wrote:

> On Tue, Sep 12, 2023 at 09:58:15AM +0200, Thomas Gleixner wrote:
>> +	for (timeout = 0; timeout < USEC_PER_SEC; timeout++) {
>> +		if (!atomic_read(cnt))
>> +			return true;
>
> <---- newline here.
>
>> +		udelay(1);
>
> And here.
>
> Otherwise it looks too crammed.

Oh well.

>> +		if (!(timeout % 1000))
>
> MSEC_PER_SEC - no naked numbers pls.

MSEC_PER_SEC? Thats really wrong because timeout counts in microseconds,
no? So USEC_PER_MSEC.

>> +			touch_nmi_watchdog();
>>  	}
>> -	return 0;
>> +	/* Prevent the late comers to make progress and let them time out */
>
> s/to make progress/from making progress/
>
> Nice, otherwise.
  
Borislav Petkov Sept. 27, 2023, 7:56 a.m. UTC | #3
On Tue, Sep 26, 2023 at 10:51:33AM +0200, Thomas Gleixner wrote:
> MSEC_PER_SEC? Thats really wrong because timeout counts in microseconds,
> no? So USEC_PER_MSEC.

Doh, yes.
  

Patch

--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -324,31 +324,24 @@  static struct platform_device	*microcode
  *   requirement can be relaxed in the future. Right now, this is conservative
  *   and good.
  */
-#define SPINUNIT 100 /* 100 nsec */
+static atomic_t late_cpus_in, late_cpus_out;
 
-
-static atomic_t late_cpus_in;
-static atomic_t late_cpus_out;
-
-static int __wait_for_cpus(atomic_t *t, long long timeout)
+static bool wait_for_cpus(atomic_t *cnt)
 {
-	int all_cpus = num_online_cpus();
-
-	atomic_inc(t);
-
-	while (atomic_read(t) < all_cpus) {
-		if (timeout < SPINUNIT) {
-			pr_err("Timeout while waiting for CPUs rendezvous, remaining: %d\n",
-				all_cpus - atomic_read(t));
-			return 1;
-		}
+	unsigned int timeout;
 
-		ndelay(SPINUNIT);
-		timeout -= SPINUNIT;
+	WARN_ON_ONCE(atomic_dec_return(cnt) < 0);
 
-		touch_nmi_watchdog();
+	for (timeout = 0; timeout < USEC_PER_SEC; timeout++) {
+		if (!atomic_read(cnt))
+			return true;
+		udelay(1);
+		if (!(timeout % 1000))
+			touch_nmi_watchdog();
 	}
-	return 0;
+	/* Prevent the late comers to make progress and let them time out */
+	atomic_inc(cnt);
+	return false;
 }
 
 /*
@@ -366,7 +359,7 @@  static int __reload_late(void *info)
 	 * Wait for all CPUs to arrive. A load will not be attempted unless all
 	 * CPUs show up.
 	 * */
-	if (__wait_for_cpus(&late_cpus_in, NSEC_PER_SEC))
+	if (!wait_for_cpus(&late_cpus_in))
 		return -1;
 
 	/*
@@ -389,7 +382,7 @@  static int __reload_late(void *info)
 	}
 
 wait_for_siblings:
-	if (__wait_for_cpus(&late_cpus_out, NSEC_PER_SEC))
+	if (!wait_for_cpus(&late_cpus_out))
 		panic("Timeout during microcode update!\n");
 
 	/*
@@ -416,8 +409,8 @@  static int microcode_reload_late(void)
 	pr_err("Attempting late microcode loading - it is dangerous and taints the kernel.\n");
 	pr_err("You should switch to early loading, if possible.\n");
 
-	atomic_set(&late_cpus_in,  0);
-	atomic_set(&late_cpus_out, 0);
+	atomic_set(&late_cpus_in, num_online_cpus());
+	atomic_set(&late_cpus_out, num_online_cpus());
 
 	/*
 	 * Take a snapshot before the microcode update in order to compare and