All of lore.kernel.org
 help / color / mirror / Atom feed
From: Viresh Kumar <viresh.kumar@linaro.org>
To: Rafael Wysocki <rjw@rjwysocki.net>
Cc: linaro-kernel@lists.linaro.org, linux-pm@vger.kernel.org,
	shawn.guo@linaro.org, sboyd@codeaurora.org,
	linux-arm-msm@vger.kernel.org, spk.linux@gmail.com,
	thomas.ab@samsung.com, t.figa@samsung.com,
	santosh.shilimkar@ti.com, thomas.petazzoni@free-electrons.com,
	pramod.gurav@smartplayin.com,
	Viresh Kumar <viresh.kumar@linaro.org>
Subject: [PATCH V3 06/10] cpufreq: cpu0: Move per-cluster initialization code to ->init()
Date: Thu, 28 Aug 2014 11:22:28 +0530	[thread overview]
Message-ID: <707301c68f9f745f33ec294d277de52fdbda0a98.1409201048.git.viresh.kumar@linaro.org> (raw)
In-Reply-To: <cover.1409201048.git.viresh.kumar@linaro.org>
In-Reply-To: <cover.1409201048.git.viresh.kumar@linaro.org>

Currently this driver only support platforms on which all CPUs share clock &
voltage lines and there is requirement to support platforms which have separate
clock & voltage lines for CPUs, like Qualcomm's Krait and ARM's big LITTLE.

Each group of CPUs sharing clock/voltage lines are represented by 'struct
cpufreq_policy' in cpufreq framework. And core calls ->init() once for each
policy.

Currently we do all initialization/allocation from probe() which wouldn't work
for above scenario. To make it work for these platforms, the first step is to
move all initialization/allocation to ->init() and add ->exit() to do the
reverse of it.

Also, remove all global variables and allocate space for them at runtime.

This patch creates 'struct private_data' for keeping all such information and
a pointer to that would be stored in policy->driver_data.

The changed probe() routine now tries to see if regulator/clocks are available
or we need to defer probe. In case they are available, it registers cpufreq
driver. Otherwise, returns with -EPROBE_DEFER.

We still *don't* support platforms with separate clock/voltage lines for CPUs.
This would be done in a separate patch later.

Tested-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
 drivers/cpufreq/cpufreq-cpu0.c | 189 +++++++++++++++++++++++++++++------------
 1 file changed, 136 insertions(+), 53 deletions(-)

diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index 741ff22..03e352b 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -28,18 +28,21 @@
 #include <linux/slab.h>
 #include <linux/thermal.h>
 
-static unsigned int transition_latency;
-static unsigned int voltage_tolerance; /* in percentage */
-
-static struct device *cpu_dev;
-static struct clk *cpu_clk;
-static struct regulator *cpu_reg;
-static struct cpufreq_frequency_table *freq_table;
-static struct thermal_cooling_device *cdev;
+struct private_data {
+	struct device *cpu_dev;
+	struct regulator *cpu_reg;
+	struct thermal_cooling_device *cdev;
+	unsigned int voltage_tolerance; /* in percentage */
+};
 
 static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
 {
 	struct dev_pm_opp *opp;
+	struct cpufreq_frequency_table *freq_table = policy->freq_table;
+	struct clk *cpu_clk = policy->clk;
+	struct private_data *priv = policy->driver_data;
+	struct device *cpu_dev = priv->cpu_dev;
+	struct regulator *cpu_reg = priv->cpu_reg;
 	unsigned long volt = 0, volt_old = 0, tol = 0;
 	unsigned int old_freq, new_freq;
 	long freq_Hz, freq_exact;
@@ -64,7 +67,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
 		}
 		volt = dev_pm_opp_get_voltage(opp);
 		rcu_read_unlock();
-		tol = volt * voltage_tolerance / 100;
+		tol = volt * priv->voltage_tolerance / 100;
 		volt_old = regulator_get_voltage(cpu_reg);
 	}
 
@@ -103,26 +106,13 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
 	return ret;
 }
 
-static int cpu0_cpufreq_init(struct cpufreq_policy *policy)
-{
-	policy->clk = cpu_clk;
-	return cpufreq_generic_init(policy, freq_table, transition_latency);
-}
-
-static struct cpufreq_driver cpu0_cpufreq_driver = {
-	.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
-	.verify = cpufreq_generic_frequency_table_verify,
-	.target_index = cpu0_set_target,
-	.get = cpufreq_generic_get,
-	.init = cpu0_cpufreq_init,
-	.name = "generic_cpu0",
-	.attr = cpufreq_generic_attr,
-};
-
-static int cpu0_cpufreq_probe(struct platform_device *pdev)
+static int allocate_resources(struct device **cdev,
+			      struct regulator **creg, struct clk **cclk)
 {
-	struct device_node *np;
-	int ret;
+	struct device *cpu_dev;
+	struct regulator *cpu_reg;
+	struct clk *cpu_clk;
+	int ret = 0;
 
 	cpu_dev = get_cpu_device(0);
 	if (!cpu_dev) {
@@ -130,12 +120,6 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	np = of_node_get(cpu_dev->of_node);
-	if (!np) {
-		dev_err(cpu_dev, "failed to find cpu0 node\n");
-		return -ENOENT;
-	}
-
 	cpu_reg = regulator_get_optional(cpu_dev, "cpu0");
 	if (IS_ERR(cpu_reg)) {
 		/*
@@ -144,8 +128,7 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
 		 */
 		if (PTR_ERR(cpu_reg) == -EPROBE_DEFER) {
 			dev_dbg(cpu_dev, "cpu0 regulator not ready, retry\n");
-			ret = -EPROBE_DEFER;
-			goto out_put_node;
+			return -EPROBE_DEFER;
 		}
 		dev_warn(cpu_dev, "failed to get cpu0 regulator: %ld\n",
 			 PTR_ERR(cpu_reg));
@@ -153,6 +136,10 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
 
 	cpu_clk = clk_get(cpu_dev, NULL);
 	if (IS_ERR(cpu_clk)) {
+		/* put regulator */
+		if (!IS_ERR(cpu_reg))
+			regulator_put(cpu_reg);
+
 		ret = PTR_ERR(cpu_clk);
 
 		/*
@@ -163,8 +150,39 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
 			dev_dbg(cpu_dev, "cpu0 clock not ready, retry\n");
 		else
 			dev_err(cpu_dev, "failed to get cpu0 clock: %d\n", ret);
+	} else {
+		*cdev = cpu_dev;
+		*creg = cpu_reg;
+		*cclk = cpu_clk;
+	}
+
+	return ret;
+}
+
+static int cpu0_cpufreq_init(struct cpufreq_policy *policy)
+{
+	struct cpufreq_frequency_table *freq_table;
+	struct thermal_cooling_device *cdev;
+	struct device_node *np;
+	struct private_data *priv;
+	struct device *cpu_dev;
+	struct regulator *cpu_reg;
+	struct clk *cpu_clk;
+	unsigned int transition_latency;
+	int ret;
+
+	/* We only support cpu0 currently */
+	ret = allocate_resources(&cpu_dev, &cpu_reg, &cpu_clk);
+	if (ret) {
+		pr_err("%s: Failed to allocate resources\n: %d", __func__, ret);
+		return ret;
+	}
 
-		goto out_put_reg;
+	np = of_node_get(cpu_dev->of_node);
+	if (!np) {
+		dev_err(cpu_dev, "failed to find cpu%d node\n", policy->cpu);
+		ret = -ENOENT;
+		goto out_put_reg_clk;
 	}
 
 	/* OPPs might be populated at runtime, don't check for error here */
@@ -173,10 +191,16 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
 	ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
 	if (ret) {
 		dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
-		goto out_put_clk;
+		goto out_put_node;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		ret = -ENOMEM;
+		goto out_free_table;
 	}
 
-	of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
+	of_property_read_u32(np, "voltage-tolerance", &priv->voltage_tolerance);
 
 	if (of_property_read_u32(np, "clock-latency", &transition_latency))
 		transition_latency = CPUFREQ_ETERNAL;
@@ -206,12 +230,6 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
 			transition_latency += ret * 1000;
 	}
 
-	ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
-	if (ret) {
-		dev_err(cpu_dev, "failed to register driver: %d\n", ret);
-		goto out_free_table;
-	}
-
 	/*
 	 * For now, just loading the cooling device;
 	 * thermal DT code takes care of matching them.
@@ -222,29 +240,94 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
 			dev_err(cpu_dev,
 				"running cpufreq without cooling device: %ld\n",
 				PTR_ERR(cdev));
+		else
+			priv->cdev = cdev;
 	}
-
 	of_node_put(np);
+
+	priv->cpu_dev = cpu_dev;
+	priv->cpu_reg = cpu_reg;
+	policy->driver_data = priv;
+
+	policy->clk = cpu_clk;
+	ret = cpufreq_generic_init(policy, freq_table, transition_latency);
+	if (ret)
+		goto out_cooling_unregister;
+
 	return 0;
 
+out_cooling_unregister:
+	cpufreq_cooling_unregister(priv->cdev);
+	kfree(priv);
 out_free_table:
 	dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
-out_put_clk:
+out_put_node:
+	of_node_put(np);
+out_put_reg_clk:
 	clk_put(cpu_clk);
-out_put_reg:
 	if (!IS_ERR(cpu_reg))
 		regulator_put(cpu_reg);
-out_put_node:
-	of_node_put(np);
+
+	return ret;
+}
+
+static int cpu0_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	struct private_data *priv = policy->driver_data;
+
+	cpufreq_cooling_unregister(priv->cdev);
+	dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
+	clk_put(policy->clk);
+	if (!IS_ERR(priv->cpu_reg))
+		regulator_put(priv->cpu_reg);
+	kfree(priv);
+
+	return 0;
+}
+
+static struct cpufreq_driver cpu0_cpufreq_driver = {
+	.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
+	.verify = cpufreq_generic_frequency_table_verify,
+	.target_index = cpu0_set_target,
+	.get = cpufreq_generic_get,
+	.init = cpu0_cpufreq_init,
+	.exit = cpu0_cpufreq_exit,
+	.name = "generic_cpu0",
+	.attr = cpufreq_generic_attr,
+};
+
+static int cpu0_cpufreq_probe(struct platform_device *pdev)
+{
+	struct device *cpu_dev;
+	struct regulator *cpu_reg;
+	struct clk *cpu_clk;
+	int ret;
+
+	/*
+	 * All per-cluster (CPUs sharing clock/voltages) initialization is done
+	 * from ->init(). In probe(), we just need to make sure that clk and
+	 * regulators are available. Else defer probe and retry.
+	 *
+	 * FIXME: Is checking this only for CPU0 sufficient ?
+	 */
+	ret = allocate_resources(&cpu_dev, &cpu_reg, &cpu_clk);
+	if (ret)
+		return ret;
+
+	clk_put(cpu_clk);
+	if (!IS_ERR(cpu_reg))
+		regulator_put(cpu_reg);
+
+	ret = cpufreq_register_driver(&cpu0_cpufreq_driver);
+	if (ret)
+		dev_err(cpu_dev, "failed register driver: %d\n", ret);
+
 	return ret;
 }
 
 static int cpu0_cpufreq_remove(struct platform_device *pdev)
 {
-	cpufreq_cooling_unregister(cdev);
 	cpufreq_unregister_driver(&cpu0_cpufreq_driver);
-	dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
-
 	return 0;
 }
 
-- 
2.0.3.693.g996b0fd


  parent reply	other threads:[~2014-08-28  5:52 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-28  5:52 [PATCH V3 00/10] CPUFreq: cpufreq-cpu0 updates for 3.{17|18 ?} Viresh Kumar
2014-08-28  5:52 ` [PATCH V3 01/10] cpufreq: Add support for per-policy driver data Viresh Kumar
2014-08-28  5:52 ` [PATCH V3 02/10] cpufreq: cpu0: Update Module Author Viresh Kumar
2014-08-28  5:52 ` [PATCH V3 03/10] cpufreq: cpu0: don't validate clock on clk_put() Viresh Kumar
2014-08-28  5:52 ` [PATCH V3 04/10] cpufreq: cpu0: print relevant error when we defer probe Viresh Kumar
2014-08-28  5:52 ` [PATCH V3 05/10] cpufreq: cpu0: use dev_{err|warn|dbg} instead of pr_{err|warn|debug} Viresh Kumar
2014-08-28  5:52 ` Viresh Kumar [this message]
2014-08-28  5:52 ` [PATCH V3 07/10] cpufreq: cpu0: try regulators with name "cpu-supply" Viresh Kumar
2014-08-28  5:52 ` [PATCH V3 08/10] cpufreq: cpu0: Make allocate_resources() work for any CPU Viresh Kumar
2014-08-28  5:52 ` [PATCH V3 09/10] cpufreq: cpu0: rename driver and internals to 'cpufreq_generic' Viresh Kumar
2014-09-08 23:34   ` Rafael J. Wysocki
2014-09-08 23:18     ` Stephen Boyd
2014-09-08 23:39       ` Rafael J. Wysocki
2014-09-08 23:52         ` Rafael J. Wysocki
2014-09-09  0:01           ` Stephen Boyd
2014-09-09  4:47             ` Viresh Kumar
2014-09-09 13:29               ` Rafael J. Wysocki
2014-09-09 13:52                 ` Viresh Kumar
2014-09-09  0:02           ` Rafael J. Wysocki
2014-08-28  5:52 ` [PATCH V3 10/10] cpufreq: generic: set platform_{driver|device} '.name' to 'cpufreq-generic' Viresh Kumar
2014-08-28 14:16 ` [PATCH V3 00/10] CPUFreq: cpufreq-cpu0 updates for 3.{17|18 ?} Santosh Shilimkar
2014-09-01  6:40   ` Viresh Kumar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=707301c68f9f745f33ec294d277de52fdbda0a98.1409201048.git.viresh.kumar@linaro.org \
    --to=viresh.kumar@linaro.org \
    --cc=linaro-kernel@lists.linaro.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=pramod.gurav@smartplayin.com \
    --cc=rjw@rjwysocki.net \
    --cc=santosh.shilimkar@ti.com \
    --cc=sboyd@codeaurora.org \
    --cc=shawn.guo@linaro.org \
    --cc=spk.linux@gmail.com \
    --cc=t.figa@samsung.com \
    --cc=thomas.ab@samsung.com \
    --cc=thomas.petazzoni@free-electrons.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.