From patchwork Wed Jul 8 01:34:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240950 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:35 -0600 Subject: [PATCH v4 15/25] x86: mp: Add iterators for CPUs In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-14-sjg@chromium.org> It is convenient to iterate through the CPUs performing work on each one and processing the result. Add a few iterator functions which handle this. These can be used by any client code. It can call mp_run_on_cpus() on each CPU that is returned, handling them one at a time. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- Changes in v4: - Update mp_next_cpu() to stop if CONFIG_SMP_AP_WORK is not enabled Changes in v3: - Add more comments on how the iterators work arch/x86/cpu/mp_init.c | 63 +++++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/mp.h | 42 ++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 721b729d92..56e07ecd8f 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -686,6 +686,69 @@ int mp_park_aps(void) return get_timer(start); } +int mp_first_cpu(int cpu_select) +{ + struct udevice *dev; + int num_cpus; + int ret; + + /* + * This assumes that CPUs are numbered from 0. This function tries to + * avoid assuming the CPU 0 is the boot CPU + */ + if (cpu_select == MP_SELECT_ALL) + return 0; /* start with the first one */ + + ret = get_bsp(&dev, &num_cpus); + if (ret < 0) + return log_msg_ret("bsp", ret); + + /* Return boot CPU if requested */ + if (cpu_select == MP_SELECT_BSP) + return ret; + + /* Return something other than the boot CPU, if APs requested */ + if (cpu_select == MP_SELECT_APS && num_cpus > 1) + return ret == 0 ? 1 : 0; + + /* Try to check for an invalid value */ + if (cpu_select < 0 || cpu_select >= num_cpus) + return -EINVAL; + + return cpu_select; /* return the only selected one */ +} + +int mp_next_cpu(int cpu_select, int prev_cpu) +{ + struct udevice *dev; + int num_cpus; + int ret; + int bsp; + + /* If we selected the BSP or a particular single CPU, we are done */ + if (!IS_ENABLED(CONFIG_SMP_AP_WORK) || cpu_select == MP_SELECT_BSP || + cpu_select >= 0) + return -EFBIG; + + /* Must be doing MP_SELECT_ALL or MP_SELECT_APS; return the next CPU */ + ret = get_bsp(&dev, &num_cpus); + if (ret < 0) + return log_msg_ret("bsp", ret); + bsp = ret; + + /* Move to the next CPU */ + assert(prev_cpu >= 0); + ret = prev_cpu + 1; + + /* Skip the BSP if needed */ + if (cpu_select == MP_SELECT_APS && ret == bsp) + ret++; + if (ret >= num_cpus) + return -EFBIG; + + return ret; +} + int mp_init(void) { int num_aps, num_cpus; diff --git a/arch/x86/include/asm/mp.h b/arch/x86/include/asm/mp.h index 93b1786b66..34d724938a 100644 --- a/arch/x86/include/asm/mp.h +++ b/arch/x86/include/asm/mp.h @@ -118,6 +118,33 @@ int mp_run_on_cpus(int cpu_select, mp_run_func func, void *arg); * @return time taken to park the APs on success (in microseconds), -ve on error */ int mp_park_aps(void); + +/** + * mp_first_cpu() - Get the first CPU to process, from a selection + * + * This is used to iterate through selected CPUs. Call this function first, then + * call mp_next_cpu() repeatedly (with the same @cpu_select) until it returns + * -EFBIG. + * + * @cpu_select: Selected CPUs (either a CPU number or MP_SELECT_...) + * @return next CPU number to run on (e.g. 0) + */ +int mp_first_cpu(int cpu_select); + +/** + * mp_next_cpu() - Get the next CPU to process, from a selection + * + * This is used to iterate through selected CPUs. After first calling + * mp_first_cpu() once, call this function repeatedly until it returns -EFBIG. + * + * The value of @cpu_select must be the same for all calls and must match the + * value passed to mp_first_cpu(), otherwise the behaviour is undefined. + * + * @cpu_select: Selected CPUs (either a CPU number or MP_SELECT_...) + * @prev_cpu: Previous value returned by mp_first_cpu()/mp_next_cpu() + * @return next CPU number to run on (e.g. 0) + */ +int mp_next_cpu(int cpu_select, int prev_cpu); #else static inline int mp_run_on_cpus(int cpu_select, mp_run_func func, void *arg) { @@ -134,6 +161,21 @@ static inline int mp_park_aps(void) return 0; } +static inline int mp_first_cpu(int cpu_select) +{ + /* We cannot run on any APs, nor a selected CPU */ + return cpu_select == MP_SELECT_APS ? -EFBIG : MP_SELECT_BSP; +} + +static inline int mp_next_cpu(int cpu_select, int prev_cpu) +{ + /* + * When MP is not enabled, there is only one CPU and we did it in + * mp_first_cpu() + */ + return -EFBIG; +} + #endif #endif /* _X86_MP_H_ */