diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2024-05-17 13:01:24 +0200 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2024-05-17 13:01:24 +0200 |
commit | 8bd6d5f1faffb560ec4ed3f72ab6b7be10985924 (patch) | |
tree | e59bcbca3e82391ee8e383065394216ada40beff /drivers/opp | |
parent | Merge tag 'pm-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafa... (diff) | |
parent | OPP: Fix required_opp_tables for multiple genpds using same table (diff) | |
download | linux-8bd6d5f1faffb560ec4ed3f72ab6b7be10985924.tar.xz linux-8bd6d5f1faffb560ec4ed3f72ab6b7be10985924.zip |
Merge tag 'opp-updates-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm into pm-opp
Merge OPP updates for v6.10 from Viresh Kumar:
"- Fix required_opp_tables for multiple genpds using same table (Viresh
Kumar)."
* tag 'opp-updates-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm:
OPP: Fix required_opp_tables for multiple genpds using same table
Diffstat (limited to 'drivers/opp')
-rw-r--r-- | drivers/opp/core.c | 31 |
1 files changed, 30 insertions, 1 deletions
diff --git a/drivers/opp/core.c b/drivers/opp/core.c index e233734b7220..cb4611fe1b5b 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -2394,7 +2394,8 @@ static void _opp_detach_genpd(struct opp_table *opp_table) static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev, const char * const *names, struct device ***virt_devs) { - struct device *virt_dev; + struct device *virt_dev, *gdev; + struct opp_table *genpd_table; int index = 0, ret = -EINVAL; const char * const *name = names; @@ -2428,6 +2429,34 @@ static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev, } /* + * The required_opp_tables parsing is not perfect, as the OPP + * core does the parsing solely based on the DT node pointers. + * The core sets the required_opp_tables entry to the first OPP + * table in the "opp_tables" list, that matches with the node + * pointer. + * + * If the target DT OPP table is used by multiple devices and + * they all create separate instances of 'struct opp_table' from + * it, then it is possible that the required_opp_tables entry + * may be set to the incorrect sibling device. + * + * Cross check it again and fix if required. + */ + gdev = dev_to_genpd_dev(virt_dev); + if (IS_ERR(gdev)) + return PTR_ERR(gdev); + + genpd_table = _find_opp_table(gdev); + if (!IS_ERR(genpd_table)) { + if (genpd_table != opp_table->required_opp_tables[index]) { + dev_pm_opp_put_opp_table(opp_table->required_opp_tables[index]); + opp_table->required_opp_tables[index] = genpd_table; + } else { + dev_pm_opp_put_opp_table(genpd_table); + } + } + + /* * Add the virtual genpd device as a user of the OPP table, so * we can call dev_pm_opp_set_opp() on it directly. * |