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