cpuidle: psci: Do not suspend topology CPUs on PREEMPT_RT

The runtime Power Management of CPU topology is not compatible with
PREEMPT_RT:

 1. Core cpuidle path disables IRQs.
 2. Core cpuidle calls cpuidle-psci.
 3. cpuidle-psci in __psci_enter_domain_idle_state() calls
    pm_runtime_put_sync_suspend() and pm_runtime_get_sync() which use
    spinlocks (which are sleeping on PREEMPT_RT).

Deep sleep modes are not a priority of Realtime kernels because the
latencies might become unpredictable.  On the other hand the PSCI CPU
idle power domain is a parent of other devices and power domain
controllers, thus it cannot be simply skipped (e.g. on Qualcomm SM8250).

Disable the idle callbacks in cpuidle-psci and mark the domain as
always on.  This is a trade-off between making PREEMPT_RT working and
still having a proper power domain hierarchy in the system.

Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Tested-by: Adrien Thierry <athierry@redhat.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
Krzysztof Kozlowski 2023-01-25 12:34:18 +01:00 committed by Rafael J. Wysocki
parent 41204a6076
commit f9901f6453
3 changed files with 16 additions and 2 deletions

View File

@ -24,6 +24,14 @@ config ARM_PSCI_CPUIDLE
It provides an idle driver that is capable of detecting and It provides an idle driver that is capable of detecting and
managing idle states through the PSCI firmware interface. managing idle states through the PSCI firmware interface.
The driver has limitations when used with PREEMPT_RT:
- If the idle states are described with the non-hierarchical layout,
all idle states are still available.
- If the idle states are described with the hierarchical layout,
only the idle states defined per CPU are available, but not the ones
being shared among a group of CPUs (aka cluster idle states).
config ARM_PSCI_CPUIDLE_DOMAIN config ARM_PSCI_CPUIDLE_DOMAIN
bool "PSCI CPU idle Domain" bool "PSCI CPU idle Domain"
depends on ARM_PSCI_CPUIDLE depends on ARM_PSCI_CPUIDLE

View File

@ -64,8 +64,11 @@ static int psci_pd_init(struct device_node *np, bool use_osi)
pd->flags |= GENPD_FLAG_IRQ_SAFE | GENPD_FLAG_CPU_DOMAIN; pd->flags |= GENPD_FLAG_IRQ_SAFE | GENPD_FLAG_CPU_DOMAIN;
/* Allow power off when OSI has been successfully enabled. */ /*
if (use_osi) * Allow power off when OSI has been successfully enabled.
* PREEMPT_RT is not yet ready to enter domain idle states.
*/
if (use_osi && !IS_ENABLED(CONFIG_PREEMPT_RT))
pd->power_off = psci_pd_power_off; pd->power_off = psci_pd_power_off;
else else
pd->flags |= GENPD_FLAG_ALWAYS_ON; pd->flags |= GENPD_FLAG_ALWAYS_ON;

View File

@ -231,6 +231,9 @@ static int psci_dt_cpu_init_topology(struct cpuidle_driver *drv,
if (!psci_has_osi_support()) if (!psci_has_osi_support())
return 0; return 0;
if (IS_ENABLED(CONFIG_PREEMPT_RT))
return 0;
data->dev = psci_dt_attach_cpu(cpu); data->dev = psci_dt_attach_cpu(cpu);
if (IS_ERR_OR_NULL(data->dev)) if (IS_ERR_OR_NULL(data->dev))
return PTR_ERR_OR_ZERO(data->dev); return PTR_ERR_OR_ZERO(data->dev);