Unverified Commit 9d976d67 authored by Anup Patel's avatar Anup Patel Committed by Palmer Dabbelt
Browse files

cpuidle: Factor-out power domain related code from PSCI domain driver



The generic power domain related code in PSCI domain driver is largely
independent of PSCI and can be shared with RISC-V SBI domain driver
hence we factor-out this code into dt_idle_genpd.c and dt_idle_genpd.h.

Signed-off-by: default avatarAnup Patel <anup.patel@wdc.com>
Signed-off-by: default avatarAnup Patel <apatel@ventanamicro.com>
Reviewed-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Signed-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parent b8200905
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -5051,6 +5051,13 @@ S: Supported
F:	drivers/cpuidle/cpuidle-psci.h
F:	drivers/cpuidle/cpuidle-psci-domain.c
CPUIDLE DRIVER - DT IDLE PM DOMAIN
M:	Ulf Hansson <ulf.hansson@linaro.org>
L:	linux-pm@vger.kernel.org
S:	Supported
F:	drivers/cpuidle/dt_idle_genpd.c
F:	drivers/cpuidle/dt_idle_genpd.h
CRAMFS FILESYSTEM
M:	Nicolas Pitre <nico@fluxnic.net>
S:	Maintained
+4 −0
Original line number Diff line number Diff line
@@ -47,6 +47,10 @@ config CPU_IDLE_GOV_HALTPOLL
config DT_IDLE_STATES
	bool

config DT_IDLE_GENPD
	depends on PM_GENERIC_DOMAINS_OF
	bool

menu "ARM CPU Idle Drivers"
depends on ARM || ARM64
source "drivers/cpuidle/Kconfig.arm"
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ config ARM_PSCI_CPUIDLE_DOMAIN
	bool "PSCI CPU idle Domain"
	depends on ARM_PSCI_CPUIDLE
	depends on PM_GENERIC_DOMAINS_OF
	select DT_IDLE_GENPD
	default y
	help
	  Select this to enable the PSCI based CPUidle driver to use PM domains,
+1 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
obj-$(CONFIG_DT_IDLE_STATES)		  += dt_idle_states.o
obj-$(CONFIG_DT_IDLE_GENPD)		  += dt_idle_genpd.o
obj-$(CONFIG_ARCH_HAS_CPU_RELAX)	  += poll_state.o
obj-$(CONFIG_HALTPOLL_CPUIDLE)		  += cpuidle-haltpoll.o

+5 −133
Original line number Diff line number Diff line
@@ -47,73 +47,14 @@ static int psci_pd_power_off(struct generic_pm_domain *pd)
	return 0;
}

static int psci_pd_parse_state_nodes(struct genpd_power_state *states,
				     int state_count)
{
	int i, ret;
	u32 psci_state, *psci_state_buf;

	for (i = 0; i < state_count; i++) {
		ret = psci_dt_parse_state_node(to_of_node(states[i].fwnode),
					&psci_state);
		if (ret)
			goto free_state;

		psci_state_buf = kmalloc(sizeof(u32), GFP_KERNEL);
		if (!psci_state_buf) {
			ret = -ENOMEM;
			goto free_state;
		}
		*psci_state_buf = psci_state;
		states[i].data = psci_state_buf;
	}

	return 0;

free_state:
	i--;
	for (; i >= 0; i--)
		kfree(states[i].data);
	return ret;
}

static int psci_pd_parse_states(struct device_node *np,
			struct genpd_power_state **states, int *state_count)
{
	int ret;

	/* Parse the domain idle states. */
	ret = of_genpd_parse_idle_states(np, states, state_count);
	if (ret)
		return ret;

	/* Fill out the PSCI specifics for each found state. */
	ret = psci_pd_parse_state_nodes(*states, *state_count);
	if (ret)
		kfree(*states);

	return ret;
}

static void psci_pd_free_states(struct genpd_power_state *states,
				unsigned int state_count)
{
	int i;

	for (i = 0; i < state_count; i++)
		kfree(states[i].data);
	kfree(states);
}

