Skip to content

Commit 8bd6d5f

Browse files
committed
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
2 parents 0c181b1 + 2a56c46 commit 8bd6d5f

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed

drivers/opp/core.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2394,7 +2394,8 @@ static void _opp_detach_genpd(struct opp_table *opp_table)
23942394
static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,
23952395
const char * const *names, struct device ***virt_devs)
23962396
{
2397-
struct device *virt_dev;
2397+
struct device *virt_dev, *gdev;
2398+
struct opp_table *genpd_table;
23982399
int index = 0, ret = -EINVAL;
23992400
const char * const *name = names;
24002401

@@ -2427,6 +2428,34 @@ static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,
24272428
goto err;
24282429
}
24292430

2431+
/*
2432+
* The required_opp_tables parsing is not perfect, as the OPP
2433+
* core does the parsing solely based on the DT node pointers.
2434+
* The core sets the required_opp_tables entry to the first OPP
2435+
* table in the "opp_tables" list, that matches with the node
2436+
* pointer.
2437+
*
2438+
* If the target DT OPP table is used by multiple devices and
2439+
* they all create separate instances of 'struct opp_table' from
2440+
* it, then it is possible that the required_opp_tables entry
2441+
* may be set to the incorrect sibling device.
2442+
*
2443+
* Cross check it again and fix if required.
2444+
*/
2445+
gdev = dev_to_genpd_dev(virt_dev);
2446+
if (IS_ERR(gdev))
2447+
return PTR_ERR(gdev);
2448+
2449+
genpd_table = _find_opp_table(gdev);
2450+
if (!IS_ERR(genpd_table)) {
2451+
if (genpd_table != opp_table->required_opp_tables[index]) {
2452+
dev_pm_opp_put_opp_table(opp_table->required_opp_tables[index]);
2453+
opp_table->required_opp_tables[index] = genpd_table;
2454+
} else {
2455+
dev_pm_opp_put_opp_table(genpd_table);
2456+
}
2457+
}
2458+
24302459
/*
24312460
* Add the virtual genpd device as a user of the OPP table, so
24322461
* we can call dev_pm_opp_set_opp() on it directly.

drivers/pmdomain/core.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,16 @@ static struct generic_pm_domain *dev_to_genpd(struct device *dev)
184184
return pd_to_genpd(dev->pm_domain);
185185
}
186186

187+
struct device *dev_to_genpd_dev(struct device *dev)
188+
{
189+
struct generic_pm_domain *genpd = dev_to_genpd(dev);
190+
191+
if (IS_ERR(genpd))
192+
return ERR_CAST(genpd);
193+
194+
return &genpd->dev;
195+
}
196+
187197
static int genpd_stop_dev(const struct generic_pm_domain *genpd,
188198
struct device *dev)
189199
{

include/linux/pm_domain.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
260260
int pm_genpd_init(struct generic_pm_domain *genpd,
261261
struct dev_power_governor *gov, bool is_off);
262262
int pm_genpd_remove(struct generic_pm_domain *genpd);
263+
struct device *dev_to_genpd_dev(struct device *dev);
263264
int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state);
264265
int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb);
265266
int dev_pm_genpd_remove_notifier(struct device *dev);
@@ -307,6 +308,11 @@ static inline int pm_genpd_remove(struct generic_pm_domain *genpd)
307308
return -EOPNOTSUPP;
308309
}
309310

311+
static inline struct device *dev_to_genpd_dev(struct device *dev)
312+
{
313+
return ERR_PTR(-EOPNOTSUPP);
314+
}
315+
310316
static inline int dev_pm_genpd_set_performance_state(struct device *dev,
311317
unsigned int state)
312318
{

0 commit comments

Comments
 (0)