Skip to content

Commit

Permalink
arm64: psci: kill psci_power_state
Browse files Browse the repository at this point in the history
A PSCI 1.0 implementation may choose to use the new extended StateID
format, the presence of which may be queried via the PSCI_FEATURES call.
The layout of this new StateID format is incompatible with the existing
format, and so to handle both we must abstract attempts to parse the
fields.

In preparation for PSCI 1.0 support, this patch introduces
psci_power_state_loses_context and psci_power_state_is_valid functions
to query information from a PSCI power state, which is no longer
decomposed (and hence the pack/unpack functions are removed). As it is
no longer decomposed, it is now passed round as an opaque u32 token.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
Cc: Will Deacon <will.deacon@arm.com>
  • Loading branch information
Mark Rutland committed May 27, 2015
1 parent ff3010e commit c8cc427
Showing 1 changed file with 37 additions and 52 deletions.
89 changes: 37 additions & 52 deletions arch/arm64/kernel/psci.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,19 @@
#define PSCI_POWER_STATE_TYPE_STANDBY 0
#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1

struct psci_power_state {
u16 id;
u8 type;
u8 affinity_level;
};
static bool psci_power_state_loses_context(u32 state)
{
return state & PSCI_0_2_POWER_STATE_TYPE_MASK;
}

static bool psci_power_state_is_valid(u32 state)
{
const u32 valid_mask = PSCI_0_2_POWER_STATE_ID_MASK |
PSCI_0_2_POWER_STATE_TYPE_MASK |
PSCI_0_2_POWER_STATE_AFFL_MASK;

return !(state & ~valid_mask);
}

