OPP Updates for 6.10

- Fix required_opp_tables for multiple genpds using same table (Viresh
   Kumar).
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEx73Crsp7f6M6scA70rkcPK6BEhwFAmZHMgEACgkQ0rkcPK6B
 Ehxt2hAAicQ9wSD6ybYppMdqvgBtFb2Ui/qu1P2VEsL6wjv4cmoLDbj/2VII/J+X
 o1VVDj4IqITn7wZlBm9IdvBLV0/JnJassI9auNaknxJQM/fe5QeFagRf9v0wgBp5
 fmN3Wgi+ZEambvWkqN3KoXiIClSyZEIziWC8tsk43L7CkXMenMeQcfWqbbbrByT9
 UaHdHzTOUj9KBlS641+OqWjb3D3W8woTV2r54vhyDeZyPuGNLLQvyL+cUUaZfmT6
 vshE0QWIhxkzIuuAQGyVxrsFKsaYNgE1xuFGKdZyAXGG0over05sROw3mHG+pBWi
 MeW4xE8lx7zRig7/rh4hHZiNOJvS3PiUGad+HTmoZTnWTQXfQ023q2/IMzoY8m3i
 5ajAc7lJa0IpF+u5F2nR3BmUcx3rMS5/iKVHC8VIqTe6nZimG1pzZDkzr3gIzQRn
 Sx+Vvs/4tdeci6PwV6cei/Qot2N1kPCwvgGO3Dyp5cAcANwae0UqP8njSTMZqHFp
 6lb/x9g5ydJfBJO0u6cV/ZtcblJKhxnt89/JOqqD2I+6W4mVJELVRWB8nT5evckd
 f5TylQxjZCcjZHaoqVEmgyaebpvSYkHzKujGvGjVlDW0NNLquGLnT7yiDiGYEjpH
 S6Mwoz/AUToG1MIDS/fg/+6w1mcc1NW1O0YV3778u6Purh88Zfw=
 =+eou
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Rafael J. Wysocki 2024-05-17 13:01:24 +02:00
commit 8bd6d5f1fa
3 changed files with 46 additions and 1 deletions

View File

@ -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;
@ -2427,6 +2428,34 @@ static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,
goto err;
}
/*
* 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.

View File

@ -184,6 +184,16 @@ static struct generic_pm_domain *dev_to_genpd(struct device *dev)
return pd_to_genpd(dev->pm_domain);
}
struct device *dev_to_genpd_dev(struct device *dev)
{
struct generic_pm_domain *genpd = dev_to_genpd(dev);
if (IS_ERR(genpd))
return ERR_CAST(genpd);
return &genpd->dev;
}
static int genpd_stop_dev(const struct generic_pm_domain *genpd,
struct device *dev)
{

View File

@ -260,6 +260,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
int pm_genpd_init(struct generic_pm_domain *genpd,
struct dev_power_governor *gov, bool is_off);
int pm_genpd_remove(struct generic_pm_domain *genpd);
struct device *dev_to_genpd_dev(struct device *dev);
int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state);
int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb);
int dev_pm_genpd_remove_notifier(struct device *dev);
@ -307,6 +308,11 @@ static inline int pm_genpd_remove(struct generic_pm_domain *genpd)
return -EOPNOTSUPP;
}
static inline struct device *dev_to_genpd_dev(struct device *dev)
{
return ERR_PTR(-EOPNOTSUPP);
}
static inline int dev_pm_genpd_set_performance_state(struct device *dev,
unsigned int state)
{