summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2004-12-21 14:05:34 -0500
committerLen Brown <lenb@dhcppc3.>2004-12-21 14:05:34 -0500
commitdb3c375960e99f1d5241a89ff69fb659fdbfaa8b (patch)
tree9626848884cda06ff4c4b070823635f3d4cfa310
parent5ff2feab75da810a25cc08ded568fc5456f53a03 (diff)
[ACPI] Split up the extraction of information from the FADT
and the pblk_address (acpi_processor_get_power_info_fadt()) and the validation whether the state is indeed available (acpi_processor_power_verify()). http://bugzilla.kernel.org/show_bug.cgi?id=1958 Signed-off-by: Bruno Ducrot <ducrot@poupinou.org> Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.de> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/acpi/processor_core.c6
-rw-r--r--drivers/acpi/processor_idle.c264
-rw-r--r--include/acpi/processor.h1
3 files changed, 157 insertions, 114 deletions
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index abbaf487c56b..2b65e8c9d75f 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -514,10 +514,8 @@ acpi_processor_get_info (
pr->throttling.address = object.processor.pblk_address;
pr->throttling.duty_offset = acpi_fadt.duty_offset;
pr->throttling.duty_width = acpi_fadt.duty_width;
- pr->power.states[ACPI_STATE_C2].address =
- object.processor.pblk_address + 4;
- pr->power.states[ACPI_STATE_C3].address =
- object.processor.pblk_address + 5;
+
+ pr->pblk = object.processor.pblk_address;
/*
* We don't care about error returns - we just try to mark
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 8ec01bdcb586..7f1a6205d19f 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -423,142 +423,184 @@ acpi_processor_set_power_policy (
}
-int acpi_processor_get_power_info (
- struct acpi_processor *pr)
+static int acpi_processor_get_power_info_fadt (struct acpi_processor *pr)
{
- int result = 0;
-
- ACPI_FUNCTION_TRACE("acpi_processor_get_power_info");
+ ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_fadt");
if (!pr)
return_VALUE(-EINVAL);
+ if (!pr->pblk)
+ return_VALUE(-ENODEV);
+
+ /* if info is obtained from pblk/fadt, type equals state */
+ pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
+ pr->power.states[ACPI_STATE_C2].type = ACPI_STATE_C2;
+ pr->power.states[ACPI_STATE_C3].type = ACPI_STATE_C3;
+
+ /* the C0 state only exists as a filler in our array,
+ * and all processors need to support C1 */
+ pr->power.states[ACPI_STATE_C0].valid = 1;
+ pr->power.states[ACPI_STATE_C1].valid = 1;
+
+ /* determine C2 and C3 address from pblk */
+ pr->power.states[ACPI_STATE_C2].address = pr->pblk + 4;
+ pr->power.states[ACPI_STATE_C3].address = pr->pblk + 5;
+
+ /* determine latencies from FADT */
+ pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.plvl2_lat;
+ pr->power.states[ACPI_STATE_C3].latency = acpi_fadt.plvl3_lat;
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "lvl2[0x%08x] lvl3[0x%08x]\n",
- pr->power.states[ACPI_STATE_C2].address,
- pr->power.states[ACPI_STATE_C3].address));
+ "lvl2[0x%08x] lvl3[0x%08x]\n",
+ pr->power.states[ACPI_STATE_C2].address,
+ pr->power.states[ACPI_STATE_C3].address));
+
+ return_VALUE(0);
+}
+
- /* TBD: Support ACPI 2.0 objects */
+static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx)
+{
+ ACPI_FUNCTION_TRACE("acpi_processor_get_power_verify_c2");
+
+ if (!cx->address)
+ return_VOID;
/*
- * C0
- * --
- * This state exists only as filler in our array.
+ * C2 latency must be less than or equal to 100
+ * microseconds.
*/
- pr->power.states[ACPI_STATE_C0].valid = 1;
+ else if (cx->latency > ACPI_PROCESSOR_MAX_C2_LATENCY) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "latency too large [%d]\n",
+ cx->latency));
+ return_VOID;
+ }
+
+ /* We're (currently) only supporting C2 on UP */
+ else if (errata.smp) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "C2 not supported in SMP mode\n"));
+ return_VOID;
+ }
/*
- * C1
- * --
- * ACPI requires C1 support for all processors.
- *
- * TBD: What about PROC_C1?
+ * Otherwise we've met all of our C2 requirements.
+ * Normalize the C2 latency to expidite policy
*/
- pr->power.states[ACPI_STATE_C1].valid = 1;
- pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
+ cx->valid = 1;
+ cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
+
+ return_VOID;
+}
+
+
+static void acpi_processor_power_verify_c3(
+ struct acpi_processor *pr,
+ struct acpi_processor_cx *cx)
+{
+ ACPI_FUNCTION_TRACE("acpi_processor_get_power_verify_c3");
+
+ if (!cx->address)
+ return_VOID;
/*
- * C2
- * --
- * We're (currently) only supporting C2 on UP systems.
- *
- * TBD: Support for C2 on MP (P_LVL2_UP).
+ * C3 latency must be less than or equal to 1000
+ * microseconds.
*/
- if (pr->power.states[ACPI_STATE_C2].address) {
-
- pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.plvl2_lat;
+ else if (cx->latency > ACPI_PROCESSOR_MAX_C3_LATENCY) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "latency too large [%d]\n",
+ cx->latency));
+ return_VOID;
+ }
- /*
- * C2 latency must be less than or equal to 100 microseconds.
- */
- if (acpi_fadt.plvl2_lat > ACPI_PROCESSOR_MAX_C2_LATENCY)
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "C2 latency too large [%d]\n",
- acpi_fadt.plvl2_lat));
- /*
- * Only support C2 on UP systems (see TBD above).
- */
- else if (errata.smp)
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "C2 not supported in SMP mode\n"));
+ /* bus mastering control is necessary */
+ else if (!pr->flags.bm_control) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "C3 support requires bus mastering control\n"));
+ return_VOID;
+ }
+ /* We're (currently) only supporting C2 on UP */
+ else if (errata.smp) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "C3 not supported in SMP mode\n"));
+ return_VOID;
+ }
- /*
- * Otherwise we've met all of our C2 requirements.
- * Normalize the C2 latency to expidite policy.
- */
- else {
- pr->power.states[ACPI_STATE_C2].valid = 1;
- pr->power.states[ACPI_STATE_C2].type = ACPI_STATE_C2;
- pr->power.states[ACPI_STATE_C2].latency_ticks =
- US_TO_PM_TIMER_TICKS(acpi_fadt.plvl2_lat);
- }
+ /*
+ * PIIX4 Erratum #18: We don't support C3 when Type-F (fast)
+ * DMA transfers are used by any ISA device to avoid livelock.
+ * Note that we could disable Type-F DMA (as recommended by
+ * the erratum), but this is known to disrupt certain ISA
+ * devices thus we take the conservative approach.
+ */
+ else if (errata.piix4.fdma) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "C3 not supported on PIIX4 with Type-F DMA\n"));
+ return_VOID;
}
/*
- * C3
- * --
- * TBD: Investigate use of WBINVD on UP/SMP system in absence of
- * bm_control.
+ * Otherwise we've met all of our C3 requirements.
+ * Normalize the C3 latency to expidite policy. Enable
+ * checking of bus mastering status (bm_check) so we can
+ * use this in our C3 policy
*/
- if (pr->power.states[ACPI_STATE_C3].address) {
+ cx->valid = 1;
+ cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
+ pr->flags.bm_check = 1;
- pr->power.states[ACPI_STATE_C3].latency = acpi_fadt.plvl3_lat;
+ return_VOID;
+}
- /*
- * C3 latency must be less than or equal to 1000 microseconds.
- */
- if (acpi_fadt.plvl3_lat > ACPI_PROCESSOR_MAX_C3_LATENCY)
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "C3 latency too large [%d]\n",
- acpi_fadt.plvl3_lat));
- /*
- * Only support C3 when bus mastering arbitration control
- * is present (able to disable bus mastering to maintain
- * cache coherency while in C3).
- */
- else if (!pr->flags.bm_control)
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "C3 support requires bus mastering control\n"));
- /*
- * Only support C3 on UP systems, as bm_control is only viable
- * on a UP system and flushing caches (e.g. WBINVD) is simply
- * too costly (at this time).
- */
- else if (errata.smp)
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "C3 not supported in SMP mode\n"));
- /*
- * PIIX4 Erratum #18: We don't support C3 when Type-F (fast)
- * DMA transfers are used by any ISA device to avoid livelock.
- * Note that we could disable Type-F DMA (as recommended by
- * the erratum), but this is known to disrupt certain ISA
- * devices thus we take the conservative approach.
- */
- else if (errata.piix4.fdma) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "C3 not supported on PIIX4 with Type-F DMA\n"));
- }
- /*
- * Otherwise we've met all of our C3 requirements.
- * Normalize the C2 latency to expidite policy. Enable
- * checking of bus mastering status (bm_check) so we can
- * use this in our C3 policy.
- */
- else {
- pr->power.states[ACPI_STATE_C3].valid = 1;
- pr->power.states[ACPI_STATE_C3].type = ACPI_STATE_C3;
- pr->power.states[ACPI_STATE_C3].latency_ticks =
- US_TO_PM_TIMER_TICKS(acpi_fadt.plvl3_lat);
- pr->flags.bm_check = 1;
+static int acpi_processor_power_verify(struct acpi_processor *pr)
+{
+ unsigned int i;
+ for (i=1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
+ struct acpi_processor_cx *cx = &pr->power.states[i];
+
+ switch (cx->type) {
+
+ case ACPI_STATE_C2:
+ acpi_processor_power_verify_c2(cx);
+ break;
+
+ case ACPI_STATE_C3:
+ acpi_processor_power_verify_c3(pr, cx);
+ break;
}
}
+ return 0;
+}
+
+int acpi_processor_get_power_info (
+ struct acpi_processor *pr)
+{
+ unsigned int i;
+ int result;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_get_power_info");
+
+ /* NOTE: the idle thread may not be running while calling
+ * this function */
+
+ for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++)
+ memset(pr->power.states, 0, sizeof(struct acpi_processor_cx));
+
+ acpi_processor_get_power_info_fadt(pr);
+
+ acpi_processor_power_verify(pr);
+
+
/*
* Set Default Policy
* ------------------
- * Now that we know which state are supported, set the default
+ * Now that we know which states are supported, set the default
* policy. Note that this policy can be changed dynamically
* (e.g. encourage deeper sleeps to conserve battery life when
* not on AC).
@@ -568,13 +610,15 @@ int acpi_processor_get_power_info (
return_VALUE(result);
/*
- * If this processor supports C2 or C3 we denote it as being 'power
- * manageable'. Note that there's really no policy involved for
- * when only C1 is supported.
+ * if one state of type C2 or C3 is available, mark this
+ * CPU as being "idle manageable"
*/
- if (pr->power.states[ACPI_STATE_C2].valid
- || pr->power.states[ACPI_STATE_C3].valid)
- pr->flags.power = 1;
+
+ for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++) {
+ if ((pr->power.states[i].valid) &&
+ (pr->power.states[i].type >= ACPI_STATE_C2))
+ pr->flags.power = 1;
+ }
return_VALUE(0);
}
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 8911b3015d70..2428ab458f3d 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -127,6 +127,7 @@ struct acpi_processor {
acpi_handle handle;
u32 acpi_id;
u32 id;
+ u32 pblk;
int performance_platform_limit;
struct acpi_processor_flags flags;
struct acpi_processor_power power;