if (!riscv_sbi_suspend_state_is_valid(*state)) {
pr_warn("Invalid SBI suspend state %#x\n", *state); return -EINVAL;
}
return0;
}
staticint sbi_dt_cpu_init_topology(struct cpuidle_driver *drv, struct sbi_cpuidle_data *data, unsignedint state_count, int cpu)
{ /* Currently limit the hierarchical topology to be used in OSI mode. */ if (!sbi_cpuidle_use_osi) return0;
data->dev = dt_idle_attach_cpu(cpu, "sbi"); if (IS_ERR_OR_NULL(data->dev)) return PTR_ERR_OR_ZERO(data->dev);
struct device_node *cpu_node __free(device_node) = of_cpu_device_node_get(cpu); if (!cpu_node) return -ENODEV;
states = devm_kcalloc(dev, state_count, sizeof(*states), GFP_KERNEL); if (!states) return -ENOMEM;
/* Parse SBI specific details from state DT nodes */ for (i = 1; i < state_count; i++) {
state_node = of_get_cpu_state_node(cpu_node, i - 1); if (!state_node) break;
ret = sbi_dt_parse_state_node(state_node, &states[i]);
of_node_put(state_node);
if (ret) return ret;
pr_debug("sbi-state %#x index %d\n", states[i], i);
} if (i != state_count) return -ENODEV;
/* Initialize optional data, used for the hierarchical topology. */
ret = sbi_dt_cpu_init_topology(drv, data, state_count, cpu); if (ret < 0) return ret;
/* Store states in the per-cpu struct. */
data->states = states;
/* RISC-V architectural WFI to be represented as state index 0. */
drv->states[0].enter = sbi_cpuidle_enter_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, "RISC-V WFI");
/* *IfnoDTidlestatesaredetected(ret==0)letthedriver *initializationfailaccordinglysincethereisnoreasonto *initializetheidledriverifonlywfiissupported,the *defaultarchictecturalback-endalreadyexecuteswfi *onidleentry.
*/
ret = dt_init_idle_driver(drv, sbi_cpuidle_state_match, 1); if (ret <= 0) {
pr_debug("HART%ld: failed to parse DT idle states\n",
cpuid_to_hartid_map(cpu)); return ret ? : -ENODEV;
}
state_count = ret + 1; /* Include WFI state as well */
/* Initialize idle states from DT. */
ret = sbi_cpuidle_dt_init_states(dev, drv, cpu, state_count); if (ret) {
pr_err("HART%ld: failed to init idle states\n",
cpuid_to_hartid_map(cpu)); return ret;
}
if (cpuidle_disabled()) return0;
ret = cpuidle_register(drv, NULL); if (ret) goto deinit;
/* Allow power off when OSI is available. */ if (sbi_cpuidle_use_osi)
pd->power_off = sbi_cpuidle_pd_power_off; else
pd->flags |= GENPD_FLAG_ALWAYS_ON;
/* Use governor for CPU PM domains if it has some states to manage. */
pd_gov = pd->states ? &pm_domain_cpu_gov : NULL;
ret = pm_genpd_init(pd, pd_gov, false); if (ret) goto free_pd_prov;
ret = of_genpd_add_provider_simple(np, pd); if (ret) goto remove_pd;
/* Detect OSI support based on CPU DT nodes */
sbi_cpuidle_use_osi = true;
for_each_possible_cpu(cpu) { struct device_node *np __free(device_node) = of_cpu_device_node_get(cpu); if (np &&
of_property_present(np, "power-domains") &&
of_property_present(np, "power-domain-names")) { continue;
} else {
sbi_cpuidle_use_osi = false; break;
}
}
/* Populate generic power domains from DT nodes */
pds_node = of_find_node_by_path("/cpus/power-domains"); if (pds_node) {
ret = sbi_genpd_probe(pds_node);
of_node_put(pds_node); if (ret) return ret;
}
/* Initialize CPU idle driver for each present CPU */
for_each_present_cpu(cpu) {
ret = sbi_cpuidle_init_cpu(&pdev->dev, cpu); if (ret) {
pr_debug("HART%ld: idle driver init failed\n",
cpuid_to_hartid_map(cpu)); goto out_fail;
}
}
/* Setup CPU hotplut notifiers */
sbi_idle_init_cpuhp();
if (cpuidle_disabled())
pr_info("cpuidle is disabled\n"); else
pr_info("idle driver registered for all CPUs\n");
return0;
out_fail: while (--cpu >= 0) {
dev = per_cpu(cpuidle_devices, cpu);
drv = cpuidle_get_cpu_driver(dev);
cpuidle_unregister(drv);
sbi_cpuidle_deinit_cpu(cpu);
}
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.