Skip to content

Commit

Permalink
drivers: firmware: psci: initialise idle states using ACPI LPI
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Sudeep Holla authored and Rafael J. Wysocki committed Jul 21, 2016
1 parent 220276e commit c2a25c1
Showing 1 changed file with 59 additions and 7 deletions.
66 changes: 59 additions & 7 deletions drivers/firmware/psci.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#define pr_fmt(fmt) "psci: " fmt

#include <linux/acpi.h>
#include <linux/arm-smccc.h>
#include <linux/cpuidle.h>
#include <linux/errno.h>
Expand Down Expand Up @@ -256,13 +257,6 @@ static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
u32 *psci_states;
struct device_node *state_node;

/*
* If the PSCI cpu_suspend function hook has not been initialized
* idle states must not be enabled, so bail out
*/
if (!psci_ops.cpu_suspend)
return -EOPNOTSUPP;

/* Count idle states */
while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states",
count))) {
Expand Down Expand Up @@ -310,11 +304,69 @@ static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
return ret;
}

#ifdef CONFIG_ACPI
#include <acpi/processor.h>

static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
{
int i, count;
u32 *psci_states;
struct acpi_lpi_state *lpi;
struct acpi_processor *pr = per_cpu(processors, cpu);

if (unlikely(!pr || !pr->flags.has_lpi))
return -EINVAL;

count = pr->power.count - 1;
if (count <= 0)
return -ENODEV;

psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
if (!psci_states)
return -ENOMEM;

for (i = 0; i < count; i++) {
u32 state;

lpi = &pr->power.lpi_states[i + 1];
/*
* Only bits[31:0] represent a PSCI power_state while
* bits[63:32] must be 0x0 as per ARM ACPI FFH Specification
*/
state = lpi->address;
if (!psci_power_state_is_valid(state)) {
pr_warn("Invalid PSCI power state %#x\n", state);
kfree(psci_states);
return -EINVAL;
}
psci_states[i] = state;
}
/* Idle states parsed correctly, initialize per-cpu pointer */
per_cpu(psci_power_state, cpu) = psci_states;
return 0;
}
#else
static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu)
{
return -EINVAL;
}
#endif

int psci_cpu_init_idle(unsigned int cpu)
{
struct device_node *cpu_node;
int ret;

/*
* If the PSCI cpu_suspend function hook has not been initialized
* idle states must not be enabled, so bail out
*/
if (!psci_ops.cpu_suspend)
return -EOPNOTSUPP;

if (!acpi_disabled)
return psci_acpi_cpu_init_idle(cpu);

cpu_node = of_get_cpu_node(cpu, NULL);
if (!cpu_node)
return -ENODEV;
Expand Down

0 comments on commit c2a25c1

Please sign in to comment.