|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v10 12/16] x86/microcode: Synchronize late microcode loading
On 12.09.2019 09:22, Chao Gao wrote:
> @@ -264,38 +336,158 @@ static int microcode_update_cpu(const struct
> microcode_patch *patch)
> return err;
> }
>
> -static long do_microcode_update(void *patch)
> +static bool wait_for_state(unsigned int state)
> +{
> + while ( loading_state != state )
> + {
> + if ( state != LOADING_EXIT && loading_state == LOADING_EXIT )
> + return false;
This is at least somewhat confusing: There's no indication here
that "loading_state" may change behind the function's back. So
in general one could be (and I initially was) tempted to suggest
dropping the apparently redundant left side of the &&. But that
would end up wrong if the compiler translates the above to two
separate reads of "loading_state". Therefore I'd like to suggest
static bool wait_for_state(typeof(loading_state) state)
{
typeof(loading_state) cur_state;
while ( (cur_state = ACCESS_ONCE(loading_state)) != state )
{
if ( cur_state == LOADING_EXIT )
return false;
cpu_relax();
}
return true;
}
or something substantially similar (if, e.g., you dislike the
use of typeof() here).
> +static int secondary_thread_fn(void)
> +{
> + unsigned int primary = cpumask_first(this_cpu(cpu_sibling_mask));
> +
> + if ( !wait_for_state(LOADING_CALLIN) )
> + return -EBUSY;
> +
> + cpumask_set_cpu(smp_processor_id(), &cpu_callin_map);
> +
> + if ( !wait_for_state(LOADING_EXIT) )
> + return -EBUSY;
This return looks to be unreachable, doesn't it?
> +static int control_thread_fn(const struct microcode_patch *patch)
> {
> - unsigned int cpu;
> - int ret = microcode_update_cpu(patch);
> + unsigned int cpu = smp_processor_id(), done;
> + unsigned long tick;
> + int ret;
> +
> + /*
> + * We intend to disable interrupt for long time, which may lead to
> + * watchdog timeout.
> + */
> + watchdog_disable();
With the move here, the comment should start "We intend to keep
interrupts disabled for a long time, ..." - they are disabled
already at this point.
> - /* Store the patch after a successful loading */
> - if ( !ret && patch )
> + /* Allow threads to call in */
> + set_state(LOADING_CALLIN);
> +
> + cpumask_set_cpu(cpu, &cpu_callin_map);
> +
> + /* Waiting for all threads calling in */
> + ret = wait_for_condition(wait_cpu_callin,
> + (void *)(unsigned long)num_online_cpus(),
I'm puzzled by my own suggestion in reply to v9, and I'm equally
puzzled that you didn't take it that little step further: All of
this casting would be unnecessary if the two wait_cpu_*()
functions took "unsigned int" as their parameters. (The
observation with v9 was that both are similar enough to allow
for a common signature, even if that signature would not be a
typical one for a callback.)
> + MICROCODE_CALLIN_TIMEOUT_US);
> + if ( ret )
> {
> - spin_lock(µcode_mutex);
> - microcode_update_cache(patch);
> - spin_unlock(µcode_mutex);
> - patch = NULL;
> + set_state(LOADING_EXIT);
> + return ret;
> }
>
> - if ( microcode_ops->end_update_percpu )
> - microcode_ops->end_update_percpu();
> + /* Let primary threads load the given ucode update */
> + set_state(LOADING_ENTER);
>
> + ret = microcode_ops->apply_microcode(patch);
> + if ( !ret )
> + atomic_inc(&cpu_updated);
> + atomic_inc(&cpu_out);
> +
> + tick = rdtsc_ordered();
> + /* Wait for primary threads finishing update */
> + done = atomic_read(&cpu_out);
Would you mind eliminating the duplication of this and ...
> + while ( done != nr_cores )
> + {
> + /*
> + * During each timeout interval, at least a CPU is expected to
> + * finish its update. Otherwise, something goes wrong.
> + *
> + * Note that RDTSC (in wait_for_condition()) is safe for threads to
> + * execute while waiting for completion of loading an update.
> + */
> + if ( wait_for_condition(wait_cpu_callout,
> + (void *)(unsigned long)(done + 1),
> + MICROCODE_UPDATE_TIMEOUT_US) )
> + panic("Timeout when finished updating microcode (finished
> %u/%u)",
> + done, nr_cores);
> +
> + /* Print warning message once if long time is spent here */
> + if ( tick && rdtsc_ordered() - tick >= cpu_khz * 1000 )
> + {
> + printk(XENLOG_WARNING
> + "WARNING: UPDATING MICROCODE HAS CONSUMED MORE THAN 1
> SECOND!\n");
> + tick = 0;
> + }
> + done = atomic_read(&cpu_out);
... this, by doing the assignment inside the while()?
Jan
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |