aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2016-06-16 09:33:11 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-06-16 09:50:36 -0400
commit79ee2e8f730411a30b271d5f9cdeae189fa66174 (patch)
treea81eb12f087ea733260210bba0fa9a1a612f54d3
parentc8541203a680a63ba7dcc4e50cd25d40e9a13dff (diff)
PM / OPP: Add 'UNKNOWN' status for shared_opp in struct opp_table
dev_pm_opp_get_sharing_cpus() returns 0 even in the case when the OPP core doesn't know whether or not the table is shared. It works on the majority of platforms, where the OPP table is never created before invoking the function and then -ENODEV is returned by it. But in the case of one platform (Jetson TK1) at least, the situation is a bit different. The OPP table has been created (somehow) before dev_pm_opp_get_sharing_cpus() is called and it returns 0. Its caller treats that as 'the CPUs don't share OPPs' and that leads to degraded performance. Fix this by converting 'shared_opp' in struct opp_table to an enum and making dev_pm_opp_get_sharing_cpus() return -EINVAL in case when the value of that field is "access unknown", so that the caller can handle it accordingly (cpufreq-dt considers that as 'all CPUs share the table', for example). Fixes: 6f707daa3833 "PM / OPP: Add dev_pm_opp_get_sharing_cpus()" Reported-and-tested-by: Alexandre Courbot <acourbot@nvidia.com> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> [ rjw : Subject & changelog ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/base/power/opp/cpu.c12
-rw-r--r--drivers/base/power/opp/of.c10
-rw-r--r--drivers/base/power/opp/opp.h8
3 files changed, 24 insertions, 6 deletions
diff --git a/drivers/base/power/opp/cpu.c b/drivers/base/power/opp/cpu.c
index 83d6e7ba1a34..8c3434bdb26d 100644
--- a/drivers/base/power/opp/cpu.c
+++ b/drivers/base/power/opp/cpu.c
@@ -211,7 +211,7 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev,
211 } 211 }
212 212
213 /* Mark opp-table as multiple CPUs are sharing it now */ 213 /* Mark opp-table as multiple CPUs are sharing it now */
214 opp_table->shared_opp = true; 214 opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
215 } 215 }
216unlock: 216unlock:
217 mutex_unlock(&opp_table_lock); 217 mutex_unlock(&opp_table_lock);
@@ -227,7 +227,8 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_sharing_cpus);
227 * 227 *
228 * This updates the @cpumask with CPUs that are sharing OPPs with @cpu_dev. 228 * This updates the @cpumask with CPUs that are sharing OPPs with @cpu_dev.
229 * 229 *
230 * Returns -ENODEV if OPP table isn't already present. 230 * Returns -ENODEV if OPP table isn't already present and -EINVAL if the OPP
231 * table's status is access-unknown.
231 * 232 *
232 * Locking: The internal opp_table and opp structures are RCU protected. 233 * Locking: The internal opp_table and opp structures are RCU protected.
233 * Hence this function internally uses RCU updater strategy with mutex locks 234 * Hence this function internally uses RCU updater strategy with mutex locks
@@ -249,9 +250,14 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
249 goto unlock; 250 goto unlock;
250 } 251 }
251 252
253 if (opp_table->shared_opp == OPP_TABLE_ACCESS_UNKNOWN) {
254 ret = -EINVAL;
255 goto unlock;
256 }
257
252 cpumask_clear(cpumask); 258 cpumask_clear(cpumask);
253 259
254 if (opp_table->shared_opp) { 260 if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED) {
255 list_for_each_entry(opp_dev, &opp_table->dev_list, node) 261 list_for_each_entry(opp_dev, &opp_table->dev_list, node)
256 cpumask_set_cpu(opp_dev->dev->id, cpumask); 262 cpumask_set_cpu(opp_dev->dev->id, cpumask);
257 } else { 263 } else {
diff --git a/drivers/base/power/opp/of.c b/drivers/base/power/opp/of.c
index 94d2010558e3..1dfd3dd92624 100644
--- a/drivers/base/power/opp/of.c
+++ b/drivers/base/power/opp/of.c
@@ -34,7 +34,10 @@ static struct opp_table *_managed_opp(const struct device_node *np)
34 * But the OPPs will be considered as shared only if the 34 * But the OPPs will be considered as shared only if the
35 * OPP table contains a "opp-shared" property. 35 * OPP table contains a "opp-shared" property.
36 */ 36 */
37 return opp_table->shared_opp ? opp_table : NULL; 37 if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED)
38 return opp_table;
39
40 return NULL;
38 } 41 }
39 } 42 }
40 43
@@ -353,7 +356,10 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
353 } 356 }
354 357
355 opp_table->np = opp_np; 358 opp_table->np = opp_np;
356 opp_table->shared_opp = of_property_read_bool(opp_np, "opp-shared"); 359 if (of_property_read_bool(opp_np, "opp-shared"))
360 opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
361 else
362 opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE;
357 363
358 mutex_unlock(&opp_table_lock); 364 mutex_unlock(&opp_table_lock);
359 365
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h
index 20f3be22e060..fabd5ca1a083 100644
--- a/drivers/base/power/opp/opp.h
+++ b/drivers/base/power/opp/opp.h
@@ -119,6 +119,12 @@ struct opp_device {
119#endif 119#endif
120}; 120};
121 121
122enum opp_table_access {
123 OPP_TABLE_ACCESS_UNKNOWN = 0,
124 OPP_TABLE_ACCESS_EXCLUSIVE = 1,
125 OPP_TABLE_ACCESS_SHARED = 2,
126};
127
122/** 128/**
123 * struct opp_table - Device opp structure 129 * struct opp_table - Device opp structure
124 * @node: table node - contains the devices with OPPs that 130 * @node: table node - contains the devices with OPPs that
@@ -166,7 +172,7 @@ struct opp_table {
166 /* For backward compatibility with v1 bindings */ 172 /* For backward compatibility with v1 bindings */
167 unsigned int voltage_tolerance_v1; 173 unsigned int voltage_tolerance_v1;
168 174
169 bool shared_opp; 175 enum opp_table_access shared_opp;
170 struct dev_pm_opp *suspend_opp; 176 struct dev_pm_opp *suspend_opp;
171 177
172 unsigned int *supported_hw; 178 unsigned int *supported_hw;