[PATCH] cpuidle: riscv-sbi: Allow cpuidle pd used by other devices
Nick Hu
nick.hu at sifive.com
Tue Aug 13 01:13:24 PDT 2024
To prevent the probe of consumer devices being deferred, create the
platform devices for each pd node under '/cpus/power-domains' and move the
driver initailization to the arch_initcall.
The consumer devices that inside the cpu/cluster power domain may register
the genpd notifier where their power domains are point to the pd nodes
under '/cpus/power-domains'. If the cpuidle.off==1, the genpd notifier
will fail due to sbi_cpuidle_pd_allow_domain_state is not set. We also
need the sbi_cpuidle_cpuhp_up/down to invoke the callbacks. Therefore,
add a cpuidle_disabled() check before registering the cpuidle driver to
address the issue.
Signed-off-by: Nick Hu <nick.hu at sifive.com>
Link: https://lore.kernel.org/lkml/20240226065113.1690534-1-nick.hu@sifive.com/
Suggested-by: Anup Patel <apatel at ventanamicro.com>
---
drivers/cpuidle/cpuidle-riscv-sbi.c | 24 +++++++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/drivers/cpuidle/cpuidle-riscv-sbi.c b/drivers/cpuidle/cpuidle-riscv-sbi.c
index a6e123dfe394..d6b01fc64f94 100644
--- a/drivers/cpuidle/cpuidle-riscv-sbi.c
+++ b/drivers/cpuidle/cpuidle-riscv-sbi.c
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
@@ -25,6 +26,7 @@
#include <asm/smp.h>
#include <asm/suspend.h>
+#include "cpuidle.h"
#include "dt_idle_states.h"
#include "dt_idle_genpd.h"
@@ -336,6 +338,9 @@ static int sbi_cpuidle_init_cpu(struct device *dev, int cpu)
return ret;
}
+ if (cpuidle_disabled())
+ return 0;
+
ret = cpuidle_register(drv, NULL);
if (ret)
goto deinit;
@@ -380,20 +385,26 @@ static int sbi_cpuidle_pd_power_off(struct generic_pm_domain *pd)
struct sbi_pd_provider {
struct list_head link;
struct device_node *node;
+ struct platform_device *pdev;
};
static LIST_HEAD(sbi_pd_providers);
static int sbi_pd_init(struct device_node *np)
{
+ struct platform_device *pdev;
struct generic_pm_domain *pd;
struct sbi_pd_provider *pd_provider;
struct dev_power_governor *pd_gov;
int ret = -ENOMEM;
+ pdev = of_platform_device_create(np, np->name, NULL);
+ if (!pdev)
+ goto out;
+
pd = dt_idle_pd_alloc(np, sbi_dt_parse_state_node);
if (!pd)
- goto out;
+ goto free_pdev;
pd_provider = kzalloc(sizeof(*pd_provider), GFP_KERNEL);
if (!pd_provider)
@@ -419,6 +430,7 @@ static int sbi_pd_init(struct device_node *np)
goto remove_pd;
pd_provider->node = of_node_get(np);
+ pd_provider->pdev = pdev;
list_add(&pd_provider->link, &sbi_pd_providers);
pr_debug("init PM domain %s\n", pd->name);
@@ -430,6 +442,8 @@ static int sbi_pd_init(struct device_node *np)
kfree(pd_provider);
free_pd:
dt_idle_pd_free(pd);
+free_pdev:
+ of_platform_device_destroy(&pdev->dev, NULL);
out:
pr_err("failed to init PM domain ret=%d %pOF\n", ret, np);
return ret;
@@ -447,6 +461,7 @@ static void sbi_pd_remove(void)
if (!IS_ERR(genpd))
kfree(genpd);
+ of_platform_device_destroy(&pd_provider->pdev->dev, NULL);
of_node_put(pd_provider->node);
list_del(&pd_provider->link);
kfree(pd_provider);
@@ -548,7 +563,10 @@ static int sbi_cpuidle_probe(struct platform_device *pdev)
/* Setup CPU hotplut notifiers */
sbi_idle_init_cpuhp();
- pr_info("idle driver registered for all CPUs\n");
+ if (cpuidle_disabled())
+ pr_info("cpuidle is disabled\n");
+ else
+ pr_info("idle driver registered for all CPUs\n");
return 0;
@@ -592,4 +610,4 @@ static int __init sbi_cpuidle_init(void)
return 0;
}
-device_initcall(sbi_cpuidle_init);
+arch_initcall(sbi_cpuidle_init);
--
2.34.1
More information about the linux-riscv
mailing list