diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/i2c_ec.c | 2 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsinit.c | 9 | ||||
-rw-r--r-- | drivers/acpi/processor_idle.c | 114 | ||||
-rw-r--r-- | drivers/acpi/sleep/poweroff.c | 1 | ||||
-rw-r--r-- | drivers/acpi/tables.c | 1 | ||||
-rw-r--r-- | drivers/acpi/thermal.c | 3 |
6 files changed, 107 insertions, 23 deletions
diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c index 8338be0990bc..76ec8b63e69f 100644 --- a/drivers/acpi/i2c_ec.c +++ b/drivers/acpi/i2c_ec.c @@ -14,7 +14,6 @@ #include <linux/slab.h> #include <linux/kernel.h> #include <linux/stddef.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/acpi.h> @@ -340,6 +339,7 @@ static int acpi_ec_hc_add(struct acpi_device *device) smbus->adapter.owner = THIS_MODULE; smbus->adapter.algo = &acpi_ec_smbus_algorithm; smbus->adapter.algo_data = smbus; + smbus->adapter.dev.parent = &device->dev; if (i2c_add_adapter(&smbus->adapter)) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index 326af8fc0ce7..33db2241044e 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c @@ -45,6 +45,7 @@ #include <acpi/acnamesp.h> #include <acpi/acdispat.h> #include <acpi/acinterp.h> +#include <linux/nmi.h> #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsinit") @@ -534,7 +535,15 @@ acpi_ns_init_one_device(acpi_handle obj_handle, info->parameter_type = ACPI_PARAM_ARGS; info->flags = ACPI_IGNORE_RETURN_VALUE; + /* + * Some hardware relies on this being executed as atomically + * as possible (without an NMI being received in the middle of + * this) - so disable NMIs and initialize the device: + */ + acpi_nmi_disable(); status = acpi_ns_evaluate(info); + acpi_nmi_enable(); + if (ACPI_SUCCESS(status)) { walk_info->num_INI++; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 59fac8d79412..835595ae06b3 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -39,6 +39,17 @@ #include <linux/moduleparam.h> #include <linux/sched.h> /* need_resched() */ #include <linux/latency.h> +#include <linux/clockchips.h> + +/* + * Include the apic definitions for x86 to have the APIC timer related defines + * available also for UP (on SMP it gets magically included via linux/smp.h). + * asm/acpi.h is not an option, as it would require more include magic. Also + * creating an empty asm-ia64/apic.h would just trade pest vs. cholera. + */ +#ifdef CONFIG_X86 +#include <asm/apic.h> +#endif /* * Include the apic definitions for x86 to have the APIC timer related defines @@ -246,6 +257,81 @@ static void acpi_cstate_enter(struct acpi_processor_cx *cstate) } } +#ifdef ARCH_APICTIMER_STOPS_ON_C3 + +/* + * Some BIOS implementations switch to C3 in the published C2 state. + * This seems to be a common problem on AMD boxen, but other vendors + * are affected too. We pick the most conservative approach: we assume + * that the local APIC stops in both C2 and C3. + */ +static void acpi_timer_check_state(int state, struct acpi_processor *pr, + struct acpi_processor_cx *cx) +{ + struct acpi_processor_power *pwr = &pr->power; + + /* + * Check, if one of the previous states already marked the lapic + * unstable + */ + if (pwr->timer_broadcast_on_state < state) + return; + + if (cx->type >= ACPI_STATE_C2) + pr->power.timer_broadcast_on_state = state; +} + +static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) +{ +#ifdef CONFIG_GENERIC_CLOCKEVENTS + unsigned long reason; + + reason = pr->power.timer_broadcast_on_state < INT_MAX ? + CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF; + + clockevents_notify(reason, &pr->id); +#else + cpumask_t mask = cpumask_of_cpu(pr->id); + + if (pr->power.timer_broadcast_on_state < INT_MAX) + on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1); + else + on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1); +#endif +} + +/* Power(C) State timer broadcast control */ +static void acpi_state_timer_broadcast(struct acpi_processor *pr, + struct acpi_processor_cx *cx, + int broadcast) +{ +#ifdef CONFIG_GENERIC_CLOCKEVENTS + + int state = cx - pr->power.states; + + if (state >= pr->power.timer_broadcast_on_state) { + unsigned long reason; + + reason = broadcast ? CLOCK_EVT_NOTIFY_BROADCAST_ENTER : + CLOCK_EVT_NOTIFY_BROADCAST_EXIT; + clockevents_notify(reason, &pr->id); + } +#endif +} + +#else + +static void acpi_timer_check_state(int state, struct acpi_processor *pr, + struct acpi_processor_cx *cstate) { } +static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) { } +static void acpi_state_timer_broadcast(struct acpi_processor *pr, + struct acpi_processor_cx *cx, + int broadcast) +{ +} + +#endif + static void acpi_processor_idle(void) { struct acpi_processor *pr = NULL; @@ -390,6 +476,7 @@ static void acpi_processor_idle(void) /* Get start time (ticks) */ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address); /* Invoke C2 */ + acpi_state_timer_broadcast(pr, cx, 1); acpi_cstate_enter(cx); /* Get end time (ticks) */ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); @@ -404,6 +491,7 @@ static void acpi_processor_idle(void) /* Compute time (ticks) that we were actually asleep */ sleep_ticks = ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD; + acpi_state_timer_broadcast(pr, cx, 0); break; case ACPI_STATE_C3: @@ -425,6 +513,7 @@ static void acpi_processor_idle(void) /* Get start time (ticks) */ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address); /* Invoke C3 */ + acpi_state_timer_broadcast(pr, cx, 1); acpi_cstate_enter(cx); /* Get end time (ticks) */ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); @@ -444,6 +533,7 @@ static void acpi_processor_idle(void) /* Compute time (ticks) that we were actually asleep */ sleep_ticks = ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD; + acpi_state_timer_broadcast(pr, cx, 0); break; default: @@ -912,11 +1002,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) unsigned int i; unsigned int working = 0; -#ifdef ARCH_APICTIMER_STOPS_ON_C3 - int timer_broadcast = 0; - cpumask_t mask = cpumask_of_cpu(pr->id); - on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1); -#endif + pr->power.timer_broadcast_on_state = INT_MAX; for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) { struct acpi_processor_cx *cx = &pr->power.states[i]; @@ -928,21 +1014,14 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) case ACPI_STATE_C2: acpi_processor_power_verify_c2(cx); -#ifdef ARCH_APICTIMER_STOPS_ON_C3 - /* Some AMD systems fake C3 as C2, but still - have timer troubles */ - if (cx->valid && - boot_cpu_data.x86_vendor == X86_VENDOR_AMD) - timer_broadcast++; -#endif + if (cx->valid) + acpi_timer_check_state(i, pr, cx); break; case ACPI_STATE_C3: acpi_processor_power_verify_c3(pr, cx); -#ifdef ARCH_APICTIMER_STOPS_ON_C3 if (cx->valid) - timer_broadcast++; -#endif + acpi_timer_check_state(i, pr, cx); break; } @@ -950,10 +1029,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) working++; } -#ifdef ARCH_APICTIMER_STOPS_ON_C3 - if (timer_broadcast) - on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1); -#endif + acpi_propagate_timer_broadcast(pr); return (working); } diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c index 47fb4b394eec..d9801eff6489 100644 --- a/drivers/acpi/sleep/poweroff.c +++ b/drivers/acpi/sleep/poweroff.c @@ -12,7 +12,6 @@ #include <linux/pm.h> #include <linux/init.h> #include <acpi/acpi_bus.h> -#include <linux/sched.h> #include <linux/sysdev.h> #include <asm/io.h> #include "sleep.h" diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index ba4cb200314a..45bd17313c4a 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -25,7 +25,6 @@ #include <linux/init.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/smp.h> #include <linux/string.h> #include <linux/types.h> diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index ff078d9b52f6..442bfd50dc3d 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -36,7 +36,8 @@ #include <linux/init.h> #include <linux/types.h> #include <linux/proc_fs.h> -#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/jiffies.h> #include <linux/kmod.h> #include <linux/seq_file.h> #include <asm/uaccess.h> |