Skip to content

Commit 6067788

Browse files
KAGA-KOKObp3tk0v
authored andcommitted
x86/microcode: Provide new control functions
The current all in one code is unreadable and really not suited for adding future features like uniform loading with package or system scope. Provide a set of new control functions which split the handling of the primary and secondary CPUs. These will replace the current rendezvous all in one function in the next step. This is intentionally a separate change because diff makes an complete unreadable mess otherwise. So the flow separates the primary and the secondary CPUs into their own functions which use the control field in the per CPU ucode_ctrl struct. primary() secondary() wait_for_all() wait_for_all() apply_ucode() wait_for_release() release() apply_ucode() Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent ba3aeb9 commit 6067788

File tree

1 file changed

+84
-0
lines changed
  • arch/x86/kernel/cpu/microcode

1 file changed

+84
-0
lines changed

arch/x86/kernel/cpu/microcode/core.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,90 @@ static bool wait_for_cpus(atomic_t *cnt)
290290
return false;
291291
}
292292

293+
static bool wait_for_ctrl(void)
294+
{
295+
unsigned int timeout;
296+
297+
for (timeout = 0; timeout < USEC_PER_SEC; timeout++) {
298+
if (this_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT)
299+
return true;
300+
udelay(1);
301+
if (!(timeout % 1000))
302+
touch_nmi_watchdog();
303+
}
304+
return false;
305+
}
306+
307+
static __maybe_unused void load_secondary(unsigned int cpu)
308+
{
309+
unsigned int ctrl_cpu = this_cpu_read(ucode_ctrl.ctrl_cpu);
310+
enum ucode_state ret;
311+
312+
/* Initial rendezvous to ensure that all CPUs have arrived */
313+
if (!wait_for_cpus(&late_cpus_in)) {
314+
pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1);
315+
this_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT);
316+
return;
317+
}
318+
319+
/*
320+
* Wait for primary threads to complete. If one of them hangs due
321+
* to the update, there is no way out. This is non-recoverable
322+
* because the CPU might hold locks or resources and confuse the
323+
* scheduler, watchdogs etc. There is no way to safely evacuate the
324+
* machine.
325+
*/
326+
if (!wait_for_ctrl())
327+
panic("Microcode load: Primary CPU %d timed out\n", ctrl_cpu);
328+
329+
/*
330+
* If the primary succeeded then invoke the apply() callback,
331+
* otherwise copy the state from the primary thread.
332+
*/
333+
if (this_cpu_read(ucode_ctrl.ctrl) == SCTRL_APPLY)
334+
ret = microcode_ops->apply_microcode(cpu);
335+
else
336+
ret = per_cpu(ucode_ctrl.result, ctrl_cpu);
337+
338+
this_cpu_write(ucode_ctrl.result, ret);
339+
this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE);
340+
}
341+
342+
static __maybe_unused void load_primary(unsigned int cpu)
343+
{
344+
struct cpumask *secondaries = topology_sibling_cpumask(cpu);
345+
enum sibling_ctrl ctrl;
346+
enum ucode_state ret;
347+
unsigned int sibling;
348+
349+
/* Initial rendezvous to ensure that all CPUs have arrived */
350+
if (!wait_for_cpus(&late_cpus_in)) {
351+
this_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT);
352+
pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1);
353+
return;
354+
}
355+
356+
ret = microcode_ops->apply_microcode(cpu);
357+
this_cpu_write(ucode_ctrl.result, ret);
358+
this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE);
359+
360+
/*
361+
* If the update was successful, let the siblings run the apply()
362+
* callback. If not, tell them it's done. This also covers the
363+
* case where the CPU has uniform loading at package or system
364+
* scope implemented but does not advertise it.
365+
*/
366+
if (ret == UCODE_UPDATED || ret == UCODE_OK)
367+
ctrl = SCTRL_APPLY;
368+
else
369+
ctrl = SCTRL_DONE;
370+
371+
for_each_cpu(sibling, secondaries) {
372+
if (sibling != cpu)
373+
per_cpu(ucode_ctrl.ctrl, sibling) = ctrl;
374+
}
375+
}
376+
293377
static int load_cpus_stopped(void *unused)
294378
{
295379
int cpu = smp_processor_id();

0 commit comments

Comments
 (0)