/*
* The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF
Expand All @@ -58,9 +66,8 @@ static bool psci_tos_resident_on(int cpu)
}

struct psci_operations {
int (*cpu_suspend)(struct psci_power_state state,
unsigned long entry_point);
int (*cpu_off)(struct psci_power_state state);
int (*cpu_suspend)(u32 state, unsigned long entry_point);
int (*cpu_off)(u32 state);
int (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
int (*migrate)(unsigned long cpuid);
int (*affinity_info)(unsigned long target_affinity,
Expand All @@ -84,7 +91,7 @@ enum psci_function {
PSCI_FN_MAX,
};

static DEFINE_PER_CPU_READ_MOSTLY(struct psci_power_state *, psci_power_state);
static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);

static u32 psci_function_id[PSCI_FN_MAX];

Expand All @@ -104,53 +111,28 @@ static int psci_to_linux_errno(int errno)
return -EINVAL;
}

static u32 psci_power_state_pack(struct psci_power_state state)
{
return ((state.id << PSCI_0_2_POWER_STATE_ID_SHIFT)
& PSCI_0_2_POWER_STATE_ID_MASK) |
((state.type << PSCI_0_2_POWER_STATE_TYPE_SHIFT)
& PSCI_0_2_POWER_STATE_TYPE_MASK) |
((state.affinity_level << PSCI_0_2_POWER_STATE_AFFL_SHIFT)
& PSCI_0_2_POWER_STATE_AFFL_MASK);
}

static void psci_power_state_unpack(u32 power_state,
struct psci_power_state *state)
{
state->id = (power_state & PSCI_0_2_POWER_STATE_ID_MASK) >>
PSCI_0_2_POWER_STATE_ID_SHIFT;
state->type = (power_state & PSCI_0_2_POWER_STATE_TYPE_MASK) >>
PSCI_0_2_POWER_STATE_TYPE_SHIFT;
state->affinity_level =
(power_state & PSCI_0_2_POWER_STATE_AFFL_MASK) >>
PSCI_0_2_POWER_STATE_AFFL_SHIFT;
}

static u32 psci_get_version(void)
{
return invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0);
}

static int psci_cpu_suspend(struct psci_power_state state,
unsigned long entry_point)
static int psci_cpu_suspend(u32 state, unsigned long entry_point)
{
int err;
u32 fn, power_state;
u32 fn;

fn = psci_function_id[PSCI_FN_CPU_SUSPEND];
power_state = psci_power_state_pack(state);
err = invoke_psci_fn(fn, power_state, entry_point, 0);
err = invoke_psci_fn(fn, state, entry_point, 0);
return psci_to_linux_errno(err);
}

static int psci_cpu_off(struct psci_power_state state)
static int psci_cpu_off(u32 state)
{
int err;
u32 fn, power_state;
u32 fn;

fn = psci_function_id[PSCI_FN_CPU_OFF];
power_state = psci_power_state_pack(state);
err = invoke_psci_fn(fn, power_state, 0, 0);
err = invoke_psci_fn(fn, state, 0, 0);
return psci_to_linux_errno(err);
}

Expand Down Expand Up @@ -194,7 +176,7 @@ static unsigned long psci_migrate_info_up_cpu(void)
static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu)
{
int i, ret, count = 0;
struct psci_power_state *psci_states;
u32 *psci_states;
struct device_node *state_node, *cpu_node;

cpu_node = of_get_cpu_node(cpu, NULL);
Expand Down Expand Up @@ -223,13 +205,13 @@ static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu)
return -ENOMEM;

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

state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);

ret = of_property_read_u32(state_node,
"arm,psci-suspend-param",
&psci_power_state);
&state);
if (ret) {
pr_warn(" * %s missing arm,psci-suspend-param property\n",
state_node->full_name);
Expand All @@ -238,9 +220,13 @@ static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu)
}

of_node_put(state_node);
pr_debug("psci-power-state %#x index %d\n", psci_power_state,
i);
psci_power_state_unpack(psci_power_state, &psci_states[i]);
pr_debug("psci-power-state %#x index %d\n", state, i);
if (!psci_power_state_is_valid(state)) {
pr_warn("Invalid PSCI power state %#x\n", state);
ret = -EINVAL;
goto free_mem;
}
psci_states[i] = state;
}
/* Idle states parsed correctly, initialize per-cpu pointer */
per_cpu(psci_power_state, cpu) = psci_states;
Expand Down Expand Up @@ -528,9 +514,8 @@ static void cpu_psci_cpu_die(unsigned int cpu)
* There are no known implementations of PSCI actually using the
* power state field, pass a sensible default for now.
*/
struct psci_power_state state = {
.type = PSCI_POWER_STATE_TYPE_POWER_DOWN,
};
u32 state = PSCI_POWER_STATE_TYPE_POWER_DOWN <<
PSCI_0_2_POWER_STATE_TYPE_SHIFT;

ret = psci_ops.cpu_off(state);

Expand Down Expand Up @@ -569,7 +554,7 @@ static int cpu_psci_cpu_kill(unsigned int cpu)

static int psci_suspend_finisher(unsigned long index)
{
struct psci_power_state *state = __this_cpu_read(psci_power_state);
u32 *state = __this_cpu_read(psci_power_state);

return psci_ops.cpu_suspend(state[index - 1],
virt_to_phys(cpu_resume));
Expand All @@ -578,15 +563,15 @@ static int psci_suspend_finisher(unsigned long index)
static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index)
{
int ret;
struct psci_power_state *state = __this_cpu_read(psci_power_state);
u32 *state = __this_cpu_read(psci_power_state);
/*
* idle state index 0 corresponds to wfi, should never be called
* from the cpu_suspend operations
*/
if (WARN_ON_ONCE(!index))
return -EINVAL;

if (state[index - 1].type == PSCI_POWER_STATE_TYPE_STANDBY)
if (!psci_power_state_loses_context(state[index - 1]))
ret = psci_ops.cpu_suspend(state[index - 1], 0);
else
ret = __cpu_suspend(index, psci_suspend_finisher);
Expand Down

0 comments on commit c8cc427

Please sign in to comment.