if (!psci_power_state_is_valid(*state)) {
pr_warn("Invalid PSCI power state %#x\n", *state); return -EINVAL;
}
return 0;
}
staticint psci_dt_cpu_init_topology(struct cpuidle_driver *drv, struct psci_cpuidle_data *data, unsignedint state_count, int cpu)
{ /* Currently limit the hierarchical topology to be used in OSI mode. */ if (!psci_has_osi_support()) return 0;
data->dev = dt_idle_attach_cpu(cpu, "psci"); if (IS_ERR_OR_NULL(data->dev)) return PTR_ERR_OR_ZERO(data->dev);
psci_cpuidle_use_syscore = true;
/* * Using the deepest state for the CPU to trigger a potential selection * of a shared state for the domain, assumes the domain states are all * deeper states. On PREEMPT_RT the hierarchical topology is limited to * s2ram and s2idle.
*/
drv->states[state_count - 1].enter_s2idle = psci_enter_s2idle_domain_idle_state; if (!IS_ENABLED(CONFIG_PREEMPT_RT))
drv->states[state_count - 1].enter = psci_enter_domain_idle_state;
return 0;
}
staticint psci_dt_cpu_init_idle(struct device *dev, struct cpuidle_driver *drv, struct device_node *cpu_node, unsignedint state_count, int cpu)
{ int i, ret = 0;
u32 *psci_states; struct device_node *state_node; struct psci_cpuidle_data *data = per_cpu_ptr(&psci_cpuidle_data, cpu);
state_count++; /* Add WFI state too */
psci_states = devm_kcalloc(dev, state_count, sizeof(*psci_states),
GFP_KERNEL); if (!psci_states) return -ENOMEM;
for (i = 1; i < state_count; i++) {
state_node = of_get_cpu_state_node(cpu_node, i - 1); if (!state_node) break;
ret = psci_dt_parse_state_node(state_node, &psci_states[i]);
of_node_put(state_node);
if (ret) return ret;
pr_debug("psci-power-state %#x index %d\n", psci_states[i], i);
}
if (i != state_count) return -ENODEV;
/* Initialize optional data, used for the hierarchical topology. */
ret = psci_dt_cpu_init_topology(drv, data, state_count, cpu); if (ret < 0) return ret;
/* Idle states parsed correctly, store them in the per-cpu struct. */
data->psci_states = psci_states; return 0;
}
/* * 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;
cpu_node = of_cpu_device_node_get(cpu); if (!cpu_node) return -ENODEV;
ret = psci_dt_cpu_init_idle(dev, drv, cpu_node, state_count, cpu);
staticint psci_idle_init_cpu(struct device *dev, int cpu)
{ struct cpuidle_driver *drv; struct device_node *cpu_node; constchar *enable_method; int ret = 0;
cpu_node = of_cpu_device_node_get(cpu); if (!cpu_node) return -ENODEV;
/* * Check whether the enable-method for the cpu is PSCI, fail * if it is not.
*/
enable_method = of_get_property(cpu_node, "enable-method", NULL); if (!enable_method || (strcmp(enable_method, "psci")))
ret = -ENODEV;
of_node_put(cpu_node); if (ret) return ret;
drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); if (!drv) return -ENOMEM;
/* * PSCI idle states relies on architectural WFI to be represented as * state index 0.
*/
drv->states[0].enter = psci_enter_idle_state;
drv->states[0].exit_latency = 1;
drv->states[0].target_residency = 1;
drv->states[0].power_usage = UINT_MAX;
strcpy(drv->states[0].name, "WFI");
strcpy(drv->states[0].desc, "ARM WFI");
/* * If no DT idle states are detected (ret == 0) let the driver * initialization fail accordingly since there is no reason to * initialize the idle driver if only wfi is supported, the * default archictectural back-end already executes wfi * on idle entry.
*/
ret = dt_init_idle_driver(drv, psci_idle_state_match, 1); if (ret <= 0) return ret ? : -ENODEV;
/* * Initialize PSCI idle states.
*/
ret = psci_cpu_init_idle(dev, drv, cpu, ret); if (ret) {
pr_err("CPU %d failed to PSCI idle\n", cpu); return ret;
}
ret = cpuidle_register(drv, NULL); if (ret) goto deinit;
/* * psci_idle_probe - Initializes PSCI cpuidle driver * * Initializes PSCI cpuidle driver for all present CPUs, if any CPU fails * to register cpuidle driver then rollback to cancel all CPUs * registration.
*/ staticint psci_cpuidle_probe(struct faux_device *fdev)
{ int cpu, ret; struct cpuidle_driver *drv; struct cpuidle_device *dev;
for_each_present_cpu(cpu) {
ret = psci_idle_init_cpu(&fdev->dev, cpu); if (ret) goto out_fail;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.