diff options
Diffstat (limited to 'drivers/acpi/processor_idle.c')
-rw-r--r-- | drivers/acpi/processor_idle.c | 50 |
1 files changed, 40 insertions, 10 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index f7ca8c55956b..10a2d913635a 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
@@ -148,6 +148,9 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr, | |||
148 | if (cpu_has(&cpu_data(pr->id), X86_FEATURE_ARAT)) | 148 | if (cpu_has(&cpu_data(pr->id), X86_FEATURE_ARAT)) |
149 | return; | 149 | return; |
150 | 150 | ||
151 | if (boot_cpu_has(X86_FEATURE_AMDC1E)) | ||
152 | type = ACPI_STATE_C1; | ||
153 | |||
151 | /* | 154 | /* |
152 | * Check, if one of the previous states already marked the lapic | 155 | * Check, if one of the previous states already marked the lapic |
153 | * unstable | 156 | * unstable |
@@ -202,21 +205,44 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr, | |||
202 | * Suspend / resume control | 205 | * Suspend / resume control |
203 | */ | 206 | */ |
204 | static int acpi_idle_suspend; | 207 | static int acpi_idle_suspend; |
208 | static u32 saved_bm_rld; | ||
209 | |||
210 | static void acpi_idle_bm_rld_save(void) | ||
211 | { | ||
212 | acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &saved_bm_rld); | ||
213 | } | ||
214 | static void acpi_idle_bm_rld_restore(void) | ||
215 | { | ||
216 | u32 resumed_bm_rld; | ||
217 | |||
218 | acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &resumed_bm_rld); | ||
219 | |||
220 | if (resumed_bm_rld != saved_bm_rld) | ||
221 | acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, saved_bm_rld); | ||
222 | } | ||
205 | 223 | ||
206 | int acpi_processor_suspend(struct acpi_device * device, pm_message_t state) | 224 | int acpi_processor_suspend(struct acpi_device * device, pm_message_t state) |
207 | { | 225 | { |
226 | if (acpi_idle_suspend == 1) | ||
227 | return 0; | ||
228 | |||
229 | acpi_idle_bm_rld_save(); | ||
208 | acpi_idle_suspend = 1; | 230 | acpi_idle_suspend = 1; |
209 | return 0; | 231 | return 0; |
210 | } | 232 | } |
211 | 233 | ||
212 | int acpi_processor_resume(struct acpi_device * device) | 234 | int acpi_processor_resume(struct acpi_device * device) |
213 | { | 235 | { |
236 | if (acpi_idle_suspend == 0) | ||
237 | return 0; | ||
238 | |||
239 | acpi_idle_bm_rld_restore(); | ||
214 | acpi_idle_suspend = 0; | 240 | acpi_idle_suspend = 0; |
215 | return 0; | 241 | return 0; |
216 | } | 242 | } |
217 | 243 | ||
218 | #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86) | 244 | #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86) |
219 | static int tsc_halts_in_c(int state) | 245 | static void tsc_check_state(int state) |
220 | { | 246 | { |
221 | switch (boot_cpu_data.x86_vendor) { | 247 | switch (boot_cpu_data.x86_vendor) { |
222 | case X86_VENDOR_AMD: | 248 | case X86_VENDOR_AMD: |
@@ -226,13 +252,17 @@ static int tsc_halts_in_c(int state) | |||
226 | * C/P/S0/S1 states when this bit is set. | 252 | * C/P/S0/S1 states when this bit is set. |
227 | */ | 253 | */ |
228 | if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) | 254 | if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) |
229 | return 0; | 255 | return; |
230 | 256 | ||
231 | /*FALL THROUGH*/ | 257 | /*FALL THROUGH*/ |
232 | default: | 258 | default: |
233 | return state > ACPI_STATE_C1; | 259 | /* TSC could halt in idle, so notify users */ |
260 | if (state > ACPI_STATE_C1) | ||
261 | mark_tsc_unstable("TSC halts in idle"); | ||
234 | } | 262 | } |
235 | } | 263 | } |
264 | #else | ||
265 | static void tsc_check_state(int state) { return; } | ||
236 | #endif | 266 | #endif |
237 | 267 | ||
238 | static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) | 268 | static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) |
@@ -578,17 +608,13 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) | |||
578 | 608 | ||
579 | pr->power.timer_broadcast_on_state = INT_MAX; | 609 | pr->power.timer_broadcast_on_state = INT_MAX; |
580 | 610 | ||
581 | for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) { | 611 | for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) { |
582 | struct acpi_processor_cx *cx = &pr->power.states[i]; | 612 | struct acpi_processor_cx *cx = &pr->power.states[i]; |
583 | 613 | ||
584 | #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86) | ||
585 | /* TSC could halt in idle, so notify users */ | ||
586 | if (tsc_halts_in_c(cx->type)) | ||
587 | mark_tsc_unstable("TSC halts in idle");; | ||
588 | #endif | ||
589 | switch (cx->type) { | 614 | switch (cx->type) { |
590 | case ACPI_STATE_C1: | 615 | case ACPI_STATE_C1: |
591 | cx->valid = 1; | 616 | cx->valid = 1; |
617 | acpi_timer_check_state(i, pr, cx); | ||
592 | break; | 618 | break; |
593 | 619 | ||
594 | case ACPI_STATE_C2: | 620 | case ACPI_STATE_C2: |
@@ -603,6 +629,8 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) | |||
603 | acpi_timer_check_state(i, pr, cx); | 629 | acpi_timer_check_state(i, pr, cx); |
604 | break; | 630 | break; |
605 | } | 631 | } |
632 | if (cx->valid) | ||
633 | tsc_check_state(cx->type); | ||
606 | 634 | ||
607 | if (cx->valid) | 635 | if (cx->valid) |
608 | working++; | 636 | working++; |
@@ -806,11 +834,12 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, | |||
806 | 834 | ||
807 | /* Do not access any ACPI IO ports in suspend path */ | 835 | /* Do not access any ACPI IO ports in suspend path */ |
808 | if (acpi_idle_suspend) { | 836 | if (acpi_idle_suspend) { |
809 | acpi_safe_halt(); | ||
810 | local_irq_enable(); | 837 | local_irq_enable(); |
838 | cpu_relax(); | ||
811 | return 0; | 839 | return 0; |
812 | } | 840 | } |
813 | 841 | ||
842 | acpi_state_timer_broadcast(pr, cx, 1); | ||
814 | kt1 = ktime_get_real(); | 843 | kt1 = ktime_get_real(); |
815 | acpi_idle_do_entry(cx); | 844 | acpi_idle_do_entry(cx); |
816 | kt2 = ktime_get_real(); | 845 | kt2 = ktime_get_real(); |
@@ -818,6 +847,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, | |||
818 | 847 | ||
819 | local_irq_enable(); | 848 | local_irq_enable(); |
820 | cx->usage++; | 849 | cx->usage++; |
850 | acpi_state_timer_broadcast(pr, cx, 0); | ||
821 | 851 | ||
822 | return idle_time; | 852 | return idle_time; |
823 | } | 853 | } |