diff options
Diffstat (limited to 'drivers/firmware/psci/psci.c')
| -rw-r--r-- | drivers/firmware/psci/psci.c | 167 | 
1 files changed, 8 insertions, 159 deletions
diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c index f82ccd39a913..84f4ff351c62 100644 --- a/drivers/firmware/psci/psci.c +++ b/drivers/firmware/psci/psci.c @@ -103,7 +103,7 @@ static inline bool psci_power_state_loses_context(u32 state)  	return state & mask;  } -static inline bool psci_power_state_is_valid(u32 state) +bool psci_power_state_is_valid(u32 state)  {  	const u32 valid_mask = psci_has_ext_power_state() ?  			       PSCI_1_0_EXT_POWER_STATE_MASK : @@ -277,175 +277,24 @@ static int __init psci_features(u32 psci_func_id)  }  #ifdef CONFIG_CPU_IDLE -static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state); - -static int psci_dt_parse_state_node(struct device_node *np, u32 *state) -{ -	int err = of_property_read_u32(np, "arm,psci-suspend-param", state); - -	if (err) { -		pr_warn("%pOF missing arm,psci-suspend-param property\n", np); -		return err; -	} - -	if (!psci_power_state_is_valid(*state)) { -		pr_warn("Invalid PSCI power state %#x\n", *state); -		return -EINVAL; -	} - -	return 0; -} - -static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu) -{ -	int i, ret = 0, count = 0; -	u32 *psci_states; -	struct device_node *state_node; - -	/* Count idle states */ -	while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states", -					      count))) { -		count++; -		of_node_put(state_node); -	} - -	if (!count) -		return -ENODEV; - -	psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL); -	if (!psci_states) -		return -ENOMEM; - -	for (i = 0; i < count; i++) { -		state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); -		ret = psci_dt_parse_state_node(state_node, &psci_states[i]); -		of_node_put(state_node); - -		if (ret) -			goto free_mem; - -		pr_debug("psci-power-state %#x index %d\n", psci_states[i], i); -	} - -	/* Idle states parsed correctly, initialize per-cpu pointer */ -	per_cpu(psci_power_state, cpu) = psci_states; -	return 0; - -free_mem: -	kfree(psci_states); -	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; - -	ret = psci_dt_cpu_init_idle(cpu_node, cpu); - -	of_node_put(cpu_node); - -	return ret; -} - -static int psci_suspend_finisher(unsigned long index) +static int psci_suspend_finisher(unsigned long state)  { -	u32 *state = __this_cpu_read(psci_power_state); +	u32 power_state = state; -	return psci_ops.cpu_suspend(state[index - 1], -				    __pa_symbol(cpu_resume)); +	return psci_ops.cpu_suspend(power_state, __pa_symbol(cpu_resume));  } -int psci_cpu_suspend_enter(unsigned long index) +int psci_cpu_suspend_enter(u32 state)  {  	int ret; -	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 (!psci_power_state_loses_context(state[index - 1])) -		ret = psci_ops.cpu_suspend(state[index - 1], 0); +	if (!psci_power_state_loses_context(state)) +		ret = psci_ops.cpu_suspend(state, 0);  	else -		ret = cpu_suspend(index, psci_suspend_finisher); +		ret = cpu_suspend(state, psci_suspend_finisher);  	return ret;  } - -/* ARM specific CPU idle operations */ -#ifdef CONFIG_ARM -static const struct cpuidle_ops psci_cpuidle_ops __initconst = { -	.suspend = psci_cpu_suspend_enter, -	.init = psci_dt_cpu_init_idle, -}; - -CPUIDLE_METHOD_OF_DECLARE(psci, "psci", &psci_cpuidle_ops); -#endif  #endif  static int psci_system_suspend(unsigned long unused)  |