diff options
| -rw-r--r-- | drivers/cpuidle/cpuidle-powernv.c | 69 |
1 files changed, 40 insertions, 29 deletions
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c index aedec0957934..30d42298a69f 100644 --- a/drivers/cpuidle/cpuidle-powernv.c +++ b/drivers/cpuidle/cpuidle-powernv.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <linux/notifier.h> | 13 | #include <linux/notifier.h> |
| 14 | #include <linux/clockchips.h> | 14 | #include <linux/clockchips.h> |
| 15 | #include <linux/of.h> | 15 | #include <linux/of.h> |
| 16 | #include <linux/slab.h> | ||
| 16 | 17 | ||
| 17 | #include <asm/machdep.h> | 18 | #include <asm/machdep.h> |
| 18 | #include <asm/firmware.h> | 19 | #include <asm/firmware.h> |
| @@ -159,69 +160,79 @@ static int powernv_add_idle_states(void) | |||
| 159 | int nr_idle_states = 1; /* Snooze */ | 160 | int nr_idle_states = 1; /* Snooze */ |
| 160 | int dt_idle_states; | 161 | int dt_idle_states; |
| 161 | const __be32 *idle_state_flags; | 162 | const __be32 *idle_state_flags; |
| 162 | const __be32 *idle_state_latency; | 163 | u32 len_flags, flags; |
| 163 | u32 len_flags, flags, latency_ns; | 164 | u32 *latency_ns, *residency_ns; |
| 164 | int i; | 165 | int i, rc; |
| 165 | 166 | ||
| 166 | /* Currently we have snooze statically defined */ | 167 | /* Currently we have snooze statically defined */ |
| 167 | 168 | ||
| 168 | power_mgt = of_find_node_by_path("/ibm,opal/power-mgt"); | 169 | power_mgt = of_find_node_by_path("/ibm,opal/power-mgt"); |
| 169 | if (!power_mgt) { | 170 | if (!power_mgt) { |
| 170 | pr_warn("opal: PowerMgmt Node not found\n"); | 171 | pr_warn("opal: PowerMgmt Node not found\n"); |
| 171 | return nr_idle_states; | 172 | goto out; |
| 172 | } | 173 | } |
| 173 | 174 | ||
| 174 | idle_state_flags = of_get_property(power_mgt, "ibm,cpu-idle-state-flags", &len_flags); | 175 | idle_state_flags = of_get_property(power_mgt, |
| 176 | "ibm,cpu-idle-state-flags", &len_flags); | ||
| 175 | if (!idle_state_flags) { | 177 | if (!idle_state_flags) { |
| 176 | pr_warn("DT-PowerMgmt: missing ibm,cpu-idle-state-flags\n"); | 178 | pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-flags in DT\n"); |
| 177 | return nr_idle_states; | 179 | goto out; |
| 178 | } | 180 | } |
| 179 | 181 | ||
| 180 | idle_state_latency = of_get_property(power_mgt, | 182 | dt_idle_states = len_flags / sizeof(u32); |
| 181 | "ibm,cpu-idle-state-latencies-ns", NULL); | 183 | |
| 182 | if (!idle_state_latency) { | 184 | latency_ns = kzalloc(sizeof(*latency_ns) * dt_idle_states, GFP_KERNEL); |
| 183 | pr_warn("DT-PowerMgmt: missing ibm,cpu-idle-state-latencies-ns\n"); | 185 | rc = of_property_read_u32_array(power_mgt, |
| 184 | return nr_idle_states; | 186 | "ibm,cpu-idle-state-latencies-ns", latency_ns, dt_idle_states); |
| 187 | if (rc) { | ||
| 188 | pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-latencies-ns in DT\n"); | ||
| 189 | goto out_free_latency; | ||
| 185 | } | 190 | } |
| 186 | 191 | ||
| 187 | dt_idle_states = len_flags / sizeof(u32); | 192 | residency_ns = kzalloc(sizeof(*residency_ns) * dt_idle_states, GFP_KERNEL); |
| 193 | rc = of_property_read_u32_array(power_mgt, | ||
| 194 | "ibm,cpu-idle-state-residency-ns", residency_ns, dt_idle_states); | ||
| 188 | 195 | ||
| 189 | for (i = 0; i < dt_idle_states; i++) { | 196 | for (i = 0; i < dt_idle_states; i++) { |
| 190 | 197 | ||
| 191 | flags = be32_to_cpu(idle_state_flags[i]); | 198 | flags = be32_to_cpu(idle_state_flags[i]); |
| 192 | 199 | ||
| 193 | /* Cpuidle accepts exit_latency in us and we estimate | 200 | /* |
| 194 | * target residency to be 10x exit_latency | 201 | * Cpuidle accepts exit_latency and target_residency in us. |
| 202 | * Use default target_residency values if f/w does not expose it. | ||
| 195 | */ | 203 | */ |
| 196 | latency_ns = be32_to_cpu(idle_state_latency[i]); | ||
| 197 | if (flags & OPAL_PM_NAP_ENABLED) { | 204 | if (flags & OPAL_PM_NAP_ENABLED) { |
| 198 | /* Add NAP state */ | 205 | /* Add NAP state */ |
| 199 | strcpy(powernv_states[nr_idle_states].name, "Nap"); | 206 | strcpy(powernv_states[nr_idle_states].name, "Nap"); |
| 200 | strcpy(powernv_states[nr_idle_states].desc, "Nap"); | 207 | strcpy(powernv_states[nr_idle_states].desc, "Nap"); |
| 201 | powernv_states[nr_idle_states].flags = 0; | 208 | powernv_states[nr_idle_states].flags = 0; |
| 202 | powernv_states[nr_idle_states].exit_latency = | 209 | powernv_states[nr_idle_states].target_residency = 100; |
| 203 | ((unsigned int)latency_ns) / 1000; | ||
| 204 | powernv_states[nr_idle_states].target_residency = | ||
| 205 | ((unsigned int)latency_ns / 100); | ||
| 206 | powernv_states[nr_idle_states].enter = &nap_loop; | 210 | powernv_states[nr_idle_states].enter = &nap_loop; |
| 207 | nr_idle_states++; | 211 | } else if (flags & OPAL_PM_SLEEP_ENABLED || |
| 208 | } | ||
| 209 | |||
| 210 | if (flags & OPAL_PM_SLEEP_ENABLED || | ||
| 211 | flags & OPAL_PM_SLEEP_ENABLED_ER1) { | 212 | flags & OPAL_PM_SLEEP_ENABLED_ER1) { |
| 212 | /* Add FASTSLEEP state */ | 213 | /* Add FASTSLEEP state */ |
| 213 | strcpy(powernv_states[nr_idle_states].name, "FastSleep"); | 214 | strcpy(powernv_states[nr_idle_states].name, "FastSleep"); |
| 214 | strcpy(powernv_states[nr_idle_states].desc, "FastSleep"); | 215 | strcpy(powernv_states[nr_idle_states].desc, "FastSleep"); |
| 215 | powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIMER_STOP; | 216 | powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIMER_STOP; |
| 216 | powernv_states[nr_idle_states].exit_latency = | 217 | powernv_states[nr_idle_states].target_residency = 300000; |
| 217 | ((unsigned int)latency_ns) / 1000; | ||
| 218 | powernv_states[nr_idle_states].target_residency = | ||
| 219 | ((unsigned int)latency_ns / 100); | ||
| 220 | powernv_states[nr_idle_states].enter = &fastsleep_loop; | 218 | powernv_states[nr_idle_states].enter = &fastsleep_loop; |
| 221 | nr_idle_states++; | ||
| 222 | } | 219 | } |
| 220 | |||
| 221 | powernv_states[nr_idle_states].exit_latency = | ||
| 222 | ((unsigned int)latency_ns[i]) / 1000; | ||
| 223 | |||
| 224 | if (!rc) { | ||
| 225 | powernv_states[nr_idle_states].target_residency = | ||
| 226 | ((unsigned int)residency_ns[i]) / 1000; | ||
| 227 | } | ||
| 228 | |||
| 229 | nr_idle_states++; | ||
| 223 | } | 230 | } |
| 224 | 231 | ||
| 232 | kfree(residency_ns); | ||
| 233 | out_free_latency: | ||
| 234 | kfree(latency_ns); | ||
| 235 | out: | ||
| 225 | return nr_idle_states; | 236 | return nr_idle_states; |
| 226 | } | 237 | } |
| 227 | 238 | ||
