summaryrefslogtreecommitdiffstats
path: root/drivers/acpi/processor_idle.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2007-12-07 19:16:17 +0100
committerIngo Molnar <mingo@elte.hu>2007-12-07 19:16:17 +0100
commite17bcb43a26a7111f851b5ff6d1258ecd355de75 (patch)
tree8e8f3fd329089270c3c6be06abca0ea650ce69b7 /drivers/acpi/processor_idle.c
parent167b1de3ee4e50d65a2bd0a2667c9cd48faf54f3 (diff)
downloadlinux-e17bcb43a26a7111f851b5ff6d1258ecd355de75.tar.gz
linux-e17bcb43a26a7111f851b5ff6d1258ecd355de75.tar.bz2
linux-e17bcb43a26a7111f851b5ff6d1258ecd355de75.zip
ACPI: move timer broadcast before busmaster disable
The timer broadcast code might access HPET, which should not be accessed after the busmaster disable. In acpi_idle_enter_simple() this change also prevents, that we modify the busmaster state without going actually idle. This might leave the ACPI bm state in a stale state, when we leave the function early in the need_resched() check. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu> Acked-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Diffstat (limited to 'drivers/acpi/processor_idle.c')
-rw-r--r--drivers/acpi/processor_idle.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index b1fbee3f7fe1..2fe34cc73c13 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -531,6 +531,11 @@ static void acpi_processor_idle(void)
case ACPI_STATE_C3:
/*
+ * Must be done before busmaster disable as we might
+ * need to access HPET !
+ */
+ acpi_state_timer_broadcast(pr, cx, 1);
+ /*
* disable bus master
* bm_check implies we need ARB_DIS
* !bm_check implies we need cache flush
@@ -557,7 +562,6 @@ 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);
/* Tell the scheduler that we are going deep-idle: */
sched_clock_idle_sleep_event();
acpi_cstate_enter(cx);
@@ -1401,9 +1405,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
if (acpi_idle_suspend)
return(acpi_idle_enter_c1(dev, state));
- if (pr->flags.bm_check)
- acpi_idle_update_bm_rld(pr, cx);
-
local_irq_disable();
current_thread_info()->status &= ~TS_POLLING;
/*
@@ -1418,13 +1419,21 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
return 0;
}
+ /*
+ * Must be done before busmaster disable as we might need to
+ * access HPET !
+ */
+ acpi_state_timer_broadcast(pr, cx, 1);
+
+ if (pr->flags.bm_check)
+ acpi_idle_update_bm_rld(pr, cx);
+
if (cx->type == ACPI_STATE_C3)
ACPI_FLUSH_CPU_CACHE();
t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
/* Tell the scheduler that we are going deep-idle: */
sched_clock_idle_sleep_event();
- acpi_state_timer_broadcast(pr, cx, 1);
acpi_idle_do_entry(cx);
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);