Add parsing for _CST

Signed-off-by: Dominik Brodowski <linux@brodo.de>

 drivers/acpi/processor_idle.c |  159 +++++++++++++++++++++++++++++++++++++++---
 include/acpi/processor.h      |   15 +++
 2 files changed, 163 insertions(+), 11 deletions(-)

diff -ruN linux-original/drivers/acpi/processor_idle.c linux/drivers/acpi/processor_idle.c
--- linux-original/drivers/acpi/processor_idle.c	2004-11-27 20:41:10.889249904 +0100
+++ linux/drivers/acpi/processor_idle.c	2004-11-27 21:20:40.852960656 +0100
@@ -429,6 +429,8 @@
 
 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)
@@ -437,6 +439,9 @@
 	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;
@@ -464,6 +469,129 @@
 }
 
 
+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 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 @@
 			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 @@
 	/* 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 @@
 	 * 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;
@@ -659,7 +798,7 @@
 
 	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 -ruN linux-original/include/acpi/processor.h linux/include/acpi/processor.h
--- linux-original/include/acpi/processor.h	2004-11-27 20:41:10.890249752 +0100
+++ linux/include/acpi/processor.h	2004-11-27 21:01:45.845508016 +0100
@@ -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;
@@ -44,6 +55,7 @@
 struct acpi_processor_power {
 	struct acpi_processor_cx *state;
 	u32			bm_activity;
+	int			count;
 	struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
 };
 
@@ -121,6 +133,7 @@
 	u8			limit:1;
 	u8			bm_control:1;
 	u8			bm_check:1;
+	u8			has_cst:1;
 	u8			reserved:2;
 };