Commit db3c3759 authored by Len Brown's avatar Len Brown Committed by Len Brown

[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=1958Signed-off-by: default avatarBruno Ducrot <ducrot@poupinou.org>
Signed-off-by: default avatarDominik Brodowski <linux@dominikbrodowski.de>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 5ff2feab
...@@ -514,10 +514,8 @@ acpi_processor_get_info ( ...@@ -514,10 +514,8 @@ acpi_processor_get_info (
pr->throttling.address = object.processor.pblk_address; pr->throttling.address = object.processor.pblk_address;
pr->throttling.duty_offset = acpi_fadt.duty_offset; pr->throttling.duty_offset = acpi_fadt.duty_offset;
pr->throttling.duty_width = acpi_fadt.duty_width; pr->throttling.duty_width = acpi_fadt.duty_width;
pr->power.states[ACPI_STATE_C2].address =
object.processor.pblk_address + 4; pr->pblk = object.processor.pblk_address;
pr->power.states[ACPI_STATE_C3].address =
object.processor.pblk_address + 5;
/* /*
* We don't care about error returns - we just try to mark * We don't care about error returns - we just try to mark
......
...@@ -423,142 +423,184 @@ acpi_processor_set_power_policy ( ...@@ -423,142 +423,184 @@ acpi_processor_set_power_policy (
} }
int acpi_processor_get_power_info ( static int acpi_processor_get_power_info_fadt (struct acpi_processor *pr)
struct acpi_processor *pr)
{ {
int result = 0; ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_fadt");
ACPI_FUNCTION_TRACE("acpi_processor_get_power_info");
if (!pr) if (!pr)
return_VALUE(-EINVAL); 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, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"lvl2[0x%08x] lvl3[0x%08x]\n", "lvl2[0x%08x] lvl3[0x%08x]\n",
pr->power.states[ACPI_STATE_C2].address, pr->power.states[ACPI_STATE_C2].address,
pr->power.states[ACPI_STATE_C3].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 * C2 latency must be less than or equal to 100
* -- * microseconds.
* This state exists only as filler in our array.
*/ */
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 * Otherwise we've met all of our C2 requirements.
* -- * Normalize the C2 latency to expidite policy
* ACPI requires C1 support for all processors.
*
* TBD: What about PROC_C1?
*/ */
pr->power.states[ACPI_STATE_C1].valid = 1; cx->valid = 1;
pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1; 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 * C3 latency must be less than or equal to 1000
* -- * microseconds.
* We're (currently) only supporting C2 on UP systems.
*
* TBD: Support for C2 on MP (P_LVL2_UP).
*/ */
if (pr->power.states[ACPI_STATE_C2].address) { else if (cx->latency > ACPI_PROCESSOR_MAX_C3_LATENCY) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.plvl2_lat; "latency too large [%d]\n",
cx->latency));
return_VOID;
}
/* /* bus mastering control is necessary */
* C2 latency must be less than or equal to 100 microseconds. else if (!pr->flags.bm_control) {
*/ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
if (acpi_fadt.plvl2_lat > ACPI_PROCESSOR_MAX_C2_LATENCY) "C3 support requires bus mastering control\n"));
ACPI_DEBUG_PRINT((ACPI_DB_INFO, return_VOID;
"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"));
/* 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. * PIIX4 Erratum #18: We don't support C3 when Type-F (fast)
* Normalize the C2 latency to expidite policy. * DMA transfers are used by any ISA device to avoid livelock.
*/ * Note that we could disable Type-F DMA (as recommended by
else { * the erratum), but this is known to disrupt certain ISA
pr->power.states[ACPI_STATE_C2].valid = 1; * devices thus we take the conservative approach.
pr->power.states[ACPI_STATE_C2].type = ACPI_STATE_C2; */
pr->power.states[ACPI_STATE_C2].latency_ticks = else if (errata.piix4.fdma) {
US_TO_PM_TIMER_TICKS(acpi_fadt.plvl2_lat); ACPI_DEBUG_PRINT((ACPI_DB_INFO,
} "C3 not supported on PIIX4 with Type-F DMA\n"));
return_VOID;
} }
/* /*
* C3 * Otherwise we've met all of our C3 requirements.
* -- * Normalize the C3 latency to expidite policy. Enable
* TBD: Investigate use of WBINVD on UP/SMP system in absence of * checking of bus mastering status (bm_check) so we can
* bm_control. * 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"));
}
/* static int acpi_processor_power_verify(struct acpi_processor *pr)
* Otherwise we've met all of our C3 requirements. {
* Normalize the C2 latency to expidite policy. Enable unsigned int i;
* checking of bus mastering status (bm_check) so we can for (i=1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
* use this in our C3 policy. struct acpi_processor_cx *cx = &pr->power.states[i];
*/
else { switch (cx->type) {
pr->power.states[ACPI_STATE_C3].valid = 1;
pr->power.states[ACPI_STATE_C3].type = ACPI_STATE_C3; case ACPI_STATE_C2:
pr->power.states[ACPI_STATE_C3].latency_ticks = acpi_processor_power_verify_c2(cx);
US_TO_PM_TIMER_TICKS(acpi_fadt.plvl3_lat); break;
pr->flags.bm_check = 1;
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 * 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 * policy. Note that this policy can be changed dynamically
* (e.g. encourage deeper sleeps to conserve battery life when * (e.g. encourage deeper sleeps to conserve battery life when
* not on AC). * not on AC).
...@@ -568,13 +610,15 @@ int acpi_processor_get_power_info ( ...@@ -568,13 +610,15 @@ int acpi_processor_get_power_info (
return_VALUE(result); return_VALUE(result);
/* /*
* If this processor supports C2 or C3 we denote it as being 'power * if one state of type C2 or C3 is available, mark this
* manageable'. Note that there's really no policy involved for * CPU as being "idle manageable"
* when only C1 is supported.
*/ */
if (pr->power.states[ACPI_STATE_C2].valid
|| pr->power.states[ACPI_STATE_C3].valid) for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++) {
pr->flags.power = 1; if ((pr->power.states[i].valid) &&
(pr->power.states[i].type >= ACPI_STATE_C2))
pr->flags.power = 1;
}
return_VALUE(0); return_VALUE(0);
} }
......
...@@ -127,6 +127,7 @@ struct acpi_processor { ...@@ -127,6 +127,7 @@ struct acpi_processor {
acpi_handle handle; acpi_handle handle;
u32 acpi_id; u32 acpi_id;
u32 id; u32 id;
u32 pblk;
int performance_platform_limit; int performance_platform_limit;
struct acpi_processor_flags flags; struct acpi_processor_flags flags;
struct acpi_processor_power power; struct acpi_processor_power power;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment