aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSudeep Holla <Sudeep.Holla@arm.com>2016-07-19 13:52:57 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-07-21 17:29:38 -0400
commitc2a25c141f4e80debd8eec3e9a5f9d25daedb54f (patch)
tree4327610767dd08bb9f3a50d961e4a19f1d4c04a2
parent220276e09bd1ccf7563b8092f7bd794336420eb1 (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.c66
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
310static 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
349static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
350{
351 return -EINVAL;
352}
353#endif
354
313int psci_cpu_init_idle(unsigned int cpu) 355int 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;