[PATCH v4 13/25] x86: mp: Allow running functions on multiple CPUs
Simon Glass
sjg at chromium.org
Mon Jul 13 22:57:12 CEST 2020
Hi Bin,
On Sun, 12 Jul 2020 at 22:56, Bin Meng <bmeng.cn at gmail.com> wrote:
>
> Hi Simon,
>
> On Wed, Jul 8, 2020 at 9:37 AM Simon Glass <sjg at chromium.org> wrote:
> >
> > Add a way to run a function on a selection of CPUs. This supports either
> > a single CPU, all CPUs, just the main CPU or just the 'APs', in Intel
> > terminology.
> >
> > It works by writing into a mailbox and then waiting for the CPUs to notice
> > it, take action and indicate they are done.
> >
> > When SMP is not yet enabled, this just calls the function on the main CPU.
> >
> > Signed-off-by: Simon Glass <sjg at chromium.org>
> > Reviewed-by: Wolfgang Wallner <wolfgang.wallner at br-automation.com>
> > ---
> >
> > Changes in v4:
> > - Only enable this feature of CONFIG_SMP_AP_WORK is enabled
> > - Allow running on the BSP if SMP is not enabled
> >
> > Changes in v3:
> > - Add a comment to run_ap_work()
> > - Rename flag to GD_FLG_SMP_READY
> > - Update the comment for run_ap_work() to explain logical_cpu_number
> > - Clarify meaning of @cpu_select in mp_run_on_cpus() comment
> >
> > arch/x86/cpu/mp_init.c | 107 +++++++++++++++++++++++++++++++++++---
> > arch/x86/include/asm/mp.h | 33 ++++++++++++
> > 2 files changed, 134 insertions(+), 6 deletions(-)
> >
> > diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c
> > index 69a23829b9..dd6d6bfab7 100644
> > --- a/arch/x86/cpu/mp_init.c
> > +++ b/arch/x86/cpu/mp_init.c
> > @@ -54,12 +54,7 @@ struct mp_flight_plan {
> > * callback
> > */
> > struct mp_callback {
> > - /**
> > - * func() - Function to call on the AP
> > - *
> > - * @arg: Argument to pass
> > - */
> > - void (*func)(void *arg);
> > + mp_run_func func;
> > void *arg;
> > int logical_cpu_number;
> > };
> > @@ -514,6 +509,70 @@ static void store_callback(struct mp_callback **slot, struct mp_callback *val)
> > dmb();
> > }
> >
> > +/**
> > + * run_ap_work() - Run a callback on selected APs
> > + *
> > + * This writes @callback to all APs and waits for them all to acknowledge it,
> > + * Note that whether each AP actually calls the callback depends on the value
> > + * of logical_cpu_number (see struct mp_callback). The logical CPU number is
> > + * the CPU device's req->seq value.
> > + *
> > + * @callback: Callback information to pass to all APs
> > + * @bsp: CPU device for the BSP
> > + * @num_cpus: The number of CPUs in the system (= number of APs + 1)
> > + * @expire_ms: Timeout to wait for all APs to finish, in milliseconds, or 0 for
> > + * no timeout
> > + * @return 0 if OK, -ETIMEDOUT if one or more APs failed to respond in time
> > + */
> > +static int run_ap_work(struct mp_callback *callback, struct udevice *bsp,
> > + int num_cpus, uint expire_ms)
> > +{
> > + int cur_cpu = bsp->req_seq;
> > + int num_aps = num_cpus - 1; /* number of non-BSPs to get this message */
> > + int cpus_accepted;
> > + ulong start;
> > + int i;
> > +
> > + if (!IS_ENABLED(CONFIG_SMP_AP_WORK)) {
> > + printf("APs already parked. CONFIG_SMP_AP_WORK not enabled\n");
> > + return -ENOTSUPP;
> > + }
> > +
> > + /* Signal to all the APs to run the func. */
> > + for (i = 0; i < num_cpus; i++) {
> > + if (cur_cpu != i)
> > + store_callback(&ap_callbacks[i], callback);
> > + }
> > + mfence();
> > +
> > + /* Wait for all the APs to signal back that call has been accepted. */
> > + start = get_timer(0);
> > +
> > + do {
> > + mdelay(1);
> > + cpus_accepted = 0;
> > +
> > + for (i = 0; i < num_cpus; i++) {
> > + if (cur_cpu == i)
> > + continue;
> > + if (!read_callback(&ap_callbacks[i]))
> > + cpus_accepted++;
>
> It looks my previous comments were not addressed. I believe there is a
> bug here that cpus_accepted will double count for the 2nd time in the
> do {} while () loop.
I thought I replied to that. I don't see how that can happen since it
is set to zero each time around the outer loop. Can you please speed
it out?
>
> > + }
> > +
> > + if (expire_ms && get_timer(start) >= expire_ms) {
> > + log(UCLASS_CPU, LOGL_CRIT,
> > + "AP call expired; %d/%d CPUs accepted\n",
> > + cpus_accepted, num_aps);
> > + return -ETIMEDOUT;
> > + }
> > + } while (cpus_accepted != num_aps);
> > +
> > + /* Make sure we can see any data written by the APs */
> > + mfence();
> > +
> > + return 0;
> > +}
> > +
Regards,
Simon
More information about the U-Boot
mailing list