aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2018-05-22 07:08:08 -0400
committerViresh Kumar <viresh.kumar@linaro.org>2018-05-22 07:30:09 -0400
commit25419de1b8dda24f3e02478b12b724a9b0cc4e78 (patch)
tree711d9dea1741493b2310780a42f0f4a4ef169598
parent6a89e012aaf4a978d4c896f3299cfc365e4a5eb8 (diff)
PM / OPP: Fix shared OPP table support in dev_pm_opp_set_supported_hw()
It should be fine to call dev_pm_opp_set_supported_hw() for all possible CPUs, even if some of them share the OPP table as the caller may not be aware of sharing policy. Lets increment the reference count of the OPP table and return its pointer. The caller need to call dev_pm_opp_put_supported_hw() the same number of times later on to drop all the references. To avoid adding another counter to count how many times dev_pm_opp_set_supported_hw() is called for the same OPP table, dev_pm_opp_put_supported_hw() frees the resources on the very first call made to it, assuming that the caller would be calling it sequentially for all the CPUs. We can revisit that if that assumption is broken in the future. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
-rw-r--r--drivers/opp/core.c26
1 files changed, 5 insertions, 21 deletions
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 6d3624ba89b6..481affb783f3 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -1157,7 +1157,6 @@ struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev,
1157 const u32 *versions, unsigned int count) 1157 const u32 *versions, unsigned int count)
1158{ 1158{
1159 struct opp_table *opp_table; 1159 struct opp_table *opp_table;
1160 int ret;
1161 1160
1162 opp_table = dev_pm_opp_get_opp_table(dev); 1161 opp_table = dev_pm_opp_get_opp_table(dev);
1163 if (!opp_table) 1162 if (!opp_table)
@@ -1166,29 +1165,20 @@ struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev,
1166 /* Make sure there are no concurrent readers while updating opp_table */ 1165 /* Make sure there are no concurrent readers while updating opp_table */
1167 WARN_ON(!list_empty(&opp_table->opp_list)); 1166 WARN_ON(!list_empty(&opp_table->opp_list));
1168 1167
1169 /* Do we already have a version hierarchy associated with opp_table? */ 1168 /* Another CPU that shares the OPP table has set the property ? */
1170 if (opp_table->supported_hw) { 1169 if (opp_table->supported_hw)
1171 dev_err(dev, "%s: Already have supported hardware list\n", 1170 return opp_table;
1172 __func__);
1173 ret = -EBUSY;
1174 goto err;
1175 }
1176 1171
1177 opp_table->supported_hw = kmemdup(versions, count * sizeof(*versions), 1172 opp_table->supported_hw = kmemdup(versions, count * sizeof(*versions),
1178 GFP_KERNEL); 1173 GFP_KERNEL);
1179 if (!opp_table->supported_hw) { 1174 if (!opp_table->supported_hw) {
1180 ret = -ENOMEM; 1175 dev_pm_opp_put_opp_table(opp_table);
1181 goto err; 1176 return ERR_PTR(-ENOMEM);
1182 } 1177 }
1183 1178
1184 opp_table->supported_hw_count = count; 1179 opp_table->supported_hw_count = count;
1185 1180
1186 return opp_table; 1181 return opp_table;
1187
1188err:
1189 dev_pm_opp_put_opp_table(opp_table);
1190
1191 return ERR_PTR(ret);
1192} 1182}
1193EXPORT_SYMBOL_GPL(dev_pm_opp_set_supported_hw); 1183EXPORT_SYMBOL_GPL(dev_pm_opp_set_supported_hw);
1194 1184
@@ -1205,12 +1195,6 @@ void dev_pm_opp_put_supported_hw(struct opp_table *opp_table)
1205 /* Make sure there are no concurrent readers while updating opp_table */ 1195 /* Make sure there are no concurrent readers while updating opp_table */
1206 WARN_ON(!list_empty(&opp_table->opp_list)); 1196 WARN_ON(!list_empty(&opp_table->opp_list));
1207 1197
1208 if (!opp_table->supported_hw) {
1209 pr_err("%s: Doesn't have supported hardware list\n",
1210 __func__);
1211 return;
1212 }
1213
1214 kfree(opp_table->supported_hw); 1198 kfree(opp_table->supported_hw);
1215 opp_table->supported_hw = NULL; 1199 opp_table->supported_hw = NULL;
1216 opp_table->supported_hw_count = 0; 1200 opp_table->supported_hw_count = 0;