From 19526d092ceb32d619fce73fe0bdca4370890124 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Sun, 22 Aug 2021 19:44:10 +0200 Subject: [PATCH 1/2] opp: core: Check for pending links before reading required_opp pointers Commit 4fa82a87ba55 ("opp: Allow required-opps to be used for non genpd use cases") dereferences the pointers in required_opp_tables but these might be set to an ERR_PTR if the list still has lazy links pending, resulting in segfaults. Prior to this patch IS_ERR was also checked on required_opp_tables[i] before reading ->is_genpd inside _opp_table_alloc_required_tables, which is at the same time the predicate to add this table to the lazy list. This segfault is solved by reordering the checks to bail on lazy pending tables before reading ->is_genpd. Fixes: 4fa82a87ba55 ("opp: Allow required-opps to be used for non genpd use cases") Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Marijn Suijten Signed-off-by: Viresh Kumar --- drivers/opp/core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 5543c54dacc5..04b4691a8aac 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -893,6 +893,10 @@ static int _set_required_opps(struct device *dev, if (!required_opp_tables) return 0; + /* required-opps not fully initialized yet */ + if (lazy_linking_pending(opp_table)) + return -EBUSY; + /* * We only support genpd's OPPs in the "required-opps" for now, as we * don't know much about other use cases. Error out if the required OPP @@ -903,10 +907,6 @@ static int _set_required_opps(struct device *dev, return -ENOENT; } - /* required-opps not fully initialized yet */ - if (lazy_linking_pending(opp_table)) - return -EBUSY; - /* Single genpd case */ if (!genpd_virt_devs) return _set_required_opp(dev, dev, opp, 0); From 3c5a272202c28c1f9309566f206ba40787246149 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 23 Aug 2021 23:24:12 +0300 Subject: [PATCH 2/2] PM: domains: Improve runtime PM performance state handling GENPD core doesn't support handling performance state changes while consumer device is runtime-suspended or when runtime PM is disabled. GENPD core may override performance state that was configured by device driver while RPM of the device was disabled or device was RPM-suspended. Let's close that gap by allowing drivers to control performance state while RPM of a consumer device is disabled and to set up performance state of RPM-suspended device that will be applied by GENPD core on RPM-resume of the device. Fixes: 5937c3ce2122 ("PM: domains: Drop/restore performance state votes for devices at runtime PM") Signed-off-by: Dmitry Osipenko Reviewed-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index a934c679e6ce..f10688e83226 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -435,7 +435,7 @@ static void genpd_restore_performance_state(struct device *dev, int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state) { struct generic_pm_domain *genpd; - int ret; + int ret = 0; genpd = dev_to_genpd_safe(dev); if (!genpd) @@ -446,7 +446,13 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state) return -EINVAL; genpd_lock(genpd); - ret = genpd_set_performance_state(dev, state); + if (pm_runtime_suspended(dev)) { + dev_gpd_data(dev)->rpm_pstate = state; + } else { + ret = genpd_set_performance_state(dev, state); + if (!ret) + dev_gpd_data(dev)->rpm_pstate = 0; + } genpd_unlock(genpd); return ret;