|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v11 1/7] microcode: split out apply_microcode() from cpu_request_microcode()
On 26.09.2019 15:53, Chao Gao wrote:
> @@ -249,49 +249,82 @@ bool microcode_update_cache(struct microcode_patch
> *patch)
> return true;
> }
>
> -static int microcode_update_cpu(const void *buf, size_t size)
> +/*
> + * Load a microcode update to current CPU.
> + *
> + * If no patch is provided, the cached patch will be loaded. Microcode update
> + * during APs bringup and CPU resuming falls into this case.
> + */
> +static int microcode_update_cpu(const struct microcode_patch *patch)
> {
> - int err;
> - unsigned int cpu = smp_processor_id();
> - struct cpu_signature *sig = &per_cpu(cpu_sig, cpu);
> + int err = microcode_ops->collect_cpu_info(&this_cpu(cpu_sig));
>
> - spin_lock(µcode_mutex);
> + if ( unlikely(err) )
> + return err;
>
> - err = microcode_ops->collect_cpu_info(sig);
> - if ( likely(!err) )
> - err = microcode_ops->cpu_request_microcode(buf, size);
> + spin_lock(µcode_mutex);
> + if ( patch )
> + err = microcode_ops->apply_microcode(patch);
> + else if ( microcode_cache )
> + {
> + err = microcode_ops->apply_microcode(microcode_cache);
> + if ( err == -EIO )
> + {
> + microcode_free_patch(microcode_cache);
> + microcode_cache = NULL;
> + }
> + }
> + else
> + /* No patch to update */
> + err = -ENOENT;
> spin_unlock(µcode_mutex);
This is still not optimal (because of the locked region being
larger than really needed), but close enough to the original
code, i.e. I guess fine for now.
> -static long do_microcode_update(void *_info)
> +static long do_microcode_update(void *patch)
> {
> - struct microcode_info *info = _info;
> - int error;
> -
> - BUG_ON(info->cpu != smp_processor_id());
> + unsigned int cpu;
> + int ret = microcode_update_cpu(patch);
>
> - error = microcode_update_cpu(info->buffer, info->buffer_size);
> - if ( error )
> - info->error = error;
> + /* Store the patch after a successful loading */
> + if ( !ret && patch )
> + {
> + spin_lock(µcode_mutex);
> + microcode_update_cache(patch);
> + spin_unlock(µcode_mutex);
> + patch = NULL;
> + }
>
> if ( microcode_ops->end_update_percpu )
> microcode_ops->end_update_percpu();
>
> - info->cpu = cpumask_next(info->cpu, &cpu_online_map);
> - if ( info->cpu < nr_cpu_ids )
> - return continue_hypercall_on_cpu(info->cpu, do_microcode_update,
> info);
> + /*
> + * Each thread tries to load ucode. Only the first thread of a core
> + * would succeed while other threads would encounter -EINVAL which
> + * indicates current ucode revision is equal to or newer than the
> + * given patch. It is actually expected; so ignore this error.
> + */
> + if ( ret == -EINVAL )
> + ret = 0;
-EINVAL is a pretty generic error, and hence I'm wondering: Is the
described situation really the only one where -EINVAL would come
back? I'm again willing to accept this for now, but I think this
wants further refinement (i.e. use of a truly dedicated error code
for just the one condition you want to filter here, maybe -EEXIST.)
> @@ -556,19 +558,22 @@ static int cpu_request_microcode(const void *buf,
> size_t bufsize)
> break;
> }
>
> - /* Update cache if this patch covers current CPU */
> - if ( microcode_fits(new_patch->mc_amd) != MIS_UCODE )
> - microcode_update_cache(new_patch);
> - else
> - microcode_free_patch(new_patch);
> -
> - if ( match_cpu(microcode_get_cache()) )
> + /*
> + * If the new patch covers current CPU, compare patches and store the
> + * one with higher revision.
> + */
> + if ( (microcode_fits(new_patch->mc_amd) != MIS_UCODE) &&
> + (!patch || (compare_patch(new_patch, patch) == NEW_UCODE)) )
> {
> - error = apply_microcode(microcode_get_cache());
> - if ( error )
> - break;
> + struct microcode_patch *tmp = patch;
> +
> + patch = new_patch;
> + new_patch = tmp;
Looks like you're open-coding SWAP() here.
> @@ -398,26 +380,44 @@ static long get_next_ucode_from_buffer(void **mc, const
> u8 *buf,
> return offset + total_size;
> }
>
> -static int cpu_request_microcode(const void *buf, size_t size)
> +static struct microcode_patch *cpu_request_microcode(const void *buf,
> + size_t size)
> {
> long offset = 0;
> int error = 0;
> void *mc;
> + struct microcode_patch *patch = NULL;
>
> while ( (offset = get_next_ucode_from_buffer(&mc, buf, size, offset)) >
> 0 )
> {
> + struct microcode_patch *new_patch;
> +
> error = microcode_sanity_check(mc);
> if ( error )
> break;
> - error = get_matching_microcode(mc);
> - if ( error < 0 )
> +
> + new_patch = alloc_microcode_patch(mc);
> + if ( IS_ERR(new_patch) )
> + {
> + error = PTR_ERR(new_patch);
> break;
> + }
> +
> /*
> - * It's possible the data file has multiple matching ucode,
> - * lets keep searching till the latest version
> + * If the new patch covers current CPU, compare patches and store the
> + * one with higher revision.
> */
> - if ( error == 1 )
> - error = 0;
> + if ( (microcode_update_match(&new_patch->mc_intel->hdr) !=
> MIS_UCODE) &&
> + (!patch || (compare_patch(new_patch, patch) == NEW_UCODE)) )
> + {
> + struct microcode_patch *tmp = patch;
> +
> + patch = new_patch;
> + new_patch = tmp;
And again here. Preferably with these last two taken care of
(which I'll take the liberty to do if I end up committing
this)
Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
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 |