diff options
author | Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> | 2006-09-25 19:28:13 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2006-10-14 00:35:39 -0400 |
commit | 991528d7348667924176f3e29addea0675298944 (patch) | |
tree | ed8552bd4c696700a95ae37b26c4197923207ae7 /drivers | |
parent | b4bd8c66435a8cdf8c90334fb3b517a23ff2ab95 (diff) |
ACPI: Processor native C-states using MWAIT
Intel processors starting with the Core Duo support
support processor native C-state using the MWAIT instruction.
Refer: Intel Architecture Software Developer's Manual
http://www.intel.com/design/Pentium4/manuals/253668.htm
Platform firmware exports the support for Native C-state to OS using
ACPI _PDC and _CST methods.
Refer: Intel Processor Vendor-Specific ACPI: Interface Specification
http://www.intel.com/technology/iapc/acpi/downloads/302223.htm
With Processor Native C-state, we use 'MWAIT' instruction on the processor
to enter different C-states (C1, C2, C3). We won't use the special IO
ports to enter C-state and no SMM mode etc required to enter C-state.
Overall this will mean better C-state support.
One major advantage of using MWAIT for all C-states is, with this and
"treat interrupt as break event" feature of MWAIT, we can now get accurate
timing for the time spent in C1, C2, .. states.
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/processor_idle.c | 101 |
1 files changed, 63 insertions, 38 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 0a395fca843b..429a39dbd75d 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
@@ -219,6 +219,23 @@ static void acpi_safe_halt(void) | |||
219 | 219 | ||
220 | static atomic_t c3_cpu_count; | 220 | static atomic_t c3_cpu_count; |
221 | 221 | ||
222 | /* Common C-state entry for C2, C3, .. */ | ||
223 | static void acpi_cstate_enter(struct acpi_processor_cx *cstate) | ||
224 | { | ||
225 | if (cstate->space_id == ACPI_CSTATE_FFH) { | ||
226 | /* Call into architectural FFH based C-state */ | ||
227 | acpi_processor_ffh_cstate_enter(cstate); | ||
228 | } else { | ||
229 | int unused; | ||
230 | /* IO port based C-state */ | ||
231 | inb(cstate->address); | ||
232 | /* Dummy wait op - must do something useless after P_LVL2 read | ||
233 | because chipsets cannot guarantee that STPCLK# signal | ||
234 | gets asserted in time to freeze execution properly. */ | ||
235 | unused = inl(acpi_fadt.xpm_tmr_blk.address); | ||
236 | } | ||
237 | } | ||
238 | |||
222 | static void acpi_processor_idle(void) | 239 | static void acpi_processor_idle(void) |
223 | { | 240 | { |
224 | struct acpi_processor *pr = NULL; | 241 | struct acpi_processor *pr = NULL; |
@@ -361,11 +378,7 @@ static void acpi_processor_idle(void) | |||
361 | /* Get start time (ticks) */ | 378 | /* Get start time (ticks) */ |
362 | t1 = inl(acpi_fadt.xpm_tmr_blk.address); | 379 | t1 = inl(acpi_fadt.xpm_tmr_blk.address); |
363 | /* Invoke C2 */ | 380 | /* Invoke C2 */ |
364 | inb(cx->address); | 381 | acpi_cstate_enter(cx); |
365 | /* Dummy wait op - must do something useless after P_LVL2 read | ||
366 | because chipsets cannot guarantee that STPCLK# signal | ||
367 | gets asserted in time to freeze execution properly. */ | ||
368 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); | ||
369 | /* Get end time (ticks) */ | 382 | /* Get end time (ticks) */ |
370 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); | 383 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); |
371 | 384 | ||
@@ -401,9 +414,7 @@ static void acpi_processor_idle(void) | |||
401 | /* Get start time (ticks) */ | 414 | /* Get start time (ticks) */ |
402 | t1 = inl(acpi_fadt.xpm_tmr_blk.address); | 415 | t1 = inl(acpi_fadt.xpm_tmr_blk.address); |
403 | /* Invoke C3 */ | 416 | /* Invoke C3 */ |
404 | inb(cx->address); | 417 | acpi_cstate_enter(cx); |
405 | /* Dummy wait op (see above) */ | ||
406 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); | ||
407 | /* Get end time (ticks) */ | 418 | /* Get end time (ticks) */ |
408 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); | 419 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); |
409 | if (pr->flags.bm_check) { | 420 | if (pr->flags.bm_check) { |
@@ -628,20 +639,16 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) | |||
628 | return 0; | 639 | return 0; |
629 | } | 640 | } |
630 | 641 | ||
631 | static int acpi_processor_get_power_info_default_c1(struct acpi_processor *pr) | 642 | static int acpi_processor_get_power_info_default(struct acpi_processor *pr) |
632 | { | 643 | { |
633 | 644 | if (!pr->power.states[ACPI_STATE_C1].valid) { | |
634 | /* Zero initialize all the C-states info. */ | 645 | /* set the first C-State to C1 */ |
635 | memset(pr->power.states, 0, sizeof(pr->power.states)); | 646 | /* all processors need to support C1 */ |
636 | 647 | pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1; | |
637 | /* set the first C-State to C1 */ | 648 | pr->power.states[ACPI_STATE_C1].valid = 1; |
638 | pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1; | 649 | } |
639 | 650 | /* the C0 state only exists as a filler in our array */ | |
640 | /* the C0 state only exists as a filler in our array, | ||
641 | * and all processors need to support C1 */ | ||
642 | pr->power.states[ACPI_STATE_C0].valid = 1; | 651 | pr->power.states[ACPI_STATE_C0].valid = 1; |
643 | pr->power.states[ACPI_STATE_C1].valid = 1; | ||
644 | |||
645 | return 0; | 652 | return 0; |
646 | } | 653 | } |
647 | 654 | ||
@@ -658,12 +665,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) | |||
658 | if (nocst) | 665 | if (nocst) |
659 | return -ENODEV; | 666 | return -ENODEV; |
660 | 667 | ||
661 | current_count = 1; | 668 | current_count = 0; |
662 | |||
663 | /* Zero initialize C2 onwards and prepare for fresh CST lookup */ | ||
664 | for (i = 2; i < ACPI_PROCESSOR_MAX_POWER; i++) | ||
665 | memset(&(pr->power.states[i]), 0, | ||
666 | sizeof(struct acpi_processor_cx)); | ||
667 | 669 | ||
668 | status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer); | 670 | status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer); |
669 | if (ACPI_FAILURE(status)) { | 671 | if (ACPI_FAILURE(status)) { |
@@ -718,22 +720,39 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) | |||
718 | (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) | 720 | (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) |
719 | continue; | 721 | continue; |
720 | 722 | ||
721 | cx.address = (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) ? | ||
722 | 0 : reg->address; | ||
723 | |||
724 | /* There should be an easy way to extract an integer... */ | 723 | /* There should be an easy way to extract an integer... */ |
725 | obj = (union acpi_object *)&(element->package.elements[1]); | 724 | obj = (union acpi_object *)&(element->package.elements[1]); |
726 | if (obj->type != ACPI_TYPE_INTEGER) | 725 | if (obj->type != ACPI_TYPE_INTEGER) |
727 | continue; | 726 | continue; |
728 | 727 | ||
729 | cx.type = obj->integer.value; | 728 | cx.type = obj->integer.value; |
730 | 729 | /* | |
731 | if ((cx.type != ACPI_STATE_C1) && | 730 | * Some buggy BIOSes won't list C1 in _CST - |
732 | (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO)) | 731 | * Let acpi_processor_get_power_info_default() handle them later |
733 | continue; | 732 | */ |
734 | 733 | if (i == 1 && cx.type != ACPI_STATE_C1) | |
735 | if ((cx.type < ACPI_STATE_C2) || (cx.type > ACPI_STATE_C3)) | 734 | current_count++; |
736 | continue; | 735 | |
736 | cx.address = reg->address; | ||
737 | cx.index = current_count + 1; | ||
738 | |||
739 | cx.space_id = ACPI_CSTATE_SYSTEMIO; | ||
740 | if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) { | ||
741 | if (acpi_processor_ffh_cstate_probe | ||
742 | (pr->id, &cx, reg) == 0) { | ||
743 | cx.space_id = ACPI_CSTATE_FFH; | ||
744 | } else if (cx.type != ACPI_STATE_C1) { | ||
745 | /* | ||
746 | * C1 is a special case where FIXED_HARDWARE | ||
747 | * can be handled in non-MWAIT way as well. | ||
748 | * In that case, save this _CST entry info. | ||
749 | * That is, we retain space_id of SYSTEM_IO for | ||
750 | * halt based C1. | ||
751 | * Otherwise, ignore this info and continue. | ||
752 | */ | ||
753 | continue; | ||
754 | } | ||
755 | } | ||
737 | 756 | ||
738 | obj = (union acpi_object *)&(element->package.elements[2]); | 757 | obj = (union acpi_object *)&(element->package.elements[2]); |
739 | if (obj->type != ACPI_TYPE_INTEGER) | 758 | if (obj->type != ACPI_TYPE_INTEGER) |
@@ -938,12 +957,18 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) | |||
938 | /* NOTE: the idle thread may not be running while calling | 957 | /* NOTE: the idle thread may not be running while calling |
939 | * this function */ | 958 | * this function */ |
940 | 959 | ||
941 | /* Adding C1 state */ | 960 | /* Zero initialize all the C-states info. */ |
942 | acpi_processor_get_power_info_default_c1(pr); | 961 | memset(pr->power.states, 0, sizeof(pr->power.states)); |
962 | |||
943 | result = acpi_processor_get_power_info_cst(pr); | 963 | result = acpi_processor_get_power_info_cst(pr); |
944 | if (result == -ENODEV) | 964 | if (result == -ENODEV) |
945 | acpi_processor_get_power_info_fadt(pr); | 965 | acpi_processor_get_power_info_fadt(pr); |
946 | 966 | ||
967 | if (result) | ||
968 | return result; | ||
969 | |||
970 | acpi_processor_get_power_info_default(pr); | ||
971 | |||
947 | pr->power.count = acpi_processor_power_verify(pr); | 972 | pr->power.count = acpi_processor_power_verify(pr); |
948 | 973 | ||
949 | /* | 974 | /* |