static int psci_pd_init(struct device_node *np, bool use_osi)
{
	struct generic_pm_domain *pd;
	struct psci_pd_provider *pd_provider;
	struct dev_power_governor *pd_gov;
	struct genpd_power_state *states = NULL;
	int ret = -ENOMEM, state_count = 0;

	pd = kzalloc(sizeof(*pd), GFP_KERNEL);
	pd = dt_idle_pd_alloc(np, psci_dt_parse_state_node);
	if (!pd)
		goto out;

@@ -121,22 +62,6 @@ static int psci_pd_init(struct device_node *np, bool use_osi)
	if (!pd_provider)
		goto free_pd;

	pd->name = kasprintf(GFP_KERNEL, "%pOF", np);
	if (!pd->name)
		goto free_pd_prov;

	/*
	 * Parse the domain idle states and let genpd manage the state selection
	 * for those being compatible with "domain-idle-state".
	 */
	ret = psci_pd_parse_states(np, &states, &state_count);
	if (ret)
		goto free_name;

	pd->free_states = psci_pd_free_states;
	pd->name = kbasename(pd->name);
	pd->states = states;
	pd->state_count = state_count;
	pd->flags |= GENPD_FLAG_IRQ_SAFE | GENPD_FLAG_CPU_DOMAIN;

	/* Allow power off when OSI has been successfully enabled. */
@@ -149,10 +74,8 @@ static int psci_pd_init(struct device_node *np, bool use_osi)
	pd_gov = state_count > 0 ? &pm_domain_cpu_gov : NULL;

	ret = pm_genpd_init(pd, pd_gov, false);
	if (ret) {
		psci_pd_free_states(states, state_count);
		goto free_name;
	}
	if (ret)
		goto free_pd_prov;

	ret = of_genpd_add_provider_simple(np, pd);
	if (ret)
@@ -166,12 +89,10 @@ static int psci_pd_init(struct device_node *np, bool use_osi)

remove_pd:
	pm_genpd_remove(pd);
free_name:
	kfree(pd->name);
free_pd_prov:
	kfree(pd_provider);
free_pd:
	kfree(pd);
	dt_idle_pd_free(pd);
out:
	pr_err("failed to init PM domain ret=%d %pOF\n", ret, np);
	return ret;
@@ -195,30 +116,6 @@ static void psci_pd_remove(void)
	}
}

static int psci_pd_init_topology(struct device_node *np)
{
	struct device_node *node;
	struct of_phandle_args child, parent;
	int ret;

	for_each_child_of_node(np, node) {
		if (of_parse_phandle_with_args(node, "power-domains",
					"#power-domain-cells", 0, &parent))
			continue;

		child.np = node;
		child.args_count = 0;
		ret = of_genpd_add_subdomain(&parent, &child);
		of_node_put(parent.np);
		if (ret) {
			of_node_put(node);
			return ret;
		}
	}

	return 0;
}

static bool psci_pd_try_set_osi_mode(void)
{
	int ret;
@@ -282,7 +179,7 @@ static int psci_cpuidle_domain_probe(struct platform_device *pdev)
		goto no_pd;

	/* Link genpd masters/subdomains to model the CPU topology. */
	ret = psci_pd_init_topology(np);
	ret = dt_idle_pd_init_topology(np);
	if (ret)
		goto remove_pd;

@@ -314,28 +211,3 @@ static int __init psci_idle_init_domains(void)
	return platform_driver_register(&psci_cpuidle_domain_driver);
}
subsys_initcall(psci_idle_init_domains);

struct device *psci_dt_attach_cpu(int cpu)
{
	struct device *dev;

	dev = dev_pm_domain_attach_by_name(get_cpu_device(cpu), "psci");
	if (IS_ERR_OR_NULL(dev))
		return dev;

	pm_runtime_irq_safe(dev);
	if (cpu_online(cpu))
		pm_runtime_get_sync(dev);

	dev_pm_syscore_device(dev, true);

	return dev;
}

void psci_dt_detach_cpu(struct device *dev)
{
	if (IS_ERR_OR_NULL(dev))
		return;

	dev_pm_domain_detach(dev, false);
}
Loading