When boot the kernel with MADT, the cpu possible and present map should be prefilled for cpu topology and cpu hot-plug.
The logic cpu id maps to GIC id is also implemented, then we can use it for ACPI driver for cpu hot-plug.
I modified the APIC.asl because only 4 cpus supported on armv8 foundation model, so limit the available cpus to 2 for test purpose.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- arch/arm64/boot/asl/foundation-v8.acpi/apic.asl | 8 +- arch/arm64/include/asm/acpi.h | 3 + arch/arm64/kernel/setup.c | 2 + arch/arm64/kernel/smp.c | 2 + drivers/acpi/plat/arm/boot.c | 98 ++++++++++++++++++++++- 5 files changed, 107 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/boot/asl/foundation-v8.acpi/apic.asl b/arch/arm64/boot/asl/foundation-v8.acpi/apic.asl index 60d1f56..c674628 100644 --- a/arch/arm64/boot/asl/foundation-v8.acpi/apic.asl +++ b/arch/arm64/boot/asl/foundation-v8.acpi/apic.asl @@ -50,8 +50,8 @@ [0002] Reserved : 0000 [0004] Local GIC Hardware ID : 00000002 [0004] Processor UID : 00000002 -[0004] Flags (decoded below) : 00000001 - Processor Enabled : 1 +[0004] Flags (decoded below) : 00000000 + Processor Enabled : 0 [0004] Parking Protocol Version : 00000000 [0004] Performance Interrupt : 00000000 [0008] Parked Address : 0000000000000000 @@ -62,8 +62,8 @@ [0002] Reserved : 0000 [0004] Local GIC Hardware ID : 00000003 [0004] Processor UID : 00000003 -[0004] Flags (decoded below) : 00000001 - Processor Enabled : 1 +[0004] Flags (decoded below) : 00000000 + Processor Enabled : 0 [0004] Parking Protocol Version : 00000000 [0004] Performance Interrupt : 00000000 [0008] Parked Address : 0000000000000000 diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 605478e..a72012b 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -73,6 +73,8 @@ extern int acpi_disabled; extern int acpi_noirq; extern int acpi_pci_disabled; extern int acpi_strict; +extern volatile int arm_cpu_to_gicid[NR_CPUS]; +extern int boot_cpu_gic_id;
struct acpi_arm_root { phys_addr_t phys_address; @@ -83,6 +85,7 @@ extern struct acpi_arm_root acpi_arm_rsdp_info; /* Low-level suspend routine. */ extern int acpi_suspend_lowlevel(void);
+extern void prefill_possible_map(void); /* Physical address to resume after wakeup */ /* BOZO: was... #define acpi_wakeup_address ((unsigned long)(real_mode_header->wakeup_start)) diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 7e37ba0..3344c77 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -301,7 +301,9 @@ void __init setup_arch(char **cmdline_p) #endif
#ifdef CONFIG_ACPI + boot_cpu_gic_id = read_cpuid_mpidr() & MPIDR_HWID_BITMASK; acpi_boot_init(); + prefill_possible_map(); #endif }
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 5d54e37..fe4ed77 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -418,7 +418,9 @@ void __init smp_prepare_cpus(unsigned int max_cpus) if (err) continue;
+#ifndef CONFIG_ACPI set_cpu_present(cpu, true); +#endif max_cpus--; } } diff --git a/drivers/acpi/plat/arm/boot.c b/drivers/acpi/plat/arm/boot.c index 3a27232..d2fa164 100644 --- a/drivers/acpi/plat/arm/boot.c +++ b/drivers/acpi/plat/arm/boot.c @@ -47,10 +47,15 @@ #include <asm/acpi.h>
static int __initdata acpi_force; +static int available_cpus __initdata; u32 acpi_rsdt_forced; int acpi_disabled; EXPORT_SYMBOL(acpi_disabled);
+/* logical CPU number maps to GIC id */ +volatile int arm_cpu_to_gicid[NR_CPUS] = { [0 ... NR_CPUS-1] = -1 }; +int boot_cpu_gic_id = -1; + /* TODO: should be moved to a head file */ #define MAX_LOCAL_APIC 256 #define MAX_IO_APICS 64 @@ -144,7 +149,30 @@ static int __init acpi_parse_madt(struct acpi_table_header *table)
static void __cpuinit acpi_register_gic(int id, u8 enabled) { - return; + int cpu; + + total_cpus++; + if (!enabled) + return; + + available_cpus++; + + /* allocate a logic cpu id for the new comer + * TODO: do sth more for the boot cpu + */ + if (boot_cpu_gic_id == id) { + /* + * boot_cpu_init() already hold bit 0 in cpu_present_mask + * for BSP. + */ + cpu = 0; + } else { + cpu = cpumask_next_zero(-1, cpu_present_mask); + } + + /* map the logic cpu id to APIC id */ + arm_cpu_to_gicid[cpu] = id; + set_cpu_present(cpu, true); }
static int __init @@ -306,6 +334,61 @@ void __init acpi_set_irq_model_gic(void) acpi_ioapic = 1; }
+static int __initdata setup_possible_cpus = -1; +static int __init _setup_possible_cpus(char *str) +{ + get_option(&str, &setup_possible_cpus); + return 0; +} +early_param("possible_cpus", _setup_possible_cpus); + +/* + * cpu_possible_mask should be static, it cannot change as cpu's + * are onlined, or offlined. The reason is per-cpu data-structures + * are allocated by some modules at init time, and dont expect to + * do this dynamically on cpu arrival/departure. + * cpu_present_mask on the other hand can change dynamically. + * In case when cpu_hotplug is not compiled, then we resort to current + * behaviour, which is cpu_possible == cpu_present. + * - Ashok Raj + * + * Three ways to find out the number of additional hotplug CPUs: + * - If the BIOS specified disabled CPUs in ACPI/mptables use that. + * - The user can overwrite it with possible_cpus=NUM + * - Otherwise don't reserve additional CPUs. + * We do this because additional CPUs waste a lot of memory. + * -AK + */ +__init void prefill_possible_map(void) +{ + int i; + int possible, disabled_cpus; + + disabled_cpus = total_cpus - available_cpus; + + if (setup_possible_cpus == -1) { + if (disabled_cpus > 0) + setup_possible_cpus = disabled_cpus; + else + setup_possible_cpus = 0; + } + + possible = available_cpus + setup_possible_cpus; + + printk(KERN_INFO "SMP: limits to %d CPUs\n", nr_cpu_ids); + /* + * --cores=4 lets nr_cpu_ids=4, so we can't get possible map correctly + */ + if (possible > nr_cpu_ids) + possible = nr_cpu_ids; + + printk(KERN_INFO "SMP: Allowing %d CPUs, %d hotplug CPUs\n", + possible, max((possible - available_cpus), 0)); + + for (i = 0; i < possible; i++) + set_cpu_possible(i, true); +} + /* * ACPI based hotplug support for CPU */ @@ -530,6 +613,18 @@ static int __init acpi_parse_madt_lapic_entries(void) return count; }
+#ifdef CONFIG_SMP + if (available_cpus == 0) { + printk(KERN_INFO "ACPI: Found 0 CPUS; assuming 1\n"); + /* FIXME: should be the real GIC id read from hardware */ + arm_cpu_to_gicid[available_cpus] = 0; + available_cpus = 1; /* We've got at least one of these */ + } +#endif + /* Make boot-up look pretty */ + printk(KERN_INFO "%d CPUs available, %d CPUs total\n", available_cpus, + total_cpus); + return 0; }
@@ -718,7 +813,6 @@ void __init acpi_arm_blob_relocate(void) * bit of fixup work on the offsets to turn them into kernel * virtual addresses so we can pass them on for later use. */ - void __init acpi_boot_table_init(void) { /*