#define P9_STOP_SPR_PSSCR      855
 
 static u32 supported_cpuidle_states;
+struct pnv_idle_states_t *pnv_idle_states;
+int nr_pnv_idle_states;
 
 /*
  * The default stop state that will be used by ppc_md.power_save
  * @dt_idle_states: Number of idle state entries
  * Returns 0 on success
  */
-static int __init pnv_power9_idle_init(struct device_node *np, u32 *flags,
-                                       int dt_idle_states)
+static int __init pnv_power9_idle_init(void)
 {
-       u64 *psscr_val = NULL;
-       u64 *psscr_mask = NULL;
-       u32 *residency_ns = NULL;
        u64 max_residency_ns = 0;
-       int rc = 0, i;
-
-       psscr_val = kcalloc(dt_idle_states, sizeof(*psscr_val), GFP_KERNEL);
-       psscr_mask = kcalloc(dt_idle_states, sizeof(*psscr_mask), GFP_KERNEL);
-       residency_ns = kcalloc(dt_idle_states, sizeof(*residency_ns),
-                              GFP_KERNEL);
-
-       if (!psscr_val || !psscr_mask || !residency_ns) {
-               rc = -1;
-               goto out;
-       }
-
-       if (of_property_read_u64_array(np,
-               "ibm,cpu-idle-state-psscr",
-               psscr_val, dt_idle_states)) {
-               pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-psscr in DT\n");
-               rc = -1;
-               goto out;
-       }
-
-       if (of_property_read_u64_array(np,
-                                      "ibm,cpu-idle-state-psscr-mask",
-                                      psscr_mask, dt_idle_states)) {
-               pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-psscr-mask in DT\n");
-               rc = -1;
-               goto out;
-       }
-
-       if (of_property_read_u32_array(np,
-                                      "ibm,cpu-idle-state-residency-ns",
-                                       residency_ns, dt_idle_states)) {
-               pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-residency-ns in DT\n");
-               rc = -1;
-               goto out;
-       }
+       int i;
 
        /*
         * Set pnv_first_deep_stop_state, pnv_deepest_stop_psscr_{val,mask},
         * the shallowest (OPAL_PM_STOP_INST_FAST) loss-less stop state.
         */
        pnv_first_deep_stop_state = MAX_STOP_STATE;
-       for (i = 0; i < dt_idle_states; i++) {
+       for (i = 0; i < nr_pnv_idle_states; i++) {
                int err;
-               u64 psscr_rl = psscr_val[i] & PSSCR_RL_MASK;
+               struct pnv_idle_states_t *state = &pnv_idle_states[i];
+               u64 psscr_rl = state->psscr_val & PSSCR_RL_MASK;
 
-               if ((flags[i] & OPAL_PM_LOSE_FULL_CONTEXT) &&
-                    (pnv_first_deep_stop_state > psscr_rl))
+               if ((state->flags & OPAL_PM_LOSE_FULL_CONTEXT) &&
+                   pnv_first_deep_stop_state > psscr_rl)
                        pnv_first_deep_stop_state = psscr_rl;
 
-               err = validate_psscr_val_mask(&psscr_val[i], &psscr_mask[i],
-                                             flags[i]);
+               err = validate_psscr_val_mask(&state->psscr_val,
+                                             &state->psscr_mask,
+                                             state->flags);
                if (err) {
-                       report_invalid_psscr_val(psscr_val[i], err);
+                       state->valid = false;
+                       report_invalid_psscr_val(state->psscr_val, err);
                        continue;
                }
 
-               if (max_residency_ns < residency_ns[i]) {
-                       max_residency_ns = residency_ns[i];
-                       pnv_deepest_stop_psscr_val = psscr_val[i];
-                       pnv_deepest_stop_psscr_mask = psscr_mask[i];
-                       pnv_deepest_stop_flag = flags[i];
+               if (max_residency_ns < state->residency_ns) {
+                       max_residency_ns = state->residency_ns;
+                       pnv_deepest_stop_psscr_val = state->psscr_val;
+                       pnv_deepest_stop_psscr_mask = state->psscr_mask;
+                       pnv_deepest_stop_flag = state->flags;
                        deepest_stop_found = true;
                }
 
                if (!default_stop_found &&
-                   (flags[i] & OPAL_PM_STOP_INST_FAST)) {
-                       pnv_default_stop_val = psscr_val[i];
-                       pnv_default_stop_mask = psscr_mask[i];
+                   (state->flags & OPAL_PM_STOP_INST_FAST)) {
+                       pnv_default_stop_val = state->psscr_val;
+                       pnv_default_stop_mask = state->psscr_mask;
                        default_stop_found = true;
                }
        }
 
        pr_info("cpuidle-powernv: Requested Level (RL) value of first deep stop = 0x%llx\n",
                pnv_first_deep_stop_state);
-out:
-       kfree(psscr_val);
-       kfree(psscr_mask);
-       kfree(residency_ns);
-       return rc;
+
+       return 0;
 }
 
 /*
  */
 static void __init pnv_probe_idle_states(void)
 {
-       struct device_node *np;
-       int dt_idle_states;
-       u32 *flags = NULL;
        int i;
 
+       if (nr_pnv_idle_states < 0) {
+               pr_warn("cpuidle-powernv: no idle states found in the DT\n");
+               return;
+       }
+
+       if (cpu_has_feature(CPU_FTR_ARCH_300)) {
+               if (pnv_power9_idle_init())
+                       return;
+       }
+
+       for (i = 0; i < nr_pnv_idle_states; i++)
+               supported_cpuidle_states |= pnv_idle_states[i].flags;
+}
+
+/*
+ * This function parses device-tree and populates all the information
+ * into pnv_idle_states structure. It also sets up nr_pnv_idle_states
+ * which is the number of cpuidle states discovered through device-tree.
+ */
+
+static int pnv_parse_cpuidle_dt(void)
+{
+       struct device_node *np;
+       int nr_idle_states, i;
+       int rc = 0;
+       u32 *temp_u32;
+       u64 *temp_u64;
+       const char **temp_string;
+
        np = of_find_node_by_path("/ibm,opal/power-mgt");
        if (!np) {
                pr_warn("opal: PowerMgmt Node not found\n");
-               goto out;
+               return -ENODEV;
        }
-       dt_idle_states = of_property_count_u32_elems(np,
-                       "ibm,cpu-idle-state-flags");
-       if (dt_idle_states < 0) {
-               pr_warn("cpuidle-powernv: no idle states found in the DT\n");
+       nr_idle_states = of_property_count_u32_elems(np,
+                                               "ibm,cpu-idle-state-flags");
+
+       pnv_idle_states = kcalloc(nr_idle_states, sizeof(*pnv_idle_states),
+                                 GFP_KERNEL);
+       temp_u32 = kcalloc(nr_idle_states, sizeof(u32),  GFP_KERNEL);
+       temp_u64 = kcalloc(nr_idle_states, sizeof(u64),  GFP_KERNEL);
+       temp_string = kcalloc(nr_idle_states, sizeof(char *),  GFP_KERNEL);
+
+       if (!(pnv_idle_states && temp_u32 && temp_u64 && temp_string)) {
+               pr_err("Could not allocate memory for dt parsing\n");
+               rc = -ENOMEM;
                goto out;
        }
 
-       flags = kcalloc(dt_idle_states, sizeof(*flags),  GFP_KERNEL);
-
-       if (of_property_read_u32_array(np,
-                       "ibm,cpu-idle-state-flags", flags, dt_idle_states)) {
+       /* Read flags */
+       if (of_property_read_u32_array(np, "ibm,cpu-idle-state-flags",
+                                      temp_u32, nr_idle_states)) {
                pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-flags in DT\n");
+               rc = -EINVAL;
                goto out;
        }
+       for (i = 0; i < nr_idle_states; i++)
+               pnv_idle_states[i].flags = temp_u32[i];
+
+       /* Read latencies */
+       if (of_property_read_u32_array(np, "ibm,cpu-idle-state-latencies-ns",
+                                      temp_u32, nr_idle_states)) {
+               pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-latencies-ns in DT\n");
+               rc = -EINVAL;
+               goto out;
+       }
+       for (i = 0; i < nr_idle_states; i++)
+               pnv_idle_states[i].latency_ns = temp_u32[i];
+
+       /* Read residencies */
+       if (of_property_read_u32_array(np, "ibm,cpu-idle-state-residency-ns",
+                                      temp_u32, nr_idle_states)) {
+               pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-latencies-ns in DT\n");
+               rc = -EINVAL;
+               goto out;
+       }
+       for (i = 0; i < nr_idle_states; i++)
+               pnv_idle_states[i].residency_ns = temp_u32[i];
 
+       /* For power9 */
        if (cpu_has_feature(CPU_FTR_ARCH_300)) {
-               if (pnv_power9_idle_init(np, flags, dt_idle_states))
+               /* Read pm_crtl_val */
+               if (of_property_read_u64_array(np, "ibm,cpu-idle-state-psscr",
+                                              temp_u64, nr_idle_states)) {
+                       pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-psscr in DT\n");
+                       rc = -EINVAL;
+                       goto out;
+               }
+               for (i = 0; i < nr_idle_states; i++)
+                       pnv_idle_states[i].psscr_val = temp_u64[i];
+
+               /* Read pm_crtl_mask */
+               if (of_property_read_u64_array(np, "ibm,cpu-idle-state-psscr-mask",
+                                              temp_u64, nr_idle_states)) {
+                       pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-psscr-mask in DT\n");
+                       rc = -EINVAL;
                        goto out;
+               }
+               for (i = 0; i < nr_idle_states; i++)
+                       pnv_idle_states[i].psscr_mask = temp_u64[i];
        }
 
-       for (i = 0; i < dt_idle_states; i++)
-               supported_cpuidle_states |= flags[i];
+       /*
+        * power8 specific properties ibm,cpu-idle-state-pmicr-mask and
+        * ibm,cpu-idle-state-pmicr-val were never used and there is no
+        * plan to use it in near future. Hence, not parsing these properties
+        */
 
+       if (of_property_read_string_array(np, "ibm,cpu-idle-state-names",
+                                         temp_string, nr_idle_states) < 0) {
+               pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-names in DT\n");
+               rc = -EINVAL;
+               goto out;
+       }
+       for (i = 0; i < nr_idle_states; i++)
+               strncpy(pnv_idle_states[i].name, temp_string[i],
+                       PNV_IDLE_NAME_LEN);
+       nr_pnv_idle_states = nr_idle_states;
+       rc = 0;
 out:
-       kfree(flags);
+       kfree(temp_u32);
+       kfree(temp_u64);
+       kfree(temp_string);
+       return rc;
 }
+
 static int __init pnv_init_idle_states(void)
 {
-
+       int rc = 0;
        supported_cpuidle_states = 0;
 
+       /* In case we error out nr_pnv_idle_states will be zero */
+       nr_pnv_idle_states = 0;
        if (cpuidle_disable != IDLE_NO_OVERRIDE)
                goto out;
-
+       rc = pnv_parse_cpuidle_dt();
+       if (rc)
+               return rc;
        pnv_probe_idle_states();
 
        if (!(supported_cpuidle_states & OPAL_PM_SLEEP_ENABLED_ER1)) {