From patchwork Wed Jul 8 01:34:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240937 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:21 -0600 Subject: [PATCH v4 01/25] x86: mp_init: Switch to livetree In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-2-sjg@chromium.org> Update this code to use livetree calls instead of flat-tree. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- (no changes since v1) arch/x86/cpu/mp_init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 7fde4ff7e1..c25d17c647 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -507,8 +507,7 @@ int mp_init_cpu(struct udevice *cpu, void *unused) * seq num in the uclass_resolve_seq() during device_probe(). To avoid * this, set req_seq to the reg number in the device tree in advance. */ - cpu->req_seq = fdtdec_get_int(gd->fdt_blob, dev_of_offset(cpu), "reg", - -1); + cpu->req_seq = dev_read_u32_default(cpu, "reg", -1); plat->ucode_version = microcode_read_rev(); plat->device_id = gd->arch.x86_device; From patchwork Wed Jul 8 01:34:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240938 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:22 -0600 Subject: [PATCH v4 02/25] x86: Move MP code into mp_init In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-3-sjg@chromium.org> At present the 'flight plan' for CPUs is passed into mp_init. But it is always the same. Move it into the mp_init file so everything is in one place. Also drop the SMI function since it does nothing. If we implement SMIs, more refactoring will be needed anyway. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- (no changes since v1) arch/x86/cpu/i386/cpu.c | 24 +++++------------------- arch/x86/cpu/mp_init.c | 22 ++++++++++------------ arch/x86/include/asm/mp.h | 17 +---------------- 3 files changed, 16 insertions(+), 47 deletions(-) diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c index d27324cb4e..9809ac5111 100644 --- a/arch/x86/cpu/i386/cpu.c +++ b/arch/x86/cpu/i386/cpu.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -626,29 +627,14 @@ int cpu_jump_to_64bit_uboot(ulong target) } #ifdef CONFIG_SMP -static int enable_smis(struct udevice *cpu, void *unused) -{ - return 0; -} - -static struct mp_flight_record mp_steps[] = { - MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL), - /* Wait for APs to finish initialization before proceeding */ - MP_FR_BLOCK_APS(NULL, NULL, enable_smis, NULL), -}; - int x86_mp_init(void) { - struct mp_params mp_params; - - mp_params.parallel_microcode_load = 0, - mp_params.flight_plan = &mp_steps[0]; - mp_params.num_records = ARRAY_SIZE(mp_steps); - mp_params.microcode_pointer = 0; + int ret; - if (mp_init(&mp_params)) { + ret = mp_init(); + if (ret) { printf("Warning: MP init failure\n"); - return -EIO; + return log_ret(ret); } return 0; diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index c25d17c647..831fd7035d 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -41,6 +41,9 @@ struct saved_msr { uint32_t hi; } __packed; +static struct mp_flight_record mp_steps[] = { + MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL), +}; struct mp_flight_plan { int num_records; @@ -372,7 +375,7 @@ static int start_aps(int ap_count, atomic_t *num_aps) return 0; } -static int bsp_do_flight_plan(struct udevice *cpu, struct mp_params *mp_params) +static int bsp_do_flight_plan(struct udevice *cpu, struct mp_flight_plan *plan) { int i; int ret = 0; @@ -380,8 +383,8 @@ static int bsp_do_flight_plan(struct udevice *cpu, struct mp_params *mp_params) const int step_us = 100; int num_aps = num_cpus - 1; - for (i = 0; i < mp_params->num_records; i++) { - struct mp_flight_record *rec = &mp_params->flight_plan[i]; + for (i = 0; i < plan->num_records; i++) { + struct mp_flight_record *rec = &plan->records[i]; /* Wait for APs if the record is not released */ if (atomic_read(&rec->barrier) == 0) { @@ -420,7 +423,7 @@ static int init_bsp(struct udevice **devp) return 0; } -int mp_init(struct mp_params *p) +int mp_init(void) { int num_aps; atomic_t *ap_count; @@ -445,11 +448,6 @@ int mp_init(struct mp_params *p) return ret; } - if (p == NULL || p->flight_plan == NULL || p->num_records < 1) { - printf("Invalid MP parameters\n"); - return -EINVAL; - } - num_cpus = cpu_get_count(cpu); if (num_cpus < 0) { debug("Cannot get number of CPUs: err=%d\n", num_cpus); @@ -464,8 +462,8 @@ int mp_init(struct mp_params *p) debug("Warning: Device tree does not describe all CPUs. Extra ones will not be started correctly\n"); /* Copy needed parameters so that APs have a reference to the plan */ - mp_info.num_records = p->num_records; - mp_info.records = p->flight_plan; + mp_info.num_records = ARRAY_SIZE(mp_steps); + mp_info.records = mp_steps; /* Load the SIPI vector */ ret = load_sipi_vector(&ap_count, num_cpus); @@ -489,7 +487,7 @@ int mp_init(struct mp_params *p) } /* Walk the flight plan for the BSP */ - ret = bsp_do_flight_plan(cpu, p); + ret = bsp_do_flight_plan(cpu, &mp_info); if (ret) { debug("CPU init failed: err=%d\n", ret); return ret; diff --git a/arch/x86/include/asm/mp.h b/arch/x86/include/asm/mp.h index 9dddf88b5a..db02904ecb 100644 --- a/arch/x86/include/asm/mp.h +++ b/arch/x86/include/asm/mp.h @@ -51,21 +51,6 @@ struct mp_flight_record { #define MP_FR_NOBLOCK_APS(ap_func, ap_arg, bsp_func, bsp_arg) \ MP_FLIGHT_RECORD(1, ap_func, ap_arg, bsp_func, bsp_arg) -/* - * The mp_params structure provides the arguments to the mp subsystem - * for bringing up APs. - * - * At present this is overkill for U-Boot, but it may make it easier to add - * SMM support. - */ -struct mp_params { - int parallel_microcode_load; - const void *microcode_pointer; - /* Flight plan for APs and BSP */ - struct mp_flight_record *flight_plan; - int num_records; -}; - /* * mp_init() will set up the SIPI vector and bring up the APs according to * mp_params. Each flight record will be executed according to the plan. Note @@ -85,7 +70,7 @@ struct mp_params { * * mp_init() returns < 0 on error, 0 on success. */ -int mp_init(struct mp_params *params); +int mp_init(void); /* Probes the CPU device */ int mp_init_cpu(struct udevice *cpu, void *unused); From patchwork Wed Jul 8 01:34:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240939 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:23 -0600 Subject: [PATCH v4 03/25] x86: mp_init: Avoid declarations in header files In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-4-sjg@chromium.org> The functions used by the flight plan are declared in the header file but are not used in any other file. Move the flight plan steps down to just above where it is used so that we can make these function static. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- (no changes since v1) arch/x86/cpu/mp_init.c | 40 +++++++++++++++++++-------------------- arch/x86/include/asm/mp.h | 3 --- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 831fd7035d..e77d7f2cd6 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -41,10 +41,6 @@ struct saved_msr { uint32_t hi; } __packed; -static struct mp_flight_record mp_steps[] = { - MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL), -}; - struct mp_flight_plan { int num_records; struct mp_flight_record *records; @@ -423,6 +419,26 @@ static int init_bsp(struct udevice **devp) return 0; } +static int mp_init_cpu(struct udevice *cpu, void *unused) +{ + struct cpu_platdata *plat = dev_get_parent_platdata(cpu); + + /* + * Multiple APs are brought up simultaneously and they may get the same + * seq num in the uclass_resolve_seq() during device_probe(). To avoid + * this, set req_seq to the reg number in the device tree in advance. + */ + cpu->req_seq = dev_read_u32_default(cpu, "reg", -1); + plat->ucode_version = microcode_read_rev(); + plat->device_id = gd->arch.x86_device; + + return device_probe(cpu); +} + +static struct mp_flight_record mp_steps[] = { + MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL), +}; + int mp_init(void) { int num_aps; @@ -495,19 +511,3 @@ int mp_init(void) return 0; } - -int mp_init_cpu(struct udevice *cpu, void *unused) -{ - struct cpu_platdata *plat = dev_get_parent_platdata(cpu); - - /* - * Multiple APs are brought up simultaneously and they may get the same - * seq num in the uclass_resolve_seq() during device_probe(). To avoid - * this, set req_seq to the reg number in the device tree in advance. - */ - cpu->req_seq = dev_read_u32_default(cpu, "reg", -1); - plat->ucode_version = microcode_read_rev(); - plat->device_id = gd->arch.x86_device; - - return device_probe(cpu); -} diff --git a/arch/x86/include/asm/mp.h b/arch/x86/include/asm/mp.h index db02904ecb..94af819ad9 100644 --- a/arch/x86/include/asm/mp.h +++ b/arch/x86/include/asm/mp.h @@ -72,9 +72,6 @@ struct mp_flight_record { */ int mp_init(void); -/* Probes the CPU device */ -int mp_init_cpu(struct udevice *cpu, void *unused); - /* Set up additional CPUs */ int x86_mp_init(void); From patchwork Wed Jul 8 01:34:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240940 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:24 -0600 Subject: [PATCH v4 04/25] x86: mp_init: Switch parameter names in start_aps() In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-5-sjg@chromium.org> These parameters are named differently from elsewhere in this file. Switch them to avoid confusion. Also add comments to this function. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Reviewed-by: Wolfgang Wallner --- (no changes since v2) Changes in v2: - Add comments to explain what start_aps() does arch/x86/cpu/mp_init.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index e77d7f2cd6..8b00d57c88 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -308,13 +308,26 @@ static int apic_wait_timeout(int total_delay, const char *msg) return 0; } -static int start_aps(int ap_count, atomic_t *num_aps) +/** + * start_aps() - Start up the APs and count how many we find + * + * This is called on the boot processor to start up all the other processors + * (here called APs). + * + * @num_aps: Number of APs we expect to find + * @ap_count: Initially zero. Incremented by this function for each AP found + * @return 0 if all APs were set up correctly or there are none to set up, + * -ENOSPC if the SIPI vector is too high in memory, + * -ETIMEDOUT if the ICR is busy or the second SIPI fails to complete + * -EIO if not all APs check in correctly + */ +static int start_aps(int num_aps, atomic_t *ap_count) { int sipi_vector; /* Max location is 4KiB below 1MiB */ const int max_vector_loc = ((1 << 20) - (1 << 12)) >> 12; - if (ap_count == 0) + if (num_aps == 0) return 0; /* The vector is sent as a 4k aligned address in one byte */ @@ -326,7 +339,7 @@ static int start_aps(int ap_count, atomic_t *num_aps) return -ENOSPC; } - debug("Attempting to start %d APs\n", ap_count); + debug("Attempting to start %d APs\n", num_aps); if (apic_wait_timeout(1000, "ICR not to be busy")) return -ETIMEDOUT; @@ -349,7 +362,7 @@ static int start_aps(int ap_count, atomic_t *num_aps) return -ETIMEDOUT; /* Wait for CPUs to check in up to 200 us */ - wait_for_aps(num_aps, ap_count, 200, 15); + wait_for_aps(ap_count, num_aps, 200, 15); /* Send 2nd SIPI */ if (apic_wait_timeout(1000, "ICR not to be busy")) @@ -362,9 +375,9 @@ static int start_aps(int ap_count, atomic_t *num_aps) return -ETIMEDOUT; /* Wait for CPUs to check in */ - if (wait_for_aps(num_aps, ap_count, 10000, 50)) { + if (wait_for_aps(ap_count, num_aps, 10000, 50)) { debug("Not all APs checked in: %d/%d\n", - atomic_read(num_aps), ap_count); + atomic_read(ap_count), num_aps); return -EIO; } From patchwork Wed Jul 8 01:34:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240942 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:25 -0600 Subject: [PATCH v4 05/25] x86: mp_init: Drop the num_cpus static variable In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-6-sjg@chromium.org> This does not need to be global across all functions in this file. Pass a parameter instead. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- (no changes since v3) Changes in v3: - Update bsp_do_flight_plan() to say 'on the BSP' arch/x86/cpu/mp_init.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 8b00d57c88..df43f71572 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -31,9 +31,6 @@ DECLARE_GLOBAL_DATA_PTR; -/* Total CPUs include BSP */ -static int num_cpus; - /* This also needs to match the sipi.S assembly code for saved MSR encoding */ struct saved_msr { uint32_t index; @@ -384,13 +381,23 @@ static int start_aps(int num_aps, atomic_t *ap_count) return 0; } -static int bsp_do_flight_plan(struct udevice *cpu, struct mp_flight_plan *plan) +/** + * bsp_do_flight_plan() - Do the flight plan on the BSP + * + * This runs the flight plan on the main CPU used to boot U-Boot + * + * @cpu: Device for the main CPU + * @plan: Flight plan to run + * @num_aps: Number of APs (CPUs other than the BSP) + * @returns 0 on success, -ETIMEDOUT if an AP failed to come up + */ +static int bsp_do_flight_plan(struct udevice *cpu, struct mp_flight_plan *plan, + int num_aps) { int i; int ret = 0; const int timeout_us = 100000; const int step_us = 100; - int num_aps = num_cpus - 1; for (i = 0; i < plan->num_records; i++) { struct mp_flight_record *rec = &plan->records[i]; @@ -410,6 +417,7 @@ static int bsp_do_flight_plan(struct udevice *cpu, struct mp_flight_plan *plan) release_barrier(&rec->barrier); } + return ret; } @@ -454,7 +462,7 @@ static struct mp_flight_record mp_steps[] = { int mp_init(void) { - int num_aps; + int num_aps, num_cpus; atomic_t *ap_count; struct udevice *cpu; int ret; @@ -516,7 +524,7 @@ int mp_init(void) } /* Walk the flight plan for the BSP */ - ret = bsp_do_flight_plan(cpu, &mp_info); + ret = bsp_do_flight_plan(cpu, &mp_info, num_aps); if (ret) { debug("CPU init failed: err=%d\n", ret); return ret; From patchwork Wed Jul 8 01:34:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240941 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:26 -0600 Subject: [PATCH v4 06/25] x86: mtrr: Fix 'ensable' typo In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-7-sjg@chromium.org> Fix a typo in the command help. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- (no changes since v1) cmd/x86/mtrr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/x86/mtrr.c b/cmd/x86/mtrr.c index 084d7315f4..5d25c5802a 100644 --- a/cmd/x86/mtrr.c +++ b/cmd/x86/mtrr.c @@ -135,5 +135,5 @@ U_BOOT_CMD( "set - set a register\n" "\t is Uncacheable, Combine, Through, Protect, Back\n" "disable - disable a register\n" - "ensable - enable a register" + "enable - enable a register" ); From patchwork Wed Jul 8 01:34:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240946 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:27 -0600 Subject: [PATCH v4 07/25] x86: mp_init: Set up the CPU numbers at the start In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-8-sjg@chromium.org> At present each CPU is given a number when it starts itself up. While this saves a tiny amount of time by doing the device-tree read in parallel, it is confusing that the numbering happens on the fly. Move this code into mp_init() and do it at the start. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- (no changes since v1) arch/x86/cpu/mp_init.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index df43f71572..6f6de49df0 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -444,12 +444,6 @@ static int mp_init_cpu(struct udevice *cpu, void *unused) { struct cpu_platdata *plat = dev_get_parent_platdata(cpu); - /* - * Multiple APs are brought up simultaneously and they may get the same - * seq num in the uclass_resolve_seq() during device_probe(). To avoid - * this, set req_seq to the reg number in the device tree in advance. - */ - cpu->req_seq = dev_read_u32_default(cpu, "reg", -1); plat->ucode_version = microcode_read_rev(); plat->device_id = gd->arch.x86_device; @@ -465,13 +459,8 @@ int mp_init(void) int num_aps, num_cpus; atomic_t *ap_count; struct udevice *cpu; - int ret; - - /* This will cause the CPUs devices to be bound */ struct uclass *uc; - ret = uclass_get(UCLASS_CPU, &uc); - if (ret) - return ret; + int ret; if (IS_ENABLED(CONFIG_QFW)) { ret = qemu_cpu_fixup(); @@ -479,6 +468,14 @@ int mp_init(void) return ret; } + /* + * Multiple APs are brought up simultaneously and they may get the same + * seq num in the uclass_resolve_seq() during device_probe(). To avoid + * this, set req_seq to the reg number in the device tree in advance. + */ + uclass_id_foreach_dev(UCLASS_CPU, cpu, uc) + cpu->req_seq = dev_read_u32_default(cpu, "reg", -1); + ret = init_bsp(&cpu); if (ret) { debug("Cannot init boot CPU: err=%d\n", ret); From patchwork Wed Jul 8 01:34:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240947 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:28 -0600 Subject: [PATCH v4 08/25] x86: mp_init: Adjust bsp_init() to return more information In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-9-sjg@chromium.org> This function is misnamed since it does not actually init the BSP. Also it is convenient to adjust it to return a little more information. Rename and update the function, to allow it to return the BSP CPU device and number, as well as the total number of CPUs. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- Changes in v4: - Update get_bsp() to return zero when SMP is not inited Changes in v2: - Drop change to include/dm/uclass.h - Mention error return in get_bsp() arch/x86/cpu/mp_init.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 6f6de49df0..9fdde7832a 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -421,9 +421,18 @@ static int bsp_do_flight_plan(struct udevice *cpu, struct mp_flight_plan *plan, return ret; } -static int init_bsp(struct udevice **devp) +/** + * get_bsp() - Get information about the bootstrap processor + * + * @devp: If non-NULL, returns CPU device corresponding to the BSP + * @cpu_countp: If non-NULL, returns the total number of CPUs + * @return CPU number of the BSP, or -ve on error. If multiprocessing is not + * enabled, returns 0 + */ +static int get_bsp(struct udevice **devp, int *cpu_countp) { char processor_name[CPU_MAX_NAME_LEN]; + struct udevice *dev; int apic_id; int ret; @@ -431,13 +440,20 @@ static int init_bsp(struct udevice **devp) debug("CPU: %s\n", processor_name); apic_id = lapicid(); - ret = find_cpu_by_apic_id(apic_id, devp); - if (ret) { + ret = find_cpu_by_apic_id(apic_id, &dev); + if (ret < 0) { printf("Cannot find boot CPU, APIC ID %d\n", apic_id); return ret; } + ret = cpu_get_count(dev); + if (ret < 0) + return log_msg_ret("count", ret); + if (devp) + *devp = dev; + if (cpu_countp) + *cpu_countp = ret; - return 0; + return dev->req_seq >= 0 ? dev->req_seq : 0; } static int mp_init_cpu(struct udevice *cpu, void *unused) @@ -476,24 +492,18 @@ int mp_init(void) uclass_id_foreach_dev(UCLASS_CPU, cpu, uc) cpu->req_seq = dev_read_u32_default(cpu, "reg", -1); - ret = init_bsp(&cpu); - if (ret) { + ret = get_bsp(&cpu, &num_cpus); + if (ret < 0) { debug("Cannot init boot CPU: err=%d\n", ret); return ret; } - num_cpus = cpu_get_count(cpu); - if (num_cpus < 0) { - debug("Cannot get number of CPUs: err=%d\n", num_cpus); - return num_cpus; - } - if (num_cpus < 2) debug("Warning: Only 1 CPU is detected\n"); ret = check_cpu_devices(num_cpus); if (ret) - debug("Warning: Device tree does not describe all CPUs. Extra ones will not be started correctly\n"); + log_warning("Warning: Device tree does not describe all CPUs. Extra ones will not be started correctly\n"); /* Copy needed parameters so that APs have a reference to the plan */ mp_info.num_records = ARRAY_SIZE(mp_steps); From patchwork Wed Jul 8 01:34:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240952 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:29 -0600 Subject: [PATCH v4 09/25] x86: cpu: Remove unnecessary #ifdefs In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-10-sjg@chromium.org> Drop some #ifdefs that are not needed or can be converted to compile-time checks. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- (no changes since v1) arch/x86/cpu/cpu.c | 58 ++++++++++++++++++++--------------------- arch/x86/cpu/i386/cpu.c | 2 -- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 23a4d633d2..d0720fb7fb 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -66,10 +66,8 @@ static const char *const x86_vendor_name[] = { int __weak x86_cleanup_before_linux(void) { -#ifdef CONFIG_BOOTSTAGE_STASH bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR, CONFIG_BOOTSTAGE_STASH_SIZE); -#endif return 0; } @@ -200,18 +198,19 @@ int last_stage_init(void) write_tables(); -#ifdef CONFIG_GENERATE_ACPI_TABLE - fadt = acpi_find_fadt(); + if (IS_ENABLED(CONFIG_GENERATE_ACPI_TABLE)) { + fadt = acpi_find_fadt(); - /* Don't touch ACPI hardware on HW reduced platforms */ - if (fadt && !(fadt->flags & ACPI_FADT_HW_REDUCED_ACPI)) { - /* - * Other than waiting for OSPM to request us to switch to ACPI - * mode, do it by ourselves, since SMI will not be triggered. - */ - enter_acpi_mode(fadt->pm1a_cnt_blk); + /* Don't touch ACPI hardware on HW reduced platforms */ + if (fadt && !(fadt->flags & ACPI_FADT_HW_REDUCED_ACPI)) { + /* + * Other than waiting for OSPM to request us to switch + * to ACPI * mode, do it by ourselves, since SMI will + * not be triggered. + */ + enter_acpi_mode(fadt->pm1a_cnt_blk); + } } -#endif return 0; } @@ -219,19 +218,20 @@ int last_stage_init(void) static int x86_init_cpus(void) { -#ifdef CONFIG_SMP - debug("Init additional CPUs\n"); - x86_mp_init(); -#else - struct udevice *dev; + if (IS_ENABLED(CONFIG_SMP)) { + debug("Init additional CPUs\n"); + x86_mp_init(); + } else { + struct udevice *dev; - /* - * This causes the cpu-x86 driver to be probed. - * We don't check return value here as we want to allow boards - * which have not been converted to use cpu uclass driver to boot. - */ - uclass_first_device(UCLASS_CPU, &dev); -#endif + /* + * This causes the cpu-x86 driver to be probed. + * We don't check return value here as we want to allow boards + * which have not been converted to use cpu uclass driver to + * boot. + */ + uclass_first_device(UCLASS_CPU, &dev); + } return 0; } @@ -269,13 +269,11 @@ int cpu_init_r(void) #ifndef CONFIG_EFI_STUB int reserve_arch(void) { -#ifdef CONFIG_ENABLE_MRC_CACHE - mrccache_reserve(); -#endif + if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) + mrccache_reserve(); -#ifdef CONFIG_SEABIOS - high_table_reserve(); -#endif + if (IS_ENABLED(CONFIG_SEABIOS)) + high_table_reserve(); if (IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)) { acpi_s3_reserve(); diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c index 9809ac5111..fca3f79b69 100644 --- a/arch/x86/cpu/i386/cpu.c +++ b/arch/x86/cpu/i386/cpu.c @@ -626,7 +626,6 @@ int cpu_jump_to_64bit_uboot(ulong target) return -EFAULT; } -#ifdef CONFIG_SMP int x86_mp_init(void) { int ret; @@ -639,4 +638,3 @@ int x86_mp_init(void) return 0; } -#endif From patchwork Wed Jul 8 01:34:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240943 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:30 -0600 Subject: [PATCH v4 10/25] x86: mp: Support APs waiting for instructions In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200707193423.v4.10.I5cdb6d2b53a528eaebda2227b8cdfe26c4c73ceb@changeid> At present the APs (non-boot CPUs) are inited once and then parked ready for the OS to use them. However in some cases we want to send new requests through, such as to change MTRRs and keep them consistent across CPUs. Change the last state of the flight plan to go into a wait loop, accepting instructions from the main CPU. Drop cpu_map since it is not used. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- Changes in v4: - Add a Kconfig to control this feature, enabled only on APL Changes in v3: - s/slow/slot/ - Use C code instead of assembler to read/write callback pointers - Update commit message to mention dropping of cpu_map Changes in v2: - Add more comments arch/x86/Kconfig | 7 ++ arch/x86/cpu/apollolake/Kconfig | 1 + arch/x86/cpu/mp_init.c | 123 +++++++++++++++++++++++++++++--- arch/x86/include/asm/mp.h | 11 +++ 4 files changed, 134 insertions(+), 8 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index c8eae24c07..cc4716fe12 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -603,6 +603,13 @@ config SMP only one CPU will be enabled regardless of the number of CPUs available. +config SMP_AP_WORK + bool + depends on SMP + help + Allow APs to do other work after initialisation instead of going + to sleep. + config MAX_CPUS int "Maximum number of CPUs permitted" depends on SMP diff --git a/arch/x86/cpu/apollolake/Kconfig b/arch/x86/cpu/apollolake/Kconfig index 942f11f566..99d4e105c2 100644 --- a/arch/x86/cpu/apollolake/Kconfig +++ b/arch/x86/cpu/apollolake/Kconfig @@ -15,6 +15,7 @@ config INTEL_APOLLOLAKE select TPL_PCH_SUPPORT select PCH_SUPPORT select P2SB + select SMP_AP_WORK imply ENABLE_MRC_CACHE imply AHCI_PCI imply SCSI diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 9fdde7832a..787de92fa3 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -43,13 +44,38 @@ struct mp_flight_plan { struct mp_flight_record *records; }; +/** + * struct mp_callback - Callback information for APs + * + * @func: Function to run + * @arg: Argument to pass to the function + * @logical_cpu_number: Either a CPU number (i.e. dev->req_seq) or a special + * value like MP_SELECT_BSP. It tells the AP whether it should process this + * callback + */ +struct mp_callback { + /** + * func() - Function to call on the AP + * + * @arg: Argument to pass + */ + void (*func)(void *arg); + void *arg; + int logical_cpu_number; +}; + static struct mp_flight_plan mp_info; -struct cpu_map { - struct udevice *dev; - int apic_id; - int err_code; -}; +/* + * ap_callbacks - Callback mailbox array + * + * Array of callback, one entry for each available CPU, indexed by the CPU + * number, which is dev->req_seq. The entry for the main CPU is never used. + * When this is NULL, there is no pending work for the CPU to run. When + * non-NULL it points to the mp_callback structure. This is shared between all + * CPUs, so should only be written by the main CPU. + */ +static struct mp_callback **ap_callbacks; static inline void barrier_wait(atomic_t *b) { @@ -147,11 +173,12 @@ static void ap_init(unsigned int cpu_index) debug("AP: slot %d apic_id %x, dev %s\n", cpu_index, apic_id, dev ? dev->name : "(apic_id not found)"); - /* Walk the flight plan */ + /* + * Walk the flight plan, which only returns if CONFIG_SMP_AP_WORK is not + * enabled + */ ap_do_flight_plan(dev); - /* Park the AP */ - debug("parking\n"); done: stop_this_cpu(); } @@ -456,6 +483,81 @@ static int get_bsp(struct udevice **devp, int *cpu_countp) return dev->req_seq >= 0 ? dev->req_seq : 0; } +/** + * read_callback() - Read the pointer in a callback slot + * + * This is called by APs to read their callback slot to see if there is a + * pointer to new instructions + * + * @slot: Pointer to the AP's callback slot + * @return value of that pointer + */ +static struct mp_callback *read_callback(struct mp_callback **slot) +{ + dmb(); + + return *slot; +} + +/** + * store_callback() - Store a pointer to the callback slot + * + * This is called by APs to write NULL into the callback slot when they have + * finished the work requested by the BSP. + * + * @slot: Pointer to the AP's callback slot + * @val: Value to write (e.g. NULL) + */ +static void store_callback(struct mp_callback **slot, struct mp_callback *val) +{ + *slot = val; + dmb(); +} + +/** + * ap_wait_for_instruction() - Wait for and process requests from the main CPU + * + * This is called by APs (here, everything other than the main boot CPU) to + * await instructions. They arrive in the form of a function call and argument, + * which is then called. This uses a simple mailbox with atomic read/set + * + * @cpu: CPU that is waiting + * @unused: Optional argument provided by struct mp_flight_record, not used here + * @return Does not return + */ +static int ap_wait_for_instruction(struct udevice *cpu, void *unused) +{ + struct mp_callback lcb; + struct mp_callback **per_cpu_slot; + + if (!IS_ENABLED(CONFIG_SMP_AP_WORK)) + return 0; + + per_cpu_slot = &ap_callbacks[cpu->req_seq]; + + while (1) { + struct mp_callback *cb = read_callback(per_cpu_slot); + + if (!cb) { + asm ("pause"); + continue; + } + + /* Copy to local variable before using the value */ + memcpy(&lcb, cb, sizeof(lcb)); + mfence(); + if (lcb.logical_cpu_number == MP_SELECT_ALL || + lcb.logical_cpu_number == MP_SELECT_APS || + cpu->req_seq == lcb.logical_cpu_number) + lcb.func(lcb.arg); + + /* Indicate we are finished */ + store_callback(per_cpu_slot, NULL); + } + + return 0; +} + static int mp_init_cpu(struct udevice *cpu, void *unused) { struct cpu_platdata *plat = dev_get_parent_platdata(cpu); @@ -468,6 +570,7 @@ static int mp_init_cpu(struct udevice *cpu, void *unused) static struct mp_flight_record mp_steps[] = { MP_FR_BLOCK_APS(mp_init_cpu, NULL, mp_init_cpu, NULL), + MP_FR_BLOCK_APS(ap_wait_for_instruction, NULL, NULL, NULL), }; int mp_init(void) @@ -505,6 +608,10 @@ int mp_init(void) if (ret) log_warning("Warning: Device tree does not describe all CPUs. Extra ones will not be started correctly\n"); + ap_callbacks = calloc(num_cpus, sizeof(struct mp_callback *)); + if (!ap_callbacks) + return -ENOMEM; + /* Copy needed parameters so that APs have a reference to the plan */ mp_info.num_records = ARRAY_SIZE(mp_steps); mp_info.records = mp_steps; diff --git a/arch/x86/include/asm/mp.h b/arch/x86/include/asm/mp.h index 94af819ad9..41b1575f4b 100644 --- a/arch/x86/include/asm/mp.h +++ b/arch/x86/include/asm/mp.h @@ -11,6 +11,17 @@ #include #include +enum { + /* Indicates that the function should run on all CPUs */ + MP_SELECT_ALL = -1, + + /* Run on boot CPUs */ + MP_SELECT_BSP = -2, + + /* Run on non-boot CPUs */ + MP_SELECT_APS = -3, +}; + typedef int (*mp_callback_t)(struct udevice *cpu, void *arg); /* From patchwork Wed Jul 8 01:34:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240944 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:31 -0600 Subject: [PATCH v4 11/25] global_data: Add a generic global_data flag for SMP state In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-11-sjg@chromium.org> Allow keeping track of whether all CPUs have been enabled yet. This allows us to know whether other CPUs need to be considered when updating CPU-specific settings such as MTRRs on x86. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- (no changes since v3) Changes in v3: - Rename flag to GD_FLG_SMP_READY include/asm-generic/global_data.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 8c78792cc9..d4a4e2215d 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -167,5 +167,6 @@ typedef struct global_data { #define GD_FLG_LOG_READY 0x08000 /* Log system is ready for use */ #define GD_FLG_WDT_READY 0x10000 /* Watchdog is ready for use */ #define GD_FLG_SKIP_LL_INIT 0x20000 /* Don't perform low-level init */ +#define GD_FLG_SMP_READY 0x40000 /* SMP init is complete */ #endif /* __ASM_GENERIC_GBL_DATA_H */ From patchwork Wed Jul 8 01:34:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240948 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:32 -0600 Subject: [PATCH v4 12/25] x86: Set the SMP flag when MP init is complete In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-12-sjg@chromium.org> Set this flag so we can track when it is safe to use CPUs other than the main one. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- (no changes since v3) Changes in v3: - Rename flag to GD_FLG_SMP_READY arch/x86/cpu/mp_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 787de92fa3..69a23829b9 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -643,6 +643,7 @@ int mp_init(void) debug("CPU init failed: err=%d\n", ret); return ret; } + gd->flags |= GD_FLG_SMP_READY; return 0; } From patchwork Wed Jul 8 01:34:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240945 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:33 -0600 Subject: [PATCH v4 13/25] x86: mp: Allow running functions on multiple CPUs In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200707193423.v4.13.I15c8366d7a11d1eeea57e5ac4d0471a95725ce9e@changeid> 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 Reviewed-by: Wolfgang Wallner --- 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++; + } + + 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; +} + /** * ap_wait_for_instruction() - Wait for and process requests from the main CPU * @@ -573,6 +632,42 @@ static struct mp_flight_record mp_steps[] = { MP_FR_BLOCK_APS(ap_wait_for_instruction, NULL, NULL, NULL), }; +int mp_run_on_cpus(int cpu_select, mp_run_func func, void *arg) +{ + struct mp_callback lcb = { + .func = func, + .arg = arg, + .logical_cpu_number = cpu_select, + }; + struct udevice *dev; + int num_cpus; + int ret; + + ret = get_bsp(&dev, &num_cpus); + if (ret < 0) + return log_msg_ret("bsp", ret); + if (cpu_select == MP_SELECT_ALL || cpu_select == MP_SELECT_BSP || + cpu_select == ret) { + /* Run on BSP first */ + func(arg); + } + + if (!IS_ENABLED(CONFIG_SMP_AP_WORK) || + !(gd->flags & GD_FLG_SMP_READY)) { + /* Allow use of this function on the BSP only */ + if (cpu_select == MP_SELECT_BSP || !cpu_select) + return 0; + return -ENOTSUPP; + } + + /* Allow up to 1 second for all APs to finish */ + ret = run_ap_work(&lcb, dev, num_cpus, 1000 /* ms */); + if (ret) + return log_msg_ret("aps", ret); + + return 0; +} + 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 41b1575f4b..eb49e690f2 100644 --- a/arch/x86/include/asm/mp.h +++ b/arch/x86/include/asm/mp.h @@ -86,4 +86,37 @@ int mp_init(void); /* Set up additional CPUs */ int x86_mp_init(void); +/** + * mp_run_func() - Function to call on the AP + * + * @arg: Argument to pass + */ +typedef void (*mp_run_func)(void *arg); + +#if defined(CONFIG_SMP) && !CONFIG_IS_ENABLED(X86_64) +/** + * mp_run_on_cpus() - Run a function on one or all CPUs + * + * This does not return until all CPUs have completed the work + * + * Running on anything other than the boot CPU is only supported if + * CONFIG_SMP_AP_WORK is enabled + * + * @cpu_select: CPU to run on (its dev->req_seq value), or MP_SELECT_ALL for + * all, or MP_SELECT_BSP for BSP + * @func: Function to run + * @arg: Argument to pass to the function + * @return 0 on success, -ve on error + */ +int mp_run_on_cpus(int cpu_select, mp_run_func func, void *arg); +#else +static inline int mp_run_on_cpus(int cpu_select, mp_run_func func, void *arg) +{ + /* There is only one CPU, so just call the function here */ + func(arg); + + return 0; +} +#endif + #endif /* _X86_MP_H_ */ From patchwork Wed Jul 8 01:34:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240949 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:34 -0600 Subject: [PATCH v4 14/25] x86: mp: Park CPUs before running the OS In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-13-sjg@chromium.org> With the new MP features the CPUs are no-longer parked when the OS is run. Fix this by calling a special function to park them, just before the OS is started. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner --- (no changes since v3) Changes in v3: - Update the comment for mp_park_aps() arch/x86/cpu/cpu.c | 5 +++++ arch/x86/cpu/mp_init.c | 18 ++++++++++++++++++ arch/x86/include/asm/mp.h | 17 +++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index d0720fb7fb..baa7dae172 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -66,6 +66,11 @@ static const char *const x86_vendor_name[] = { int __weak x86_cleanup_before_linux(void) { + int ret; + + ret = mp_park_aps(); + if (ret) + return log_msg_ret("park", ret); bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR, CONFIG_BOOTSTAGE_STASH_SIZE); diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index dd6d6bfab7..721b729d92 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -668,6 +668,24 @@ int mp_run_on_cpus(int cpu_select, mp_run_func func, void *arg) return 0; } +static void park_this_cpu(void *unused) +{ + stop_this_cpu(); +} + +int mp_park_aps(void) +{ + unsigned long start; + int ret; + + start = get_timer(0); + ret = mp_run_on_cpus(MP_SELECT_APS, park_this_cpu, NULL); + if (ret) + return ret; + + return get_timer(start); +} + 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 eb49e690f2..93b1786b66 100644 --- a/arch/x86/include/asm/mp.h +++ b/arch/x86/include/asm/mp.h @@ -109,6 +109,15 @@ typedef void (*mp_run_func)(void *arg); * @return 0 on success, -ve on error */ int mp_run_on_cpus(int cpu_select, mp_run_func func, void *arg); + +/** + * mp_park_aps() - Park the APs ready for the OS + * + * This halts all CPUs except the main one, ready for the OS to use them + * + * @return time taken to park the APs on success (in microseconds), -ve on error + */ +int mp_park_aps(void); #else static inline int mp_run_on_cpus(int cpu_select, mp_run_func func, void *arg) { @@ -117,6 +126,14 @@ static inline int mp_run_on_cpus(int cpu_select, mp_run_func func, void *arg) return 0; } + +static inline int mp_park_aps(void) +{ + /* No APs to park */ + + return 0; +} + #endif #endif /* _X86_MP_H_ */ 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_ */ From patchwork Wed Jul 8 01:34:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240953 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:36 -0600 Subject: [PATCH v4 16/25] x86: mtrr: Use MP calls to list the MTRRs In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-15-sjg@chromium.org> Update the mtrr command to use mp_run_on_cpus() to obtain its information. Since the selected CPU is the boot CPU this does not change the result, but it sets the stage for supporting other CPUs. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- (no changes since v2) Changes in v2: - Rename mtrr_save_all() to mtrr_read_all() arch/x86/cpu/mtrr.c | 11 +++++++++++ arch/x86/include/asm/mtrr.h | 30 ++++++++++++++++++++++++++++++ cmd/x86/mtrr.c | 25 +++++++++++++++++++++---- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c index 7ec0733337..c9b4e7d06e 100644 --- a/arch/x86/cpu/mtrr.c +++ b/arch/x86/cpu/mtrr.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,16 @@ static void set_var_mtrr(uint reg, uint type, uint64_t start, uint64_t size) wrmsrl(MTRR_PHYS_MASK_MSR(reg), mask | MTRR_PHYS_MASK_VALID); } +void mtrr_read_all(struct mtrr_info *info) +{ + int i; + + for (i = 0; i < MTRR_COUNT; i++) { + info->mtrr[i].base = native_read_msr(MTRR_PHYS_BASE_MSR(i)); + info->mtrr[i].mask = native_read_msr(MTRR_PHYS_MASK_MSR(i)); + } +} + int mtrr_commit(bool do_caches) { struct mtrr_request *req = gd->arch.mtrr_req; diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index 212a699c1b..e1f1a44643 100644 --- a/arch/x86/include/asm/mtrr.h +++ b/arch/x86/include/asm/mtrr.h @@ -70,6 +70,26 @@ struct mtrr_state { bool enable_cache; }; +/** + * struct mtrr - Information about a single MTRR + * + * @base: Base address and MTRR_BASE_TYPE_MASK + * @mask: Mask and MTRR_PHYS_MASK_VALID + */ +struct mtrr { + u64 base; + u64 mask; +}; + +/** + * struct mtrr_info - Information about all MTRRs + * + * @mtrr: Information about each mtrr + */ +struct mtrr_info { + struct mtrr mtrr[MTRR_COUNT]; +}; + /** * mtrr_open() - Prepare to adjust MTRRs * @@ -129,6 +149,16 @@ int mtrr_commit(bool do_caches); */ int mtrr_set_next_var(uint type, uint64_t base, uint64_t size); +/** + * mtrr_read_all() - Save all the MTRRs + * + * This reads all MTRRs from the boot CPU into a struct so they can be loaded + * onto other CPUs + * + * @info: Place to put the MTRR info + */ +void mtrr_read_all(struct mtrr_info *info); + #endif #if ((CONFIG_XIP_ROM_SIZE & (CONFIG_XIP_ROM_SIZE - 1)) != 0) diff --git a/cmd/x86/mtrr.c b/cmd/x86/mtrr.c index 5d25c5802a..f357f58767 100644 --- a/cmd/x86/mtrr.c +++ b/cmd/x86/mtrr.c @@ -5,7 +5,9 @@ #include #include +#include #include +#include #include static const char *const mtrr_type_name[MTRR_TYPE_COUNT] = { @@ -18,19 +20,32 @@ static const char *const mtrr_type_name[MTRR_TYPE_COUNT] = { "Back", }; -static int do_mtrr_list(void) +static void read_mtrrs(void *arg) { + struct mtrr_info *info = arg; + + mtrr_read_all(info); +} + +static int do_mtrr_list(int cpu_select) +{ + struct mtrr_info info; + int ret; int i; printf("Reg Valid Write-type %-16s %-16s %-16s\n", "Base ||", "Mask ||", "Size ||"); + memset(&info, '\0', sizeof(info)); + ret = mp_run_on_cpus(cpu_select, read_mtrrs, &info); + if (ret) + return log_msg_ret("run", ret); for (i = 0; i < MTRR_COUNT; i++) { const char *type = "Invalid"; uint64_t base, mask, size; bool valid; - base = native_read_msr(MTRR_PHYS_BASE_MSR(i)); - mask = native_read_msr(MTRR_PHYS_MASK_MSR(i)); + base = info.mtrr[i].base; + mask = info.mtrr[i].mask; size = ~mask & ((1ULL << CONFIG_CPU_ADDR_BITS) - 1); size |= (1 << 12) - 1; size += 1; @@ -102,11 +117,13 @@ static int do_mtrr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { const char *cmd; + int cpu_select; uint reg; + cpu_select = MP_SELECT_BSP; cmd = argv[1]; if (argc < 2 || *cmd == 'l') - return do_mtrr_list(); + return do_mtrr_list(cpu_select); argc -= 2; argv += 2; if (argc <= 0) From patchwork Wed Jul 8 01:34:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240951 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:37 -0600 Subject: [PATCH v4 17/25] x86: Don't enable SMP in SPL In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200707193423.v4.17.I9cd33fea6b1875fc7606864fb74ae8d92fb46d7b@changeid> SMP should be set up in U-Boot where possible, not SPL. Disable it in SPL. For 64-bit U-Boot we should find a way to allow SMP operations in U-Boot, but this is somewhat more complicated. For now that is disabled too. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Reviewed-by: Wolfgang Wallner --- (no changes since v2) Changes in v2: - Add a new patch to avoid enabling SMP in SPL arch/x86/cpu/Makefile | 2 +- arch/x86/include/asm/mp.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index ee0499f5d7..16e67e3da2 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -60,7 +60,7 @@ ifndef CONFIG_SYS_COREBOOT obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += irq.o endif ifndef CONFIG_$(SPL_)X86_64 -obj-$(CONFIG_SMP) += mp_init.o +obj-$(CONFIG_$(SPL_)SMP) += mp_init.o endif obj-y += mtrr.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/x86/include/asm/mp.h b/arch/x86/include/asm/mp.h index 34d724938a..5b8811832a 100644 --- a/arch/x86/include/asm/mp.h +++ b/arch/x86/include/asm/mp.h @@ -93,7 +93,7 @@ int x86_mp_init(void); */ typedef void (*mp_run_func)(void *arg); -#if defined(CONFIG_SMP) && !CONFIG_IS_ENABLED(X86_64) +#if CONFIG_IS_ENABLED(SMP) && !CONFIG_IS_ENABLED(X86_64) /** * mp_run_on_cpus() - Run a function on one or all CPUs * From patchwork Wed Jul 8 01:34:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240954 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:38 -0600 Subject: [PATCH v4 18/25] x86: coral: Update the memory map In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-16-sjg@chromium.org> This currently excludes the temporary memory used to start up the APs. Add it. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Reviewed-by: Wolfgang Wallner --- (no changes since v2) Changes in v2: - Add new patch to add AP_DEFAULT_BASE to coral's memory map doc/board/google/chromebook_coral.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/board/google/chromebook_coral.rst b/doc/board/google/chromebook_coral.rst index 40bd9397d4..c39f1e310c 100644 --- a/doc/board/google/chromebook_coral.rst +++ b/doc/board/google/chromebook_coral.rst @@ -188,6 +188,7 @@ Partial memory map fef00000 1000 CONFIG_BOOTSTAGE_STASH_ADDR fef00000 Base of CAR region + 30000 AP_DEFAULT_BASE (used to start up additional CPUs) f0000 CONFIG_ROM_TABLE_ADDR 120000 BSS (defined in u-boot-spl.lds) 200000 FSP-S (which is run after U-Boot is relocated) From patchwork Wed Jul 8 01:34:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240955 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:39 -0600 Subject: [PATCH v4 19/25] x86: mtrr: Update MTRRs on all CPUs In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-17-sjg@chromium.org> When the boot CPU MTRRs are updated, perform the same update on all other CPUs so they are kept in sync. This avoids kernel warnings about mismatched MTRRs. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- (no changes since v2) Changes in v2: - Rename function to mtrr_write_all() arch/x86/cpu/mtrr.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c index c9b4e7d06e..5c567551e5 100644 --- a/arch/x86/cpu/mtrr.c +++ b/arch/x86/cpu/mtrr.c @@ -74,10 +74,61 @@ void mtrr_read_all(struct mtrr_info *info) } } +void mtrr_write_all(struct mtrr_info *info) +{ + struct mtrr_state state; + int i; + + for (i = 0; i < MTRR_COUNT; i++) { + mtrr_open(&state, true); + wrmsrl(MTRR_PHYS_BASE_MSR(i), info->mtrr[i].base); + wrmsrl(MTRR_PHYS_MASK_MSR(i), info->mtrr[i].mask); + mtrr_close(&state, true); + } +} + +static void write_mtrrs(void *arg) +{ + struct mtrr_info *info = arg; + + mtrr_write_all(info); +} + +static void read_mtrrs(void *arg) +{ + struct mtrr_info *info = arg; + + mtrr_read_all(info); +} + +/** + * mtrr_copy_to_aps() - Copy the MTRRs from the boot CPU to other CPUs + * + * @return 0 on success, -ve on failure + */ +static int mtrr_copy_to_aps(void) +{ + struct mtrr_info info; + int ret; + + ret = mp_run_on_cpus(MP_SELECT_BSP, read_mtrrs, &info); + if (ret == -ENXIO) + return 0; + else if (ret) + return log_msg_ret("bsp", ret); + + ret = mp_run_on_cpus(MP_SELECT_APS, write_mtrrs, &info); + if (ret) + return log_msg_ret("bsp", ret); + + return 0; +} + int mtrr_commit(bool do_caches) { struct mtrr_request *req = gd->arch.mtrr_req; struct mtrr_state state; + int ret; int i; debug("%s: enabled=%d, count=%d\n", __func__, gd->arch.has_mtrr, @@ -99,6 +150,12 @@ int mtrr_commit(bool do_caches) mtrr_close(&state, do_caches); debug("mtrr done\n"); + if (gd->flags & GD_FLG_RELOC) { + ret = mtrr_copy_to_aps(); + if (ret) + return log_msg_ret("copy", ret); + } + return 0; } From patchwork Wed Jul 8 01:34:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240956 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:40 -0600 Subject: [PATCH v4 20/25] x86: mtrr: Add support for writing to MTRRs on any CPU In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200707193423.v4.20.I79f1122b437ee390b87d4446bbcfc51dd581d908@changeid> To enable support for the 'mtrr' command, add a way to perform MTRR operations on selected CPUs. This works by setting up a little 'operation' structure and sending it around the CPUs for action. Signed-off-by: Simon Glass Reviewed-by: Bin Meng Reviewed-by: Wolfgang Wallner --- (no changes since v2) Changes in v2: - Keep things building by temporarily renaming the function in cmd/ arch/x86/cpu/mtrr.c | 81 +++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/mtrr.h | 21 ++++++++++ cmd/x86/mtrr.c | 6 +-- 3 files changed, 105 insertions(+), 3 deletions(-) diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c index 5c567551e5..2468d88a80 100644 --- a/arch/x86/cpu/mtrr.c +++ b/arch/x86/cpu/mtrr.c @@ -221,3 +221,84 @@ int mtrr_set_next_var(uint type, uint64_t start, uint64_t size) return 0; } + +/** enum mtrr_opcode - supported operations for mtrr_do_oper() */ +enum mtrr_opcode { + MTRR_OP_SET, + MTRR_OP_SET_VALID, +}; + +/** + * struct mtrr_oper - An MTRR operation to perform on a CPU + * + * @opcode: Indicates operation to perform + * @reg: MTRR reg number to select (0-7, -1 = all) + * @valid: Valid value to write for MTRR_OP_SET_VALID + * @base: Base value to write for MTRR_OP_SET + * @mask: Mask value to write for MTRR_OP_SET + */ +struct mtrr_oper { + enum mtrr_opcode opcode; + int reg; + bool valid; + u64 base; + u64 mask; +}; + +static void mtrr_do_oper(void *arg) +{ + struct mtrr_oper *oper = arg; + u64 mask; + + switch (oper->opcode) { + case MTRR_OP_SET_VALID: + mask = native_read_msr(MTRR_PHYS_MASK_MSR(oper->reg)); + if (oper->valid) + mask |= MTRR_PHYS_MASK_VALID; + else + mask &= ~MTRR_PHYS_MASK_VALID; + wrmsrl(MTRR_PHYS_MASK_MSR(oper->reg), mask); + break; + case MTRR_OP_SET: + wrmsrl(MTRR_PHYS_BASE_MSR(oper->reg), oper->base); + wrmsrl(MTRR_PHYS_MASK_MSR(oper->reg), oper->mask); + break; + } +} + +static int mtrr_start_op(int cpu_select, struct mtrr_oper *oper) +{ + struct mtrr_state state; + int ret; + + mtrr_open(&state, true); + ret = mp_run_on_cpus(cpu_select, mtrr_do_oper, oper); + mtrr_close(&state, true); + if (ret) + return log_msg_ret("run", ret); + + return 0; +} + +int mtrr_set_valid(int cpu_select, int reg, bool valid) +{ + struct mtrr_oper oper; + + oper.opcode = MTRR_OP_SET_VALID; + oper.reg = reg; + oper.valid = valid; + + return mtrr_start_op(cpu_select, &oper); +} + +int mtrr_set(int cpu_select, int reg, u64 base, u64 mask) +{ + struct mtrr_oper oper; + + oper.opcode = MTRR_OP_SET; + oper.reg = reg; + oper.base = base; + oper.mask = mask; + + return mtrr_start_op(cpu_select, &oper); +} diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index e1f1a44643..48db1dd82f 100644 --- a/arch/x86/include/asm/mtrr.h +++ b/arch/x86/include/asm/mtrr.h @@ -159,6 +159,27 @@ int mtrr_set_next_var(uint type, uint64_t base, uint64_t size); */ void mtrr_read_all(struct mtrr_info *info); +/** + * mtrr_set_valid() - Set the valid flag for a selected MTRR and CPU(s) + * + * @cpu_select: Selected CPUs (either a CPU number or MP_SELECT_...) + * @reg: MTRR register to write (0-7) + * @valid: Valid flag to write + * @return 0 on success, -ve on error + */ +int mtrr_set_valid(int cpu_select, int reg, bool valid); + +/** + * mtrr_set() - Set the valid flag for a selected MTRR and CPU(s) + * + * @cpu_select: Selected CPUs (either a CPU number or MP_SELECT_...) + * @reg: MTRR register to write (0-7) + * @base: Base address and MTRR_BASE_TYPE_MASK + * @mask: Mask and MTRR_PHYS_MASK_VALID + * @return 0 on success, -ve on error + */ +int mtrr_set(int cpu_select, int reg, u64 base, u64 mask); + #endif #if ((CONFIG_XIP_ROM_SIZE & (CONFIG_XIP_ROM_SIZE - 1)) != 0) diff --git a/cmd/x86/mtrr.c b/cmd/x86/mtrr.c index f357f58767..46ef6a2830 100644 --- a/cmd/x86/mtrr.c +++ b/cmd/x86/mtrr.c @@ -96,7 +96,7 @@ static int do_mtrr_set(uint reg, int argc, char *const argv[]) return 0; } -static int mtrr_set_valid(int reg, bool valid) +static int mtrr_set_valid_(int reg, bool valid) { struct mtrr_state state; uint64_t mask; @@ -134,9 +134,9 @@ static int do_mtrr(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_USAGE; } if (*cmd == 'e') - return mtrr_set_valid(reg, true); + return mtrr_set_valid_(reg, true); else if (*cmd == 'd') - return mtrr_set_valid(reg, false); + return mtrr_set_valid_(reg, false); else if (*cmd == 's') return do_mtrr_set(reg, argc - 1, argv + 1); else From patchwork Wed Jul 8 01:34:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240957 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:41 -0600 Subject: [PATCH v4 21/25] x86: mtrr: Update the command to use the new mtrr calls In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-18-sjg@chromium.org> Use the multi-CPU calls to set the MTRR values. This still supports only the boot CPU for now. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- (no changes since v2) Changes in v2: - Drop the renamed mtrr_set_valid_() instead of mtrr_set_valid() cmd/x86/mtrr.c | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/cmd/x86/mtrr.c b/cmd/x86/mtrr.c index 46ef6a2830..b047a9897c 100644 --- a/cmd/x86/mtrr.c +++ b/cmd/x86/mtrr.c @@ -59,14 +59,14 @@ static int do_mtrr_list(int cpu_select) return 0; } -static int do_mtrr_set(uint reg, int argc, char *const argv[]) +static int do_mtrr_set(int cpu_select, uint reg, int argc, char *const argv[]) { const char *typename = argv[0]; - struct mtrr_state state; uint32_t start, size; uint64_t base, mask; int i, type = -1; bool valid; + int ret; if (argc < 3) return CMD_RET_USAGE; @@ -88,27 +88,9 @@ static int do_mtrr_set(uint reg, int argc, char *const argv[]) if (valid) mask |= MTRR_PHYS_MASK_VALID; - mtrr_open(&state, true); - wrmsrl(MTRR_PHYS_BASE_MSR(reg), base); - wrmsrl(MTRR_PHYS_MASK_MSR(reg), mask); - mtrr_close(&state, true); - - return 0; -} - -static int mtrr_set_valid_(int reg, bool valid) -{ - struct mtrr_state state; - uint64_t mask; - - mtrr_open(&state, true); - mask = native_read_msr(MTRR_PHYS_MASK_MSR(reg)); - if (valid) - mask |= MTRR_PHYS_MASK_VALID; - else - mask &= ~MTRR_PHYS_MASK_VALID; - wrmsrl(MTRR_PHYS_MASK_MSR(reg), mask); - mtrr_close(&state, true); + ret = mtrr_set(cpu_select, reg, base, mask); + if (ret) + return CMD_RET_FAILURE; return 0; } @@ -134,11 +116,11 @@ static int do_mtrr(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_USAGE; } if (*cmd == 'e') - return mtrr_set_valid_(reg, true); + return mtrr_set_valid(cpu_select, reg, true); else if (*cmd == 'd') - return mtrr_set_valid_(reg, false); + return mtrr_set_valid(cpu_select, reg, false); else if (*cmd == 's') - return do_mtrr_set(reg, argc - 1, argv + 1); + return do_mtrr_set(cpu_select, reg, argc - 1, argv + 1); else return CMD_RET_USAGE; From patchwork Wed Jul 8 01:34:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240958 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:42 -0600 Subject: [PATCH v4 22/25] x86: mtrr: Restructure so command execution is in one place In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-19-sjg@chromium.org> At present do_mtrr() does the 'list' subcommand at the top and the rest below. Update it to do them all in the same place so we can (in a later patch) add parsing of the CPU number for all subcommands. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- (no changes since v1) cmd/x86/mtrr.c | 55 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/cmd/x86/mtrr.c b/cmd/x86/mtrr.c index b047a9897c..b51b1cd7e2 100644 --- a/cmd/x86/mtrr.c +++ b/cmd/x86/mtrr.c @@ -98,31 +98,48 @@ static int do_mtrr_set(int cpu_select, uint reg, int argc, char *const argv[]) static int do_mtrr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - const char *cmd; + int cmd; int cpu_select; uint reg; + int ret; cpu_select = MP_SELECT_BSP; - cmd = argv[1]; - if (argc < 2 || *cmd == 'l') + argc--; + argv++; + cmd = argv[0] ? *argv[0] : 0; + if (argc < 1 || !cmd) { + cmd = 'l'; + reg = 0; + } else { + if (argc < 2) + return CMD_RET_USAGE; + reg = simple_strtoul(argv[1], NULL, 16); + if (reg >= MTRR_COUNT) { + printf("Invalid register number\n"); + return CMD_RET_USAGE; + } + } + if (cmd == 'l') { return do_mtrr_list(cpu_select); - argc -= 2; - argv += 2; - if (argc <= 0) - return CMD_RET_USAGE; - reg = simple_strtoul(argv[0], NULL, 16); - if (reg >= MTRR_COUNT) { - printf("Invalid register number\n"); - return CMD_RET_USAGE; + } else { + switch (cmd) { + case 'e': + ret = mtrr_set_valid(cpu_select, reg, true); + break; + case 'd': + ret = mtrr_set_valid(cpu_select, reg, false); + break; + case 's': + ret = do_mtrr_set(cpu_select, reg, argc - 2, argv + 2); + break; + default: + return CMD_RET_USAGE; + } + if (ret) { + printf("Operation failed (err=%d)\n", ret); + return CMD_RET_FAILURE; + } } - if (*cmd == 'e') - return mtrr_set_valid(cpu_select, reg, true); - else if (*cmd == 'd') - return mtrr_set_valid(cpu_select, reg, false); - else if (*cmd == 's') - return do_mtrr_set(cpu_select, reg, argc - 1, argv + 1); - else - return CMD_RET_USAGE; return 0; } From patchwork Wed Jul 8 01:34:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240959 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:43 -0600 Subject: [PATCH v4 23/25] x86: mtrr: Update 'mtrr' to allow setting MTRRs on any CPU In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-20-sjg@chromium.org> Add a -c option to mtrr to allow any CPU to be updated with this command. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- (no changes since v3) Changes in v3: - Mention that the CPU number is in hex cmd/x86/mtrr.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/cmd/x86/mtrr.c b/cmd/x86/mtrr.c index b51b1cd7e2..d8a7e56d5a 100644 --- a/cmd/x86/mtrr.c +++ b/cmd/x86/mtrr.c @@ -104,6 +104,17 @@ static int do_mtrr(struct cmd_tbl *cmdtp, int flag, int argc, int ret; cpu_select = MP_SELECT_BSP; + if (argc >= 3 && !strcmp("-c", argv[1])) { + const char *cpustr; + + cpustr = argv[2]; + if (*cpustr == 'a') + cpu_select = MP_SELECT_ALL; + else + cpu_select = simple_strtol(cpustr, NULL, 16); + argc -= 2; + argv += 2; + } argc--; argv++; cmd = argv[0] ? *argv[0] : 0; @@ -145,11 +156,14 @@ static int do_mtrr(struct cmd_tbl *cmdtp, int flag, int argc, } U_BOOT_CMD( - mtrr, 6, 1, do_mtrr, + mtrr, 8, 1, do_mtrr, "Use x86 memory type range registers (32-bit only)", "[list] - list current registers\n" "set - set a register\n" "\t is Uncacheable, Combine, Through, Protect, Back\n" "disable - disable a register\n" - "enable - enable a register" + "enable - enable a register\n" + "\n" + "Precede command with '-c |all' to access a particular hex CPU, e.g.\n" + " mtrr -c all list; mtrr -c 2e list" ); From patchwork Wed Jul 8 01:34:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240961 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:44 -0600 Subject: [PATCH v4 24/25] x86: mp: Add more comments to the module In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-21-sjg@chromium.org> Add a description of how this module works and also some missing function comments. Reviewed-by: Wolfgang Wallner Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- (no changes since v3) Changes in v3: - Remove stray asterisk from comments - Drop mention of cpu_map which was handled in a previous patch Changes in v2: - Add a new patch with more comments arch/x86/cpu/mp_init.c | 91 ++++++++++++++++++++++++++++++++++++++- arch/x86/include/asm/mp.h | 14 +++++- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 56e07ecd8f..b7c8a22fc6 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -32,13 +32,99 @@ DECLARE_GLOBAL_DATA_PTR; +/* + * Setting up multiprocessing + * + * See https://www.intel.com/content/www/us/en/intelligent-systems/intel-boot-loader-development-kit/minimal-intel-architecture-boot-loader-paper.html + * + * Note that this file refers to the boot CPU (the one U-Boot is running on) as + * the BSP (BootStrap Processor) and the others as APs (Application Processors). + * + * This module works by loading some setup code into RAM at AP_DEFAULT_BASE and + * telling each AP to execute it. The code that each AP runs is in + * sipi_vector.S (see ap_start16) which includes a struct sipi_params at the + * end of it. Those parameters are set up by the C code. + + * Setting up is handled by load_sipi_vector(). It inits the common block of + * parameters (sipi_params) which tell the APs what to do. This block includes + * microcode and the MTTRs (Memory-Type-Range Registers) from the main CPU. + * There is also an ap_count which each AP increments as it starts up, so the + * BSP can tell how many checked in. + * + * The APs are started with a SIPI (Startup Inter-Processor Interrupt) which + * tells an AP to start executing at a particular address, in this case + * AP_DEFAULT_BASE which contains the code copied from ap_start16. This protocol + * is handled by start_aps(). + * + * After being started, each AP runs the code in ap_start16, switches to 32-bit + * mode, runs the code at ap_start, then jumps to c_handler which is ap_init(). + * This runs a very simple 'flight plan' described in mp_steps(). This sets up + * the CPU and waits for further instructions by looking at its entry in + * ap_callbacks[]. Note that the flight plan is only actually run for each CPU + * in bsp_do_flight_plan(): once the BSP completes each flight record, it sets + * mp_flight_record->barrier to 1 to allow the APs to executed the record one + * by one. + * + * CPUS are numbered sequentially from 0 using the device tree: + * + * cpus { + * u-boot,dm-pre-reloc; + * #address-cells = <1>; + * #size-cells = <0>; + * + * cpu at 0 { + * u-boot,dm-pre-reloc; + * device_type = "cpu"; + * compatible = "intel,apl-cpu"; + * reg = <0>; + * intel,apic-id = <0>; + * }; + * + * cpu at 1 { + * device_type = "cpu"; + * compatible = "intel,apl-cpu"; + * reg = <1>; + * intel,apic-id = <2>; + * }; + * + * Here the 'reg' property is the CPU number and then is placed in dev->req_seq + * so that we can index into ap_callbacks[] using that. The APIC ID is different + * and may not be sequential (it typically is if hyperthreading is supported). + * + * Once APs are inited they wait in ap_wait_for_instruction() for instructions. + * Instructions come in the form of a function to run. This logic is in + * mp_run_on_cpus() which supports running on any one AP, all APs, just the BSP + * or all CPUs. The BSP logic is handled directly in mp_run_on_cpus(), by + * calling the function. For the APs, callback information is stored in a + * single, common struct mp_callback and a pointer to this is written to each + * AP's slot in ap_callbacks[] by run_ap_work(). All APs get the message even + * if it is only for one of them. When an AP notices a message it checks whether + * it should call the function (see check in ap_wait_for_instruction()) and then + * does so if needed. After that it sets its slot to NULL to indicate it is + * done. + * + * While U-Boot is running it can use mp_run_on_cpus() to run code on the APs. + * An example of this is the 'mtrr' command which allows reading and changing + * the MTRRs on all CPUs. + * + * Before U-Boot exits it calls mp_park_aps() which tells all CPUs to halt by + * executing a 'hlt' instruction. That allows them to be used by Linux when it + * starts up. + */ + /* This also needs to match the sipi.S assembly code for saved MSR encoding */ -struct saved_msr { +struct __packed saved_msr { uint32_t index; uint32_t lo; uint32_t hi; -} __packed; +}; +/** + * struct mp_flight_plan - Holds the flight plan + * + * @num_records: Number of flight records + * @records: Pointer to each record + */ struct mp_flight_plan { int num_records; struct mp_flight_record *records; @@ -59,6 +145,7 @@ struct mp_callback { int logical_cpu_number; }; +/* Stores the flight plan so that APs can find it */ static struct mp_flight_plan mp_info; /* diff --git a/arch/x86/include/asm/mp.h b/arch/x86/include/asm/mp.h index 5b8811832a..192aae55e6 100644 --- a/arch/x86/include/asm/mp.h +++ b/arch/x86/include/asm/mp.h @@ -36,6 +36,14 @@ typedef int (*mp_callback_t)(struct udevice *cpu, void *arg); * * Note that ap_call() and bsp_call() can be NULL. In the NULL case the * callback will just not be called. + * + * @barrier: Ensures that the BSP and AP don't run the flight record at the same + * time + * @cpus_entered: Counts the number of APs that have run this record + * @ap_call: Function for the APs to call + * @ap_arg: Argument to pass to @ap_call + * @bsp_call: Function for the BSP to call + * @bsp_arg: Argument to pass to @bsp_call */ struct mp_flight_record { atomic_t barrier; @@ -83,7 +91,11 @@ struct mp_flight_record { */ int mp_init(void); -/* Set up additional CPUs */ +/** + * x86_mp_init() - Set up additional CPUs + * + * @returns < 0 on error, 0 on success. + */ int x86_mp_init(void); /** From patchwork Wed Jul 8 01:34:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 240960 List-Id: U-Boot discussion From: sjg at chromium.org (Simon Glass) Date: Tue, 7 Jul 2020 19:34:45 -0600 Subject: [PATCH v4 25/25] x86: mtrr: Enhance 'mtrr' command to list MTRRs on any CPU In-Reply-To: <20200708013446.2600256-1-sjg@chromium.org> References: <20200708013446.2600256-1-sjg@chromium.org> Message-ID: <20200708013446.2600256-22-sjg@chromium.org> Update this command so it can list the MTRRs on a selected CPU. If '-c all' is used, then all CPUs are listed. Signed-off-by: Simon Glass Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng Tested-by: Bin Meng --- (no changes since v1) cmd/x86/mtrr.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/cmd/x86/mtrr.c b/cmd/x86/mtrr.c index d8a7e56d5a..e118bba5a2 100644 --- a/cmd/x86/mtrr.c +++ b/cmd/x86/mtrr.c @@ -131,7 +131,27 @@ static int do_mtrr(struct cmd_tbl *cmdtp, int flag, int argc, } } if (cmd == 'l') { - return do_mtrr_list(cpu_select); + bool first; + int i; + + i = mp_first_cpu(cpu_select); + if (i < 0) { + printf("Invalid CPU (err=%d)\n", i); + return CMD_RET_FAILURE; + } + first = true; + for (; i >= 0; i = mp_next_cpu(cpu_select, i)) { + if (!first) + printf("\n"); + printf("CPU %d:\n", i); + ret = do_mtrr_list(i); + if (ret) { + printf("Failed to read CPU %d (err=%d)\n", i, + ret); + return CMD_RET_FAILURE; + } + first = false; + } } else { switch (cmd) { case 'e':