diff options
author | Sudeep Holla <Sudeep.Holla@arm.com> | 2016-07-19 13:52:57 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-07-21 17:29:38 -0400 |
commit | c2a25c141f4e80debd8eec3e9a5f9d25daedb54f (patch) | |
tree | 4327610767dd08bb9f3a50d961e4a19f1d4c04a2 | |
parent | 220276e09bd1ccf7563b8092f7bd794336420eb1 (diff) |
drivers: firmware: psci: initialise idle states using ACPI LPI
This patch adds support for initialisation of PSCI CPUIdle states
from Low Power Idle(_LPI) entries in the ACPI tables when acpi is
enabled.
Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/firmware/psci.c | 66 |
1 files changed, 59 insertions, 7 deletions
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 03e04582791c..8263429e21b8 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #define pr_fmt(fmt) "psci: " fmt | 14 | #define pr_fmt(fmt) "psci: " fmt |
15 | 15 | ||
16 | #include <linux/acpi.h> | ||
16 | #include <linux/arm-smccc.h> | 17 | #include <linux/arm-smccc.h> |
17 | #include <linux/cpuidle.h> | 18 | #include <linux/cpuidle.h> |
18 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
@@ -256,13 +257,6 @@ static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu) | |||
256 | u32 *psci_states; | 257 | u32 *psci_states; |
257 | struct device_node *state_node; | 258 | struct device_node *state_node; |
258 | 259 | ||
259 | /* | ||
260 | * If the PSCI cpu_suspend function hook has not been initialized | ||
261 | * idle states must not be enabled, so bail out | ||
262 | */ | ||
263 | if (!psci_ops.cpu_suspend) | ||
264 | return -EOPNOTSUPP; | ||
265 | |||
266 | /* Count idle states */ | 260 | /* Count idle states */ |
267 | while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states", | 261 | while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states", |
268 | count))) { | 262 | count))) { |
@@ -310,11 +304,69 @@ free_mem: | |||
310 | return ret; | 304 | return ret; |
311 | } | 305 | } |
312 | 306 | ||
307 | #ifdef CONFIG_ACPI | ||
308 | #include <acpi/processor.h> | ||
309 | |||
310 | static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu) | ||
311 | { | ||
312 | int i, count; | ||
313 | u32 *psci_states; | ||
314 | struct acpi_lpi_state *lpi; | ||
315 | struct acpi_processor *pr = per_cpu(processors, cpu); | ||
316 | |||
317 | if (unlikely(!pr || !pr->flags.has_lpi)) | ||
318 | return -EINVAL; | ||
319 | |||
320 | count = pr->power.count - 1; | ||
321 | if (count <= 0) | ||
322 | return -ENODEV; | ||
323 | |||
324 | psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL); | ||
325 | if (!psci_states) | ||
326 | return -ENOMEM; | ||
327 | |||
328 | for (i = 0; i < count; i++) { | ||
329 | u32 state; | ||
330 | |||
331 | lpi = &pr->power.lpi_states[i + 1]; | ||
332 | /* | ||
333 | * Only bits[31:0] represent a PSCI power_state while | ||
334 | * bits[63:32] must be 0x0 as per ARM ACPI FFH Specification | ||
335 | */ | ||
336 | state = lpi->address; | ||
337 | if (!psci_power_state_is_valid(state)) { | ||
338 | pr_warn("Invalid PSCI power state %#x\n", state); | ||
339 | kfree(psci_states); | ||
340 | return -EINVAL; | ||
341 | } | ||
342 | psci_states[i] = state; | ||
343 | } | ||
344 | /* Idle states parsed correctly, initialize per-cpu pointer */ | ||
345 | per_cpu(psci_power_state, cpu) = psci_states; | ||
346 | return 0; | ||
347 | } | ||
348 | #else | ||
349 | static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu) | ||
350 | { | ||
351 | return -EINVAL; | ||
352 | } | ||
353 | #endif | ||
354 | |||
313 | int psci_cpu_init_idle(unsigned int cpu) | 355 | int psci_cpu_init_idle(unsigned int cpu) |
314 | { | 356 | { |
315 | struct device_node *cpu_node; | 357 | struct device_node *cpu_node; |
316 | int ret; | 358 | int ret; |
317 | 359 | ||
360 | /* | ||
361 | * If the PSCI cpu_suspend function hook has not been initialized | ||
362 | * idle states must not be enabled, so bail out | ||
363 | */ | ||
364 | if (!psci_ops.cpu_suspend) | ||
365 | return -EOPNOTSUPP; | ||
366 | |||
367 | if (!acpi_disabled) | ||
368 | return psci_acpi_cpu_init_idle(cpu); | ||
369 | |||
318 | cpu_node = of_get_cpu_node(cpu, NULL); | 370 | cpu_node = of_get_cpu_node(cpu, NULL); |
319 | if (!cpu_node) | 371 | if (!cpu_node) |
320 | return -ENODEV; | 372 | return -ENODEV; |