summaryrefslogtreecommitdiffstats
path: root/drivers/opp/core.c
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2019-11-25 09:27:58 +0100
committerViresh Kumar <viresh.kumar@linaro.org>2021-02-02 06:00:53 +0100
commit7eba0c7641b0009818e469dbfcdd87a0155ab9d4 (patch)
tree4c8591e45e740d406e41b5cd320166d667a2df6c /drivers/opp/core.c
parentopp: Remove dev_pm_opp_set_bw() (diff)
downloadlinux-7eba0c7641b0009818e469dbfcdd87a0155ab9d4.tar.xz
linux-7eba0c7641b0009818e469dbfcdd87a0155ab9d4.zip
opp: Allow lazy-linking of required-opps
The OPP core currently requires the required opp tables to be available before the dependent OPP table is added, as it needs to create links from the dependent OPP table to the required ones. This may not be convenient for all the platforms though, as this requires strict ordering for probing the drivers. This patch allows lazy-linking of the required-opps. The OPP tables for which the required-opp-tables aren't available at the time of their initialization, are added to a special list of OPP tables: lazy_opp_tables. Later on, whenever a new OPP table is registered with the OPP core, we check if it is required by an OPP table in the pending list; if yes, then we complete the linking then and there. An OPP table is marked unusable until the time all its required-opp tables are available. And if lazy-linking fails for an OPP table, the OPP core disables all of its OPPs to make sure no one can use them. Tested-by: Hsin-Yi Wang <hsinyi@chromium.org> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Diffstat (limited to 'drivers/opp/core.c')
-rw-r--r--drivers/opp/core.c45
1 files changed, 36 insertions, 9 deletions
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 6958a5cd2fd8..e03600547b98 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -27,6 +27,10 @@
* various states of availability.
*/
LIST_HEAD(opp_tables);
+
+/* OPP tables with uninitialized required OPPs */
+LIST_HEAD(lazy_opp_tables);
+
/* Lock to allow exclusive modification to the device and opp lists */
DEFINE_MUTEX(opp_table_lock);
/* Flag indicating that opp_tables list is being updated at the moment */
@@ -163,6 +167,10 @@ unsigned int dev_pm_opp_get_required_pstate(struct dev_pm_opp *opp,
return 0;
}
+ /* required-opps not fully initialized yet */
+ if (lazy_linking_pending(opp->opp_table))
+ return 0;
+
return opp->required_opps[index]->pstate;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_required_pstate);
@@ -885,6 +893,10 @@ static int _set_required_opps(struct device *dev,
if (!required_opp_tables)
return 0;
+ /* required-opps not fully initialized yet */
+ if (lazy_linking_pending(opp_table))
+ return -EBUSY;
+
/* Single genpd case */
if (!genpd_virt_devs)
return _set_required_opp(dev, dev, opp, 0);
@@ -1181,6 +1193,7 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index)
mutex_init(&opp_table->lock);
mutex_init(&opp_table->genpd_virt_dev_lock);
INIT_LIST_HEAD(&opp_table->dev_list);
+ INIT_LIST_HEAD(&opp_table->lazy);
/* Mark regulator count uninitialized */
opp_table->regulator_count = -1;
@@ -1632,6 +1645,21 @@ static int _opp_is_duplicate(struct device *dev, struct dev_pm_opp *new_opp,
return 0;
}
+void _required_opps_available(struct dev_pm_opp *opp, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (opp->required_opps[i]->available)
+ continue;
+
+ opp->available = false;
+ pr_warn("%s: OPP not supported by required OPP %pOF (%lu)\n",
+ __func__, opp->required_opps[i]->np, opp->rate);
+ return;
+ }
+}
+
/*
* Returns:
* 0: On success. And appropriate error message for duplicate OPPs.
@@ -1646,7 +1674,6 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
struct opp_table *opp_table, bool rate_not_available)
{
struct list_head *head;
- unsigned int i;
int ret;
mutex_lock(&opp_table->lock);
@@ -1672,15 +1699,11 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
__func__, new_opp->rate);
}
- for (i = 0; i < opp_table->required_opp_count; i++) {
- if (new_opp->required_opps[i]->available)
- continue;
+ /* required-opps not fully initialized yet */
+ if (lazy_linking_pending(opp_table))
+ return 0;
- new_opp->available = false;
- dev_warn(dev, "%s: OPP not supported by required OPP %pOF (%lu)\n",
- __func__, new_opp->required_opps[i]->np, new_opp->rate);
- break;
- }
+ _required_opps_available(new_opp, opp_table->required_opp_count);
return 0;
}
@@ -2388,6 +2411,10 @@ int dev_pm_opp_xlate_performance_state(struct opp_table *src_table,
if (!src_table || !src_table->required_opp_count)
return pstate;
+ /* required-opps not fully initialized yet */
+ if (lazy_linking_pending(src_table))
+ return -EBUSY;
+
for (i = 0; i < src_table->required_opp_count; i++) {
if (src_table->required_opp_tables[i]->np == dst_table->np)
break;