Subrata Banik has uploaded this change for review. ( https://review.coreboot.org/25725
Change subject: cpu/x86: Add support to run function with argument over APs ......................................................................
cpu/x86: Add support to run function with argument over APs
This patch ensures that user can pass a function with given argument list to execute over APs.
BUG=b:74436746 BRANCH=none TEST=Able to run functions over APs with argument.
Change-Id: I668b36752f6b21cb99cd1416c385d53e96117213 Signed-off-by: Subrata Banik subrata.banik@intel.com --- M src/cpu/x86/mp_init.c M src/include/cpu/x86/mp.h 2 files changed, 106 insertions(+), 24 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/25/25725/1
diff --git a/src/cpu/x86/mp_init.c b/src/cpu/x86/mp_init.c index 18b2c1e..e8b0683 100644 --- a/src/cpu/x86/mp_init.c +++ b/src/cpu/x86/mp_init.c @@ -41,7 +41,13 @@ #define MAX_APIC_IDS 256
typedef void (*mp_callback_t)(void); +typedef void (*mp_callback_arg_t)(void *data);
+struct mp_callback_arg_config { + uintptr_t function_arg; +}; + +struct mp_callback_arg_config mp_arg_list[CONFIG_MAX_CPUS]; /* * A mp_flight_record details a sequence of calls for the APs to perform * along with the BSP to coordinate sequencing. Each flight record either @@ -600,8 +606,14 @@ info = cpu_info(); info->cpu = alloc_find_dev(cpu_bus, &cpu_path);
- if (info->index != 0) + if (info->index != 0) { printk(BIOS_CRIT, "BSP index(%d) != 0!\n", info->index); + if (cpu_path.apic.apic_id == 0) { + info->index = 0; + printk(BIOS_CRIT, "Seting correct BSP index %x\n", + info->index); + } + }
/* Track BSP in cpu_map structures. */ add_cpu_map_entry(info); @@ -936,6 +948,7 @@ }
static mp_callback_t ap_callbacks[CONFIG_MAX_CPUS]; +static mp_callback_arg_t ap_callbacks_arg[CONFIG_MAX_CPUS];
static mp_callback_t read_callback(mp_callback_t *slot) { @@ -947,7 +960,19 @@ *(volatile mp_callback_t *)slot = value; }
-static int execute_callback_on_ap(void) +static mp_callback_arg_t read_callback_arg(mp_callback_arg_t *slot) +{ + return *(volatile mp_callback_arg_t *)slot; +} + +static void store_callback_arg(mp_callback_arg_t *slot, mp_callback_arg_t + value, int index, void *arg) +{ + *(volatile mp_callback_arg_t *)slot = value; + mp_arg_list[index].function_arg = (uintptr_t)arg; +} + +static int execute_callback_on_ap(void *arg) { int cpus_accepted; int i; @@ -955,17 +980,25 @@
cpus_accepted = 0;
- for (i = 0; i < ARRAY_SIZE(ap_callbacks); i++) { - if (cur_cpu == i) - continue; - if (read_callback(&ap_callbacks[i]) == NULL) - cpus_accepted++; + if (arg == NULL) { + for (i = 0; i < ARRAY_SIZE(ap_callbacks); i++) { + if (cur_cpu == i) + continue; + if (read_callback(&ap_callbacks[i]) == NULL) + cpus_accepted++; + } + } else { + for (i = 0; i < ARRAY_SIZE(ap_callbacks_arg); i++) { + if (cur_cpu == i) + continue; + if (read_callback_arg(&ap_callbacks_arg[i]) == NULL) + cpus_accepted++; + } } - return cpus_accepted; }
-static int run_ap_work(mp_callback_t func, long expire_us) +static int run_ap_work(mp_callback_t func, long expire_us, void *arg) { int i; int cpus_accepted; @@ -977,11 +1010,20 @@ return -1; }
- /* Signal to all the APs to run the func. */ - for (i = 0; i < ARRAY_SIZE(ap_callbacks); i++) { - if (cur_cpu == i) - continue; - store_callback(&ap_callbacks[i], func); + if (arg == NULL) { + /* Signal to all the APs to run the func. */ + for (i = 0; i < ARRAY_SIZE(ap_callbacks); i++) { + if (cur_cpu == i) + continue; + store_callback(&ap_callbacks[i], func); + } + } else { + for (i = 0; i < ARRAY_SIZE(ap_callbacks_arg); i++) { + if (cur_cpu == i) + continue; + store_callback_arg(&ap_callbacks_arg[i], + (mp_callback_arg_t)func, i, arg); + } } mfence();
@@ -992,14 +1034,14 @@ */ stopwatch_init_usecs_expire(&sw, expire_us); do { - cpus_accepted = execute_callback_on_ap(); + cpus_accepted = execute_callback_on_ap(arg); if (cpus_accepted == global_num_aps) return 0; } while (!stopwatch_expired(&sw)); } else { /* Wait for all the APs to signal back with no timeout */ do { - cpus_accepted = execute_callback_on_ap(); + cpus_accepted = execute_callback_on_ap(arg); if (cpus_accepted == global_num_aps) return 0; } while (1); @@ -1012,27 +1054,42 @@ static void ap_wait_for_instruction(void) { int cur_cpu = cpu_index(); + void *arg;
if (!IS_ENABLED(CONFIG_PARALLEL_MP_AP_WORK)) return;
while (1) { mp_callback_t func = read_callback(&ap_callbacks[cur_cpu]); + mp_callback_arg_t func_arg = read_callback_arg( + &ap_callbacks_arg[cur_cpu]);
- if (func == NULL) { - asm ("pause"); - continue; + arg = (void *)mp_arg_list[cur_cpu].function_arg; + if (arg == NULL) { + if (func == NULL) { + asm ("pause"); + continue; + } + + store_callback(&ap_callbacks[cur_cpu], NULL); + mfence(); + func(); + } else { + if (func_arg == NULL) { + asm ("pause"); + continue; + } + store_callback_arg(&ap_callbacks_arg[cur_cpu], NULL, + cur_cpu, NULL); + mfence(); + func_arg(arg); } - - store_callback(&ap_callbacks[cur_cpu], NULL); - mfence(); - func(); } }
int mp_run_on_aps(void (*func)(void), long expire_us) { - return run_ap_work(func, expire_us); + return run_ap_work(func, expire_us, NULL); }
int mp_run_on_all_cpus(void (*func)(void), long expire_us) @@ -1042,6 +1099,18 @@ return mp_run_on_aps(func, expire_us); }
+int mp_run_on_aps_arg(void (*func)(void *data), long expire_us, void *arg) +{ + return run_ap_work((mp_callback_t)func, expire_us, arg); +} + +int mp_run_on_all_cpus_arg(void (*func)(void *data), long expire_us, void *arg) +{ + /* Run on BSP first. */ + func(arg); + return mp_run_on_aps_arg(func, expire_us, arg); +} + int mp_park_aps(void) { struct stopwatch sw; diff --git a/src/include/cpu/x86/mp.h b/src/include/cpu/x86/mp.h index 04fba6a..84a1735 100644 --- a/src/include/cpu/x86/mp.h +++ b/src/include/cpu/x86/mp.h @@ -143,6 +143,19 @@ int mp_run_on_all_cpus(void (*func)(void), long expire_us);
/* + * After APs are up and PARALLEL_MP_AP_WORK is enabled one can issue work + * to all the APs to perform. Currently the BSP is the only CPU that is allowed + * to issue work. i.e. the APs should not call any of these functions. + * + * BSP should call this function after passing argument. + * All functions return < 0 on error, 0 on success. + */ +int mp_run_on_aps_arg(void (*func)(void *data), long expire_us, void *arg); + +/* Like mp_run_on_aps_arg() but also runs func on BSP. */ +int mp_run_on_all_cpus_arg(void (*func)(void *data), long expire_us, void *arg); + +/* * Park all APs to prepare for OS boot. This is handled automatically * by the coreboot infrastructure. */