diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c
index 39d4bb6..c13549b 100644
--- a/drivers/cpuidle/cpuidle-pseries.c
+++ b/drivers/cpuidle/cpuidle-pseries.c
@@ -21,6 +21,7 @@
 #include <asm/runlatch.h>
 #include <asm/idle.h>
 #include <asm/plpar_wrappers.h>
+#include <asm/rtas.h>
 
 struct cpuidle_driver pseries_idle_driver = {
 	.name             = "pseries_idle",
@@ -105,9 +106,120 @@ static void check_and_cede_processor(void)
 	}
 }
 
-#define NR_CEDE_STATES		1  /* CEDE with latency-hint 0 */
+struct xcede_latency_records {
+	u8  latency_hint;
+	u64 wakeup_latency_tb_ticks;
+	u8  responsive_to_irqs;
+};
+
+/*
+ * XCEDE : Extended CEDE states discovered through the
+ *         "ibm,get-systems-parameter" rtas-call with the token
+ *         CEDE_LATENCY_TOKEN
+ */
+#define MAX_XCEDE_STATES		4
+#define	XCEDE_LATENCY_RECORD_SIZE	10
+#define XCEDE_LATENCY_PARAM_MAX_LENGTH	(2 + 2 + \
+					(MAX_XCEDE_STATES * XCEDE_LATENCY_RECORD_SIZE))
+
+#define CEDE_LATENCY_TOKEN		45
+
+#define NR_CEDE_STATES		(MAX_XCEDE_STATES + 1) /* CEDE with latency-hint 0 */
 #define NR_DEDICATED_STATES	(NR_CEDE_STATES + 1) /* Includes snooze */
 
+struct xcede_latency_records xcede_records[MAX_XCEDE_STATES];
+unsigned int nr_xcede_records;
+char xcede_parameters[XCEDE_LATENCY_PARAM_MAX_LENGTH];
+
+static int parse_cede_parameters(void)
+{
+	int ret = -1, i;
+	u16 payload_length;
+	u8 xcede_record_size;
+	u32 total_xcede_records_size;
+	char *payload;
+
+	memset(xcede_parameters, 0, XCEDE_LATENCY_PARAM_MAX_LENGTH);
+
+	ret = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1,
+			NULL, CEDE_LATENCY_TOKEN, __pa(xcede_parameters),
+			XCEDE_LATENCY_PARAM_MAX_LENGTH);
+
+	if (ret) {
+		pr_err("xcede: Error parsing CEDE_LATENCY_TOKEN\n");
+		return ret;
+	}
+
+	payload_length = be16_to_cpu(*(__be16 *)(&xcede_parameters[0]));
+	payload = &xcede_parameters[2];
+
+	/*
+	 * If the platform supports the cede latency settings
+	 * information system parameter it must provide the following
+	 * information in the NULL terminated parameter string:
+	 *
+	 * a. The first byte is the length “N” of each cede
+	 *    latency setting record minus one (zero indicates a length
+	 *    of 1 byte).
+	 *
+	 * b. For each supported cede latency setting a cede latency
+	 *    setting record consisting of the first “N” bytes as per
+	 *    the following table.
+	 *
+	 *	-----------------------------
+	 *	| Field           | Field  |
+	 *	| Name            | Length |
+	 *	-----------------------------
+	 *	| Cede Latency    | 1 Byte |
+	 *	| Specifier Value |        |
+	 *	-----------------------------
+	 *	| Maximum wakeup  |        |
+	 *	| latency in      | 8 Bytes|
+	 *	| tb-ticks        |        |
+	 *	-----------------------------
+	 *	| Responsive to   |        |
+	 *	| external        | 1 Byte |
+	 *	| interrupts      |        |
+	 *	-----------------------------
+	 *
+	 * This version has cede latency record size = 10.
+	 */
+	xcede_record_size = (u8)payload[0] + 1;
+
+	if (xcede_record_size != XCEDE_LATENCY_RECORD_SIZE) {
+		pr_err("xcede : Expected record-size %d. Observed size %d.\n",
+		       XCEDE_LATENCY_RECORD_SIZE, xcede_record_size);
+		return -EINVAL;
+	}
+
+	pr_info("xcede : xcede_record_size = %d\n", xcede_record_size);
+
+	/*
+	 * Since the payload_length includes the last NULL byte and
+	 * the xcede_record_size, the remaining bytes correspond to
+	 * array of all cede_latency settings.
+	 */
+	total_xcede_records_size = payload_length - 2;
+	nr_xcede_records = total_xcede_records_size / xcede_record_size;
+
+	payload++;
+	for (i = 0; i < nr_xcede_records; i++) {
+		struct xcede_latency_records *record = &xcede_records[i];
+
+		record->latency_hint = (u8)payload[0];
+		record->wakeup_latency_tb_ticks  =
+			be64_to_cpu(*(__be64 *)(&payload[1]));
+		record->responsive_to_irqs = (u8)payload[9];
+		payload += xcede_record_size;
+		pr_info("xcede : Record %d : hint = %u, latency =0x%llx tb-ticks, Wake-on-irq = %u\n",
+			i, record->latency_hint,
+			record->wakeup_latency_tb_ticks,
+			record->responsive_to_irqs);
+	}
+
+	return 0;
+}
+
 u8 cede_latency_hint[NR_DEDICATED_STATES];
 static int dedicated_cede_loop(struct cpuidle_device *dev,
 				struct cpuidle_driver *drv,
@@ -238,6 +350,19 @@ static int pseries_cpuidle_driver_init(void)
 	return 0;
 }
 
+static int add_pseries_idle_states(void)
+{
+	int nr_states = 2; /* By default we have snooze, CEDE */
+
+	if (parse_cede_parameters())
+		return nr_states;
+
+	pr_info("cpuidle : Skipping the %d Extended CEDE idle states\n",
+		nr_xcede_records);
+
+	return nr_states;
+}
+
 /*
  * pseries_idle_probe()
  * Choose state table for shared versus dedicated partition
@@ -260,7 +385,7 @@ static int pseries_idle_probe(void)
 			max_idle_state = ARRAY_SIZE(shared_states);
 		} else {
 			cpuidle_state_table = dedicated_states;
-			max_idle_state = ARRAY_SIZE(dedicated_states);
+			max_idle_state = add_pseries_idle_states();
 		}
 	} else
 		return -ENODEV;
