Merge tag 'pm-6.10-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management fixes from Rafael Wysocki:
"These fix the amd-pstate driver and the operating performance point
(OPP) handling related to generic PM domains.
Specifics:
- Fix a memory leak in the exit path of amd-pstate (Peng Ma)
- Fix required_opp_tables handling in the cases when multiple generic
PM domains share one OPP table (Viresh Kumar)"
* tag 'pm-6.10-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
OPP: Fix required_opp_tables for multiple genpds using same table
cpufreq: amd-pstate: fix memory leak on CPU EPP exit
This commit is contained in:
@@ -1441,6 +1441,13 @@ free_cpudata1:
|
||||
|
||||
static int amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct amd_cpudata *cpudata = policy->driver_data;
|
||||
|
||||
if (cpudata) {
|
||||
kfree(cpudata);
|
||||
policy->driver_data = NULL;
|
||||
}
|
||||
|
||||
pr_debug("CPU %d exiting\n", policy->cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+30
-1
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user