summaryrefslogtreecommitdiffstats
path: root/arch/x86/cpu/mp_init.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/cpu/mp_init.c')
-rw-r--r--arch/x86/cpu/mp_init.c84
1 files changed, 78 insertions, 6 deletions
diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c
index 4334f5b3e5..7917350bff 100644
--- a/arch/x86/cpu/mp_init.c
+++ b/arch/x86/cpu/mp_init.c
@@ -20,8 +20,11 @@
#include <asm/mtrr.h>
#include <asm/processor.h>
#include <asm/sipi.h>
+#include <asm/fw_cfg.h>
#include <dm/device-internal.h>
#include <dm/uclass-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
#include <linux/linkage.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -104,7 +107,7 @@ static void ap_do_flight_plan(struct udevice *cpu)
}
}
-static int find_cpu_by_apid_id(int apic_id, struct udevice **devp)
+static int find_cpu_by_apic_id(int apic_id, struct udevice **devp)
{
struct udevice *dev;
@@ -137,7 +140,7 @@ static void ap_init(unsigned int cpu_index)
enable_lapic();
apic_id = lapicid();
- ret = find_cpu_by_apid_id(apic_id, &dev);
+ ret = find_cpu_by_apic_id(apic_id, &dev);
if (ret) {
debug("Unknown CPU apic_id %x\n", apic_id);
goto done;
@@ -210,7 +213,7 @@ static int save_bsp_msrs(char *start, int size)
return msr_count;
}
-static int load_sipi_vector(atomic_t **ap_countp)
+static int load_sipi_vector(atomic_t **ap_countp, int num_cpus)
{
struct sipi_params_16bit *params16;
struct sipi_params *params;
@@ -239,7 +242,7 @@ static int load_sipi_vector(atomic_t **ap_countp)
params->idt_ptr = (uint32_t)x86_get_idt();
params->stack_size = CONFIG_AP_STACK_SIZE;
- size = params->stack_size * CONFIG_MAX_CPUS;
+ size = params->stack_size * num_cpus;
stack = memalign(size, 4096);
if (!stack)
return -ENOMEM;
@@ -432,7 +435,7 @@ static int init_bsp(struct udevice **devp)
lapic_setup();
apic_id = lapicid();
- ret = find_cpu_by_apid_id(apic_id, devp);
+ ret = find_cpu_by_apic_id(apic_id, devp);
if (ret) {
printf("Cannot find boot CPU, APIC ID %d\n", apic_id);
return ret;
@@ -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);
@@ -483,7 +555,7 @@ int mp_init(struct mp_params *p)
mp_info.records = p->flight_plan;
/* Load the SIPI vector */
- ret = load_sipi_vector(&ap_count);
+ ret = load_sipi_vector(&ap_count, num_cpus);
if (ap_count == NULL)
return -1;
OpenPOWER on IntegriCloud