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()).

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

 drivers/acpi/processor_core.c |    6
 drivers/acpi/processor_idle.c |  296 ++++++++++++++++++++++++------------------
 include/acpi/processor.h      |    1
 3 files changed, 176 insertions(+), 127 deletions(-)

diff -ruN linux-original/drivers/acpi/processor_core.c linux/drivers/acpi/processor_core.c
--- linux-original/drivers/acpi/processor_core.c	2004-11-27 16:24:34.000000000 +0100
+++ linux/drivers/acpi/processor_core.c	2004-11-27 19:06:55.828447016 +0100
@@ -514,10 +514,8 @@
 		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 -ruN linux-original/drivers/acpi/processor_idle.c linux/drivers/acpi/processor_idle.c
--- linux-original/drivers/acpi/processor_idle.c	2004-11-27 19:35:27.177282448 +0100
+++ linux/drivers/acpi/processor_idle.c	2004-11-27 19:32:38.707893688 +0100
@@ -411,144 +411,192 @@
 	return_VALUE(0);
 }
 
-
-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;
+	}
+
+	/* module parameter or DMI table */
+	else if (!c2) {
+		printk(KERN_INFO "C2 disabled\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).
-	 */
-	if (pr->power.states[ACPI_STATE_C2].address) {
-
-		pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.plvl2_lat;
-
-		/*
-		 * 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"));
-
-
-		else if (!c2)
-			printk(KERN_INFO "C2 disabled\n");
-
-		/*
-		 * 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);
-		}
+	 * C3 latency must be less than or equal to 1000
+	 * microseconds.
+	 */
+	else if (cx->latency > ACPI_PROCESSOR_MAX_C3_LATENCY) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				  "latency too large [%d]\n",
+				  cx->latency));
+		return_VOID;
+	}
+
+	/* 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;
 	}
 
 	/*
-	 * C3
-	 * --
-	 * TBD: Investigate use of WBINVD on UP/SMP system in absence of
-	 *	bm_control.
-	 */
-	if (pr->power.states[ACPI_STATE_C3].address) {
-
-		pr->power.states[ACPI_STATE_C3].latency = acpi_fadt.plvl3_lat;
-
-		/*
-		 * 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"));
-		}
-		else if (!c3)
-			printk(KERN_INFO "C3 disabled\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"));
+		return_VOID;
+	}
+
+	/* module parameter or DMI table */
+	else if (!c3) {
+		printk(KERN_INFO "C3 disabled\n");
+		return_VOID;
+	}
+
+	/*
+	 * 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
+	 */
+	cx->valid = 1;
+	cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
+	pr->flags.bm_check = 1;
+
+	return_VOID;
+}
+
+
+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;
 
-		/*
-		 * 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;
+		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
 	 * ------------------
@@ -562,13 +610,15 @@
 		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 (pr->power.states[ACPI_STATE_C2].valid
-		|| pr->power.states[ACPI_STATE_C3].valid)
-		pr->flags.power = 1;
+	 * 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++) {
+		if ((pr->power.states[i].valid) &&
+		    (pr->power.states[i].type >= ACPI_STATE_C2))
+			pr->flags.power = 1;
+	}
 
 	return_VALUE(0);
 }
diff -ruN linux-original/include/acpi/processor.h linux/include/acpi/processor.h
--- linux-original/include/acpi/processor.h	2004-11-27 19:35:27.178282296 +0100
+++ linux/include/acpi/processor.h	2004-11-27 19:02:23.132903040 +0100
@@ -127,6 +127,7 @@
 	acpi_handle		handle;
 	u32			acpi_id;
 	u32			id;
+	u32			pblk;
 	int			performance_platform_limit;
 	struct acpi_processor_flags flags;
 	struct acpi_processor_power power;