Skip to content

Commit 9ec87c5

Browse files
committed
OPP: Fix support for required OPPs for multiple PM domains
It has turned out that having _set_required_opps() to recursively call dev_pm_opp_set_opp() to set the required OPPs, doesn't really work as well as we expected. More precisely, at each recursive call to dev_pm_opp_set_opp() we are changing an OPP for a required_dev that belongs to a required-OPP table. The problem with this, is that we may have several devices sharing the same required-OPP table, which leads to an incorrect behaviour in regards to aggregating the per device votes. To fix the problem for a required-OPP table belonging to a PM domain, which is the only existing usecase for now, let's simply replace the call to dev_pm_opp_set_opp() in _set_required_opps() by a call to _set_opp_level(). Moving forward we may potentially need to add support for other types of required-OPP tables. In this case, the aggregation needs to be thought of. Fixes: e37440e ("OPP: Call dev_pm_opp_set_opp() for required OPPs") Cc: [email protected] Signed-off-by: Ulf Hansson <[email protected]> Acked-by: Viresh Kumar <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 52dd070 commit 9ec87c5

File tree

1 file changed

+22
-34
lines changed

1 file changed

+22
-34
lines changed

drivers/opp/core.c

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,27 @@ static int _set_opp_bw(const struct opp_table *opp_table,
10611061
return 0;
10621062
}
10631063

1064+
static int _set_opp_level(struct device *dev, struct dev_pm_opp *opp)
1065+
{
1066+
unsigned int level = 0;
1067+
int ret = 0;
1068+
1069+
if (opp) {
1070+
if (opp->level == OPP_LEVEL_UNSET)
1071+
return 0;
1072+
1073+
level = opp->level;
1074+
}
1075+
1076+
/* Request a new performance state through the device's PM domain. */
1077+
ret = dev_pm_domain_set_performance_state(dev, level);
1078+
if (ret)
1079+
dev_err(dev, "Failed to set performance state %u (%d)\n", level,
1080+
ret);
1081+
1082+
return ret;
1083+
}
1084+
10641085
/* This is only called for PM domain for now */
10651086
static int _set_required_opps(struct device *dev, struct opp_table *opp_table,
10661087
struct dev_pm_opp *opp, bool up)
@@ -1091,7 +1112,7 @@ static int _set_required_opps(struct device *dev, struct opp_table *opp_table,
10911112
if (devs[index]) {
10921113
required_opp = opp ? opp->required_opps[index] : NULL;
10931114

1094-
ret = dev_pm_opp_set_opp(devs[index], required_opp);
1115+
ret = _set_opp_level(devs[index], required_opp);
10951116
if (ret)
10961117
return ret;
10971118
}
@@ -1102,27 +1123,6 @@ static int _set_required_opps(struct device *dev, struct opp_table *opp_table,
11021123
return 0;
11031124
}
11041125

1105-
static int _set_opp_level(struct device *dev, struct dev_pm_opp *opp)
1106-
{
1107-
unsigned int level = 0;
1108-
int ret = 0;
1109-
1110-
if (opp) {
1111-
if (opp->level == OPP_LEVEL_UNSET)
1112-
return 0;
1113-
1114-
level = opp->level;
1115-
}
1116-
1117-
/* Request a new performance state through the device's PM domain. */
1118-
ret = dev_pm_domain_set_performance_state(dev, level);
1119-
if (ret)
1120-
dev_err(dev, "Failed to set performance state %u (%d)\n", level,
1121-
ret);
1122-
1123-
return ret;
1124-
}
1125-
11261126
static void _find_current_opp(struct device *dev, struct opp_table *opp_table)
11271127
{
11281128
struct dev_pm_opp *opp = ERR_PTR(-ENODEV);
@@ -2457,18 +2457,6 @@ static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,
24572457
}
24582458
}
24592459

2460-
/*
2461-
* Add the virtual genpd device as a user of the OPP table, so
2462-
* we can call dev_pm_opp_set_opp() on it directly.
2463-
*
2464-
* This will be automatically removed when the OPP table is
2465-
* removed, don't need to handle that here.
2466-
*/
2467-
if (!_add_opp_dev(virt_dev, opp_table->required_opp_tables[index])) {
2468-
ret = -ENOMEM;
2469-
goto err;
2470-
}
2471-
24722460
opp_table->required_devs[index] = virt_dev;
24732461
index++;
24742462
name++;

0 commit comments

Comments
 (0)