summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2004-12-21 14:45:13 -0500
committerLen Brown <lenb@dhcppc3.>2004-12-21 14:45:13 -0500
commit9ec0be52d8a61ffd74307265d07548ba526c8414 (patch)
tree5bd9f58db1cbff1daab46c99d047e63d7c210e14
parent2af6e243847bd8409c702c0a26133e48f52b030f (diff)
[ACPI] Add _CST parsing
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_idle.c159
-rw-r--r--include/acpi/processor.h15
2 files changed, 163 insertions, 11 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index e40e5af0a072..4883ecb738a8 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -441,6 +441,8 @@ acpi_processor_set_power_policy (
static int acpi_processor_get_power_info_fadt (struct acpi_processor *pr)
{
+ int i;
+
ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_fadt");
if (!pr)
@@ -449,6 +451,9 @@ static int acpi_processor_get_power_info_fadt (struct acpi_processor *pr)
if (!pr->pblk)
return_VALUE(-ENODEV);
+ for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++)
+ memset(pr->power.states, 0, sizeof(struct acpi_processor_cx));
+
/* 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;
@@ -476,6 +481,129 @@ static int acpi_processor_get_power_info_fadt (struct acpi_processor *pr)
}
+static int acpi_processor_get_power_info_cst (struct acpi_processor *pr)
+{
+ acpi_status status = 0;
+ acpi_integer count;
+ int i;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *cst;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_cst");
+
+ if (errata.smp)
+ return_VALUE(-ENODEV);
+ pr->power.count = 0;
+ for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++)
+ memset(pr->power.states, 0, sizeof(struct acpi_processor_cx));
+
+ status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No _CST, giving up\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ cst = (union acpi_object *) buffer.pointer;
+
+ /* There must be at least 2 elements */
+ if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "not enough elements in _CST\n"));
+ status = -EFAULT;
+ goto end;
+ }
+
+ count = cst->package.elements[0].integer.value;
+
+ /* Validate number of power states. */
+ if (count < 1 || count != cst->package.count - 1) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "count given by _CST is not valid\n"));
+ status = -EFAULT;
+ goto end;
+ }
+
+ /* We support up to ACPI_PROCESSOR_MAX_POWER. */
+ if (count > ACPI_PROCESSOR_MAX_POWER) {
+ printk(KERN_WARNING "Limiting number of power states to max (%d)\n", ACPI_PROCESSOR_MAX_POWER);
+ printk(KERN_WARNING "Please increase ACPI_PROCESSOR_MAX_POWER if needed.\n");
+ count = ACPI_PROCESSOR_MAX_POWER;
+ }
+
+ /* Tell driver that at least _CST is supported. */
+ pr->flags.has_cst = 1;
+
+ for (i = 1; i <= count; i++) {
+ union acpi_object *element;
+ union acpi_object *obj;
+ struct acpi_power_register *reg;
+ struct acpi_processor_cx cx;
+
+ memset(&cx, 0, sizeof(cx));
+
+ element = (union acpi_object *) &(cst->package.elements[i]);
+ if (element->type != ACPI_TYPE_PACKAGE)
+ continue;
+
+ if (element->package.count != 4)
+ continue;
+
+ obj = (union acpi_object *) &(element->package.elements[0]);
+
+ if (obj->type != ACPI_TYPE_BUFFER)
+ continue;
+
+ reg = (struct acpi_power_register *) obj->buffer.pointer;
+
+ if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO &&
+ (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE))
+ continue;
+
+ cx.address = (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) ?
+ 0 : reg->address;
+
+ /* There should be an easy way to extract an integer... */
+ obj = (union acpi_object *) &(element->package.elements[1]);
+ if (obj->type != ACPI_TYPE_INTEGER)
+ continue;
+
+ cx.type = obj->integer.value;
+
+ if ((cx.type != ACPI_STATE_C1) &&
+ (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO))
+ continue;
+
+ if ((cx.type < ACPI_STATE_C1) ||
+ (cx.type > ACPI_STATE_C3))
+ continue;
+
+ obj = (union acpi_object *) &(element->package.elements[2]);
+ if (obj->type != ACPI_TYPE_INTEGER)
+ continue;
+
+ cx.latency = obj->integer.value;
+
+ obj = (union acpi_object *) &(element->package.elements[3]);
+ if (obj->type != ACPI_TYPE_INTEGER)
+ continue;
+
+ cx.power = obj->integer.value;
+
+ (pr->power.count)++;
+ memcpy(&(pr->power.states[pr->power.count]), &cx, sizeof(cx));
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d power states\n", pr->power.count));
+
+ /* Validate number of power states discovered */
+ if (pr->power.count < 2)
+ status = -ENODEV;
+
+end:
+ acpi_os_free(buffer.pointer);
+
+ return_VALUE(status);
+}
+
+
static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx)
{
ACPI_FUNCTION_TRACE("acpi_processor_get_power_verify_c2");
@@ -576,10 +704,15 @@ static void acpi_processor_power_verify_c3(
static int acpi_processor_power_verify(struct acpi_processor *pr)
{
unsigned int i;
+ unsigned int working = 0;
+
for (i=1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
struct acpi_processor_cx *cx = &pr->power.states[i];
switch (cx->type) {
+ case ACPI_STATE_C1:
+ cx->valid = 1;
+ break;
case ACPI_STATE_C2:
acpi_processor_power_verify_c2(cx);
@@ -589,9 +722,12 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
acpi_processor_power_verify_c3(pr, cx);
break;
}
+
+ if (cx->valid)
+ working++;
}
- return 0;
+ return (working);
}
int acpi_processor_get_power_info (
@@ -605,13 +741,15 @@ int 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);
+ result = acpi_processor_get_power_info_cst(pr);
+ if ((result) || (acpi_processor_power_verify(pr) < 2)) {
+ result = acpi_processor_get_power_info_fadt(pr);
+ if (result)
+ return_VALUE(result);
+ if (acpi_processor_power_verify(pr) < 2)
+ return_VALUE(-ENODEV);
+ }
/*
* Set Default Policy
@@ -629,8 +767,9 @@ int acpi_processor_get_power_info (
* if one state of type C2 or C3 is available, mark this
* CPU as being "idle manageable"
*/
-
- for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++) {
+ for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
+ if (pr->power.states[i].valid)
+ pr->power.count = i;
if ((pr->power.states[i].valid) &&
(pr->power.states[i].type >= ACPI_STATE_C2))
pr->flags.power = 1;
@@ -661,7 +800,7 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
seq_puts(seq, "states:\n");
- for (i = 1; i < ACPI_C_STATE_COUNT; i++) {
+ for (i = 1; i <= pr->power.count; i++) {
seq_printf(seq, " %c%d: ",
(&pr->power.states[i] == pr->power.state?'*':' '), i);
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 21a1c19c80ae..780e2ada96d8 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -6,7 +6,7 @@
#define ACPI_PROCESSOR_BUSY_METRIC 10
-#define ACPI_PROCESSOR_MAX_POWER ACPI_C_STATE_COUNT
+#define ACPI_PROCESSOR_MAX_POWER 8
#define ACPI_PROCESSOR_MAX_C2_LATENCY 100
#define ACPI_PROCESSOR_MAX_C3_LATENCY 1000
@@ -18,6 +18,17 @@
struct acpi_processor_cx;
+struct acpi_power_register {
+ u8 descriptor;
+ u16 length;
+ u8 space_id;
+ u8 bit_width;
+ u8 bit_offset;
+ u8 reserved;
+ u64 address;
+} __attribute__ ((packed));
+
+
struct acpi_processor_cx_policy {
u32 count;
struct acpi_processor_cx *state;
@@ -45,6 +56,7 @@ struct acpi_processor_power {
struct acpi_processor_cx *state;
u32 default_state;
u32 bm_activity;
+ int count;
struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
};
@@ -122,6 +134,7 @@ struct acpi_processor_flags {
u8 limit:1;
u8 bm_control:1;
u8 bm_check:1;
+ u8 has_cst:1;
u8 reserved:2;
};