From de752c5e73d8fa02a3cc585ca346dae0be86c14d Mon Sep 17 00:00:00 2001 From: Miao Yan Date: Thu, 7 Jan 2016 01:32:04 -0800 Subject: [PATCH] x86: qemu: fix cpu device in smp boot Currently, when booting with more that one CPU enabled, U-Boot scans 'cpu' node in device tree and calculates CPU number. This does not scale well as changing CPU number also requires modifying .dts and re-compiling U-Boot. This patch uses fw_cfg interface provided by QEMU to detect online CPU number at runtime, and dynamically adds 'cpu' device to U-Boot's driver model. Signed-off-by: Miao Yan Reviewed-by: Simon Glass Reviewed-by: Bin Meng Tested-by: Bin Meng --- arch/x86/cpu/mp_init.c | 72 +++++++++++++++++++++++++++++++++++++++++ arch/x86/cpu/qemu/cpu.c | 11 ------- 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index 2a3ce488a9..7917350bff 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -20,8 +20,11 @@ #include #include #include +#include #include #include +#include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -441,6 +444,69 @@ static int init_bsp(struct udevice **devp) return 0; } +#ifdef CONFIG_QEMU +static int qemu_cpu_fixup(void) +{ + int ret; + int cpu_num; + int cpu_online; + struct udevice *dev, *pdev; + struct cpu_platdata *plat; + char *cpu; + + /* first we need to find '/cpus' */ + for (device_find_first_child(dm_root(), &pdev); + pdev; + device_find_next_child(&pdev)) { + if (!strcmp(pdev->name, "cpus")) + break; + } + if (!pdev) { + printf("unable to find cpus device\n"); + return -ENODEV; + } + + /* calculate cpus that are already bound */ + cpu_num = 0; + for (uclass_find_first_device(UCLASS_CPU, &dev); + dev; + uclass_find_next_device(&dev)) { + cpu_num++; + } + + /* get actual cpu number */ + cpu_online = qemu_fwcfg_online_cpus(); + if (cpu_online < 0) { + printf("unable to get online cpu number: %d\n", cpu_online); + return cpu_online; + } + + /* bind addtional cpus */ + dev = NULL; + for (; cpu_num < cpu_online; cpu_num++) { + /* + * allocate device name here as device_bind_driver() does + * not copy device name, 8 bytes are enough for + * sizeof("cpu@") + 3 digits cpu number + '\0' + */ + cpu = malloc(8); + if (!cpu) { + printf("unable to allocate device name\n"); + return -ENOMEM; + } + sprintf(cpu, "cpu@%d", cpu_num); + ret = device_bind_driver(pdev, "cpu_qemu", cpu, &dev); + if (ret) { + printf("binding cpu@%d failed: %d\n", cpu_num, ret); + return ret; + } + plat = dev_get_parent_platdata(dev); + plat->cpu_id = cpu_num; + } + return 0; +} +#endif + int mp_init(struct mp_params *p) { int num_aps; @@ -454,6 +520,12 @@ int mp_init(struct mp_params *p) if (ret) return ret; +#ifdef CONFIG_QEMU + ret = qemu_cpu_fixup(); + if (ret) + return ret; +#endif + ret = init_bsp(&cpu); if (ret) { debug("Cannot init boot CPU: err=%d\n", ret); diff --git a/arch/x86/cpu/qemu/cpu.c b/arch/x86/cpu/qemu/cpu.c index a4bf53dace..a1b70c6bde 100644 --- a/arch/x86/cpu/qemu/cpu.c +++ b/arch/x86/cpu/qemu/cpu.c @@ -13,16 +13,6 @@ DECLARE_GLOBAL_DATA_PTR; -int cpu_qemu_bind(struct udevice *dev) -{ - struct cpu_platdata *plat = dev_get_parent_platdata(dev); - - plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, - "intel,apic-id", -1); - - return 0; -} - int cpu_qemu_get_desc(struct udevice *dev, char *buf, int size) { if (size < CPU_MAX_NAME_LEN) @@ -52,6 +42,5 @@ U_BOOT_DRIVER(cpu_qemu_drv) = { .name = "cpu_qemu", .id = UCLASS_CPU, .of_match = cpu_qemu_ids, - .bind = cpu_qemu_bind, .ops = &cpu_qemu_ops, }; -- 2.39.5