Hi Guys,
I have just pushed this series of patches to the official repo.
Branch is acpi-armv8
This brings us to the same state in armv8 as we are in for armv7. Without the prototype stuff like i2c drivers. But is a base to start work on for armv8.
I have tried to get these patches as checkpatch clean as possible.
I want to try and merge armv7 and armv8 changes into one and maintain that together as I think there is very little different in the two platforms from the point of initialisation or drivers.
Thanks
Graeme
From: Al Stone al.stone@linaro.org
Some hacks that will allow compilation of drivers/acpi on arm. These will need to be replaced with proper solutions.
Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org --- drivers/acpi/acpi_pad.c | 15 +++++++++++++++ drivers/acpi/acpica/tbutils.c | 1 + drivers/acpi/bus.c | 11 +++++++---- drivers/acpi/osl.c | 14 ++++++++++++++ drivers/acpi/processor_core.c | 25 +++++++++++++++++++------ drivers/acpi/processor_driver.c | 9 +++++++++ drivers/acpi/processor_idle.c | 36 ++++++++++++++++++++++++++++++++++++ drivers/acpi/reboot.c | 11 +++++++++-- 8 files changed, 110 insertions(+), 12 deletions(-)
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 31de104..a145e8b 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -30,7 +30,10 @@ #include <linux/slab.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#ifdef CONFIG_X86 + /* BOZO: abstract out? */ #include <asm/mwait.h> +#endif
#define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad" #define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator" @@ -47,6 +50,8 @@ static unsigned char lapic_marked_unstable;
static void power_saving_mwait_init(void) { +#ifdef CONFIG_X86 + /* BOZO: abstract out? */ unsigned int eax, ebx, ecx, edx; unsigned int highest_cstate = 0; unsigned int highest_subcstate = 0; @@ -72,6 +77,7 @@ static void power_saving_mwait_init(void) } power_saving_mwait_eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) | (highest_subcstate - 1); +#endif
#if defined(CONFIG_X86) switch (boot_cpu_data.x86_vendor) { @@ -173,8 +179,11 @@ static int power_saving_thread(void *data)
while (!need_resched()) { if (tsc_detected_unstable && !tsc_marked_unstable) { +#ifdef CONFIG_X86 + /* BOZO: abstract out? */ /* TSC could halt in idle, so notify users */ mark_tsc_unstable("TSC halts in idle"); +#endif tsc_marked_unstable = 1; } if (lapic_detected_unstable && !lapic_marked_unstable) { @@ -193,10 +202,16 @@ static int power_saving_thread(void *data) CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); stop_critical_timings();
+#ifdef CONFIG_X86 + /* BOZO: abstract out? */ __monitor((void *)¤t_thread_info()->flags, 0, 0); +#endif smp_mb(); +#ifdef CONFIG_X86 + /* BOZO: abstract out? */ if (!need_resched()) __mwait(power_saving_mwait_eax, 1); +#endif
start_critical_timings(); if (lapic_marked_unstable) diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index ce3d5db..2b6d8dc 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -634,6 +634,7 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address) acpi_status status;
ACPI_FUNCTION_TRACE(tb_parse_root_table); + printk(KERN_INFO "(I) entering acpi_tb_parse_root_table\n");
/* * Map the entire RSDP and extract the address of the RSDT or XSDT diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 01708a1..303c4ac 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -79,10 +79,6 @@ static struct dmi_system_id dsdt_dmi_table[] __initdata = { }, {} }; -#else -static struct dmi_system_id dsdt_dmi_table[] __initdata = { - {} -}; #endif
/* -------------------------------------------------------------------------- @@ -618,6 +614,9 @@ static int __init acpi_bus_init_irq(void) case ACPI_IRQ_MODEL_PLATFORM: message = "platform specific model"; break; + case ACPI_IRQ_MODEL_GIC: + message = "GIC"; + break; default: printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n"); return -ENODEV; @@ -654,11 +653,15 @@ void __init acpi_early_init(void)
acpi_gbl_permanent_mmap = 1;
+#ifdef CONFIG_X86 /* + * NB: ARM does not use DMI; only older Intel products do. + * * If the machine falls into the DMI check table, * DSDT will be copied to memory */ dmi_check_system(dsdt_dmi_table); +#endif
status = acpi_reallocate_root_table(); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 586e7e9..ab57f09 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1030,9 +1030,18 @@ acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, return AE_ERROR; }
+#ifdef CONFIG_X86 + /* + * BOZO: probably should not call this function at all + * if there is no PCI... + */ result = raw_pci_read(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, &value32); +#else + result = 0; + value32 = 0; +#endif *value = value32;
return (result ? AE_ERROR : AE_OK); @@ -1058,9 +1067,14 @@ acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, return AE_ERROR; }
+#ifdef CONFIG_X86 + /* BOZO: how do we handle not having PCI? */ result = raw_pci_write(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, value); +#else + result = 0; +#endif
return (result ? AE_ERROR : AE_OK); } diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 164d495..09e5e4f 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -164,9 +164,6 @@ exit:
int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) { -#ifdef CONFIG_SMP - int i; -#endif int apic_id = -1;
apic_id = map_mat_entry(handle, type, acpi_id); @@ -199,16 +196,32 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) return apic_id; }
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) + + /* + * BOZO: need to abstract this out to have it make sense -- + * it's not that ARM has no equivalent, it's that apic_id is + * arch-specific + */ + +#else + #ifdef CONFIG_SMP - for_each_possible_cpu(i) { - if (cpu_physical_id(i) == apic_id) - return i; + { + int i; + for_each_possible_cpu(i) { + if (cpu_physical_id(i) == apic_id) + return i; + } } #else /* In UP kernel, only processor 0 is valid */ if (apic_id == 0) return apic_id; #endif + +#endif /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */ + return -1; } EXPORT_SYMBOL_GPL(acpi_get_cpuid); diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index bec717f..de80f78 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -374,9 +374,12 @@ static int acpi_processor_get_info(struct acpi_device *device) * ensure we get the right value in the "physical id" field * of /proc/cpuinfo */ +#ifdef CONFIG_X86 + /* BOZO: abstract out? */ status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer); if (ACPI_SUCCESS(status)) arch_fix_phys_package_id(pr->id, object.integer.value); +#endif
return 0; } @@ -838,10 +841,13 @@ static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr) if (acpi_map_lsapic(handle, &pr->id)) return AE_ERROR;
+#ifdef CONFIG_X86 + /* BOZO: abstract out? */ if (arch_register_cpu(pr->id)) { acpi_unmap_lsapic(pr->id); return AE_ERROR; } +#endif
/* CPU got hot-plugged, but cpu_data is not initialized yet * Set flag to delay cpu_idle/throttling initialization @@ -875,7 +881,10 @@ static int acpi_processor_handle_eject(struct acpi_processor *pr) "brought the CPU back online\n", pr->id); return -EAGAIN; } +#ifdef CONFIG_X86 + /* BOZO: abstract out? */ arch_unregister_cpu(pr->id); +#endif acpi_unmap_lsapic(pr->id); put_online_cpus(); return (0); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index ee255c6..0b6132a 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -120,17 +120,26 @@ static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = { */ static void acpi_safe_halt(void) { +#ifdef CONFIG_X86 + /* BOZO: abstract out? */ current_thread_info()->status &= ~TS_POLLING; +#endif /* * TS_POLLING-cleared state must be visible before we * test NEED_RESCHED: */ smp_mb(); if (!need_resched()) { +#ifdef CONFIG_X86 + /* BOZO: abstract out? */ safe_halt(); +#endif local_irq_disable(); } +#ifdef CONFIG_X86 + /* BOZO: abstract out? */ current_thread_info()->status |= TS_POLLING; +#endif }
#ifdef ARCH_APICTIMER_STOPS_ON_C3 @@ -752,6 +761,8 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index)
while (1) {
+#ifdef CONFIG_X86 + /* BOZO: abstract out? */ if (cx->entry_method == ACPI_CSTATE_HALT) safe_halt(); else if (cx->entry_method == ACPI_CSTATE_SYSTEMIO) { @@ -759,6 +770,7 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) /* See comment in acpi_idle_do_entry() */ inl(acpi_gbl_FADT.xpm_timer_block.address); } else +#endif return -ENODEV; }
@@ -784,7 +796,10 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, return -EINVAL;
if (cx->entry_method != ACPI_CSTATE_FFH) { +#ifdef CONFIG_X86 + /* BOZO: abstract out? */ current_thread_info()->status &= ~TS_POLLING; +#endif /* * TS_POLLING-cleared state must be visible before we test * NEED_RESCHED: @@ -792,7 +807,10 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, smp_mb();
if (unlikely(need_resched())) { +#ifdef CONFIG_X86 + /* BOZO: abstract out? */ current_thread_info()->status |= TS_POLLING; +#endif return -EINVAL; } } @@ -812,8 +830,11 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
sched_clock_idle_wakeup_event(0);
+#ifdef CONFIG_X86 + /* BOZO: abstract out? */ if (cx->entry_method != ACPI_CSTATE_FFH) current_thread_info()->status |= TS_POLLING; +#endif
lapic_timer_state_broadcast(pr, cx, 0); return index; @@ -852,7 +873,10 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, }
if (cx->entry_method != ACPI_CSTATE_FFH) { +#ifdef CONFIG_X86 + /* BOZO: abstract out? */ current_thread_info()->status &= ~TS_POLLING; +#endif /* * TS_POLLING-cleared state must be visible before we test * NEED_RESCHED: @@ -860,12 +884,18 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, smp_mb();
if (unlikely(need_resched())) { +#ifdef CONFIG_X86 + /* BOZO: abstract out? */ current_thread_info()->status |= TS_POLLING; +#endif return -EINVAL; } }
+#ifdef CONFIG_X86 + /* BOZO: abstract out? */ acpi_unlazy_tlb(smp_processor_id()); +#endif
/* Tell the scheduler that we are going deep-idle: */ sched_clock_idle_sleep_event(); @@ -908,8 +938,11 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
sched_clock_idle_wakeup_event(0);
+#ifdef CONFIG_X86 + /* BOZO: abstract out? */ if (cx->entry_method != ACPI_CSTATE_FFH) current_thread_info()->status |= TS_POLLING; +#endif
lapic_timer_state_broadcast(pr, cx, 0); return index; @@ -1169,7 +1202,10 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr)
if (!first_run) { dmi_check_system(processor_power_dmi_table); +#ifdef CONFIG_X86 + /* BOZO: abstract out? */ max_cstate = acpi_processor_cstate_check(max_cstate); +#endif if (max_cstate < ACPI_C_STATES_MAX) printk(KERN_NOTICE "ACPI: processor limited to max C-state %d\n", diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c index a6c77e8b..410d0be 100644 --- a/drivers/acpi/reboot.c +++ b/drivers/acpi/reboot.c @@ -6,9 +6,7 @@ void acpi_reboot(void) { struct acpi_generic_address *rr; - struct pci_bus *bus0; u8 reset_value; - unsigned int devfn;
if (acpi_disabled) return; @@ -31,7 +29,15 @@ void acpi_reboot(void) /* The reset register can only exist in I/O, Memory or PCI config space * on a device on bus 0. */ switch (rr->space_id) { +/* + * There are some rare cases in the ARM world with PCI is not one + * of the buses available to us, even though we use ACPI. + */ +#ifdef CONFIG_PCI case ACPI_ADR_SPACE_PCI_CONFIG: + struct pci_bus *bus0; + unsigned int devfn; + /* The reset register can only live on bus 0. */ bus0 = pci_find_bus(0, 0); if (!bus0) @@ -44,6 +50,7 @@ void acpi_reboot(void) pci_bus_write_config_byte(bus0, devfn, (rr->address & 0xffff), reset_value); break; +#endif
case ACPI_ADR_SPACE_SYSTEM_MEMORY: case ACPI_ADR_SPACE_SYSTEM_IO:
On 11/giu/2013, at 12:23, Graeme Gregory graeme.gregory@linaro.org wrote:
From: Al Stone al.stone@linaro.org
Some hacks that will allow compilation of drivers/acpi on arm. These will need to be replaced with proper solutions.
Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org
drivers/acpi/acpi_pad.c | 15 +++++++++++++++ drivers/acpi/acpica/tbutils.c | 1 + drivers/acpi/bus.c | 11 +++++++---- drivers/acpi/osl.c | 14 ++++++++++++++ drivers/acpi/processor_core.c | 25 +++++++++++++++++++------ drivers/acpi/processor_driver.c | 9 +++++++++ drivers/acpi/processor_idle.c | 36 ++++++++++++++++++++++++++++++++++++ drivers/acpi/reboot.c | 11 +++++++++-- 8 files changed, 110 insertions(+), 12 deletions(-)
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 31de104..a145e8b 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -30,7 +30,10 @@ #include <linux/slab.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#ifdef CONFIG_X86
- /* BOZO: abstract out? */
#include <asm/mwait.h> +#endif
#define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad" #define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator" @@ -47,6 +50,8 @@ static unsigned char lapic_marked_unstable;
static void power_saving_mwait_init(void) { +#ifdef CONFIG_X86
- /* BOZO: abstract out? */ unsigned int eax, ebx, ecx, edx; unsigned int highest_cstate = 0; unsigned int highest_subcstate = 0;
@@ -72,6 +77,7 @@ static void power_saving_mwait_init(void) } power_saving_mwait_eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) | (highest_subcstate - 1); +#endif
#if defined(CONFIG_X86) switch (boot_cpu_data.x86_vendor) { @@ -173,8 +179,11 @@ static int power_saving_thread(void *data)
while (!need_resched()) { if (tsc_detected_unstable && !tsc_marked_unstable) {
+#ifdef CONFIG_X86
/* BOZO: abstract out? */ /* TSC could halt in idle, so notify users */ mark_tsc_unstable("TSC halts in idle");
+#endif tsc_marked_unstable = 1; } if (lapic_detected_unstable && !lapic_marked_unstable) { @@ -193,10 +202,16 @@ static int power_saving_thread(void *data) CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); stop_critical_timings();
+#ifdef CONFIG_X86
- /* BOZO: abstract out? */ __monitor((void *)¤t_thread_info()->flags, 0, 0);
+#endif smp_mb(); +#ifdef CONFIG_X86
- /* BOZO: abstract out? */ if (!need_resched()) __mwait(power_saving_mwait_eax, 1);
+#endif
start_critical_timings(); if (lapic_marked_unstable)
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index ce3d5db..2b6d8dc 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -634,6 +634,7 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address) acpi_status status;
ACPI_FUNCTION_TRACE(tb_parse_root_table);
printk(KERN_INFO "(I) entering acpi_tb_parse_root_table\n");
/*
- Map the entire RSDP and extract the address of the RSDT or XSDT
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 01708a1..303c4ac 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -79,10 +79,6 @@ static struct dmi_system_id dsdt_dmi_table[] __initdata = { }, {} }; -#else -static struct dmi_system_id dsdt_dmi_table[] __initdata = {
- {}
-}; #endif
/* -------------------------------------------------------------------------- @@ -618,6 +614,9 @@ static int __init acpi_bus_init_irq(void) case ACPI_IRQ_MODEL_PLATFORM: message = "platform specific model"; break;
- case ACPI_IRQ_MODEL_GIC:
message = "GIC";
default: printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n"); return -ENODEV;break;
@@ -654,11 +653,15 @@ void __init acpi_early_init(void)
acpi_gbl_permanent_mmap = 1;
+#ifdef CONFIG_X86 /*
* NB: ARM does not use DMI; only older Intel products do.
*
*/
- If the machine falls into the DMI check table,
- DSDT will be copied to memory
there is activity ongoing to support SMBIOS DMI tables and DMI decode with Grant and Yi Li at Linaro... and I was actually wondering if such tables had to be passed via FDT (as being prototyped by Li, if I am not wrong) or if there is any ACPI table for this.
And you have actually highlighted it in your patch, wrapping the DMI init into the #ifdef x86.
Guess that Li can help you remove the #ifdef once his task is complete :-)
dmi_check_system(dsdt_dmi_table); +#endif
status = acpi_reallocate_root_table(); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 586e7e9..ab57f09 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1030,9 +1030,18 @@ acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, return AE_ERROR; }
+#ifdef CONFIG_X86
- /*
* BOZO: probably should not call this function at all
* if there is no PCI...
result = raw_pci_read(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, &value32);*/
+#else
- result = 0;
- value32 = 0;
+#endif *value = value32;
return (result ? AE_ERROR : AE_OK); @@ -1058,9 +1067,14 @@ acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, return AE_ERROR; }
+#ifdef CONFIG_X86
- /* BOZO: how do we handle not having PCI? */ result = raw_pci_write(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, value);
+#else
- result = 0;
+#endif
return (result ? AE_ERROR : AE_OK); } diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 164d495..09e5e4f 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -164,9 +164,6 @@ exit:
int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) { -#ifdef CONFIG_SMP
- int i;
-#endif int apic_id = -1;
apic_id = map_mat_entry(handle, type, acpi_id); @@ -199,16 +196,32 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) return apic_id; }
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
- /*
* BOZO: need to abstract this out to have it make sense --
* it's not that ARM has no equivalent, it's that apic_id is
* arch-specific
*/
+#else
#ifdef CONFIG_SMP
- for_each_possible_cpu(i) {
if (cpu_physical_id(i) == apic_id)
return i;
- {
int i;
for_each_possible_cpu(i) {
if (cpu_physical_id(i) == apic_id)
return i;
}}
#else /* In UP kernel, only processor 0 is valid */ if (apic_id == 0) return apic_id; #endif
+#endif /* defined(CONFIG_ARM) || defined(CONFIG_ARM64) */
- return -1;
} EXPORT_SYMBOL_GPL(acpi_get_cpuid); diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index bec717f..de80f78 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -374,9 +374,12 @@ static int acpi_processor_get_info(struct acpi_device *device) * ensure we get the right value in the "physical id" field * of /proc/cpuinfo */ +#ifdef CONFIG_X86
- /* BOZO: abstract out? */ status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer); if (ACPI_SUCCESS(status)) arch_fix_phys_package_id(pr->id, object.integer.value);
+#endif
return 0; } @@ -838,10 +841,13 @@ static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr) if (acpi_map_lsapic(handle, &pr->id)) return AE_ERROR;
+#ifdef CONFIG_X86
- /* BOZO: abstract out? */ if (arch_register_cpu(pr->id)) { acpi_unmap_lsapic(pr->id); return AE_ERROR; }
+#endif
/* CPU got hot-plugged, but cpu_data is not initialized yet * Set flag to delay cpu_idle/throttling initialization @@ -875,7 +881,10 @@ static int acpi_processor_handle_eject(struct acpi_processor *pr) "brought the CPU back online\n", pr->id); return -EAGAIN; } +#ifdef CONFIG_X86
- /* BOZO: abstract out? */ arch_unregister_cpu(pr->id);
+#endif acpi_unmap_lsapic(pr->id); put_online_cpus(); return (0); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index ee255c6..0b6132a 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -120,17 +120,26 @@ static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = { */ static void acpi_safe_halt(void) { +#ifdef CONFIG_X86
- /* BOZO: abstract out? */ current_thread_info()->status &= ~TS_POLLING;
+#endif /* * TS_POLLING-cleared state must be visible before we * test NEED_RESCHED: */ smp_mb(); if (!need_resched()) { +#ifdef CONFIG_X86
/* BOZO: abstract out? */ safe_halt();
+#endif local_irq_disable(); } +#ifdef CONFIG_X86
- /* BOZO: abstract out? */ current_thread_info()->status |= TS_POLLING;
+#endif }
#ifdef ARCH_APICTIMER_STOPS_ON_C3 @@ -752,6 +761,8 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index)
while (1) {
+#ifdef CONFIG_X86
/* BOZO: abstract out? */ if (cx->entry_method == ACPI_CSTATE_HALT) safe_halt(); else if (cx->entry_method == ACPI_CSTATE_SYSTEMIO) {
@@ -759,6 +770,7 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) /* See comment in acpi_idle_do_entry() */ inl(acpi_gbl_FADT.xpm_timer_block.address); } else +#endif return -ENODEV; }
@@ -784,7 +796,10 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, return -EINVAL;
if (cx->entry_method != ACPI_CSTATE_FFH) { +#ifdef CONFIG_X86
/* BOZO: abstract out? */ current_thread_info()->status &= ~TS_POLLING;
+#endif /* * TS_POLLING-cleared state must be visible before we test * NEED_RESCHED: @@ -792,7 +807,10 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, smp_mb();
if (unlikely(need_resched())) {
+#ifdef CONFIG_X86
/* BOZO: abstract out? */ current_thread_info()->status |= TS_POLLING;
+#endif return -EINVAL; } } @@ -812,8 +830,11 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
sched_clock_idle_wakeup_event(0);
+#ifdef CONFIG_X86
- /* BOZO: abstract out? */ if (cx->entry_method != ACPI_CSTATE_FFH) current_thread_info()->status |= TS_POLLING;
+#endif
lapic_timer_state_broadcast(pr, cx, 0); return index; @@ -852,7 +873,10 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, }
if (cx->entry_method != ACPI_CSTATE_FFH) { +#ifdef CONFIG_X86
/* BOZO: abstract out? */ current_thread_info()->status &= ~TS_POLLING;
+#endif /* * TS_POLLING-cleared state must be visible before we test * NEED_RESCHED: @@ -860,12 +884,18 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, smp_mb();
if (unlikely(need_resched())) {
+#ifdef CONFIG_X86
/* BOZO: abstract out? */ current_thread_info()->status |= TS_POLLING;
+#endif return -EINVAL; } }
+#ifdef CONFIG_X86
- /* BOZO: abstract out? */ acpi_unlazy_tlb(smp_processor_id());
+#endif
/* Tell the scheduler that we are going deep-idle: */ sched_clock_idle_sleep_event(); @@ -908,8 +938,11 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
sched_clock_idle_wakeup_event(0);
+#ifdef CONFIG_X86
- /* BOZO: abstract out? */ if (cx->entry_method != ACPI_CSTATE_FFH) current_thread_info()->status |= TS_POLLING;
+#endif
lapic_timer_state_broadcast(pr, cx, 0); return index; @@ -1169,7 +1202,10 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr)
if (!first_run) { dmi_check_system(processor_power_dmi_table); +#ifdef CONFIG_X86
- /* BOZO: abstract out? */ max_cstate = acpi_processor_cstate_check(max_cstate);
+#endif if (max_cstate < ACPI_C_STATES_MAX) printk(KERN_NOTICE "ACPI: processor limited to max C-state %d\n", diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c index a6c77e8b..410d0be 100644 --- a/drivers/acpi/reboot.c +++ b/drivers/acpi/reboot.c @@ -6,9 +6,7 @@ void acpi_reboot(void) { struct acpi_generic_address *rr;
struct pci_bus *bus0; u8 reset_value;
unsigned int devfn;
if (acpi_disabled) return;
@@ -31,7 +29,15 @@ void acpi_reboot(void) /* The reset register can only exist in I/O, Memory or PCI config space * on a device on bus 0. */ switch (rr->space_id) { +/*
- There are some rare cases in the ARM world with PCI is not one
- of the buses available to us, even though we use ACPI.
- */
+#ifdef CONFIG_PCI case ACPI_ADR_SPACE_PCI_CONFIG:
struct pci_bus *bus0;
unsigned int devfn;
/* The reset register can only live on bus 0. */ bus0 = pci_find_bus(0, 0); if (!bus0)
@@ -44,6 +50,7 @@ void acpi_reboot(void) pci_bus_write_config_byte(bus0, devfn, (rr->address & 0xffff), reset_value); break; +#endif
case ACPI_ADR_SPACE_SYSTEM_MEMORY: case ACPI_ADR_SPACE_SYSTEM_IO: -- 1.7.10.4
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
From: Graeme Gregory graeme.gregory@linaro.org
Not all platforms that are using ACPI have PCI so don't try and initialise non existent PCI stuff.
Signed-off-by: Graeme Gregory graeme.gregory@linaro.org --- drivers/acpi/scan.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 5e7e991..97b9227 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1785,8 +1785,10 @@ int __init acpi_scan_init(void) printk(KERN_ERR PREFIX "Could not register bus type\n"); }
+#if defined(CONFIG_PCI) acpi_pci_root_init(); acpi_pci_link_init(); +#endif acpi_platform_init(); acpi_csrt_init(); acpi_container_init(); @@ -1812,7 +1814,9 @@ int __init acpi_scan_init(void)
acpi_update_all_gpes();
+#if defined(CONFIG_PCI) acpi_pci_root_hp_init(); +#endif
out: mutex_unlock(&acpi_scan_lock);
From: Naresh Bhat naresh.bhat@linaro.org
Fix compilation issue with AEPI (Platform Error Interface)
Signed-off-by: Naresh Bhat naresh.bhat@linaro.org --- drivers/acpi/apei/erst.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 6d894bf..99f4edf 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -35,6 +35,7 @@ #include <linux/nmi.h> #include <linux/hardirq.h> #include <linux/pstore.h> +#include <linux/vmalloc.h> #include <acpi/apei.h>
#include "apei-internal.h"
From: Al Stone al.stone@linaro.org
Start to add ACPI initialisation calls to the arch/arm files.
This does not yet perform an actual ACPI initialisation.
Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org --- drivers/acpi/bus.c | 4 +++ drivers/acpi/osl.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/of/fdt.c | 52 ++++++++++++++++++++++++++++++++++++++- include/linux/of_fdt.h | 4 +++ 4 files changed, 123 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 303c4ac..db6c0c6 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -79,6 +79,10 @@ static struct dmi_system_id dsdt_dmi_table[] __initdata = { }, {} }; +#else +static struct dmi_system_id dsdt_dmi_table[] __initdata = { + {} +}; #endif
/* -------------------------------------------------------------------------- diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index ab57f09..dc0987e 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -242,6 +242,65 @@ static int __init setup_acpi_rsdp(char *arg) early_param("acpi_rsdp", setup_acpi_rsdp); #endif
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) +#include <asm/acpi.h> +#include <acpi/actbl.h> + +void acpi_find_arm_root_pointer(acpi_physical_address *pa) +{ + /* BOZO: temporarily clunky. + * What we do is, while using u-boot still, is use the values + * that have already been retrieved from the FDT node + * (/chosen/linux,acpi-start and /chosen/linux,acpi-len) which + * contain the address of the first byte of the RSDP after it + * has been loaded into RAM during u-boot (e.g., using something + * like fatload mmc 0:2 42008000 my.blob), and the size of the + * data in the complete ACPI blob. We only do this since we have + * to collaborate with FDT so we have to load FDT and the ACPI + * tables in but only have one address we can use via bootm. + * With UEFI, we should just be able to use the efi_enabled + * branch below in acpi_os_get_root_pointer(). + */ + + void *address; + struct acpi_table_rsdp *rp; + + if (!acpi_arm_rsdp_info.phys_address && !acpi_arm_rsdp_info.size) { + printk(KERN_ERR "(E) ACPI: failed to find rsdp info\n"); + *pa = (acpi_physical_address)NULL; + return; + } + + address = phys_to_virt(acpi_arm_rsdp_info.phys_address); + address += ACPI_BLOB_HEADER_SIZE; + *pa = (acpi_physical_address)address; + + rp = (struct acpi_table_rsdp *)address; + printk(KERN_DEBUG "(I) ACPI rsdp rp: 0x%08lx\n", (long unsigned int)rp); + if (rp) { + printk(KERN_DEBUG "(I) ACPI rsdp content:\n"); + printk(KERN_DEBUG "(I) signature: %.8s\n", rp->signature); + printk(KERN_DEBUG "(I) checksum: 0x%02x\n", rp->checksum); + printk(KERN_DEBUG "(I) oem_id: %.6s\n", rp->oem_id); + printk(KERN_DEBUG "(I) revision: %d\n", rp->revision); + printk(KERN_DEBUG "(I) rsdt: 0x%08lX\n", + (long unsigned int)rp->rsdt_physical_address); + printk(KERN_DEBUG "(I) length: %d\n", rp->length); + printk(KERN_DEBUG "(I) xsdt: 0x%016llX\n", + (u64)rp->xsdt_physical_address); + printk(KERN_DEBUG "(I) x_checksum: 0x%02x\n", + rp->extended_checksum); + + *pa = (acpi_physical_address)(virt_to_phys(rp)); + } else { + printk(KERN_ERR "(E) ACPI missing rsdp info\n"); + *pa = (acpi_physical_address)NULL; + } + + return; +} +#endif + acpi_physical_address __init acpi_os_get_root_pointer(void) { #ifdef CONFIG_KEXEC @@ -262,7 +321,11 @@ acpi_physical_address __init acpi_os_get_root_pointer(void) } else { acpi_physical_address pa = 0;
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) + acpi_find_arm_root_pointer(&pa); +#else acpi_find_root_pointer(&pa); +#endif return pa; } } @@ -372,6 +435,7 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size) return __acpi_map_table((unsigned long)phys, size);
mutex_lock(&acpi_ioremap_lock); + /* Check if there's a suitable mapping already. */ map = acpi_map_lookup(phys, size); if (map) { diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 808be06..0535169 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -696,6 +696,56 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, return 1; }
+#if (defined(CONFIG_ARM64) || defined (CONFIG_ARM)) && defined(CONFIG_ACPI) +#include <linux/memblock.h> +#include <linux/acpi.h> +#include <asm/acpi.h> +#include <acpi/actbl.h> + +int __init early_init_dt_scan_acpi(unsigned long node, const char *uname, + int depth, void *data) +{ + unsigned long l; + unsigned int *p; + struct acpi_arm_root *pinfo; + unsigned char *sig; + + pr_debug("search "chosen" for acpi info, depth: %d, uname: %s\n", + depth, uname); + + if (depth != 1 || !data || + (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) + return 0; + + /* Retrieve acpi,address line */ + pinfo = (struct acpi_arm_root *)data; + p = of_get_flat_dt_prop(node, "linux,acpi-start", &l); + if (p != NULL && l > 0) + pinfo->phys_address = be32_to_cpu(*p); + + /* Retrieve acpi,size line */ + p = of_get_flat_dt_prop(node, "linux,acpi-len", &l); + if (p != NULL && l > 0) + pinfo->size = be32_to_cpu(*p); + + printk("acpi: start info is 0x%016llX, %lu bytes\n", + pinfo->phys_address, pinfo->size); + + memblock_reserve(pinfo->phys_address, pinfo->size); + + sig = phys_to_virt(pinfo->phys_address); + + printk("acpi: sig is "%c%c%c%c"\n", + sig[0], sig[1], sig[2], sig[3]); + printk("acpi: info is %02x %02x %02x %02x\n", + sig[4], sig[5], sig[6], sig[7]); + printk("acpi: first table is "%c%c%c%c"\n", + sig[8], sig[9], sig[10], sig[11]); + + return 1; +} +#endif + /** * unflatten_device_tree - create tree of device_nodes from flat blob * @@ -707,7 +757,7 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, void __init unflatten_device_tree(void) { __unflatten_device_tree(initial_boot_params, &of_allnodes, - early_init_dt_alloc_memory_arch); + early_init_dt_alloc_memory_arch);
/* Get pointer to "/chosen" and "/aliasas" nodes for use everywhere */ of_alias_scan(early_init_dt_alloc_memory_arch); diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h index ed136ad..98c1029 100644 --- a/include/linux/of_fdt.h +++ b/include/linux/of_fdt.h @@ -93,6 +93,10 @@ extern unsigned long of_get_flat_dt_root(void);
extern int early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data); +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) +extern int early_init_dt_scan_acpi(unsigned long node, const char *uname, + int depth, void *data); +#endif extern void early_init_dt_check_for_initrd(unsigned long node); extern int early_init_dt_scan_memory(unsigned long node, const char *uname, int depth, void *data);
From: Al Stone al.stone@linaro.org
This executable creates ACPI binary blobs in the case where they are not provided by the boot firmware of the device from OEM.
Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org --- scripts/Makefile | 1 + scripts/mab/Makefile | 13 ++ scripts/mab/mab.c | 558 ++++++++++++++++++++++++++++++++++++++++++++++++++ scripts/mab/mab.h | 92 +++++++++ 4 files changed, 664 insertions(+) create mode 100644 scripts/mab/Makefile create mode 100644 scripts/mab/mab.c create mode 100644 scripts/mab/mab.h
diff --git a/scripts/Makefile b/scripts/Makefile index 01e7adb..8ac44ad 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -37,6 +37,7 @@ subdir-$(CONFIG_MODVERSIONS) += genksyms subdir-y += mod subdir-$(CONFIG_SECURITY_SELINUX) += selinux subdir-$(CONFIG_DTC) += dtc +subdir-$(CONFIG_MAB) += mab
# Let clean descend into subdirs subdir- += basic kconfig package selinux diff --git a/scripts/mab/Makefile b/scripts/mab/Makefile new file mode 100644 index 0000000..4b920aa --- /dev/null +++ b/scripts/mab/Makefile @@ -0,0 +1,13 @@ +# scripts/mab makefile + +hostprogs-y := mab +always := $(hostprogs-y) + +mab-objs := mab.o + +# need to be able to see the ACPI headers for table structs + +HOSTCFLAGS_MAB := -g -I$(src) + +HOSTCFLAGS_mab.o := $(HOSTCFLAGS_MAB) + diff --git a/scripts/mab/mab.c b/scripts/mab/mab.c new file mode 100644 index 0000000..487d686 --- /dev/null +++ b/scripts/mab/mab.c @@ -0,0 +1,558 @@ +/* + * mab.c: main program for the tool to Make A Blob of ACPI tables + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * Copyright (c) 2013, Al Stone ahs3@redhat.com + * + * NB: all values are assumed to be little-endian in the blob. + * + */ + +#include "mab.h" + +#include <ctype.h> +#include <endian.h> +#include <errno.h> +#include <libgen.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sys/queue.h> +#include <sys/types.h> +#include <sys/stat.h> + + +void usage(void) +{ + printf("%s %s\n", PROGNAME, VERSION); + printf("usage: %s -d <dir> -o <blob> -i <manifest> ", PROGNAME); + printf("[-c <iasl-cmd>] [-q]\n"); + printf("\n"); + printf(" -d <dir> => directory of ASL files\n"); + printf(" -o <blob> => file name for resulting ACPI blob\n"); + printf(" -i <manifest> => list of AML files needed\n"); + printf(" -c <iasl-cmd> => iasl command to use (default: iasl -l)\n"); + printf(" -q => if given, supress output\n"); +} + +int get_file_size(char *fname) +{ + struct stat buf; + int err; + + err = stat(fname, &buf); + if (err) + printf("? cannot stat %s (%d)\n", fname, err); + return (err == 0 ? buf.st_size : 0); +} + +int valid_sig(char *sig) +{ + char **p; + + p = known_sigs; + while (*p != NULL) { + if (strcmp(*p, sig) == 0) + return 1; + p++; + } + return 0; +} + +struct table *build_table_entry(char *dir, char *buf) +{ + struct table *tmp; + char sig[MAX_LINE]; + char fname[MAX_LINE]; + int ii, n; + char *p; + + tmp = (struct table *)malloc(sizeof(struct table)); + if (tmp != NULL) { + memset(tmp, 0, sizeof(struct table)); + memset(sig, 0, MAX_LINE); + memset(fname, 0, MAX_LINE); + + /* parse the line */ + n = 0; + for (ii = 0; ii < strlen(buf); ii++) { + if (buf[ii] == ':' || isspace(buf[ii])) + break; + sig[n++] = buf[ii]; + } + if (!valid_sig(sig)) { + free(tmp); + return NULL; + } + while (buf[ii] == ':' || isspace(buf[ii])) + ii++; + n = 0; + for (; ii < strlen(buf); ii++) { + if (buf[ii] == '\n' || !isascii(buf[ii])) + break; + fname[n++] = buf[ii]; + } + + /* fill in the struct */ + tmp->signature = (char *)malloc(strlen(sig) + 1); + memset(tmp->signature, 0, strlen(sig) + 1); + memcpy(tmp->signature, sig, strlen(sig)); + + n = strlen(fname) + strlen(dir) + 2; + tmp->asl_name = (char *)malloc(n); + memset(tmp->asl_name, 0, n); + strcpy(tmp->asl_name, dir); + strcat(tmp->asl_name, "/"); + strcat(tmp->asl_name, fname); + + tmp->aml_name = (char *)malloc(n); + memset(tmp->aml_name, 0, n); + strcpy(tmp->aml_name, tmp->asl_name); + p = strrchr(tmp->aml_name, '.'); + if (p) + strcpy(p, ".aml"); + + tmp->file_size = -1; /* need to build .aml file first */ + tmp->offset = -1; + } + + return tmp; +} + +int read_manifest(char *dir, char *fname) +{ + FILE *fp; + struct table *p; + char line[MAX_LINE]; + char *tmp; + char buf[MAX_LINE]; + + memset(buf, 0, MAX_LINE); + strcpy(buf, dir); + strcat(buf, "/"); + strcat(buf, fname); + fp = fopen(buf, "r"); + if (!fp) + return -ENOENT; + + LIST_INIT(&thead); + memset(line, 0, MAX_LINE); + tmp = fgets(line, MAX_LINE, fp); + while (tmp != NULL) { + if (strlen(line) > 0 && line[0] != '#' && line[0] != '\n') { + p = build_table_entry(dir, line); + if (p) + LIST_INSERT_HEAD(&thead, p, tables); + } + memset(line, 0, MAX_LINE); + tmp = fgets(line, MAX_LINE, fp); + } + fclose(fp); + + return 0; +} + +void set_blob_header(unsigned char *blob, int blob_size) +{ + uint32_t *psize; + + /* the resulting blob contents are always little-endian */ + memcpy(blob, BLOB_MAGIC, BLOB_MAGIC_SIZE); + + psize = (uint32_t *)(blob + BLOB_MAGIC_SIZE); + *psize = (uint32_t)(htobe32(blob_size)); + +} + +struct table *find_table(char *sig) +{ + struct table *np; + + LIST_FOREACH(np, &thead, tables) { + if (strcmp(np->signature, sig) == 0) + return np; + } + return NULL; +} + +void write_table(unsigned char *blob, struct table *tp, int offset) +{ + unsigned char *buf; + unsigned char *start; + FILE *fp; + + buf = (unsigned char *)malloc(tp->file_size); + memset(buf, 0, tp->file_size); + + tp->offset = offset; + start = (unsigned char *)(blob + BLOB_HEADER_SIZE + offset); + fp = fopen(tp->aml_name, "r"); + if (fp) { + fread(start, 1, tp->file_size, fp); + fclose(fp); + } +} + +void write_blob(char *dir, char *fname, unsigned char *blob, int size) +{ + FILE *fp; + char newname[MAX_LINE]; + + memset(newname, 0, MAX_LINE); + strcpy(newname, dir); + strcat(newname, "/"); + strcat(newname, fname); + + fp = fopen(newname, "w+"); + if (fp) { + fwrite(blob, 1, size, fp); + fclose(fp); + } else { + printf("? could not open the blob file: %s\n", newname); + } +} + +void set_checksum(unsigned char *start, int len, uint8_t *cksum) +{ + uint8_t newsum, oldsum; + uint8_t *p; + + newsum = 0; + for (p = (uint8_t *)start; p < (uint8_t *)(start + len); p++) + newsum += *p; + + oldsum = *cksum; + newsum = (uint8_t)(newsum - oldsum); + + *cksum = (uint8_t)(0 - newsum); +} + +int add_table(unsigned char *blob, char *table_name, int offset, int reqd) +{ + struct table *p; + + p = find_table(table_name); + if (p) { + write_table(blob, p, offset); + } else { + if (reqd) { + printf("? %s table is required\n", table_name); + return 0; + } + } + + /* NB: ACPI table size cannot be zero -- there must be a header */ + return p->file_size; +} + +void fixup_rsdp(unsigned char *blob) +{ + /* We could use the 32-bit RSDT address but that has + * essentially been deprecated. Instead, use the 64-bit + * XSDT address though be sure to use little-endian values. + */ + const int RSDP_CHECKSUM_BYTES = 20; + const int RSDP_CHECKSUM_OFFSET = 8; + const int XSDT_ADDR_OFFSET = 24; + + uint8_t *pcksum; + uint64_t *tmp; + struct table *rsdpp; + struct table *p; + + /* NB: there are no safety checks on the find_table() + * return value because if we've gotten this far and + * the RSDP doesn't exist, something else has gone + * seriously wrong far earlier. + */ + rsdpp = find_table("rsdp"); + tmp = (uint64_t *)(blob + BLOB_HEADER_SIZE + + rsdpp->offset + XSDT_ADDR_OFFSET); + + p = find_table("xsdt"); + if (p) + *tmp = p->offset; + else + *tmp = (uint64_t)0; + + /* always reset the checksum, even if it is seldom used */ + pcksum = (uint8_t *)(blob + BLOB_HEADER_SIZE); + pcksum = (uint8_t *)(pcksum + rsdpp->offset + RSDP_CHECKSUM_OFFSET); + set_checksum((unsigned char *)(blob + BLOB_HEADER_SIZE + rsdpp->offset), + RSDP_CHECKSUM_BYTES, pcksum); +} + +void fixup_facp(unsigned char *blob, int *offset) +{ + const int DSDT_ADDR_OFFSET = 40; + const int FACP_CHECKSUM_OFFSET = 9; + const int FIRMWARE_CTRL_OFFSET = 36; + const int X_DSDT_ADDR_OFFSET = 140; + const int X_FIRMWARE_CTRL_OFFSET = 132; + + struct table *facpp; + struct table *p; + uint32_t *stmp; + uint64_t *ltmp; + uint8_t *pcksum; + + facpp = find_table("facp"); + + /* add in the DSDT and X_DSDT addresses */ + stmp = (uint32_t *)(blob + BLOB_HEADER_SIZE + + facpp->offset + DSDT_ADDR_OFFSET); + ltmp = (uint64_t *)(blob + BLOB_HEADER_SIZE + + facpp->offset + X_DSDT_ADDR_OFFSET); + p = find_table("dsdt"); + if (p) { + *stmp = (uint32_t)p->offset; + *ltmp = (uint64_t)p->offset; + } else { + *stmp = (uint32_t)0; + *ltmp = (uint64_t)0; + return; + } + + /* add in the FIRMWARE_CTRL and X_FIRMWARE_CTRL addresses */ + stmp = (uint32_t *)(blob + BLOB_HEADER_SIZE + + facpp->offset + FIRMWARE_CTRL_OFFSET); + ltmp = (uint64_t *)(blob + BLOB_HEADER_SIZE + + facpp->offset + X_FIRMWARE_CTRL_OFFSET); + p = find_table("facs"); + if (p) { + *stmp = (uint32_t)p->offset; + *ltmp = (uint64_t)p->offset; + } else { + *stmp = (uint32_t)0; + *ltmp = (uint64_t)0; + return; + } + + /* always reset the checksum, even if it is seldom used */ + pcksum = (uint8_t *)(blob + BLOB_HEADER_SIZE); + pcksum = (uint8_t *)(pcksum + facpp->offset + FACP_CHECKSUM_OFFSET); + set_checksum((unsigned char *)(blob + BLOB_HEADER_SIZE + facpp->offset), + facpp->file_size, pcksum); +} + +void fixup_xsdt(unsigned char *blob, int *offset) +{ + const int FACP_ADDR_OFFSET = 36; + const int XSDT_CHECKSUM_OFFSET = 9; + const int XSDT_HEADER_SIZE = 36; + + struct table *xsdtp; + struct table *p; + uint64_t *tmp; + uint8_t *pcksum; + int delta; + int allowed; + + xsdtp = find_table("xsdt"); + tmp = (uint64_t *)(blob + BLOB_HEADER_SIZE + + xsdtp->offset + FACP_ADDR_OFFSET); + allowed = (xsdtp->file_size - XSDT_HEADER_SIZE) / sizeof(uint64_t); + + /* first table must be FACP (aka FADT) */ + p = find_table("facp"); + if (p) + *tmp = p->offset; + else { + *tmp = (uint64_t)0; + return; + } + + /* any tables not already in use go here */ + allowed--; + tmp++; + LIST_FOREACH(p, &thead, tables) { + if (p->offset < 0) { + if ((unsigned long long)tmp < + (unsigned long long) + (xsdtp + xsdtp->file_size)) { + delta = add_table(blob, p->signature, + *offset, NOT_REQUIRED); + *offset += delta; + *tmp++ = p->offset; + allowed--; + if (allowed < 1) + break; + } + } + } + + /* always reset the checksum, even if it is seldom used */ + pcksum = (uint8_t *)(blob + BLOB_HEADER_SIZE); + pcksum = (uint8_t *)(pcksum + xsdtp->offset + XSDT_CHECKSUM_OFFSET); + set_checksum((unsigned char *)(blob + BLOB_HEADER_SIZE + xsdtp->offset), + xsdtp->file_size, pcksum); +} + +void build_aml(int q, char *dir, char *iasl_cmd, struct table *tp) +{ + char cmd[MAX_LINE]; + struct stat mbuf; + struct stat sbuf; + + if (!tp) + return; + + if ((stat(tp->aml_name, &mbuf) == 0) && + (stat(tp->asl_name, &sbuf) == 0)) { + if (mbuf.st_mtime > sbuf.st_mtime) + return; /* AML file is newer than ASL file */ + } + + strcpy(cmd, iasl_cmd); + strcat(cmd, " "); + strcat(cmd, tp->asl_name); + if (q) + strcat(cmd, " >/dev/null 2&1"); + + system(cmd); +} + +int main(int argc, char *argv[]) +{ + int err = 0; + int ii, jj; + int blob_size; + int offset; + int delta; + unsigned char *blob; + char *manifest_name; + char *homedir; + char *acpi_blob_name; + char *iasl_cmd; + char sig[SIG_LENGTH]; + struct table *np; + int opt; + int quiet; + + /* parameter handling */ + manifest_name = NULL; + homedir = NULL; + acpi_blob_name = NULL; + iasl_cmd = NULL; + quiet = 0; + + while ((opt = getopt(argc, argv, "d:o:i:c:q")) != EOF) { + switch (opt) { + case 'd': + homedir = optarg; + break; + case 'o': + acpi_blob_name = optarg; + break; + case 'i': + manifest_name = optarg; + break; + case 'c': + iasl_cmd = optarg; + break; + case 'q': + quiet = 1; + break; + default: + usage(); + return 1; + } + } + + if ((argc > (optind + 1)) || + (manifest_name == NULL) || + (acpi_blob_name == NULL) || + (homedir == NULL)) { + printf("? missing a parameter value\n"); + usage(); + return 1; + } + if (!iasl_cmd) + iasl_cmd = "iasl -l"; + + /* what tables do we need to do something about? */ + err = read_manifest(homedir, manifest_name); + if (err) { + printf("? could not read manifest: %s\n", manifest_name); + return 1; + } + + /* build the AML for each of the files */ + LIST_FOREACH(np, &thead, tables) { + build_aml(quiet, homedir, iasl_cmd, np); + np->file_size = get_file_size(np->aml_name); + } + + /* build up the contents of the blob, table by table */ + blob_size = 0; + LIST_FOREACH(np, &thead, tables) + blob_size += np->file_size; + blob = (unsigned char *)malloc(blob_size + BLOB_HEADER_SIZE); + memset(blob, 0, blob_size + BLOB_HEADER_SIZE); + + set_blob_header(blob, blob_size); + offset = 0; + + delta = add_table(blob, "rsdp", offset, REQUIRED); + if (!delta) + return 1; + offset += delta; + + delta = add_table(blob, "xsdt", offset, REQUIRED); + if (!delta) + return 1; + offset += delta; + + delta = add_table(blob, "facp", offset, REQUIRED); + if (!delta) + return 1; + offset += delta; + + delta = add_table(blob, "dsdt", offset, REQUIRED); + if (!delta) + return 1; + offset += delta; + + delta = add_table(blob, "facs", offset, REQUIRED); + if (!delta) + return 1; + offset += delta; + + /* patch up all the offsets if needed */ + fixup_rsdp(blob); + fixup_facp(blob, &offset); + + /* this fixup MUST always be called LAST -- it uses any unused tables */ + fixup_xsdt(blob, &offset); + + /* all done, so write out the blob */ + write_blob(homedir, acpi_blob_name, blob, blob_size + BLOB_HEADER_SIZE); + + if (!quiet) { + printf("%s %s\n", PROGNAME, VERSION); + LIST_FOREACH(np, &thead, tables) { + if (np->offset < 0) { + for (jj = 0; jj < SIG_LENGTH; jj++) + sig[jj] = toupper(np->signature[jj]); + printf("? no room in XSDT for %s (%4s)\n", + basename(np->asl_name), sig); + } + } + ii = 0; + LIST_FOREACH(np, &thead, tables) { + printf("[%03d] %4s : %s (%d bytes @ 0x%08x)\n", ii, + np->signature, basename(np->aml_name), + np->file_size, np->offset); + ii++; + } + } + + return err; +} + diff --git a/scripts/mab/mab.h b/scripts/mab/mab.h new file mode 100644 index 0000000..4ac3ae6 --- /dev/null +++ b/scripts/mab/mab.h @@ -0,0 +1,92 @@ +#ifndef _MAB_H +#define _MAB_H +/* + * mab.h: tool to Make A Blob of ACPI tables + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * Copyright (c) 2013, Al Stone ahs3@redhat.com + * + * NB: all values are assumed to be little-endian in the blob. + * + */ + +#include <stdint.h> +#include <string.h> + +#include <sys/queue.h> + +#define BLOB_HEADER_SIZE 8 +#define BLOB_MAGIC "ACPI" +#define BLOB_MAGIC_SIZE 4 +#define MAX_LINE 1024 +#define NOT_REQUIRED 0 +#define REQUIRED 1 +#define SIG_LENGTH 4 + +const char VERSION[] = { "0.27.2" }; +const char PROGNAME[] = { "mab" }; + +char *known_sigs[] = { + "apic", + "bert", + "cpep", + "dsdt", + "ecdt", + "einj", + "erst", + "facp", + "facs", + "fpdt", + "gtdt", + "hest", + "mcfg", + "mchi", + "mpst", + "msct", + "oem", + "pcct", + "pmtt", + "rasf", + "rsdp", + "slit", + "spmi", + "srat", + "ssdt", + "uefi", + "xsdt", + NULL +}; + +LIST_HEAD(table_head, table) thead; +struct table_head *theadp; + +struct table { + char *signature; /* an ACPI table name/signature */ + char *asl_name; /* ASL file name */ + char *aml_name; /* corresponding AML name */ + int file_size; /* aka table size */ + int offset; /* location in the blob */ + LIST_ENTRY(table) tables; +}; + +int add_table(unsigned char *blob, char *table_name, int offset, int reqd); +void build_aml(int q, char *dir, char *iasl_cmd, struct table *tp); +struct table *build_table_entry(char *dir, char *buf); +struct table *find_table(char *sig); +int get_file_size(char *fname); +int read_manifest(char *dir, char *fname); +void set_blob_header(unsigned char *blob, int blob_size); +void set_checksum(unsigned char *start, int len, uint8_t *cksum); +void write_blob(char *dir, char *fname, unsigned char *blob, int size); +void write_table(unsigned char *blob, struct table *tp, int offset); +void usage(void); +int valid_sig(char *sig); + +void fixup_facp(unsigned char *blob, int *offset); +void fixup_rsdp(unsigned char *blob); +void fixup_xsdt(unsigned char *blob, int *offset); + +#endif
From: Al Stone al.stone@linaro.org
Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org --- scripts/Makefile.lib | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 07125e6..b14a32b 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -283,6 +283,15 @@ cmd_dtc_cpp = $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ $(obj)/%.dtb: $(src)/%.dtsp FORCE $(call if_changed_dep,dtc_cpp)
+# +# MAB: make an ACPI blob +# --------------------------------------------------------------------------- +quiet_cmd_mab = MAB $@ +cmd_mab = $(objtree)/scripts/mab/mab -d $(src)/$@ -i $(basename $@).manifest -o $@ + +$(obj)/%.acpi: %(src)/%.manifest FORCE + $(call cmd,mab) + # Bzip2 # ---------------------------------------------------------------------------
From: Al Stone al.stone@linaro.org
Add the Makefile stuff to enable arm platform to build acpi blobs from the arch/arm/boot/asl/ directory.
Signed-off-by: Al Stone al.stone@linaro.org --- arch/arm/Makefile | 3 +++ arch/arm/boot/asl/Makefile | 10 ++++++++++ 2 files changed, 13 insertions(+) create mode 100644 arch/arm/boot/asl/Makefile
diff --git a/arch/arm/Makefile b/arch/arm/Makefile index ee4605f..eedae30 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -299,6 +299,9 @@ zinstall uinstall install: vmlinux dtbs: scripts $(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) dtbs
+%.acpi: scripts + $(Q)$(MAKE) $(build)=$(boot)/asl MACHINE=$(MACHINE) $@ + # We use MRPROPER_FILES and CLEAN_FILES now archclean: $(Q)$(MAKE) $(clean)=$(boot) diff --git a/arch/arm/boot/asl/Makefile b/arch/arm/boot/asl/Makefile new file mode 100644 index 0000000..56d60af --- /dev/null +++ b/arch/arm/boot/asl/Makefile @@ -0,0 +1,10 @@ +ifeq ($(CONFIG_ACPI),y) + +%.acpi: FORCE + $(call cmd,mab) + +endif + +subdir-$(CONFIG_ARCH_EXYNOS5) += exynos5-arndale.acpi + +clean-files += *.acpi
From: Graeme Gregory graeme.gregory@linaro.org
Hide the compiled mab from git so we don't keep checking in old versions.
Signed-off-by: Graeme Gregory graeme.gregory@linaro.org --- scripts/mab/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 scripts/mab/.gitignore
diff --git a/scripts/mab/.gitignore b/scripts/mab/.gitignore new file mode 100644 index 0000000..0c4a76f --- /dev/null +++ b/scripts/mab/.gitignore @@ -0,0 +1,2 @@ +mab +
From: Al Stone al.stone@linaro.org
Needed because arm uses GIC which is defined in ACPI 5.0 spec.
Signed-off-by: Al Stone al.stone@linaro.org --- include/linux/acpi.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index bcbdd74..893670e 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -49,6 +49,7 @@ enum acpi_irq_model_id { ACPI_IRQ_MODEL_IOAPIC, ACPI_IRQ_MODEL_IOSAPIC, ACPI_IRQ_MODEL_PLATFORM, + ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_COUNT };
From: Al Stone al.stone@linaro.org
This is not needed by ARM compile so disable to remove compile error messages.
Signed-off-by: Al Stone al.stone@linaro.org --- drivers/acpi/bus.c | 4 ---- 1 file changed, 4 deletions(-)
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index db6c0c6..303c4ac 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -79,10 +79,6 @@ static struct dmi_system_id dsdt_dmi_table[] __initdata = { }, {} }; -#else -static struct dmi_system_id dsdt_dmi_table[] __initdata = { - {} -}; #endif
/* --------------------------------------------------------------------------
From: Graeme Gregory graeme.gregory@linaro.org
ACPI requires a cpu.h, add a dummy one copied from arm. This will need updated or replaced as cpu hotplug for armv8 is worked out.
Signed-off-by: Graeme Gregory graeme.gregory@linaro.org --- arch/arm64/include/asm/cpu.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 arch/arm64/include/asm/cpu.h
diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h new file mode 100644 index 0000000..5341811 --- /dev/null +++ b/arch/arm64/include/asm/cpu.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2004-2005 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_ARM_CPU_H +#define __ASM_ARM_CPU_H + +#include <linux/percpu.h> +#include <linux/cpu.h> + +struct cpuinfo_arm { + struct cpu cpu; + u32 cpuid; +#ifdef CONFIG_SMP + unsigned int loops_per_jiffy; +#endif +}; + +DECLARE_PER_CPU(struct cpuinfo_arm, cpu_data); + +#endif
From: Graeme Gregory graeme.gregory@linaro.org
Not all platforms with ACPI have PCI so only try and call pci based functions when CONFIG_PCI is set.
Signed-off-by: Graeme Gregory graeme.gregory@linaro.org --- drivers/pnp/pnpacpi/rsparser.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index b8f4ea7..464f8c9 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -113,8 +113,10 @@ static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
static void pnpacpi_add_irqresource(struct pnp_dev *dev, struct resource *r) { +#ifdef CONFIG_PCI if (!(r->flags & IORESOURCE_DISABLED)) pcibios_penalize_isa_irq(r->start, 1); +#endif
pnp_add_resource(dev, r); }
From: Graeme Gregory graeme.gregory@linaro.org
armv8 servers will use ACPI for initialisation in the same manner that current x86/x86_64 ones do. Add the calls to initialise the ACPI tables and load devices using the drivers/acpi subsytem.
Signed-off-by: Graeme Gregory graeme.gregory@linaro.org --- arch/arm64/Kconfig | 2 + arch/arm64/include/asm/acpi.h | 153 ++++++ arch/arm64/include/asm/io.h | 1 + arch/arm64/include/asm/processor.h | 13 + arch/arm64/kernel/Makefile | 3 + arch/arm64/kernel/acpi/Makefile | 6 + arch/arm64/kernel/acpi/acpi_div_64_by_32.S | 105 ++++ arch/arm64/kernel/acpi/boot.c | 731 ++++++++++++++++++++++++++++ arch/arm64/kernel/acpi/sleep.c | 126 +++++ arch/arm64/kernel/acpi/sleep.h | 17 + arch/arm64/kernel/process.c | 8 + arch/arm64/kernel/setup.c | 19 + include/acpi/pdc_arm64.h | 39 ++ 13 files changed, 1223 insertions(+) create mode 100644 arch/arm64/include/asm/acpi.h create mode 100644 arch/arm64/kernel/acpi/Makefile create mode 100644 arch/arm64/kernel/acpi/acpi_div_64_by_32.S create mode 100644 arch/arm64/kernel/acpi/boot.c create mode 100644 arch/arm64/kernel/acpi/sleep.c create mode 100644 arch/arm64/kernel/acpi/sleep.h create mode 100644 include/acpi/pdc_arm64.h
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 43b0e9f..b795dda 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -238,6 +238,8 @@ source "net/Kconfig"
source "drivers/Kconfig"
+source "drivers/acpi/Kconfig" + source "fs/Kconfig"
source "arch/arm64/Kconfig.debug" diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h new file mode 100644 index 0000000..3ef9fc0 --- /dev/null +++ b/arch/arm64/include/asm/acpi.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2013, Al Stone ahs3@redhat.com + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#ifndef _ASM_ARM_ACPI_H +#define _ASM_ARM_ACPI_H + +#ifdef __KERNEL__ + +#include <acpi/pdc_arm64.h> + +#include <asm/cacheflush.h> + +#include <linux/init.h> + +#define COMPILER_DEPENDENT_INT64 long long +#define COMPILER_DEPENDENT_UINT64 unsigned long long + +/* + * Calling conventions: + * + * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) + * ACPI_EXTERNAL_XFACE - External ACPI interfaces + * ACPI_INTERNAL_XFACE - Internal ACPI interfaces + * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces + */ +#define ACPI_SYSTEM_XFACE +#define ACPI_EXTERNAL_XFACE +#define ACPI_INTERNAL_XFACE +#define ACPI_INTERNAL_VAR_XFACE + +/* Asm macros */ +#define ACPI_ASM_MACROS +#define BREAKPOINT3 +#define ACPI_DISABLE_IRQS() local_irq_disable() +#define ACPI_ENABLE_IRQS() local_irq_enable() +#define ACPI_FLUSH_CPU_CACHE() flush_cache_all() + +#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) (\ + asm ("mov r0, %2\n" \ + "mov r1, %3\n" \ + "mov r2, %4\n" \ + "bl __arm_acpi_div_64_by_32\n" \ + "mov %0, r0\n" \ + "mov %1, r1\n" \ + : "=r"(q32), "=r"(r32) /* output */ \ + : "r"(n_hi), "r"(n_lo), "r"(d32) /* input */ \ + : "r0", "r1", "r2" /* clobbered registers */ \ + )) + +#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) (\ + asm ("mov r0, %2\n" \ + "mov r1, %3\n" \ + "and r2, r0, #1\n" \ + "lsr r0, r0, #1\n" \ + "lsr r1, r1, #1\n" \ + "orr r1, r1, r2, lsl #31\n" \ + "mov %0, r0\n" \ + "mov %1, r1\n" \ + : "=r"(n_hi), "=r"(n_lo) /* output operands */ \ + : "0"(n_hi), "1"(n_lo) /* input operands */ \ + : "r0", "r1", "r2" /* clobbered registers */ \ + )) + +/* Blob handling macros */ +#define ACPI_BLOB_HEADER_SIZE 8 + +int __acpi_acquire_global_lock(unsigned int *lock); +int __acpi_release_global_lock(unsigned int *lock); + +#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \ + ((Acq) = __acpi_acquire_global_lock(&facs->global_lock)) + +#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \ + ((Acq) = __acpi_release_global_lock(&facs->global_lock)) + +/* Basic configuration for ACPI */ +/* BOZO: hardware reduced acpi only? */ +#ifdef CONFIG_ACPI +extern int acpi_disabled; +extern int acpi_noirq; +extern int acpi_pci_disabled; +extern int acpi_strict; + +struct acpi_arm_root { + phys_addr_t phys_address; + unsigned long size; +}; +extern struct acpi_arm_root acpi_arm_rsdp_info; + +/* Low-level suspend routine. */ +extern int acpi_suspend_lowlevel(void); + +/* Physical address to resume after wakeup */ +/* BOZO: was... +#define acpi_wakeup_address ((unsigned long)(real_mode_header->wakeup_start)) +*/ +#define acpi_wakeup_address (0) + + +static inline void disable_acpi(void) +{ + acpi_disabled = 1; + acpi_pci_disabled = 1; + acpi_noirq = 1; +} + +static inline bool arch_has_acpi_pdc(void) +{ + /* BOZO: replace x86 specific-ness here */ + return 0; /* always false for now */ +} + +static inline void arch_acpi_set_pdc_bits(u32 *buf) +{ + /* BOZO: replace x86 specific-ness here */ +} + +static inline void acpi_noirq_set(void) { acpi_noirq = 1; } +static inline void acpi_disable_pci(void) +{ + acpi_pci_disabled = 1; + acpi_noirq_set(); +} + +#else /* !CONFIG_ACPI */ +#define acpi_disabled 1 /* ACPI sometimes enabled on ARM */ +#define acpi_noirq 1 /* ACPI sometimes enabled on ARM */ +#define acpi_pci_disabled 1 /* ACPI PCI sometimes enabled on ARM */ +#define acpi_strict 1 /* no ACPI spec workarounds on ARM */ +#endif + +#endif /*__KERNEL__*/ + +#endif /*_ASM_ARM_ACPI_H*/ diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h index 2e12258..849af4b 100644 --- a/arch/arm64/include/asm/io.h +++ b/arch/arm64/include/asm/io.h @@ -232,6 +232,7 @@ extern void __iounmap(volatile void __iomem *addr); #define ioremap(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE)) #define ioremap_nocache(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE)) #define ioremap_wc(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC)) +#define ioremap_cache(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEFAULT)) #define iounmap __iounmap
#define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF) diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index ab239b2..53326fd 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -155,6 +155,19 @@ static inline void spin_lock_prefetch(const void *x) prefetchw(x); }
+/* + * Not all ARM devices have ACPI, but some do + * BOZO: is this correct? + */ +#ifdef CONFIG_ACPI +enum idle_boot_override { IDLE_NO_OVERRIDE = 0, IDLE_HALT, IDLE_NOMWAIT, + IDLE_POLL, IDLE_FORCE_MWAIT }; + +extern unsigned long boot_option_idle_override; +#endif + +/* end BOZO */ + #define HAVE_ARCH_PICK_MMAP_LAYOUT
#endif diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 7b4b564..615c672 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -27,3 +27,6 @@ extra-y := $(head-y) vmlinux.lds # vDSO - this must be built first to generate the symbol offsets $(call objectify,$(arm64-obj-y)): $(obj)/vdso/vdso-offsets.h $(obj)/vdso/vdso-offsets.h: $(obj)/vdso + +obj-$(CONFIG_ACPI) += acpi/ + diff --git a/arch/arm64/kernel/acpi/Makefile b/arch/arm64/kernel/acpi/Makefile new file mode 100644 index 0000000..e28c063 --- /dev/null +++ b/arch/arm64/kernel/acpi/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_ACPI) += boot.o + +# BOZO: need to re-enable this properly +#obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o +obj-$(CONFIG_ACPI_SLEEP) += sleep.o + diff --git a/arch/arm64/kernel/acpi/acpi_div_64_by_32.S b/arch/arm64/kernel/acpi/acpi_div_64_by_32.S new file mode 100644 index 0000000..99a14a4 --- /dev/null +++ b/arch/arm64/kernel/acpi/acpi_div_64_by_32.S @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2013, Al Stone ahs3@redhat.com + * + * __acpi_arm_div64_by_32: perform integer division of a 64-bit value + * a 32-bit value + * + * The algorithm is borrowed from the GMP library, but has been redone + * here in order to put this implementation under a GPLv2 license. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef __ARM_ARCH_8__ + +#include <linux/linkage.h> + +/* + * This needs to be called in the following manner: + * n_lo => r0 # these are the low 32 bits of the dividend + * n_hi => r1 # the high 32 bits of the dividend + * d32 => r2 # the 32-bit divisor + * + * The result is: + * q32 <= r0 # the 32-bit quotient + * r32 <= r1 # the 32-bit remainder + * + * This should be consistent with the normal ARMv7 calling conventions. + * + */ + +ENTRY(__arm_acpi_div_64_by_32) + mov r12, #32 // loop counter + cmp r2, #0x80000000 // check divisor MSB and clear carry + bcs bigdiv + +loop: adcs r1, r1, r1 // handle each bit + adc r0, r0, r0 + cmp r0, r2 + subcs r0, r0, r2 + sub r12, r12, #1 + teq r12, #0 + bne loop + + mov r3, r0 // stash the remainder for a tic + adc r0, r1, r1 // quotient: add in last carry + mov r1, r3 // remainder (now in right register) + mov pc, lr + +bigdiv: stmfd sp!, { r8, lr } // clear some scratch space + + and r8, r1, #1 // save LSB of dividend + mov lr, r0, lsl #31 + orrs r1, lr, r1, lsr #1 // r1 = lower part >> 1 bit + mov r0, r0, lsr #1 // r0 = higher part >> 1 bit + + and lr, r2, #1 // save LSB of divisor + movs r2, r2, lsr #1 // r2 = floor(divisor / 2) + adc r2, r2, #0 // r2 = ceil(divisor / 2) + +loop2: adcs r1, r1, r1 // handle each bit + adc r0, r0, r0 + cmp r0, r2 + subcs r0, r0, r2 + sub r12, r12, #1 + teq r12, #0 + bne loop2 + + adc r1, r1, r1 // shift and add last carry + add r0, r8, r0, lsl #1 // shift in remaining dividend LSB + tst lr, lr + beq evendiv + + rsb r2, lr, r2, lsl #1 // restore divisor value + adds r0, r0, r1 // adjust for omitted divisor LSB + addcs r1, r1, #1 // adjust quotient if a carry results + subcs r0, r0, r2 // adjust remainder, if carry + cmp r0, r2 + subcs r0, r0, #1 // adjust remainder + addcs r1, r1, #1 // adjust quotient + +evendiv: + mov r3, r0 // stash the remainder for a tic + mov r0, r1 // quotient + mov r1, r3 // remainder + + ldmfd sp!, { r8, pc } // restore the registers used + +ENDPROC(__arm_acpi_div_64_by_32) + +#else /* ! __ARM_ARCH_7A__ */ +#error __arm_acpi_div_64_by_32 not defined for this architecture +#endif + diff --git a/arch/arm64/kernel/acpi/boot.c b/arch/arm64/kernel/acpi/boot.c new file mode 100644 index 0000000..5db7f6b --- /dev/null +++ b/arch/arm64/kernel/acpi/boot.c @@ -0,0 +1,731 @@ +/* + * boot.c - Architecture-Specific Low-Level ACPI Boot Support + * + * Copyright (C) 2001, 2002 Paul Diefenbaugh paul.s.diefenbaugh@intel.com + * Copyright (C) 2001 Jun Nakajima jun.nakajima@intel.com + * Copyright (C) 2013, Al Stone ahs3@redhat.com (ARM version) + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +/* + * BOZO: this needs to be done right.... + */ +#include <linux/init.h> +#include <linux/acpi.h> +#include <linux/acpi_pmtmr.h> +#include <linux/efi.h> +#include <linux/cpumask.h> +#include <linux/memblock.h> +#include <linux/module.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/slab.h> +#include <linux/bootmem.h> +#include <linux/ioport.h> +#include <linux/pci.h> + +#include <asm/pgtable.h> +#include <asm/io.h> +#include <asm/smp.h> +#include <asm/acpi.h> + +static int __initdata acpi_force; +u32 acpi_rsdt_forced; +int acpi_disabled; +EXPORT_SYMBOL(acpi_disabled); + +#define BAD_MADT_ENTRY(entry, end) ( \ + (!entry) || (unsigned long)entry + sizeof(*entry) > end || \ + ((struct acpi_subtable_header *)entry)->length < sizeof(*entry)) + +#define PREFIX "ACPI: " + +int acpi_noirq; /* skip ACPI IRQ initialization */ +int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */ +EXPORT_SYMBOL(acpi_pci_disabled); + +int acpi_lapic; +int acpi_ioapic; +int acpi_strict; + +u8 acpi_sci_flags __initdata; +int acpi_sci_override_gsi __initdata; +int acpi_skip_timer_override __initdata; +int acpi_use_timer_override __initdata; +int acpi_fix_pin2_polarity __initdata; + +struct acpi_arm_root acpi_arm_rsdp_info; /* info about RSDP from FDT */ + +/* + * Boot-time Configuration + */ + +/* + * The default interrupt routing model is PIC (8259). This gets + * overridden if IOAPICs are enumerated (below). + * + * Since we're on ARM, it clearly has to be GIC. + */ +enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_GIC; + +static unsigned int gsi_to_irq(unsigned int gsi) +{ + int irq = irq_create_mapping(NULL, gsi); + + return irq; +} + +/* + * BOZO: is it reasonable to just reserve the memory space? Or are there + * other restrictions needed? Or does it need copying to some other place? + */ +char *__init __acpi_map_table(unsigned long phys, unsigned long size) +{ + if (!phys || !size) + return NULL; + + /* we're already in memory so we cannot io_remap the entry */ + return phys_to_virt(phys); +} + +void __init __acpi_unmap_table(char *map, unsigned long size) +{ + if (!map || !size) + return; + + /* we're already in memory so we cannot io_remap the entry; + * since we're not io_remap'ing, unmap'ing is especially + * pointless + */ + return; +} + +/* + * acpi_pic_sci_set_trigger() + * + * use ELCR to set PIC-mode trigger type for SCI + * + * If a PIC-mode SCI is not recognized or gives spurious IRQ7's + * it may require Edge Trigger -- use "acpi_sci=edge" + * + * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers + * for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge. + * ECLR1 is IRQs 0-7 (IRQ 0, 1, 2 must be 0) + * ECLR2 is IRQs 8-15 (IRQ 8, 13 must be 0) + */ + +void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) +{ + unsigned int mask = 1 << irq; + unsigned int old, new; + + /* Real old ELCR mask */ + old = inb(0x4d0) | (inb(0x4d1) << 8); + + /* + * If we use ACPI to set PCI IRQs, then we should clear ELCR + * since we will set it correctly as we enable the PCI irq + * routing. + */ + new = acpi_noirq ? old : 0; + + /* + * Update SCI information in the ELCR, it isn't in the PCI + * routing tables.. + */ + switch (trigger) { + case 1: /* Edge - clear */ + new &= ~mask; + break; + case 3: /* Level - set */ + new |= mask; + break; + } + + if (old == new) + return; + + printk(PREFIX "setting ELCR to %04x (from %04x)\n", new, old); + outb(new, 0x4d0); + outb(new >> 8, 0x4d1); +} + +int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) +{ + *irq = gsi_to_irq(gsi); + + return 0; +} +EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); + +static int acpi_register_gsi_pic(struct device *dev, u32 gsi, + int trigger, int polarity) +{ +#ifdef CONFIG_PCI + /* + * Make sure all (legacy) PCI IRQs are set as level-triggered. + */ + if (trigger == ACPI_LEVEL_SENSITIVE) + eisa_set_level_irq(gsi); +#endif + + return gsi; +} + +static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi, + int trigger, int polarity) +{ + return gsi; +} + +int (*__acpi_register_gsi)(struct device *dev, u32 gsi, + int trigger, int polarity) = acpi_register_gsi_pic; + +/* + * success: return IRQ number (>=0) + * failure: return < 0 + */ +int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) +{ + unsigned int irq; + unsigned int plat_gsi = gsi; + + plat_gsi = (*__acpi_register_gsi)(dev, gsi, trigger, polarity); + + irq = gsi_to_irq(plat_gsi); + + return irq; +} +EXPORT_SYMBOL_GPL(acpi_register_gsi); + +void acpi_unregister_gsi(u32 gsi) +{ +} +EXPORT_SYMBOL_GPL(acpi_unregister_gsi); + +void __init acpi_set_irq_model_pic(void) +{ + acpi_irq_model = ACPI_IRQ_MODEL_PIC; + __acpi_register_gsi = acpi_register_gsi_pic; + acpi_ioapic = 0; +} + +void __init acpi_set_irq_model_ioapic(void) +{ + acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; + __acpi_register_gsi = acpi_register_gsi_ioapic; + acpi_ioapic = 1; +} + +/* + * ACPI based hotplug support for CPU + */ +#ifdef CONFIG_ACPI_HOTPLUG_CPU +#include <acpi/processor.h> + +static void __cpuinit acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) +{ +#ifdef CONFIG_ACPI_NUMA + int nid; + + nid = acpi_get_node(handle); + if (nid == -1 || !node_online(nid)) + return; + set_apicid_to_node(physid, nid); + numa_set_node(cpu, nid); +#endif +} + +static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + struct acpi_madt_local_apic *lapic; + cpumask_var_t tmp_map, new_map; + u8 physid; + int cpu; + int retval = -ENOMEM; + + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) + return -EINVAL; + + if (!buffer.length || !buffer.pointer) + return -EINVAL; + + obj = buffer.pointer; + if (obj->type != ACPI_TYPE_BUFFER || + obj->buffer.length < sizeof(*lapic)) { + kfree(buffer.pointer); + return -EINVAL; + } + + lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer; + + if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC || + !(lapic->lapic_flags & ACPI_MADT_ENABLED)) { + kfree(buffer.pointer); + return -EINVAL; + } + + physid = lapic->id; + + kfree(buffer.pointer); + buffer.length = ACPI_ALLOCATE_BUFFER; + buffer.pointer = NULL; + lapic = NULL; + + if (!alloc_cpumask_var(&tmp_map, GFP_KERNEL)) + goto out; + + if (!alloc_cpumask_var(&new_map, GFP_KERNEL)) + goto free_tmp_map; + + cpumask_copy(tmp_map, cpu_present_mask); +#ifdef CONFIG_X86 + /* BOZO: ?? */ + acpi_register_lapic(physid, ACPI_MADT_ENABLED); +#endif + + /* + * If acpi_register_lapic successfully generates a new logical cpu + * number, then the following will get us exactly what was mapped + */ + cpumask_andnot(new_map, cpu_present_mask, tmp_map); + if (cpumask_empty(new_map)) { + printk("Unable to map lapic to logical cpu number\n"); + retval = -EINVAL; + goto free_new_map; + } + + acpi_processor_set_pdc(handle); + + cpu = cpumask_first(new_map); + acpi_map_cpu2node(handle, cpu, physid); + + *pcpu = cpu; + retval = 0; + +free_new_map: + free_cpumask_var(new_map); +free_tmp_map: + free_cpumask_var(tmp_map); +out: + return retval; +} + +/* wrapper to silence section mismatch warning */ +int __ref acpi_map_lsapic(acpi_handle handle, int *pcpu) +{ + return _acpi_map_lsapic(handle, pcpu); +} +EXPORT_SYMBOL(acpi_map_lsapic); + +int acpi_unmap_lsapic(int cpu) +{ +#ifdef CONFIG_X86 + /* BOZO: ??? */ + per_cpu(x86_cpu_to_apicid, cpu) = -1; + set_cpu_present(cpu, false); + num_processors--; +#endif + + return 0; +} +EXPORT_SYMBOL(acpi_unmap_lsapic); +#endif /* CONFIG_ACPI_HOTPLUG_CPU */ + +static int __init acpi_parse_sbf(struct acpi_table_header *table) +{ + struct acpi_table_boot *sb; + + sb = (struct acpi_table_boot *)table; + if (!sb) { + printk(KERN_WARNING PREFIX "Unable to map SBF\n"); + return -ENODEV; + } + + return 0; +} + +#ifdef CONFIG_HPET_TIMER +#include <asm/hpet.h> + +static struct __initdata resource * hpet_res; + +static int __init acpi_parse_hpet(struct acpi_table_header *table) +{ + struct acpi_table_hpet *hpet_tbl; + + hpet_tbl = (struct acpi_table_hpet *)table; + if (!hpet_tbl) { + printk(KERN_WARNING PREFIX "Unable to map HPET\n"); + return -ENODEV; + } + + if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) { + printk(KERN_WARNING PREFIX "HPET timers must be located in " + "memory.\n"); + return -1; + } + + hpet_address = hpet_tbl->address.address; + hpet_blockid = hpet_tbl->sequence; + + /* + * Some broken BIOSes advertise HPET at 0x0. We really do not + * want to allocate a resource there. + */ + if (!hpet_address) { + printk(KERN_WARNING PREFIX + "HPET id: %#x base: %#lx is invalid\n", + hpet_tbl->id, hpet_address); + return 0; + } + printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", + hpet_tbl->id, hpet_address); + + /* + * Allocate and initialize the HPET firmware resource for adding into + * the resource tree during the lateinit timeframe. + */ +#define HPET_RESOURCE_NAME_SIZE 9 + hpet_res = alloc_bootmem(sizeof(*hpet_res) + HPET_RESOURCE_NAME_SIZE); + + hpet_res->name = (void *)&hpet_res[1]; + hpet_res->flags = IORESOURCE_MEM; + snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE, "HPET %u", + hpet_tbl->sequence); + + hpet_res->start = hpet_address; + hpet_res->end = hpet_address + (1 * 1024) - 1; + + return 0; +} + +/* + * hpet_insert_resource inserts the HPET resources used into the resource + * tree. + */ +static __init int hpet_insert_resource(void) +{ + if (!hpet_res) + return 1; + + return insert_resource(&iomem_resource, hpet_res); +} + +late_initcall(hpet_insert_resource); + +#else +#define acpi_parse_hpet NULL +#endif + +static int __init acpi_parse_fadt(struct acpi_table_header *table) +{ + return 0; +} + +static void __init early_acpi_process_madt(void) +{ +} + +static void __init acpi_process_madt(void) +{ + return; +} + +void set_checksum(u8 *start, int len, u8 *cksum) +{ + u8 newsum, oldsum; + u8 *p; + + newsum = 0; + for (p = (u8 *)start; p < (u8 *)(start + len); p++) + newsum += *p; + + oldsum = *cksum; + newsum = (u8)(newsum - oldsum); + + *cksum = (u8)(0 - newsum); +} + +void __init acpi_arm_blob_relocate(void) +{ + /* + * Fortunately, there are only a few tables that need to + * have their offsets converted to actual addresses. + * + * NB: all values in the blob are little-endian. + */ + + struct acpi_table_rsdp *rp; + struct acpi_table_xsdt *xp; + struct acpi_table_fadt *fp; + phys_addr_t paddress; + void *vaddress; + u32 entries; + u32 ii; + u64 *tmp; + + if (!acpi_arm_rsdp_info.phys_address && !acpi_arm_rsdp_info.size) { + printk(KERN_ERR "(E) ACPI: failed to find rsdp info\n"); + return; + } + + paddress = acpi_arm_rsdp_info.phys_address; + paddress += ACPI_BLOB_HEADER_SIZE; + vaddress = phys_to_virt(paddress); + + /* fixups for the rsdp */ + rp = (struct acpi_table_rsdp *)vaddress; + if (rp->rsdt_physical_address) + rp->rsdt_physical_address += paddress; + if (rp->xsdt_physical_address) + rp->xsdt_physical_address += paddress; + set_checksum((u8 *)rp, rp->length, &(rp->checksum)); + + /* fixups for the xsdt */ + vaddress = phys_to_virt(rp->xsdt_physical_address); + xp = (struct acpi_table_xsdt *)vaddress; + entries = xp->header.length - sizeof (struct acpi_table_header); + entries /= 8; /* length is in bytes */ + tmp = (u64 *)(&(xp->table_offset_entry[0])); + for (ii = 0; ii < entries; ii++) + *tmp++ += paddress; + set_checksum((u8 *)xp, xp->header.length, &(xp->header.checksum)); + + /* fixups for the fadt */ + vaddress = phys_to_virt(xp->table_offset_entry[0]); + fp = (struct acpi_table_fadt *)vaddress; + if (fp->facs) + fp->facs += paddress; + if (fp->dsdt) + fp->dsdt += paddress; + if (fp->Xfacs) + fp->Xfacs += paddress; + if (fp->Xdsdt) + fp->Xdsdt += paddress; + + /* Always fix up the checksums since we've changed bits. */ + set_checksum((u8 *)fp, fp->header.length, &(fp->header.checksum)); +} + +/* + * ========== OLD COMMENTS FROM x86 ================================= + * acpi_boot_table_init() and acpi_boot_init() + * called from setup_arch(), always. + * 1. checksums all tables + * 2. enumerates lapics + * 3. enumerates io-apics + * + * acpi_table_init() is separate to allow reading SRAT without + * other side effects. + * + * side effects of acpi_boot_init: + * acpi_lapic = 1 if LAPIC found + * acpi_ioapic = 1 if IOAPIC found + * if (acpi_lapic && acpi_ioapic) smp_found_config = 1; + * if acpi_blacklisted() acpi_disabled = 1; + * acpi_irq_model=... + * ... + * ================================================================== + * + * We have to approach this a little different on ARMv7. We are + * passed in an ACPI blob and we really have no idea where in RAM + * it will be located. So, what should have been the physical + * addresses of other tables cannot really be hardcoded into the + * tables. What we will do is put an offset in the blob that is + * the offset from the beginning of the RSDP structure. However, + * what that means is that we have to unpack the blob and do a + * 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) +{ + /* + * If acpi_disabled, bail out + */ + if (acpi_disabled) + return; + + printk(KERN_DEBUG "acpi: enter acpi_boot_table_init\n"); + + /* + * Fix up the addresses in the ACPI we've loaded + * in. The blob has them as offsets and we need + * actual addresses. + */ + acpi_arm_blob_relocate(); + + /* + * Initialize the ACPI boot-time table parser. + */ + if (acpi_table_init()) { + disable_acpi(); + return; + } + + printk(KERN_INFO "(I) acpi_table_init call completed\n"); + acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf); + + printk(KERN_INFO "(I) exit acpi_boot_table_init\n"); +} + +int __init early_acpi_boot_init(void) +{ + /* + * If acpi_disabled, bail out + */ + if (acpi_disabled) + return 1; + + printk(KERN_INFO "enter early_acpi_boot_init\n"); + + /* + * Process the Multiple APIC Description Table (MADT), if present + */ + early_acpi_process_madt(); + + return 0; +} + +int __init acpi_boot_init(void) +{ + /* + * If acpi_disabled, bail out + */ + if (acpi_disabled) + return 1; + + printk(KERN_INFO "enter acpi_boot_init\n"); + + acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf); + + /* + * set sci_int and PM timer address + */ + acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt); + + /* + * Process the Multiple APIC Description Table (MADT), if present + */ + acpi_process_madt(); + + acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet); + + return 0; +} + +static int __init parse_acpi(char *arg) +{ + if (!arg) + return -EINVAL; + + /* "acpi=off" disables both ACPI table parsing and interpreter */ + if (strcmp(arg, "off") == 0) { + disable_acpi(); + } + /* acpi=force to over-ride black-list */ + else if (strcmp(arg, "force") == 0) { + acpi_force = 1; + acpi_disabled = 0; + } + /* acpi=strict disables out-of-spec workarounds */ + else if (strcmp(arg, "strict") == 0) { + acpi_strict = 1; + } + /* acpi=rsdt use RSDT instead of XSDT */ + else if (strcmp(arg, "rsdt") == 0) { + acpi_rsdt_forced = 1; + } + /* "acpi=noirq" disables ACPI interrupt routing */ + else if (strcmp(arg, "noirq") == 0) { + acpi_noirq_set(); + } + /* "acpi=copy_dsdt" copys DSDT */ + else if (strcmp(arg, "copy_dsdt") == 0) { + acpi_gbl_copy_dsdt_locally = 1; + } else { + /* Core will printk when we return error. */ + return -EINVAL; + } + return 0; +} +early_param("acpi", parse_acpi); + +/* FIXME: Using pci= for an ACPI parameter is a travesty. */ +static int __init parse_pci(char *arg) +{ + if (arg && strcmp(arg, "noacpi") == 0) + acpi_disable_pci(); + return 0; +} +early_param("pci", parse_pci); + +int __init acpi_mps_check(void) +{ + return 0; +} + +static int __init setup_acpi_sci(char *s) +{ + if (!s) + return -EINVAL; + if (!strcmp(s, "edge")) + acpi_sci_flags = ACPI_MADT_TRIGGER_EDGE | + (acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK); + else if (!strcmp(s, "level")) + acpi_sci_flags = ACPI_MADT_TRIGGER_LEVEL | + (acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK); + else if (!strcmp(s, "high")) + acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_HIGH | + (acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK); + else if (!strcmp(s, "low")) + acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_LOW | + (acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK); + else + return -EINVAL; + return 0; +} +early_param("acpi_sci", setup_acpi_sci); + +int __acpi_acquire_global_lock(unsigned int *lock) +{ + unsigned int old, new, val; + do { + old = *lock; + new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1)); + val = cmpxchg(lock, old, new); + } while (unlikely (val != old)); + return (new < 3) ? -1 : 0; +} + +int __acpi_release_global_lock(unsigned int *lock) +{ + unsigned int old, new, val; + do { + old = *lock; + new = old & ~0x3; + val = cmpxchg(lock, old, new); + } while (unlikely (val != old)); + return old & 0x1; +} + diff --git a/arch/arm64/kernel/acpi/sleep.c b/arch/arm64/kernel/acpi/sleep.c new file mode 100644 index 0000000..9129c7e --- /dev/null +++ b/arch/arm64/kernel/acpi/sleep.c @@ -0,0 +1,126 @@ +/* + * sleep.c - x86-specific ACPI sleep support. + * + * Copyright (C) 2001-2003 Patrick Mochel + * Copyright (C) 2001-2003 Pavel Machek pavel@ucw.cz + */ + +int acpi_suspend_lowlevel(void) +{ + /* BOZO: dummy routine; see below for actual */ + return 0; +} + +#ifdef CONFIG_X86 +/* BOZO: disable everything for now... */ + +#include <linux/acpi.h> +#include <linux/bootmem.h> +#include <linux/memblock.h> +#include <linux/dmi.h> +#include <linux/cpumask.h> +#include <asm/segment.h> +#include <asm/desc.h> +#include <asm/pgtable.h> +#include <asm/cacheflush.h> +#include <asm/realmode.h> + +#include "../../realmode/rm/wakeup.h" +#include "sleep.h" + +unsigned long acpi_realmode_flags; + +#if defined(CONFIG_SMP) && defined(CONFIG_64BIT) +static char temp_stack[4096]; +#endif + +/** + * acpi_suspend_lowlevel - save kernel state + * + * Create an identity mapped page table and copy the wakeup routine to + * low memory. + */ +int acpi_suspend_lowlevel(void) +{ + struct wakeup_header *header = + (struct wakeup_header *) __va(real_mode_header->wakeup_header); + + if (header->signature != WAKEUP_HEADER_SIGNATURE) { + printk(KERN_ERR "wakeup header does not match\n"); + return -EINVAL; + } + + header->video_mode = saved_video_mode; + + header->pmode_behavior = 0; + +#ifndef CONFIG_64BIT + store_gdt((struct desc_ptr *)&header->pmode_gdt); + + if (!rdmsr_safe(MSR_EFER, + &header->pmode_efer_low, + &header->pmode_efer_high)) + header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_EFER); +#endif /* !CONFIG_64BIT */ + + header->pmode_cr0 = read_cr0(); + if (__this_cpu_read(cpu_info.cpuid_level) >= 0) { + header->pmode_cr4 = read_cr4(); + header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_CR4); + } + if (!rdmsr_safe(MSR_IA32_MISC_ENABLE, + &header->pmode_misc_en_low, + &header->pmode_misc_en_high)) + header->pmode_behavior |= + (1 << WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE); + header->realmode_flags = acpi_realmode_flags; + header->real_magic = 0x12345678; + +#ifndef CONFIG_64BIT + header->pmode_entry = (u32)&wakeup_pmode_return; + header->pmode_cr3 = (u32)__pa(&initial_page_table); + saved_magic = 0x12345678; +#else /* CONFIG_64BIT */ +#ifdef CONFIG_SMP + stack_start = (unsigned long)temp_stack + sizeof(temp_stack); + early_gdt_descr.address = + (unsigned long)get_cpu_gdt_table(smp_processor_id()); + initial_gs = per_cpu_offset(smp_processor_id()); +#endif + initial_code = (unsigned long)wakeup_long64; + saved_magic = 0x123456789abcdef0L; +#endif /* CONFIG_64BIT */ + + do_suspend_lowlevel(); + return 0; +} + +static int __init acpi_sleep_setup(char *str) +{ + while ((str != NULL) && (*str != '\0')) { + if (strncmp(str, "s3_bios", 7) == 0) + acpi_realmode_flags |= 1; + if (strncmp(str, "s3_mode", 7) == 0) + acpi_realmode_flags |= 2; + if (strncmp(str, "s3_beep", 7) == 0) + acpi_realmode_flags |= 4; +#ifdef CONFIG_HIBERNATION + if (strncmp(str, "s4_nohwsig", 10) == 0) + acpi_no_s4_hw_signature(); +#endif + if (strncmp(str, "nonvs", 5) == 0) + acpi_nvs_nosave(); + if (strncmp(str, "nonvs_s3", 8) == 0) + acpi_nvs_nosave_s3(); + if (strncmp(str, "old_ordering", 12) == 0) + acpi_old_suspend_ordering(); + str = strchr(str, ','); + if (str != NULL) + str += strspn(str, ", \t"); + } + return 1; +} + +__setup("acpi_sleep=", acpi_sleep_setup); + +#endif diff --git a/arch/arm64/kernel/acpi/sleep.h b/arch/arm64/kernel/acpi/sleep.h new file mode 100644 index 0000000..67f59f8c --- /dev/null +++ b/arch/arm64/kernel/acpi/sleep.h @@ -0,0 +1,17 @@ +/* + * Variables and functions used by the code in sleep.c + */ + +#include <asm/realmode.h> + +extern unsigned long saved_video_mode; +extern long saved_magic; + +extern int wakeup_pmode_return; + +extern u8 wake_sleep_flags; + +extern unsigned long acpi_copy_wakeup_routine(unsigned long); +extern void wakeup_long64(void); + +extern void do_suspend_lowlevel(void); diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index bbefb6f..d4e8c03 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -367,3 +367,11 @@ unsigned long randomize_et_dyn(unsigned long base) { return randomize_base(base); } + +#ifdef CONFIG_ACPI + +unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE; +EXPORT_SYMBOL(boot_option_idle_override); + +#endif + diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 6a9a532..80410e6 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -41,6 +41,9 @@ #include <linux/memblock.h> #include <linux/of_fdt.h> #include <linux/of_platform.h> +#ifdef CONFIG_ACPI +#include <linux/acpi.h> +#endif
#include <asm/cputype.h> #include <asm/elf.h> @@ -54,6 +57,10 @@ #include <asm/memblock.h> #include <asm/psci.h>
+#ifdef CONFIG_ACPI +#include <asm/acpi.h> +#endif + unsigned int processor_id; EXPORT_SYMBOL(processor_id);
@@ -166,6 +173,10 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)
/* Retrieve various information from the /chosen node */ of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); +#ifdef CONFIG_ACPI + /* Retrieve ACPI pointers from /chosen node */ + of_scan_flat_dt(early_init_dt_scan_acpi, &acpi_arm_rsdp_info); +#endif /* Initialize {size,address}-cells info */ of_scan_flat_dt(early_init_dt_scan_root, NULL); /* Setup memory, calling early_init_dt_add_memory_arch */ @@ -264,6 +275,14 @@ void __init setup_arch(char **cmdline_p) paging_init(); request_standard_resources();
+#ifdef CONFIG_ACPI + /* + * Parse the ACPI tables for possible boot-time configuration + */ + acpi_boot_table_init(); + early_acpi_boot_init(); +#endif + unflatten_device_tree();
psci_init(); diff --git a/include/acpi/pdc_arm64.h b/include/acpi/pdc_arm64.h new file mode 100644 index 0000000..ac8f197 --- /dev/null +++ b/include/acpi/pdc_arm64.h @@ -0,0 +1,39 @@ + +/* _PDC bit definition for ARMv7 processors */ + +#ifndef __PDC_ARM_H__ +#define __PDC_ARM_H__ + +/* BOZO: is this even necessary? */ + +/* _PDC bit definition for ARM processors */ + +#define ACPI_PDC_P_FFH (0x0001) +#define ACPI_PDC_C_C1_HALT (0x0002) +#define ACPI_PDC_T_FFH (0x0004) +#define ACPI_PDC_SMP_C1PT (0x0008) +#define ACPI_PDC_SMP_C2C3 (0x0010) +#define ACPI_PDC_SMP_P_SWCOORD (0x0020) +#define ACPI_PDC_SMP_C_SWCOORD (0x0040) +#define ACPI_PDC_SMP_T_SWCOORD (0x0080) +#define ACPI_PDC_C_C1_FFH (0x0100) +#define ACPI_PDC_C_C2C3_FFH (0x0200) +#define ACPI_PDC_SMP_P_HWCOORD (0x0800) + +#define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \ + ACPI_PDC_C_C1_HALT | \ + ACPI_PDC_P_FFH) + +#define ACPI_PDC_EST_CAPABILITY_SWSMP (ACPI_PDC_SMP_C1PT | \ + ACPI_PDC_C_C1_HALT | \ + ACPI_PDC_SMP_P_SWCOORD | \ + ACPI_PDC_SMP_P_HWCOORD | \ + ACPI_PDC_P_FFH) + +#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \ + ACPI_PDC_SMP_C1PT | \ + ACPI_PDC_C_C1_HALT | \ + ACPI_PDC_C_C1_FFH | \ + ACPI_PDC_C_C2C3_FFH) + +#endif /* __PDC_ARM_H__ */
On 11/giu/2013, at 12:23, Graeme Gregory graeme.gregory@linaro.org wrote:
From: Graeme Gregory graeme.gregory@linaro.org
armv8 servers will use ACPI for initialisation in the same manner that current x86/x86_64 ones do. Add the calls to initialise the ACPI tables and load devices using the drivers/acpi subsytem.
Signed-off-by: Graeme Gregory graeme.gregory@linaro.org
arch/arm64/Kconfig | 2 + arch/arm64/include/asm/acpi.h | 153 ++++++ arch/arm64/include/asm/io.h | 1 + arch/arm64/include/asm/processor.h | 13 + arch/arm64/kernel/Makefile | 3 + arch/arm64/kernel/acpi/Makefile | 6 + arch/arm64/kernel/acpi/acpi_div_64_by_32.S | 105 ++++ arch/arm64/kernel/acpi/boot.c | 731 ++++++++++++++++++++++++++++ arch/arm64/kernel/acpi/sleep.c | 126 +++++ arch/arm64/kernel/acpi/sleep.h | 17 + arch/arm64/kernel/process.c | 8 + arch/arm64/kernel/setup.c | 19 + include/acpi/pdc_arm64.h | 39 ++ 13 files changed, 1223 insertions(+) create mode 100644 arch/arm64/include/asm/acpi.h create mode 100644 arch/arm64/kernel/acpi/Makefile create mode 100644 arch/arm64/kernel/acpi/acpi_div_64_by_32.S create mode 100644 arch/arm64/kernel/acpi/boot.c create mode 100644 arch/arm64/kernel/acpi/sleep.c create mode 100644 arch/arm64/kernel/acpi/sleep.h create mode 100644 include/acpi/pdc_arm64.h
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 43b0e9f..b795dda 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -238,6 +238,8 @@ source "net/Kconfig"
source "drivers/Kconfig"
+source "drivers/acpi/Kconfig"
source "fs/Kconfig"
source "arch/arm64/Kconfig.debug" diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h new file mode 100644 index 0000000..3ef9fc0 --- /dev/null +++ b/arch/arm64/include/asm/acpi.h @@ -0,0 +1,153 @@ +/*
- Copyright (C) 2013, Al Stone ahs3@redhat.com
would you kindly use linaro.org email address, please?
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
+#ifndef _ASM_ARM_ACPI_H +#define _ASM_ARM_ACPI_H
+#ifdef __KERNEL__
+#include <acpi/pdc_arm64.h>
+#include <asm/cacheflush.h>
+#include <linux/init.h>
+#define COMPILER_DEPENDENT_INT64 long long +#define COMPILER_DEPENDENT_UINT64 unsigned long long
+/*
- Calling conventions:
- ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads)
- ACPI_EXTERNAL_XFACE - External ACPI interfaces
- ACPI_INTERNAL_XFACE - Internal ACPI interfaces
- ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces
- */
+#define ACPI_SYSTEM_XFACE +#define ACPI_EXTERNAL_XFACE +#define ACPI_INTERNAL_XFACE +#define ACPI_INTERNAL_VAR_XFACE
+/* Asm macros */ +#define ACPI_ASM_MACROS +#define BREAKPOINT3 +#define ACPI_DISABLE_IRQS() local_irq_disable() +#define ACPI_ENABLE_IRQS() local_irq_enable() +#define ACPI_FLUSH_CPU_CACHE() flush_cache_all()
+#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) (\
- asm ("mov r0, %2\n" \
"mov r1, %3\n" \
"mov r2, %4\n" \
"bl __arm_acpi_div_64_by_32\n" \
"mov %0, r0\n" \
"mov %1, r1\n" \
: "=r"(q32), "=r"(r32) /* output */ \
: "r"(n_hi), "r"(n_lo), "r"(d32) /* input */ \
: "r0", "r1", "r2" /* clobbered registers */ \
- ))
+#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) (\
- asm ("mov r0, %2\n" \
"mov r1, %3\n" \
"and r2, r0, #1\n" \
"lsr r0, r0, #1\n" \
"lsr r1, r1, #1\n" \
"orr r1, r1, r2, lsl #31\n" \
"mov %0, r0\n" \
"mov %1, r1\n" \
: "=r"(n_hi), "=r"(n_lo) /* output operands */ \
: "0"(n_hi), "1"(n_lo) /* input operands */ \
: "r0", "r1", "r2" /* clobbered registers */ \
- ))
+/* Blob handling macros */ +#define ACPI_BLOB_HEADER_SIZE 8
+int __acpi_acquire_global_lock(unsigned int *lock); +int __acpi_release_global_lock(unsigned int *lock);
+#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
- ((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
+#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \
- ((Acq) = __acpi_release_global_lock(&facs->global_lock))
+/* Basic configuration for ACPI */ +/* BOZO: hardware reduced acpi only? */ +#ifdef CONFIG_ACPI +extern int acpi_disabled; +extern int acpi_noirq; +extern int acpi_pci_disabled; +extern int acpi_strict;
+struct acpi_arm_root {
- phys_addr_t phys_address;
- unsigned long size;
+}; +extern struct acpi_arm_root acpi_arm_rsdp_info;
+/* Low-level suspend routine. */ +extern int acpi_suspend_lowlevel(void);
+/* Physical address to resume after wakeup */ +/* BOZO: was... +#define acpi_wakeup_address ((unsigned long)(real_mode_header->wakeup_start)) +*/ +#define acpi_wakeup_address (0)
+static inline void disable_acpi(void) +{
- acpi_disabled = 1;
- acpi_pci_disabled = 1;
- acpi_noirq = 1;
+}
+static inline bool arch_has_acpi_pdc(void) +{
- /* BOZO: replace x86 specific-ness here */
- return 0; /* always false for now */
+}
+static inline void arch_acpi_set_pdc_bits(u32 *buf) +{
- /* BOZO: replace x86 specific-ness here */
+}
+static inline void acpi_noirq_set(void) { acpi_noirq = 1; } +static inline void acpi_disable_pci(void) +{
- acpi_pci_disabled = 1;
- acpi_noirq_set();
+}
+#else /* !CONFIG_ACPI */ +#define acpi_disabled 1 /* ACPI sometimes enabled on ARM */ +#define acpi_noirq 1 /* ACPI sometimes enabled on ARM */ +#define acpi_pci_disabled 1 /* ACPI PCI sometimes enabled on ARM */ +#define acpi_strict 1 /* no ACPI spec workarounds on ARM */ +#endif
+#endif /*__KERNEL__*/
+#endif /*_ASM_ARM_ACPI_H*/ diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h index 2e12258..849af4b 100644 --- a/arch/arm64/include/asm/io.h +++ b/arch/arm64/include/asm/io.h @@ -232,6 +232,7 @@ extern void __iounmap(volatile void __iomem *addr); #define ioremap(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE)) #define ioremap_nocache(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE)) #define ioremap_wc(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC)) +#define ioremap_cache(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEFAULT)) #define iounmap __iounmap
#define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF) diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index ab239b2..53326fd 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -155,6 +155,19 @@ static inline void spin_lock_prefetch(const void *x) prefetchw(x); }
+/*
- Not all ARM devices have ACPI, but some do
- BOZO: is this correct?
- */
+#ifdef CONFIG_ACPI +enum idle_boot_override { IDLE_NO_OVERRIDE = 0, IDLE_HALT, IDLE_NOMWAIT,
IDLE_POLL, IDLE_FORCE_MWAIT };
+extern unsigned long boot_option_idle_override; +#endif
+/* end BOZO */
#define HAVE_ARCH_PICK_MMAP_LAYOUT
#endif diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 7b4b564..615c672 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -27,3 +27,6 @@ extra-y := $(head-y) vmlinux.lds # vDSO - this must be built first to generate the symbol offsets $(call objectify,$(arm64-obj-y)): $(obj)/vdso/vdso-offsets.h $(obj)/vdso/vdso-offsets.h: $(obj)/vdso
+obj-$(CONFIG_ACPI) += acpi/
diff --git a/arch/arm64/kernel/acpi/Makefile b/arch/arm64/kernel/acpi/Makefile new file mode 100644 index 0000000..e28c063 --- /dev/null +++ b/arch/arm64/kernel/acpi/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_ACPI) += boot.o
+# BOZO: need to re-enable this properly +#obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o +obj-$(CONFIG_ACPI_SLEEP) += sleep.o
diff --git a/arch/arm64/kernel/acpi/acpi_div_64_by_32.S b/arch/arm64/kernel/acpi/acpi_div_64_by_32.S new file mode 100644 index 0000000..99a14a4 --- /dev/null +++ b/arch/arm64/kernel/acpi/acpi_div_64_by_32.S @@ -0,0 +1,105 @@ +/*
- Copyright (c) 2013, Al Stone ahs3@redhat.com
would you kindly use linaro.org email address, please?
- __acpi_arm_div64_by_32: perform integer division of a 64-bit value
a 32-bit value
- The algorithm is borrowed from the GMP library, but has been redone
- here in order to put this implementation under a GPLv2 license.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
+#ifdef __ARM_ARCH_8__
+#include <linux/linkage.h>
+/*
- This needs to be called in the following manner:
n_lo => r0 # these are the low 32 bits of the dividend
n_hi => r1 # the high 32 bits of the dividend
d32 => r2 # the 32-bit divisor
- The result is:
q32 <= r0 # the 32-bit quotient
r32 <= r1 # the 32-bit remainder
- This should be consistent with the normal ARMv7 calling conventions.
- */
+ENTRY(__arm_acpi_div_64_by_32)
mov r12, #32 // loop counter
cmp r2, #0x80000000 // check divisor MSB and clear carry
bcs bigdiv
+loop: adcs r1, r1, r1 // handle each bit
adc r0, r0, r0
cmp r0, r2
subcs r0, r0, r2
sub r12, r12, #1
teq r12, #0
bne loop
mov r3, r0 // stash the remainder for a tic
adc r0, r1, r1 // quotient: add in last carry
mov r1, r3 // remainder (now in right register)
mov pc, lr
+bigdiv: stmfd sp!, { r8, lr } // clear some scratch space
and r8, r1, #1 // save LSB of dividend
mov lr, r0, lsl #31
orrs r1, lr, r1, lsr #1 // r1 = lower part >> 1 bit
mov r0, r0, lsr #1 // r0 = higher part >> 1 bit
and lr, r2, #1 // save LSB of divisor
movs r2, r2, lsr #1 // r2 = floor(divisor / 2)
adc r2, r2, #0 // r2 = ceil(divisor / 2)
+loop2: adcs r1, r1, r1 // handle each bit
adc r0, r0, r0
cmp r0, r2
subcs r0, r0, r2
sub r12, r12, #1
teq r12, #0
bne loop2
adc r1, r1, r1 // shift and add last carry
add r0, r8, r0, lsl #1 // shift in remaining dividend LSB
tst lr, lr
beq evendiv
rsb r2, lr, r2, lsl #1 // restore divisor value
adds r0, r0, r1 // adjust for omitted divisor LSB
addcs r1, r1, #1 // adjust quotient if a carry results
subcs r0, r0, r2 // adjust remainder, if carry
cmp r0, r2
subcs r0, r0, #1 // adjust remainder
addcs r1, r1, #1 // adjust quotient
+evendiv:
mov r3, r0 // stash the remainder for a tic
mov r0, r1 // quotient
mov r1, r3 // remainder
ldmfd sp!, { r8, pc } // restore the registers used
+ENDPROC(__arm_acpi_div_64_by_32)
+#else /* ! __ARM_ARCH_7A__ */ +#error __arm_acpi_div_64_by_32 not defined for this architecture +#endif
diff --git a/arch/arm64/kernel/acpi/boot.c b/arch/arm64/kernel/acpi/boot.c new file mode 100644 index 0000000..5db7f6b --- /dev/null +++ b/arch/arm64/kernel/acpi/boot.c @@ -0,0 +1,731 @@ +/*
- boot.c - Architecture-Specific Low-Level ACPI Boot Support
- Copyright (C) 2001, 2002 Paul Diefenbaugh paul.s.diefenbaugh@intel.com
- Copyright (C) 2001 Jun Nakajima jun.nakajima@intel.com
- Copyright (C) 2013, Al Stone ahs3@redhat.com (ARM version)
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
+/*
- BOZO: this needs to be done right....
- */
+#include <linux/init.h> +#include <linux/acpi.h> +#include <linux/acpi_pmtmr.h> +#include <linux/efi.h> +#include <linux/cpumask.h> +#include <linux/memblock.h> +#include <linux/module.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/slab.h> +#include <linux/bootmem.h> +#include <linux/ioport.h> +#include <linux/pci.h>
+#include <asm/pgtable.h> +#include <asm/io.h> +#include <asm/smp.h> +#include <asm/acpi.h>
+static int __initdata acpi_force; +u32 acpi_rsdt_forced; +int acpi_disabled; +EXPORT_SYMBOL(acpi_disabled);
+#define BAD_MADT_ENTRY(entry, end) ( \
(!entry) || (unsigned long)entry + sizeof(*entry) > end || \
((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
+#define PREFIX "ACPI: "
+int acpi_noirq; /* skip ACPI IRQ initialization */ +int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */ +EXPORT_SYMBOL(acpi_pci_disabled);
+int acpi_lapic; +int acpi_ioapic; +int acpi_strict;
+u8 acpi_sci_flags __initdata; +int acpi_sci_override_gsi __initdata; +int acpi_skip_timer_override __initdata; +int acpi_use_timer_override __initdata; +int acpi_fix_pin2_polarity __initdata;
+struct acpi_arm_root acpi_arm_rsdp_info; /* info about RSDP from FDT */
+/*
- Boot-time Configuration
- */
+/*
- The default interrupt routing model is PIC (8259). This gets
- overridden if IOAPICs are enumerated (below).
- Since we're on ARM, it clearly has to be GIC.
- */
+enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_GIC;
+static unsigned int gsi_to_irq(unsigned int gsi) +{
- int irq = irq_create_mapping(NULL, gsi);
- return irq;
+}
+/*
- BOZO: is it reasonable to just reserve the memory space? Or are there
- other restrictions needed? Or does it need copying to some other place?
- */
+char *__init __acpi_map_table(unsigned long phys, unsigned long size) +{
- if (!phys || !size)
return NULL;
- /* we're already in memory so we cannot io_remap the entry */
- return phys_to_virt(phys);
+}
+void __init __acpi_unmap_table(char *map, unsigned long size) +{
- if (!map || !size)
return;
- /* we're already in memory so we cannot io_remap the entry;
* since we're not io_remap'ing, unmap'ing is especially
* pointless
*/
- return;
+}
+/*
- acpi_pic_sci_set_trigger()
- use ELCR to set PIC-mode trigger type for SCI
- If a PIC-mode SCI is not recognized or gives spurious IRQ7's
- it may require Edge Trigger -- use "acpi_sci=edge"
- Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers
- for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge.
- ECLR1 is IRQs 0-7 (IRQ 0, 1, 2 must be 0)
- ECLR2 is IRQs 8-15 (IRQ 8, 13 must be 0)
- */
+void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) +{
- unsigned int mask = 1 << irq;
- unsigned int old, new;
- /* Real old ELCR mask */
- old = inb(0x4d0) | (inb(0x4d1) << 8);
- /*
* If we use ACPI to set PCI IRQs, then we should clear ELCR
* since we will set it correctly as we enable the PCI irq
* routing.
*/
- new = acpi_noirq ? old : 0;
- /*
* Update SCI information in the ELCR, it isn't in the PCI
* routing tables..
*/
- switch (trigger) {
- case 1: /* Edge - clear */
new &= ~mask;
break;
- case 3: /* Level - set */
new |= mask;
break;
- }
- if (old == new)
return;
- printk(PREFIX "setting ELCR to %04x (from %04x)\n", new, old);
- outb(new, 0x4d0);
- outb(new >> 8, 0x4d1);
+}
+int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) +{
- *irq = gsi_to_irq(gsi);
- return 0;
+} +EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
+static int acpi_register_gsi_pic(struct device *dev, u32 gsi,
int trigger, int polarity)
+{ +#ifdef CONFIG_PCI
- /*
* Make sure all (legacy) PCI IRQs are set as level-triggered.
*/
- if (trigger == ACPI_LEVEL_SENSITIVE)
eisa_set_level_irq(gsi);
+#endif
- return gsi;
+}
+static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
int trigger, int polarity)
+{
- return gsi;
+}
+int (*__acpi_register_gsi)(struct device *dev, u32 gsi,
int trigger, int polarity) = acpi_register_gsi_pic;
+/*
- success: return IRQ number (>=0)
- failure: return < 0
- */
+int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) +{
- unsigned int irq;
- unsigned int plat_gsi = gsi;
- plat_gsi = (*__acpi_register_gsi)(dev, gsi, trigger, polarity);
- irq = gsi_to_irq(plat_gsi);
- return irq;
+} +EXPORT_SYMBOL_GPL(acpi_register_gsi);
+void acpi_unregister_gsi(u32 gsi) +{ +} +EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
+void __init acpi_set_irq_model_pic(void) +{
- acpi_irq_model = ACPI_IRQ_MODEL_PIC;
- __acpi_register_gsi = acpi_register_gsi_pic;
- acpi_ioapic = 0;
+}
+void __init acpi_set_irq_model_ioapic(void) +{
- acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
- __acpi_register_gsi = acpi_register_gsi_ioapic;
- acpi_ioapic = 1;
+}
+/*
- ACPI based hotplug support for CPU
- */
+#ifdef CONFIG_ACPI_HOTPLUG_CPU +#include <acpi/processor.h>
+static void __cpuinit acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) +{ +#ifdef CONFIG_ACPI_NUMA
- int nid;
- nid = acpi_get_node(handle);
- if (nid == -1 || !node_online(nid))
return;
- set_apicid_to_node(physid, nid);
- numa_set_node(cpu, nid);
+#endif +}
+static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu) +{
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
- struct acpi_madt_local_apic *lapic;
- cpumask_var_t tmp_map, new_map;
- u8 physid;
- int cpu;
- int retval = -ENOMEM;
- if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
return -EINVAL;
- if (!buffer.length || !buffer.pointer)
return -EINVAL;
- obj = buffer.pointer;
- if (obj->type != ACPI_TYPE_BUFFER ||
obj->buffer.length < sizeof(*lapic)) {
kfree(buffer.pointer);
return -EINVAL;
- }
- lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer;
- if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC ||
!(lapic->lapic_flags & ACPI_MADT_ENABLED)) {
kfree(buffer.pointer);
return -EINVAL;
- }
- physid = lapic->id;
- kfree(buffer.pointer);
- buffer.length = ACPI_ALLOCATE_BUFFER;
- buffer.pointer = NULL;
- lapic = NULL;
- if (!alloc_cpumask_var(&tmp_map, GFP_KERNEL))
goto out;
- if (!alloc_cpumask_var(&new_map, GFP_KERNEL))
goto free_tmp_map;
- cpumask_copy(tmp_map, cpu_present_mask);
+#ifdef CONFIG_X86
- /* BOZO: ?? */
- acpi_register_lapic(physid, ACPI_MADT_ENABLED);
+#endif
- /*
* If acpi_register_lapic successfully generates a new logical cpu
* number, then the following will get us exactly what was mapped
*/
- cpumask_andnot(new_map, cpu_present_mask, tmp_map);
- if (cpumask_empty(new_map)) {
printk("Unable to map lapic to logical cpu number\n");
retval = -EINVAL;
goto free_new_map;
- }
- acpi_processor_set_pdc(handle);
- cpu = cpumask_first(new_map);
- acpi_map_cpu2node(handle, cpu, physid);
- *pcpu = cpu;
- retval = 0;
+free_new_map:
- free_cpumask_var(new_map);
+free_tmp_map:
- free_cpumask_var(tmp_map);
+out:
- return retval;
+}
+/* wrapper to silence section mismatch warning */ +int __ref acpi_map_lsapic(acpi_handle handle, int *pcpu) +{
- return _acpi_map_lsapic(handle, pcpu);
+} +EXPORT_SYMBOL(acpi_map_lsapic);
+int acpi_unmap_lsapic(int cpu) +{ +#ifdef CONFIG_X86
- /* BOZO: ??? */
- per_cpu(x86_cpu_to_apicid, cpu) = -1;
- set_cpu_present(cpu, false);
- num_processors--;
+#endif
- return 0;
+} +EXPORT_SYMBOL(acpi_unmap_lsapic); +#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+static int __init acpi_parse_sbf(struct acpi_table_header *table) +{
- struct acpi_table_boot *sb;
- sb = (struct acpi_table_boot *)table;
- if (!sb) {
printk(KERN_WARNING PREFIX "Unable to map SBF\n");
return -ENODEV;
- }
- return 0;
+}
+#ifdef CONFIG_HPET_TIMER +#include <asm/hpet.h>
+static struct __initdata resource * hpet_res;
+static int __init acpi_parse_hpet(struct acpi_table_header *table) +{
- struct acpi_table_hpet *hpet_tbl;
- hpet_tbl = (struct acpi_table_hpet *)table;
- if (!hpet_tbl) {
printk(KERN_WARNING PREFIX "Unable to map HPET\n");
return -ENODEV;
- }
- if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) {
printk(KERN_WARNING PREFIX "HPET timers must be located in "
"memory.\n");
return -1;
- }
- hpet_address = hpet_tbl->address.address;
- hpet_blockid = hpet_tbl->sequence;
- /*
* Some broken BIOSes advertise HPET at 0x0. We really do not
* want to allocate a resource there.
*/
- if (!hpet_address) {
printk(KERN_WARNING PREFIX
"HPET id: %#x base: %#lx is invalid\n",
hpet_tbl->id, hpet_address);
return 0;
- }
- printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
hpet_tbl->id, hpet_address);
- /*
* Allocate and initialize the HPET firmware resource for adding into
* the resource tree during the lateinit timeframe.
*/
+#define HPET_RESOURCE_NAME_SIZE 9
- hpet_res = alloc_bootmem(sizeof(*hpet_res) + HPET_RESOURCE_NAME_SIZE);
- hpet_res->name = (void *)&hpet_res[1];
- hpet_res->flags = IORESOURCE_MEM;
- snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE, "HPET %u",
hpet_tbl->sequence);
- hpet_res->start = hpet_address;
- hpet_res->end = hpet_address + (1 * 1024) - 1;
- return 0;
+}
+/*
- hpet_insert_resource inserts the HPET resources used into the resource
- tree.
- */
+static __init int hpet_insert_resource(void) +{
- if (!hpet_res)
return 1;
- return insert_resource(&iomem_resource, hpet_res);
+}
+late_initcall(hpet_insert_resource);
+#else +#define acpi_parse_hpet NULL +#endif
+static int __init acpi_parse_fadt(struct acpi_table_header *table) +{
- return 0;
+}
+static void __init early_acpi_process_madt(void) +{ +}
+static void __init acpi_process_madt(void) +{
- return;
+}
+void set_checksum(u8 *start, int len, u8 *cksum) +{
- u8 newsum, oldsum;
- u8 *p;
- newsum = 0;
- for (p = (u8 *)start; p < (u8 *)(start + len); p++)
newsum += *p;
- oldsum = *cksum;
- newsum = (u8)(newsum - oldsum);
- *cksum = (u8)(0 - newsum);
+}
+void __init acpi_arm_blob_relocate(void) +{
- /*
* Fortunately, there are only a few tables that need to
* have their offsets converted to actual addresses.
*
* NB: all values in the blob are little-endian.
*/
- struct acpi_table_rsdp *rp;
- struct acpi_table_xsdt *xp;
- struct acpi_table_fadt *fp;
- phys_addr_t paddress;
- void *vaddress;
- u32 entries;
- u32 ii;
- u64 *tmp;
- if (!acpi_arm_rsdp_info.phys_address && !acpi_arm_rsdp_info.size) {
printk(KERN_ERR "(E) ACPI: failed to find rsdp info\n");
return;
- }
- paddress = acpi_arm_rsdp_info.phys_address;
- paddress += ACPI_BLOB_HEADER_SIZE;
- vaddress = phys_to_virt(paddress);
- /* fixups for the rsdp */
- rp = (struct acpi_table_rsdp *)vaddress;
- if (rp->rsdt_physical_address)
rp->rsdt_physical_address += paddress;
- if (rp->xsdt_physical_address)
rp->xsdt_physical_address += paddress;
- set_checksum((u8 *)rp, rp->length, &(rp->checksum));
- /* fixups for the xsdt */
- vaddress = phys_to_virt(rp->xsdt_physical_address);
- xp = (struct acpi_table_xsdt *)vaddress;
- entries = xp->header.length - sizeof (struct acpi_table_header);
- entries /= 8; /* length is in bytes */
- tmp = (u64 *)(&(xp->table_offset_entry[0]));
- for (ii = 0; ii < entries; ii++)
*tmp++ += paddress;
- set_checksum((u8 *)xp, xp->header.length, &(xp->header.checksum));
- /* fixups for the fadt */
- vaddress = phys_to_virt(xp->table_offset_entry[0]);
- fp = (struct acpi_table_fadt *)vaddress;
- if (fp->facs)
fp->facs += paddress;
- if (fp->dsdt)
fp->dsdt += paddress;
- if (fp->Xfacs)
fp->Xfacs += paddress;
- if (fp->Xdsdt)
fp->Xdsdt += paddress;
- /* Always fix up the checksums since we've changed bits. */
- set_checksum((u8 *)fp, fp->header.length, &(fp->header.checksum));
+}
+/*
- ========== OLD COMMENTS FROM x86 =================================
- acpi_boot_table_init() and acpi_boot_init()
- called from setup_arch(), always.
- checksums all tables
- enumerates lapics
- enumerates io-apics
- acpi_table_init() is separate to allow reading SRAT without
- other side effects.
- side effects of acpi_boot_init:
- acpi_lapic = 1 if LAPIC found
- acpi_ioapic = 1 if IOAPIC found
- if (acpi_lapic && acpi_ioapic) smp_found_config = 1;
- if acpi_blacklisted() acpi_disabled = 1;
- acpi_irq_model=...
- ...
- ==================================================================
- We have to approach this a little different on ARMv7. We are
- passed in an ACPI blob and we really have no idea where in RAM
- it will be located. So, what should have been the physical
- addresses of other tables cannot really be hardcoded into the
- tables. What we will do is put an offset in the blob that is
- the offset from the beginning of the RSDP structure. However,
- what that means is that we have to unpack the blob and do a
- 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) +{
- /*
* If acpi_disabled, bail out
*/
- if (acpi_disabled)
return;
- printk(KERN_DEBUG "acpi: enter acpi_boot_table_init\n");
- /*
* Fix up the addresses in the ACPI we've loaded
* in. The blob has them as offsets and we need
* actual addresses.
*/
- acpi_arm_blob_relocate();
- /*
* Initialize the ACPI boot-time table parser.
*/
- if (acpi_table_init()) {
disable_acpi();
return;
- }
- printk(KERN_INFO "(I) acpi_table_init call completed\n");
- acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
- printk(KERN_INFO "(I) exit acpi_boot_table_init\n");
+}
+int __init early_acpi_boot_init(void) +{
- /*
* If acpi_disabled, bail out
*/
- if (acpi_disabled)
return 1;
- printk(KERN_INFO "enter early_acpi_boot_init\n");
- /*
* Process the Multiple APIC Description Table (MADT), if present
*/
- early_acpi_process_madt();
- return 0;
+}
+int __init acpi_boot_init(void) +{
- /*
* If acpi_disabled, bail out
*/
- if (acpi_disabled)
return 1;
- printk(KERN_INFO "enter acpi_boot_init\n");
- acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
- /*
* set sci_int and PM timer address
*/
- acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt);
- /*
* Process the Multiple APIC Description Table (MADT), if present
*/
- acpi_process_madt();
- acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet);
- return 0;
+}
+static int __init parse_acpi(char *arg) +{
- if (!arg)
return -EINVAL;
- /* "acpi=off" disables both ACPI table parsing and interpreter */
- if (strcmp(arg, "off") == 0) {
disable_acpi();
- }
- /* acpi=force to over-ride black-list */
- else if (strcmp(arg, "force") == 0) {
acpi_force = 1;
acpi_disabled = 0;
- }
- /* acpi=strict disables out-of-spec workarounds */
- else if (strcmp(arg, "strict") == 0) {
acpi_strict = 1;
- }
- /* acpi=rsdt use RSDT instead of XSDT */
- else if (strcmp(arg, "rsdt") == 0) {
acpi_rsdt_forced = 1;
- }
- /* "acpi=noirq" disables ACPI interrupt routing */
- else if (strcmp(arg, "noirq") == 0) {
acpi_noirq_set();
- }
- /* "acpi=copy_dsdt" copys DSDT */
- else if (strcmp(arg, "copy_dsdt") == 0) {
acpi_gbl_copy_dsdt_locally = 1;
- } else {
/* Core will printk when we return error. */
return -EINVAL;
- }
- return 0;
+} +early_param("acpi", parse_acpi);
+/* FIXME: Using pci= for an ACPI parameter is a travesty. */ +static int __init parse_pci(char *arg) +{
- if (arg && strcmp(arg, "noacpi") == 0)
acpi_disable_pci();
- return 0;
+} +early_param("pci", parse_pci);
+int __init acpi_mps_check(void) +{
- return 0;
+}
+static int __init setup_acpi_sci(char *s) +{
- if (!s)
return -EINVAL;
- if (!strcmp(s, "edge"))
acpi_sci_flags = ACPI_MADT_TRIGGER_EDGE |
(acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
- else if (!strcmp(s, "level"))
acpi_sci_flags = ACPI_MADT_TRIGGER_LEVEL |
(acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
- else if (!strcmp(s, "high"))
acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_HIGH |
(acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
- else if (!strcmp(s, "low"))
acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_LOW |
(acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
- else
return -EINVAL;
- return 0;
+} +early_param("acpi_sci", setup_acpi_sci);
+int __acpi_acquire_global_lock(unsigned int *lock) +{
- unsigned int old, new, val;
- do {
old = *lock;
new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
val = cmpxchg(lock, old, new);
- } while (unlikely (val != old));
- return (new < 3) ? -1 : 0;
+}
+int __acpi_release_global_lock(unsigned int *lock) +{
- unsigned int old, new, val;
- do {
old = *lock;
new = old & ~0x3;
val = cmpxchg(lock, old, new);
- } while (unlikely (val != old));
- return old & 0x1;
+}
diff --git a/arch/arm64/kernel/acpi/sleep.c b/arch/arm64/kernel/acpi/sleep.c new file mode 100644 index 0000000..9129c7e --- /dev/null +++ b/arch/arm64/kernel/acpi/sleep.c @@ -0,0 +1,126 @@ +/*
- sleep.c - x86-specific ACPI sleep support.
- Copyright (C) 2001-2003 Patrick Mochel
- Copyright (C) 2001-2003 Pavel Machek pavel@ucw.cz
- */
+int acpi_suspend_lowlevel(void) +{
- /* BOZO: dummy routine; see below for actual */
- return 0;
+}
+#ifdef CONFIG_X86 +/* BOZO: disable everything for now... */
+#include <linux/acpi.h> +#include <linux/bootmem.h> +#include <linux/memblock.h> +#include <linux/dmi.h> +#include <linux/cpumask.h> +#include <asm/segment.h> +#include <asm/desc.h> +#include <asm/pgtable.h> +#include <asm/cacheflush.h> +#include <asm/realmode.h>
+#include "../../realmode/rm/wakeup.h" +#include "sleep.h"
+unsigned long acpi_realmode_flags;
+#if defined(CONFIG_SMP) && defined(CONFIG_64BIT) +static char temp_stack[4096]; +#endif
+/**
- acpi_suspend_lowlevel - save kernel state
- Create an identity mapped page table and copy the wakeup routine to
- low memory.
- */
+int acpi_suspend_lowlevel(void) +{
- struct wakeup_header *header =
(struct wakeup_header *) __va(real_mode_header->wakeup_header);
- if (header->signature != WAKEUP_HEADER_SIGNATURE) {
printk(KERN_ERR "wakeup header does not match\n");
return -EINVAL;
- }
- header->video_mode = saved_video_mode;
- header->pmode_behavior = 0;
+#ifndef CONFIG_64BIT
- store_gdt((struct desc_ptr *)&header->pmode_gdt);
- if (!rdmsr_safe(MSR_EFER,
&header->pmode_efer_low,
&header->pmode_efer_high))
header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_EFER);
+#endif /* !CONFIG_64BIT */
- header->pmode_cr0 = read_cr0();
- if (__this_cpu_read(cpu_info.cpuid_level) >= 0) {
header->pmode_cr4 = read_cr4();
header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_CR4);
- }
- if (!rdmsr_safe(MSR_IA32_MISC_ENABLE,
&header->pmode_misc_en_low,
&header->pmode_misc_en_high))
header->pmode_behavior |=
(1 << WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE);
- header->realmode_flags = acpi_realmode_flags;
- header->real_magic = 0x12345678;
+#ifndef CONFIG_64BIT
- header->pmode_entry = (u32)&wakeup_pmode_return;
- header->pmode_cr3 = (u32)__pa(&initial_page_table);
- saved_magic = 0x12345678;
+#else /* CONFIG_64BIT */ +#ifdef CONFIG_SMP
- stack_start = (unsigned long)temp_stack + sizeof(temp_stack);
- early_gdt_descr.address =
(unsigned long)get_cpu_gdt_table(smp_processor_id());
- initial_gs = per_cpu_offset(smp_processor_id());
+#endif
- initial_code = (unsigned long)wakeup_long64;
saved_magic = 0x123456789abcdef0L;
+#endif /* CONFIG_64BIT */
- do_suspend_lowlevel();
- return 0;
+}
+static int __init acpi_sleep_setup(char *str) +{
- while ((str != NULL) && (*str != '\0')) {
if (strncmp(str, "s3_bios", 7) == 0)
acpi_realmode_flags |= 1;
if (strncmp(str, "s3_mode", 7) == 0)
acpi_realmode_flags |= 2;
if (strncmp(str, "s3_beep", 7) == 0)
acpi_realmode_flags |= 4;
+#ifdef CONFIG_HIBERNATION
if (strncmp(str, "s4_nohwsig", 10) == 0)
acpi_no_s4_hw_signature();
+#endif
if (strncmp(str, "nonvs", 5) == 0)
acpi_nvs_nosave();
if (strncmp(str, "nonvs_s3", 8) == 0)
acpi_nvs_nosave_s3();
if (strncmp(str, "old_ordering", 12) == 0)
acpi_old_suspend_ordering();
str = strchr(str, ',');
if (str != NULL)
str += strspn(str, ", \t");
- }
- return 1;
+}
+__setup("acpi_sleep=", acpi_sleep_setup);
+#endif diff --git a/arch/arm64/kernel/acpi/sleep.h b/arch/arm64/kernel/acpi/sleep.h new file mode 100644 index 0000000..67f59f8c --- /dev/null +++ b/arch/arm64/kernel/acpi/sleep.h @@ -0,0 +1,17 @@ +/*
- Variables and functions used by the code in sleep.c
- */
+#include <asm/realmode.h>
+extern unsigned long saved_video_mode; +extern long saved_magic;
+extern int wakeup_pmode_return;
+extern u8 wake_sleep_flags;
+extern unsigned long acpi_copy_wakeup_routine(unsigned long); +extern void wakeup_long64(void);
+extern void do_suspend_lowlevel(void); diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index bbefb6f..d4e8c03 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -367,3 +367,11 @@ unsigned long randomize_et_dyn(unsigned long base) { return randomize_base(base); }
+#ifdef CONFIG_ACPI
+unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE; +EXPORT_SYMBOL(boot_option_idle_override);
+#endif
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 6a9a532..80410e6 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -41,6 +41,9 @@ #include <linux/memblock.h> #include <linux/of_fdt.h> #include <linux/of_platform.h> +#ifdef CONFIG_ACPI +#include <linux/acpi.h> +#endif
#include <asm/cputype.h> #include <asm/elf.h> @@ -54,6 +57,10 @@ #include <asm/memblock.h> #include <asm/psci.h>
+#ifdef CONFIG_ACPI +#include <asm/acpi.h> +#endif
unsigned int processor_id; EXPORT_SYMBOL(processor_id);
@@ -166,6 +173,10 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)
/* Retrieve various information from the /chosen node */ of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); +#ifdef CONFIG_ACPI
- /* Retrieve ACPI pointers from /chosen node */
- of_scan_flat_dt(early_init_dt_scan_acpi, &acpi_arm_rsdp_info);
+#endif /* Initialize {size,address}-cells info */ of_scan_flat_dt(early_init_dt_scan_root, NULL); /* Setup memory, calling early_init_dt_add_memory_arch */ @@ -264,6 +275,14 @@ void __init setup_arch(char **cmdline_p) paging_init(); request_standard_resources();
+#ifdef CONFIG_ACPI
- /*
* Parse the ACPI tables for possible boot-time configuration
*/
- acpi_boot_table_init();
- early_acpi_boot_init();
+#endif
unflatten_device_tree();
psci_init();
diff --git a/include/acpi/pdc_arm64.h b/include/acpi/pdc_arm64.h new file mode 100644 index 0000000..ac8f197 --- /dev/null +++ b/include/acpi/pdc_arm64.h @@ -0,0 +1,39 @@
+/* _PDC bit definition for ARMv7 processors */
+#ifndef __PDC_ARM_H__ +#define __PDC_ARM_H__
+/* BOZO: is this even necessary? */
+/* _PDC bit definition for ARM processors */
+#define ACPI_PDC_P_FFH (0x0001) +#define ACPI_PDC_C_C1_HALT (0x0002) +#define ACPI_PDC_T_FFH (0x0004) +#define ACPI_PDC_SMP_C1PT (0x0008) +#define ACPI_PDC_SMP_C2C3 (0x0010) +#define ACPI_PDC_SMP_P_SWCOORD (0x0020) +#define ACPI_PDC_SMP_C_SWCOORD (0x0040) +#define ACPI_PDC_SMP_T_SWCOORD (0x0080) +#define ACPI_PDC_C_C1_FFH (0x0100) +#define ACPI_PDC_C_C2C3_FFH (0x0200) +#define ACPI_PDC_SMP_P_HWCOORD (0x0800)
+#define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \
ACPI_PDC_C_C1_HALT | \
ACPI_PDC_P_FFH)
+#define ACPI_PDC_EST_CAPABILITY_SWSMP (ACPI_PDC_SMP_C1PT | \
ACPI_PDC_C_C1_HALT | \
ACPI_PDC_SMP_P_SWCOORD | \
ACPI_PDC_SMP_P_HWCOORD | \
ACPI_PDC_P_FFH)
+#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \
ACPI_PDC_SMP_C1PT | \
ACPI_PDC_C_C1_HALT | \
ACPI_PDC_C_C1_FFH | \
ACPI_PDC_C_C2C3_FFH)
+#endif /* __PDC_ARM_H__ */
1.7.10.4
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
On Wed, Jun 12, 2013 at 07:26:34PM -0400, Andrea Gallo wrote:
On 11/giu/2013, at 12:23, Graeme Gregory graeme.gregory@linaro.org wrote:
From: Graeme Gregory graeme.gregory@linaro.org
armv8 servers will use ACPI for initialisation in the same manner that current x86/x86_64 ones do. Add the calls to initialise the ACPI tables and load devices using the drivers/acpi subsytem.
Signed-off-by: Graeme Gregory graeme.gregory@linaro.org
arch/arm64/Kconfig | 2 + arch/arm64/include/asm/acpi.h | 153 ++++++ arch/arm64/include/asm/io.h | 1 + arch/arm64/include/asm/processor.h | 13 + arch/arm64/kernel/Makefile | 3 + arch/arm64/kernel/acpi/Makefile | 6 + arch/arm64/kernel/acpi/acpi_div_64_by_32.S | 105 ++++ arch/arm64/kernel/acpi/boot.c | 731 ++++++++++++++++++++++++++++ arch/arm64/kernel/acpi/sleep.c | 126 +++++ arch/arm64/kernel/acpi/sleep.h | 17 + arch/arm64/kernel/process.c | 8 + arch/arm64/kernel/setup.c | 19 + include/acpi/pdc_arm64.h | 39 ++ 13 files changed, 1223 insertions(+) create mode 100644 arch/arm64/include/asm/acpi.h create mode 100644 arch/arm64/kernel/acpi/Makefile create mode 100644 arch/arm64/kernel/acpi/acpi_div_64_by_32.S create mode 100644 arch/arm64/kernel/acpi/boot.c create mode 100644 arch/arm64/kernel/acpi/sleep.c create mode 100644 arch/arm64/kernel/acpi/sleep.h create mode 100644 include/acpi/pdc_arm64.h
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 43b0e9f..b795dda 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -238,6 +238,8 @@ source "net/Kconfig"
source "drivers/Kconfig"
+source "drivers/acpi/Kconfig"
source "fs/Kconfig"
source "arch/arm64/Kconfig.debug" diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h new file mode 100644 index 0000000..3ef9fc0 --- /dev/null +++ b/arch/arm64/include/asm/acpi.h @@ -0,0 +1,153 @@ +/*
- Copyright (C) 2013, Al Stone ahs3@redhat.com
would you kindly use linaro.org email address, please?
I corrected many cases of this, still have a few more to catch!
Graeme
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
+#ifndef _ASM_ARM_ACPI_H +#define _ASM_ARM_ACPI_H
+#ifdef __KERNEL__
+#include <acpi/pdc_arm64.h>
+#include <asm/cacheflush.h>
+#include <linux/init.h>
+#define COMPILER_DEPENDENT_INT64 long long +#define COMPILER_DEPENDENT_UINT64 unsigned long long
+/*
- Calling conventions:
- ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads)
- ACPI_EXTERNAL_XFACE - External ACPI interfaces
- ACPI_INTERNAL_XFACE - Internal ACPI interfaces
- ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces
- */
+#define ACPI_SYSTEM_XFACE +#define ACPI_EXTERNAL_XFACE +#define ACPI_INTERNAL_XFACE +#define ACPI_INTERNAL_VAR_XFACE
+/* Asm macros */ +#define ACPI_ASM_MACROS +#define BREAKPOINT3 +#define ACPI_DISABLE_IRQS() local_irq_disable() +#define ACPI_ENABLE_IRQS() local_irq_enable() +#define ACPI_FLUSH_CPU_CACHE() flush_cache_all()
+#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) (\
- asm ("mov r0, %2\n" \
"mov r1, %3\n" \
"mov r2, %4\n" \
"bl __arm_acpi_div_64_by_32\n" \
"mov %0, r0\n" \
"mov %1, r1\n" \
: "=r"(q32), "=r"(r32) /* output */ \
: "r"(n_hi), "r"(n_lo), "r"(d32) /* input */ \
: "r0", "r1", "r2" /* clobbered registers */ \
- ))
+#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) (\
- asm ("mov r0, %2\n" \
"mov r1, %3\n" \
"and r2, r0, #1\n" \
"lsr r0, r0, #1\n" \
"lsr r1, r1, #1\n" \
"orr r1, r1, r2, lsl #31\n" \
"mov %0, r0\n" \
"mov %1, r1\n" \
: "=r"(n_hi), "=r"(n_lo) /* output operands */ \
: "0"(n_hi), "1"(n_lo) /* input operands */ \
: "r0", "r1", "r2" /* clobbered registers */ \
- ))
+/* Blob handling macros */ +#define ACPI_BLOB_HEADER_SIZE 8
+int __acpi_acquire_global_lock(unsigned int *lock); +int __acpi_release_global_lock(unsigned int *lock);
+#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
- ((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
+#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \
- ((Acq) = __acpi_release_global_lock(&facs->global_lock))
+/* Basic configuration for ACPI */ +/* BOZO: hardware reduced acpi only? */ +#ifdef CONFIG_ACPI +extern int acpi_disabled; +extern int acpi_noirq; +extern int acpi_pci_disabled; +extern int acpi_strict;
+struct acpi_arm_root {
- phys_addr_t phys_address;
- unsigned long size;
+}; +extern struct acpi_arm_root acpi_arm_rsdp_info;
+/* Low-level suspend routine. */ +extern int acpi_suspend_lowlevel(void);
+/* Physical address to resume after wakeup */ +/* BOZO: was... +#define acpi_wakeup_address ((unsigned long)(real_mode_header->wakeup_start)) +*/ +#define acpi_wakeup_address (0)
+static inline void disable_acpi(void) +{
- acpi_disabled = 1;
- acpi_pci_disabled = 1;
- acpi_noirq = 1;
+}
+static inline bool arch_has_acpi_pdc(void) +{
- /* BOZO: replace x86 specific-ness here */
- return 0; /* always false for now */
+}
+static inline void arch_acpi_set_pdc_bits(u32 *buf) +{
- /* BOZO: replace x86 specific-ness here */
+}
+static inline void acpi_noirq_set(void) { acpi_noirq = 1; } +static inline void acpi_disable_pci(void) +{
- acpi_pci_disabled = 1;
- acpi_noirq_set();
+}
+#else /* !CONFIG_ACPI */ +#define acpi_disabled 1 /* ACPI sometimes enabled on ARM */ +#define acpi_noirq 1 /* ACPI sometimes enabled on ARM */ +#define acpi_pci_disabled 1 /* ACPI PCI sometimes enabled on ARM */ +#define acpi_strict 1 /* no ACPI spec workarounds on ARM */ +#endif
+#endif /*__KERNEL__*/
+#endif /*_ASM_ARM_ACPI_H*/ diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h index 2e12258..849af4b 100644 --- a/arch/arm64/include/asm/io.h +++ b/arch/arm64/include/asm/io.h @@ -232,6 +232,7 @@ extern void __iounmap(volatile void __iomem *addr); #define ioremap(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE)) #define ioremap_nocache(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE)) #define ioremap_wc(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC)) +#define ioremap_cache(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEFAULT)) #define iounmap __iounmap
#define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF) diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index ab239b2..53326fd 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -155,6 +155,19 @@ static inline void spin_lock_prefetch(const void *x) prefetchw(x); }
+/*
- Not all ARM devices have ACPI, but some do
- BOZO: is this correct?
- */
+#ifdef CONFIG_ACPI +enum idle_boot_override { IDLE_NO_OVERRIDE = 0, IDLE_HALT, IDLE_NOMWAIT,
IDLE_POLL, IDLE_FORCE_MWAIT };
+extern unsigned long boot_option_idle_override; +#endif
+/* end BOZO */
#define HAVE_ARCH_PICK_MMAP_LAYOUT
#endif diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 7b4b564..615c672 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -27,3 +27,6 @@ extra-y := $(head-y) vmlinux.lds # vDSO - this must be built first to generate the symbol offsets $(call objectify,$(arm64-obj-y)): $(obj)/vdso/vdso-offsets.h $(obj)/vdso/vdso-offsets.h: $(obj)/vdso
+obj-$(CONFIG_ACPI) += acpi/
diff --git a/arch/arm64/kernel/acpi/Makefile b/arch/arm64/kernel/acpi/Makefile new file mode 100644 index 0000000..e28c063 --- /dev/null +++ b/arch/arm64/kernel/acpi/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_ACPI) += boot.o
+# BOZO: need to re-enable this properly +#obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o +obj-$(CONFIG_ACPI_SLEEP) += sleep.o
diff --git a/arch/arm64/kernel/acpi/acpi_div_64_by_32.S b/arch/arm64/kernel/acpi/acpi_div_64_by_32.S new file mode 100644 index 0000000..99a14a4 --- /dev/null +++ b/arch/arm64/kernel/acpi/acpi_div_64_by_32.S @@ -0,0 +1,105 @@ +/*
- Copyright (c) 2013, Al Stone ahs3@redhat.com
would you kindly use linaro.org email address, please?
- __acpi_arm_div64_by_32: perform integer division of a 64-bit value
a 32-bit value
- The algorithm is borrowed from the GMP library, but has been redone
- here in order to put this implementation under a GPLv2 license.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
+#ifdef __ARM_ARCH_8__
+#include <linux/linkage.h>
+/*
- This needs to be called in the following manner:
n_lo => r0 # these are the low 32 bits of the dividend
n_hi => r1 # the high 32 bits of the dividend
d32 => r2 # the 32-bit divisor
- The result is:
q32 <= r0 # the 32-bit quotient
r32 <= r1 # the 32-bit remainder
- This should be consistent with the normal ARMv7 calling conventions.
- */
+ENTRY(__arm_acpi_div_64_by_32)
mov r12, #32 // loop counter
cmp r2, #0x80000000 // check divisor MSB and clear carry
bcs bigdiv
+loop: adcs r1, r1, r1 // handle each bit
adc r0, r0, r0
cmp r0, r2
subcs r0, r0, r2
sub r12, r12, #1
teq r12, #0
bne loop
mov r3, r0 // stash the remainder for a tic
adc r0, r1, r1 // quotient: add in last carry
mov r1, r3 // remainder (now in right register)
mov pc, lr
+bigdiv: stmfd sp!, { r8, lr } // clear some scratch space
and r8, r1, #1 // save LSB of dividend
mov lr, r0, lsl #31
orrs r1, lr, r1, lsr #1 // r1 = lower part >> 1 bit
mov r0, r0, lsr #1 // r0 = higher part >> 1 bit
and lr, r2, #1 // save LSB of divisor
movs r2, r2, lsr #1 // r2 = floor(divisor / 2)
adc r2, r2, #0 // r2 = ceil(divisor / 2)
+loop2: adcs r1, r1, r1 // handle each bit
adc r0, r0, r0
cmp r0, r2
subcs r0, r0, r2
sub r12, r12, #1
teq r12, #0
bne loop2
adc r1, r1, r1 // shift and add last carry
add r0, r8, r0, lsl #1 // shift in remaining dividend LSB
tst lr, lr
beq evendiv
rsb r2, lr, r2, lsl #1 // restore divisor value
adds r0, r0, r1 // adjust for omitted divisor LSB
addcs r1, r1, #1 // adjust quotient if a carry results
subcs r0, r0, r2 // adjust remainder, if carry
cmp r0, r2
subcs r0, r0, #1 // adjust remainder
addcs r1, r1, #1 // adjust quotient
+evendiv:
mov r3, r0 // stash the remainder for a tic
mov r0, r1 // quotient
mov r1, r3 // remainder
ldmfd sp!, { r8, pc } // restore the registers used
+ENDPROC(__arm_acpi_div_64_by_32)
+#else /* ! __ARM_ARCH_7A__ */ +#error __arm_acpi_div_64_by_32 not defined for this architecture +#endif
diff --git a/arch/arm64/kernel/acpi/boot.c b/arch/arm64/kernel/acpi/boot.c new file mode 100644 index 0000000..5db7f6b --- /dev/null +++ b/arch/arm64/kernel/acpi/boot.c @@ -0,0 +1,731 @@ +/*
- boot.c - Architecture-Specific Low-Level ACPI Boot Support
- Copyright (C) 2001, 2002 Paul Diefenbaugh paul.s.diefenbaugh@intel.com
- Copyright (C) 2001 Jun Nakajima jun.nakajima@intel.com
- Copyright (C) 2013, Al Stone ahs3@redhat.com (ARM version)
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
+/*
- BOZO: this needs to be done right....
- */
+#include <linux/init.h> +#include <linux/acpi.h> +#include <linux/acpi_pmtmr.h> +#include <linux/efi.h> +#include <linux/cpumask.h> +#include <linux/memblock.h> +#include <linux/module.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/slab.h> +#include <linux/bootmem.h> +#include <linux/ioport.h> +#include <linux/pci.h>
+#include <asm/pgtable.h> +#include <asm/io.h> +#include <asm/smp.h> +#include <asm/acpi.h>
+static int __initdata acpi_force; +u32 acpi_rsdt_forced; +int acpi_disabled; +EXPORT_SYMBOL(acpi_disabled);
+#define BAD_MADT_ENTRY(entry, end) ( \
(!entry) || (unsigned long)entry + sizeof(*entry) > end || \
((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
+#define PREFIX "ACPI: "
+int acpi_noirq; /* skip ACPI IRQ initialization */ +int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */ +EXPORT_SYMBOL(acpi_pci_disabled);
+int acpi_lapic; +int acpi_ioapic; +int acpi_strict;
+u8 acpi_sci_flags __initdata; +int acpi_sci_override_gsi __initdata; +int acpi_skip_timer_override __initdata; +int acpi_use_timer_override __initdata; +int acpi_fix_pin2_polarity __initdata;
+struct acpi_arm_root acpi_arm_rsdp_info; /* info about RSDP from FDT */
+/*
- Boot-time Configuration
- */
+/*
- The default interrupt routing model is PIC (8259). This gets
- overridden if IOAPICs are enumerated (below).
- Since we're on ARM, it clearly has to be GIC.
- */
+enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_GIC;
+static unsigned int gsi_to_irq(unsigned int gsi) +{
- int irq = irq_create_mapping(NULL, gsi);
- return irq;
+}
+/*
- BOZO: is it reasonable to just reserve the memory space? Or are there
- other restrictions needed? Or does it need copying to some other place?
- */
+char *__init __acpi_map_table(unsigned long phys, unsigned long size) +{
- if (!phys || !size)
return NULL;
- /* we're already in memory so we cannot io_remap the entry */
- return phys_to_virt(phys);
+}
+void __init __acpi_unmap_table(char *map, unsigned long size) +{
- if (!map || !size)
return;
- /* we're already in memory so we cannot io_remap the entry;
* since we're not io_remap'ing, unmap'ing is especially
* pointless
*/
- return;
+}
+/*
- acpi_pic_sci_set_trigger()
- use ELCR to set PIC-mode trigger type for SCI
- If a PIC-mode SCI is not recognized or gives spurious IRQ7's
- it may require Edge Trigger -- use "acpi_sci=edge"
- Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers
- for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge.
- ECLR1 is IRQs 0-7 (IRQ 0, 1, 2 must be 0)
- ECLR2 is IRQs 8-15 (IRQ 8, 13 must be 0)
- */
+void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) +{
- unsigned int mask = 1 << irq;
- unsigned int old, new;
- /* Real old ELCR mask */
- old = inb(0x4d0) | (inb(0x4d1) << 8);
- /*
* If we use ACPI to set PCI IRQs, then we should clear ELCR
* since we will set it correctly as we enable the PCI irq
* routing.
*/
- new = acpi_noirq ? old : 0;
- /*
* Update SCI information in the ELCR, it isn't in the PCI
* routing tables..
*/
- switch (trigger) {
- case 1: /* Edge - clear */
new &= ~mask;
break;
- case 3: /* Level - set */
new |= mask;
break;
- }
- if (old == new)
return;
- printk(PREFIX "setting ELCR to %04x (from %04x)\n", new, old);
- outb(new, 0x4d0);
- outb(new >> 8, 0x4d1);
+}
+int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) +{
- *irq = gsi_to_irq(gsi);
- return 0;
+} +EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
+static int acpi_register_gsi_pic(struct device *dev, u32 gsi,
int trigger, int polarity)
+{ +#ifdef CONFIG_PCI
- /*
* Make sure all (legacy) PCI IRQs are set as level-triggered.
*/
- if (trigger == ACPI_LEVEL_SENSITIVE)
eisa_set_level_irq(gsi);
+#endif
- return gsi;
+}
+static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
int trigger, int polarity)
+{
- return gsi;
+}
+int (*__acpi_register_gsi)(struct device *dev, u32 gsi,
int trigger, int polarity) = acpi_register_gsi_pic;
+/*
- success: return IRQ number (>=0)
- failure: return < 0
- */
+int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) +{
- unsigned int irq;
- unsigned int plat_gsi = gsi;
- plat_gsi = (*__acpi_register_gsi)(dev, gsi, trigger, polarity);
- irq = gsi_to_irq(plat_gsi);
- return irq;
+} +EXPORT_SYMBOL_GPL(acpi_register_gsi);
+void acpi_unregister_gsi(u32 gsi) +{ +} +EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
+void __init acpi_set_irq_model_pic(void) +{
- acpi_irq_model = ACPI_IRQ_MODEL_PIC;
- __acpi_register_gsi = acpi_register_gsi_pic;
- acpi_ioapic = 0;
+}
+void __init acpi_set_irq_model_ioapic(void) +{
- acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
- __acpi_register_gsi = acpi_register_gsi_ioapic;
- acpi_ioapic = 1;
+}
+/*
- ACPI based hotplug support for CPU
- */
+#ifdef CONFIG_ACPI_HOTPLUG_CPU +#include <acpi/processor.h>
+static void __cpuinit acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) +{ +#ifdef CONFIG_ACPI_NUMA
- int nid;
- nid = acpi_get_node(handle);
- if (nid == -1 || !node_online(nid))
return;
- set_apicid_to_node(physid, nid);
- numa_set_node(cpu, nid);
+#endif +}
+static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu) +{
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
- struct acpi_madt_local_apic *lapic;
- cpumask_var_t tmp_map, new_map;
- u8 physid;
- int cpu;
- int retval = -ENOMEM;
- if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
return -EINVAL;
- if (!buffer.length || !buffer.pointer)
return -EINVAL;
- obj = buffer.pointer;
- if (obj->type != ACPI_TYPE_BUFFER ||
obj->buffer.length < sizeof(*lapic)) {
kfree(buffer.pointer);
return -EINVAL;
- }
- lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer;
- if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC ||
!(lapic->lapic_flags & ACPI_MADT_ENABLED)) {
kfree(buffer.pointer);
return -EINVAL;
- }
- physid = lapic->id;
- kfree(buffer.pointer);
- buffer.length = ACPI_ALLOCATE_BUFFER;
- buffer.pointer = NULL;
- lapic = NULL;
- if (!alloc_cpumask_var(&tmp_map, GFP_KERNEL))
goto out;
- if (!alloc_cpumask_var(&new_map, GFP_KERNEL))
goto free_tmp_map;
- cpumask_copy(tmp_map, cpu_present_mask);
+#ifdef CONFIG_X86
- /* BOZO: ?? */
- acpi_register_lapic(physid, ACPI_MADT_ENABLED);
+#endif
- /*
* If acpi_register_lapic successfully generates a new logical cpu
* number, then the following will get us exactly what was mapped
*/
- cpumask_andnot(new_map, cpu_present_mask, tmp_map);
- if (cpumask_empty(new_map)) {
printk("Unable to map lapic to logical cpu number\n");
retval = -EINVAL;
goto free_new_map;
- }
- acpi_processor_set_pdc(handle);
- cpu = cpumask_first(new_map);
- acpi_map_cpu2node(handle, cpu, physid);
- *pcpu = cpu;
- retval = 0;
+free_new_map:
- free_cpumask_var(new_map);
+free_tmp_map:
- free_cpumask_var(tmp_map);
+out:
- return retval;
+}
+/* wrapper to silence section mismatch warning */ +int __ref acpi_map_lsapic(acpi_handle handle, int *pcpu) +{
- return _acpi_map_lsapic(handle, pcpu);
+} +EXPORT_SYMBOL(acpi_map_lsapic);
+int acpi_unmap_lsapic(int cpu) +{ +#ifdef CONFIG_X86
- /* BOZO: ??? */
- per_cpu(x86_cpu_to_apicid, cpu) = -1;
- set_cpu_present(cpu, false);
- num_processors--;
+#endif
- return 0;
+} +EXPORT_SYMBOL(acpi_unmap_lsapic); +#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+static int __init acpi_parse_sbf(struct acpi_table_header *table) +{
- struct acpi_table_boot *sb;
- sb = (struct acpi_table_boot *)table;
- if (!sb) {
printk(KERN_WARNING PREFIX "Unable to map SBF\n");
return -ENODEV;
- }
- return 0;
+}
+#ifdef CONFIG_HPET_TIMER +#include <asm/hpet.h>
+static struct __initdata resource * hpet_res;
+static int __init acpi_parse_hpet(struct acpi_table_header *table) +{
- struct acpi_table_hpet *hpet_tbl;
- hpet_tbl = (struct acpi_table_hpet *)table;
- if (!hpet_tbl) {
printk(KERN_WARNING PREFIX "Unable to map HPET\n");
return -ENODEV;
- }
- if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) {
printk(KERN_WARNING PREFIX "HPET timers must be located in "
"memory.\n");
return -1;
- }
- hpet_address = hpet_tbl->address.address;
- hpet_blockid = hpet_tbl->sequence;
- /*
* Some broken BIOSes advertise HPET at 0x0. We really do not
* want to allocate a resource there.
*/
- if (!hpet_address) {
printk(KERN_WARNING PREFIX
"HPET id: %#x base: %#lx is invalid\n",
hpet_tbl->id, hpet_address);
return 0;
- }
- printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
hpet_tbl->id, hpet_address);
- /*
* Allocate and initialize the HPET firmware resource for adding into
* the resource tree during the lateinit timeframe.
*/
+#define HPET_RESOURCE_NAME_SIZE 9
- hpet_res = alloc_bootmem(sizeof(*hpet_res) + HPET_RESOURCE_NAME_SIZE);
- hpet_res->name = (void *)&hpet_res[1];
- hpet_res->flags = IORESOURCE_MEM;
- snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE, "HPET %u",
hpet_tbl->sequence);
- hpet_res->start = hpet_address;
- hpet_res->end = hpet_address + (1 * 1024) - 1;
- return 0;
+}
+/*
- hpet_insert_resource inserts the HPET resources used into the resource
- tree.
- */
+static __init int hpet_insert_resource(void) +{
- if (!hpet_res)
return 1;
- return insert_resource(&iomem_resource, hpet_res);
+}
+late_initcall(hpet_insert_resource);
+#else +#define acpi_parse_hpet NULL +#endif
+static int __init acpi_parse_fadt(struct acpi_table_header *table) +{
- return 0;
+}
+static void __init early_acpi_process_madt(void) +{ +}
+static void __init acpi_process_madt(void) +{
- return;
+}
+void set_checksum(u8 *start, int len, u8 *cksum) +{
- u8 newsum, oldsum;
- u8 *p;
- newsum = 0;
- for (p = (u8 *)start; p < (u8 *)(start + len); p++)
newsum += *p;
- oldsum = *cksum;
- newsum = (u8)(newsum - oldsum);
- *cksum = (u8)(0 - newsum);
+}
+void __init acpi_arm_blob_relocate(void) +{
- /*
* Fortunately, there are only a few tables that need to
* have their offsets converted to actual addresses.
*
* NB: all values in the blob are little-endian.
*/
- struct acpi_table_rsdp *rp;
- struct acpi_table_xsdt *xp;
- struct acpi_table_fadt *fp;
- phys_addr_t paddress;
- void *vaddress;
- u32 entries;
- u32 ii;
- u64 *tmp;
- if (!acpi_arm_rsdp_info.phys_address && !acpi_arm_rsdp_info.size) {
printk(KERN_ERR "(E) ACPI: failed to find rsdp info\n");
return;
- }
- paddress = acpi_arm_rsdp_info.phys_address;
- paddress += ACPI_BLOB_HEADER_SIZE;
- vaddress = phys_to_virt(paddress);
- /* fixups for the rsdp */
- rp = (struct acpi_table_rsdp *)vaddress;
- if (rp->rsdt_physical_address)
rp->rsdt_physical_address += paddress;
- if (rp->xsdt_physical_address)
rp->xsdt_physical_address += paddress;
- set_checksum((u8 *)rp, rp->length, &(rp->checksum));
- /* fixups for the xsdt */
- vaddress = phys_to_virt(rp->xsdt_physical_address);
- xp = (struct acpi_table_xsdt *)vaddress;
- entries = xp->header.length - sizeof (struct acpi_table_header);
- entries /= 8; /* length is in bytes */
- tmp = (u64 *)(&(xp->table_offset_entry[0]));
- for (ii = 0; ii < entries; ii++)
*tmp++ += paddress;
- set_checksum((u8 *)xp, xp->header.length, &(xp->header.checksum));
- /* fixups for the fadt */
- vaddress = phys_to_virt(xp->table_offset_entry[0]);
- fp = (struct acpi_table_fadt *)vaddress;
- if (fp->facs)
fp->facs += paddress;
- if (fp->dsdt)
fp->dsdt += paddress;
- if (fp->Xfacs)
fp->Xfacs += paddress;
- if (fp->Xdsdt)
fp->Xdsdt += paddress;
- /* Always fix up the checksums since we've changed bits. */
- set_checksum((u8 *)fp, fp->header.length, &(fp->header.checksum));
+}
+/*
- ========== OLD COMMENTS FROM x86 =================================
- acpi_boot_table_init() and acpi_boot_init()
- called from setup_arch(), always.
- checksums all tables
- enumerates lapics
- enumerates io-apics
- acpi_table_init() is separate to allow reading SRAT without
- other side effects.
- side effects of acpi_boot_init:
- acpi_lapic = 1 if LAPIC found
- acpi_ioapic = 1 if IOAPIC found
- if (acpi_lapic && acpi_ioapic) smp_found_config = 1;
- if acpi_blacklisted() acpi_disabled = 1;
- acpi_irq_model=...
- ...
- ==================================================================
- We have to approach this a little different on ARMv7. We are
- passed in an ACPI blob and we really have no idea where in RAM
- it will be located. So, what should have been the physical
- addresses of other tables cannot really be hardcoded into the
- tables. What we will do is put an offset in the blob that is
- the offset from the beginning of the RSDP structure. However,
- what that means is that we have to unpack the blob and do a
- 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) +{
- /*
* If acpi_disabled, bail out
*/
- if (acpi_disabled)
return;
- printk(KERN_DEBUG "acpi: enter acpi_boot_table_init\n");
- /*
* Fix up the addresses in the ACPI we've loaded
* in. The blob has them as offsets and we need
* actual addresses.
*/
- acpi_arm_blob_relocate();
- /*
* Initialize the ACPI boot-time table parser.
*/
- if (acpi_table_init()) {
disable_acpi();
return;
- }
- printk(KERN_INFO "(I) acpi_table_init call completed\n");
- acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
- printk(KERN_INFO "(I) exit acpi_boot_table_init\n");
+}
+int __init early_acpi_boot_init(void) +{
- /*
* If acpi_disabled, bail out
*/
- if (acpi_disabled)
return 1;
- printk(KERN_INFO "enter early_acpi_boot_init\n");
- /*
* Process the Multiple APIC Description Table (MADT), if present
*/
- early_acpi_process_madt();
- return 0;
+}
+int __init acpi_boot_init(void) +{
- /*
* If acpi_disabled, bail out
*/
- if (acpi_disabled)
return 1;
- printk(KERN_INFO "enter acpi_boot_init\n");
- acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
- /*
* set sci_int and PM timer address
*/
- acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt);
- /*
* Process the Multiple APIC Description Table (MADT), if present
*/
- acpi_process_madt();
- acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet);
- return 0;
+}
+static int __init parse_acpi(char *arg) +{
- if (!arg)
return -EINVAL;
- /* "acpi=off" disables both ACPI table parsing and interpreter */
- if (strcmp(arg, "off") == 0) {
disable_acpi();
- }
- /* acpi=force to over-ride black-list */
- else if (strcmp(arg, "force") == 0) {
acpi_force = 1;
acpi_disabled = 0;
- }
- /* acpi=strict disables out-of-spec workarounds */
- else if (strcmp(arg, "strict") == 0) {
acpi_strict = 1;
- }
- /* acpi=rsdt use RSDT instead of XSDT */
- else if (strcmp(arg, "rsdt") == 0) {
acpi_rsdt_forced = 1;
- }
- /* "acpi=noirq" disables ACPI interrupt routing */
- else if (strcmp(arg, "noirq") == 0) {
acpi_noirq_set();
- }
- /* "acpi=copy_dsdt" copys DSDT */
- else if (strcmp(arg, "copy_dsdt") == 0) {
acpi_gbl_copy_dsdt_locally = 1;
- } else {
/* Core will printk when we return error. */
return -EINVAL;
- }
- return 0;
+} +early_param("acpi", parse_acpi);
+/* FIXME: Using pci= for an ACPI parameter is a travesty. */ +static int __init parse_pci(char *arg) +{
- if (arg && strcmp(arg, "noacpi") == 0)
acpi_disable_pci();
- return 0;
+} +early_param("pci", parse_pci);
+int __init acpi_mps_check(void) +{
- return 0;
+}
+static int __init setup_acpi_sci(char *s) +{
- if (!s)
return -EINVAL;
- if (!strcmp(s, "edge"))
acpi_sci_flags = ACPI_MADT_TRIGGER_EDGE |
(acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
- else if (!strcmp(s, "level"))
acpi_sci_flags = ACPI_MADT_TRIGGER_LEVEL |
(acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
- else if (!strcmp(s, "high"))
acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_HIGH |
(acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
- else if (!strcmp(s, "low"))
acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_LOW |
(acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
- else
return -EINVAL;
- return 0;
+} +early_param("acpi_sci", setup_acpi_sci);
+int __acpi_acquire_global_lock(unsigned int *lock) +{
- unsigned int old, new, val;
- do {
old = *lock;
new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
val = cmpxchg(lock, old, new);
- } while (unlikely (val != old));
- return (new < 3) ? -1 : 0;
+}
+int __acpi_release_global_lock(unsigned int *lock) +{
- unsigned int old, new, val;
- do {
old = *lock;
new = old & ~0x3;
val = cmpxchg(lock, old, new);
- } while (unlikely (val != old));
- return old & 0x1;
+}
diff --git a/arch/arm64/kernel/acpi/sleep.c b/arch/arm64/kernel/acpi/sleep.c new file mode 100644 index 0000000..9129c7e --- /dev/null +++ b/arch/arm64/kernel/acpi/sleep.c @@ -0,0 +1,126 @@ +/*
- sleep.c - x86-specific ACPI sleep support.
- Copyright (C) 2001-2003 Patrick Mochel
- Copyright (C) 2001-2003 Pavel Machek pavel@ucw.cz
- */
+int acpi_suspend_lowlevel(void) +{
- /* BOZO: dummy routine; see below for actual */
- return 0;
+}
+#ifdef CONFIG_X86 +/* BOZO: disable everything for now... */
+#include <linux/acpi.h> +#include <linux/bootmem.h> +#include <linux/memblock.h> +#include <linux/dmi.h> +#include <linux/cpumask.h> +#include <asm/segment.h> +#include <asm/desc.h> +#include <asm/pgtable.h> +#include <asm/cacheflush.h> +#include <asm/realmode.h>
+#include "../../realmode/rm/wakeup.h" +#include "sleep.h"
+unsigned long acpi_realmode_flags;
+#if defined(CONFIG_SMP) && defined(CONFIG_64BIT) +static char temp_stack[4096]; +#endif
+/**
- acpi_suspend_lowlevel - save kernel state
- Create an identity mapped page table and copy the wakeup routine to
- low memory.
- */
+int acpi_suspend_lowlevel(void) +{
- struct wakeup_header *header =
(struct wakeup_header *) __va(real_mode_header->wakeup_header);
- if (header->signature != WAKEUP_HEADER_SIGNATURE) {
printk(KERN_ERR "wakeup header does not match\n");
return -EINVAL;
- }
- header->video_mode = saved_video_mode;
- header->pmode_behavior = 0;
+#ifndef CONFIG_64BIT
- store_gdt((struct desc_ptr *)&header->pmode_gdt);
- if (!rdmsr_safe(MSR_EFER,
&header->pmode_efer_low,
&header->pmode_efer_high))
header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_EFER);
+#endif /* !CONFIG_64BIT */
- header->pmode_cr0 = read_cr0();
- if (__this_cpu_read(cpu_info.cpuid_level) >= 0) {
header->pmode_cr4 = read_cr4();
header->pmode_behavior |= (1 << WAKEUP_BEHAVIOR_RESTORE_CR4);
- }
- if (!rdmsr_safe(MSR_IA32_MISC_ENABLE,
&header->pmode_misc_en_low,
&header->pmode_misc_en_high))
header->pmode_behavior |=
(1 << WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE);
- header->realmode_flags = acpi_realmode_flags;
- header->real_magic = 0x12345678;
+#ifndef CONFIG_64BIT
- header->pmode_entry = (u32)&wakeup_pmode_return;
- header->pmode_cr3 = (u32)__pa(&initial_page_table);
- saved_magic = 0x12345678;
+#else /* CONFIG_64BIT */ +#ifdef CONFIG_SMP
- stack_start = (unsigned long)temp_stack + sizeof(temp_stack);
- early_gdt_descr.address =
(unsigned long)get_cpu_gdt_table(smp_processor_id());
- initial_gs = per_cpu_offset(smp_processor_id());
+#endif
- initial_code = (unsigned long)wakeup_long64;
saved_magic = 0x123456789abcdef0L;
+#endif /* CONFIG_64BIT */
- do_suspend_lowlevel();
- return 0;
+}
+static int __init acpi_sleep_setup(char *str) +{
- while ((str != NULL) && (*str != '\0')) {
if (strncmp(str, "s3_bios", 7) == 0)
acpi_realmode_flags |= 1;
if (strncmp(str, "s3_mode", 7) == 0)
acpi_realmode_flags |= 2;
if (strncmp(str, "s3_beep", 7) == 0)
acpi_realmode_flags |= 4;
+#ifdef CONFIG_HIBERNATION
if (strncmp(str, "s4_nohwsig", 10) == 0)
acpi_no_s4_hw_signature();
+#endif
if (strncmp(str, "nonvs", 5) == 0)
acpi_nvs_nosave();
if (strncmp(str, "nonvs_s3", 8) == 0)
acpi_nvs_nosave_s3();
if (strncmp(str, "old_ordering", 12) == 0)
acpi_old_suspend_ordering();
str = strchr(str, ',');
if (str != NULL)
str += strspn(str, ", \t");
- }
- return 1;
+}
+__setup("acpi_sleep=", acpi_sleep_setup);
+#endif diff --git a/arch/arm64/kernel/acpi/sleep.h b/arch/arm64/kernel/acpi/sleep.h new file mode 100644 index 0000000..67f59f8c --- /dev/null +++ b/arch/arm64/kernel/acpi/sleep.h @@ -0,0 +1,17 @@ +/*
- Variables and functions used by the code in sleep.c
- */
+#include <asm/realmode.h>
+extern unsigned long saved_video_mode; +extern long saved_magic;
+extern int wakeup_pmode_return;
+extern u8 wake_sleep_flags;
+extern unsigned long acpi_copy_wakeup_routine(unsigned long); +extern void wakeup_long64(void);
+extern void do_suspend_lowlevel(void); diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index bbefb6f..d4e8c03 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -367,3 +367,11 @@ unsigned long randomize_et_dyn(unsigned long base) { return randomize_base(base); }
+#ifdef CONFIG_ACPI
+unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE; +EXPORT_SYMBOL(boot_option_idle_override);
+#endif
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 6a9a532..80410e6 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -41,6 +41,9 @@ #include <linux/memblock.h> #include <linux/of_fdt.h> #include <linux/of_platform.h> +#ifdef CONFIG_ACPI +#include <linux/acpi.h> +#endif
#include <asm/cputype.h> #include <asm/elf.h> @@ -54,6 +57,10 @@ #include <asm/memblock.h> #include <asm/psci.h>
+#ifdef CONFIG_ACPI +#include <asm/acpi.h> +#endif
unsigned int processor_id; EXPORT_SYMBOL(processor_id);
@@ -166,6 +173,10 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)
/* Retrieve various information from the /chosen node */ of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); +#ifdef CONFIG_ACPI
- /* Retrieve ACPI pointers from /chosen node */
- of_scan_flat_dt(early_init_dt_scan_acpi, &acpi_arm_rsdp_info);
+#endif /* Initialize {size,address}-cells info */ of_scan_flat_dt(early_init_dt_scan_root, NULL); /* Setup memory, calling early_init_dt_add_memory_arch */ @@ -264,6 +275,14 @@ void __init setup_arch(char **cmdline_p) paging_init(); request_standard_resources();
+#ifdef CONFIG_ACPI
- /*
* Parse the ACPI tables for possible boot-time configuration
*/
- acpi_boot_table_init();
- early_acpi_boot_init();
+#endif
unflatten_device_tree();
psci_init();
diff --git a/include/acpi/pdc_arm64.h b/include/acpi/pdc_arm64.h new file mode 100644 index 0000000..ac8f197 --- /dev/null +++ b/include/acpi/pdc_arm64.h @@ -0,0 +1,39 @@
+/* _PDC bit definition for ARMv7 processors */
+#ifndef __PDC_ARM_H__ +#define __PDC_ARM_H__
+/* BOZO: is this even necessary? */
+/* _PDC bit definition for ARM processors */
+#define ACPI_PDC_P_FFH (0x0001) +#define ACPI_PDC_C_C1_HALT (0x0002) +#define ACPI_PDC_T_FFH (0x0004) +#define ACPI_PDC_SMP_C1PT (0x0008) +#define ACPI_PDC_SMP_C2C3 (0x0010) +#define ACPI_PDC_SMP_P_SWCOORD (0x0020) +#define ACPI_PDC_SMP_C_SWCOORD (0x0040) +#define ACPI_PDC_SMP_T_SWCOORD (0x0080) +#define ACPI_PDC_C_C1_FFH (0x0100) +#define ACPI_PDC_C_C2C3_FFH (0x0200) +#define ACPI_PDC_SMP_P_HWCOORD (0x0800)
+#define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \
ACPI_PDC_C_C1_HALT | \
ACPI_PDC_P_FFH)
+#define ACPI_PDC_EST_CAPABILITY_SWSMP (ACPI_PDC_SMP_C1PT | \
ACPI_PDC_C_C1_HALT | \
ACPI_PDC_SMP_P_SWCOORD | \
ACPI_PDC_SMP_P_HWCOORD | \
ACPI_PDC_P_FFH)
+#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \
ACPI_PDC_SMP_C1PT | \
ACPI_PDC_C_C1_HALT | \
ACPI_PDC_C_C1_FFH | \
ACPI_PDC_C_C2C3_FFH)
+#endif /* __PDC_ARM_H__ */
1.7.10.4
Linaro-acpi mailing list Linaro-acpi@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-acpi
On 06/12/2013 05:26 PM, Andrea Gallo wrote:
On 11/giu/2013, at 12:23, Graeme Gregory graeme.gregory@linaro.org wrote:
From: Graeme Gregory graeme.gregory@linaro.org
armv8 servers will use ACPI for initialisation in the same manner that current x86/x86_64 ones do. Add the calls to initialise the ACPI tables and load devices using the drivers/acpi subsytem.
Signed-off-by: Graeme Gregory graeme.gregory@linaro.org
arch/arm64/Kconfig | 2 + arch/arm64/include/asm/acpi.h | 153 ++++++ arch/arm64/include/asm/io.h | 1 + arch/arm64/include/asm/processor.h | 13 + arch/arm64/kernel/Makefile | 3 + arch/arm64/kernel/acpi/Makefile | 6 + arch/arm64/kernel/acpi/acpi_div_64_by_32.S | 105 ++++ arch/arm64/kernel/acpi/boot.c | 731 ++++++++++++++++++++++++++++ arch/arm64/kernel/acpi/sleep.c | 126 +++++ arch/arm64/kernel/acpi/sleep.h | 17 + arch/arm64/kernel/process.c | 8 + arch/arm64/kernel/setup.c | 19 + include/acpi/pdc_arm64.h | 39 ++ 13 files changed, 1223 insertions(+) create mode 100644 arch/arm64/include/asm/acpi.h create mode 100644 arch/arm64/kernel/acpi/Makefile create mode 100644 arch/arm64/kernel/acpi/acpi_div_64_by_32.S create mode 100644 arch/arm64/kernel/acpi/boot.c create mode 100644 arch/arm64/kernel/acpi/sleep.c create mode 100644 arch/arm64/kernel/acpi/sleep.h create mode 100644 include/acpi/pdc_arm64.h
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 43b0e9f..b795dda 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -238,6 +238,8 @@ source "net/Kconfig"
source "drivers/Kconfig"
+source "drivers/acpi/Kconfig"
source "fs/Kconfig"
source "arch/arm64/Kconfig.debug" diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h new file mode 100644 index 0000000..3ef9fc0 --- /dev/null +++ b/arch/arm64/include/asm/acpi.h @@ -0,0 +1,153 @@ +/*
- Copyright (C) 2013, Al Stone ahs3@redhat.com
would you kindly use linaro.org email address, please?
Argh. Force of habit (and a couple of rc files). Sorry about that.
Do you know if the member agreement says that Red Hat will assign copyright or not? That would be my only concern with changing these lines. For the "Signed-off-by" patches, I just need to remember to use the right address :). For copyright, though, what does the member agreement say (I've also asked jcm)?
From: Graeme Gregory graeme.gregory@linaro.org
Add Kconfig and Makefile magic to build acpi on arm and arm64 platforms.
Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Al Stone al.stone@linaro.org --- drivers/acpi/Kconfig | 32 +++++++++++++++++++------------- drivers/acpi/Makefile | 2 +- 2 files changed, 20 insertions(+), 14 deletions(-)
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 4bf68c8..2f0b4de 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -5,10 +5,10 @@ menuconfig ACPI bool "ACPI (Advanced Configuration and Power Interface) Support" depends on !IA64_HP_SIM - depends on IA64 || X86 - depends on PCI + depends on ((IA64 || X86) && PCI) || (ARM || ARM64) select PNP - default y + select MAB if (ARM || ARM64) + default y if !(ARM || ARM64) help Advanced Configuration and Power Interface (ACPI) support for Linux requires an ACPI-compliant platform (hardware/firmware), @@ -46,6 +46,7 @@ config ACPI_SLEEP config ACPI_PROCFS bool "Deprecated /proc/acpi files" depends on PROC_FS + depends on IA64 || X86 help For backwards compatibility, this option allows deprecated /proc/acpi/ files to exist, even when @@ -59,6 +60,7 @@ config ACPI_PROCFS config ACPI_PROCFS_POWER bool "Deprecated power /proc/acpi directories" depends on PROC_FS + depends on IA64 || X86 help For backwards compatibility, this option allows deprecated power /proc/acpi/ directories to exist, even when @@ -94,6 +96,7 @@ config ACPI_EC_DEBUGFS config ACPI_PROC_EVENT bool "Deprecated /proc/acpi/event support" depends on PROC_FS + depends on IA64 || X86 default y help A user-space daemon, acpid, typically reads /proc/acpi/event @@ -111,9 +114,9 @@ config ACPI_PROC_EVENT
config ACPI_AC tristate "AC Adapter" - depends on X86 + depends on X86 || ARM || ARM64 select POWER_SUPPLY - default y + default y if !(ARM || ARM64) help This driver supports the AC Adapter object, which indicates whether a system is on AC or not. If you have a system that can @@ -124,9 +127,9 @@ config ACPI_AC
config ACPI_BATTERY tristate "Battery" - depends on X86 + depends on X86 || ARM || ARM64 select POWER_SUPPLY - default y + default y if !(ARM || ARM64) help This driver adds support for battery information through /proc/acpi/battery. If you have a mobile system with a battery, @@ -150,7 +153,8 @@ config ACPI_BUTTON
config ACPI_VIDEO tristate "Video" - depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL + depends on (X86 || (ARM || ARM64)) && \ + BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL depends on INPUT select THERMAL help @@ -199,6 +203,7 @@ config ACPI_PROCESSOR
To compile this driver as a module, choose M here: the module will be called processor. + config ACPI_IPMI tristate "IPMI" depends on IPMI_SI && IPMI_HANDLER @@ -220,7 +225,7 @@ config ACPI_HOTPLUG_CPU config ACPI_PROCESSOR_AGGREGATOR tristate "Processor Aggregator" depends on ACPI_PROCESSOR - depends on X86 + depends on X86 || ARM || ARM64 help ACPI 4.0 defines processor Aggregator, which enables OS to perform specific processor configuration and control that applies to all @@ -245,7 +250,7 @@ config ACPI_THERMAL config ACPI_NUMA bool "NUMA support" depends on NUMA - depends on (X86 || IA64) + depends on (X86 || IA64 || ARM64) default y if IA64_GENERIC || IA64_SGI_SN2
config ACPI_CUSTOM_DSDT_FILE @@ -309,6 +314,7 @@ config ACPI_DEBUG_FUNC_TRACE config ACPI_PCI_SLOT bool "PCI slot detection driver" depends on SYSFS + depends on PCI default n help This driver creates entries in /sys/bus/pci/slots/ for all PCI @@ -321,8 +327,8 @@ config X86_PM_TIMER depends on X86 default y help - The Power Management Timer is available on all ACPI-capable, - in most cases even if ACPI is unusable or blacklisted. + The Power Management Timer is available on all ACPI-capable + systems, in most cases even if ACPI is unusable or blacklisted.
This timing source is not affected by power management features like aggressive processor idling, throttling, frequency and/or @@ -363,7 +369,7 @@ config ACPI_HOTPLUG_MEMORY
config ACPI_SBS tristate "Smart Battery System" - depends on X86 + depends on X86 || ARM || ARM64 select POWER_SUPPLY help This driver supports the Smart Battery System, another diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 474fcfe..ec3f3e0 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -37,7 +37,7 @@ acpi-y += resource.o acpi-y += processor_core.o acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o -acpi-y += pci_root.o pci_link.o pci_irq.o +acpi-$(CONFIG_PCI) += pci_root.o pci_link.o pci_irq.o acpi-y += csrt.o acpi-y += acpi_platform.o acpi-y += power.o
On 06/11/2013 10:22 AM, Graeme Gregory wrote:
Hi Guys,
I have just pushed this series of patches to the official repo.
Branch is acpi-armv8
This brings us to the same state in armv8 as we are in for armv7. Without the prototype stuff like i2c drivers. But is a base to start work on for armv8.
I have tried to get these patches as checkpatch clean as possible.
I want to try and merge armv7 and armv8 changes into one and maintain that together as I think there is very little different in the two platforms from the point of initialisation or drivers.
Nice. Have you thought about the initial ASL just yet?
Shall I just clone the Arndale ASL for aarch64 use? Or has someone already started on that (I'm thinking Naresh might have...)? Either way it should be pretty straightforward to do....
On Tue, Jun 11, 2013 at 03:48:58PM -0600, Al Stone wrote:
On 06/11/2013 10:22 AM, Graeme Gregory wrote:
Hi Guys,
I have just pushed this series of patches to the official repo.
Branch is acpi-armv8
This brings us to the same state in armv8 as we are in for armv7. Without the prototype stuff like i2c drivers. But is a base to start work on for armv8.
I have tried to get these patches as checkpatch clean as possible.
I want to try and merge armv7 and armv8 changes into one and maintain that together as I think there is very little different in the two platforms from the point of initialisation or drivers.
Nice. Have you thought about the initial ASL just yet?
Shall I just clone the Arndale ASL for aarch64 use? Or has someone already started on that (I'm thinking Naresh might have...)? Either way it should be pretty straightforward to do....
So far I fed it the same acpi blob Ive been feeding to the Arndale.
Today I shall clone the Arndale ASL into an foundation.acpi directory and we can make a go from there.
Graeme
On Tue, Jun 11, 2013 at 03:48:58PM -0600, Al Stone wrote:
On 06/11/2013 10:22 AM, Graeme Gregory wrote:
Hi Guys,
I have just pushed this series of patches to the official repo.
Branch is acpi-armv8
This brings us to the same state in armv8 as we are in for armv7. Without the prototype stuff like i2c drivers. But is a base to start work on for armv8.
I have tried to get these patches as checkpatch clean as possible.
I want to try and merge armv7 and armv8 changes into one and maintain that together as I think there is very little different in the two platforms from the point of initialisation or drivers.
Nice. Have you thought about the initial ASL just yet?
Shall I just clone the Arndale ASL for aarch64 use? Or has someone already started on that (I'm thinking Naresh might have...)? Either way it should be pretty straightforward to do....
I have just pushed skeleton ASL files for foundation-v8.
Graeme