From 668057b07db069daac3ca4e4978f8373db9cb71c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 20 Oct 2022 13:55:13 +0200 Subject: cpuidle: psci: Extend information in log about OSI/PC mode It's useful to understand whether we are using OS-initiated (OSI) mode or Platform Coordinated (PC) mode, when initializing the CPU PM domains. Therefore, let's extend the print in the log after a successful probe with this information. Signed-off-by: Ulf Hansson Acked-by: Sudeep Holla Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/cpuidle-psci-domain.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cpuidle/cpuidle-psci-domain.c b/drivers/cpuidle/cpuidle-psci-domain.c index 821984947ed9..c80cf9ddabd8 100644 --- a/drivers/cpuidle/cpuidle-psci-domain.c +++ b/drivers/cpuidle/cpuidle-psci-domain.c @@ -181,7 +181,8 @@ static int psci_cpuidle_domain_probe(struct platform_device *pdev) if (ret) goto remove_pd; - pr_info("Initialized CPU PM domain topology\n"); + pr_info("Initialized CPU PM domain topology using %s mode\n", + use_osi ? "OSI" : "PC"); return 0; put_node: -- cgit v1.2.3 From ee3c2c8ad6ba6785f14a60e4081d7c82e88162a2 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 21 Oct 2022 17:10:12 +0200 Subject: cpuidle: dt: Return the correct numbers of parsed idle states While we correctly skips to initialize an idle state from a disabled idle state node in DT, the returned value from dt_init_idle_driver() don't get adjusted accordingly. Instead the number of found idle state nodes are returned, while the callers are expecting the number of successfully initialized idle states from DT. This leads to cpuidle drivers unnecessarily continues to initialize their idle state specific data. Moreover, in the case when all idle states have been disabled in DT, we would end up registering a cpuidle driver, rather than relying on the default arch specific idle call. Fixes: 9f14da345599 ("drivers: cpuidle: implement DT based idle states infrastructure") Signed-off-by: Ulf Hansson Reviewed-by: Sudeep Holla Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/dt_idle_states.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c index 252f2a9686a6..448bc796b0b4 100644 --- a/drivers/cpuidle/dt_idle_states.c +++ b/drivers/cpuidle/dt_idle_states.c @@ -223,6 +223,6 @@ int dt_init_idle_driver(struct cpuidle_driver *drv, * also be 0 on platforms with missing DT idle states or legacy DT * configuration predating the DT idle states bindings. */ - return i; + return state_idx - start_idx; } EXPORT_SYMBOL_GPL(dt_init_idle_driver); -- cgit v1.2.3 From cb51aeec147334d25fa8336d3334ea92e2134052 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 21 Oct 2022 17:10:13 +0200 Subject: cpuidle: dt: Clarify a comment and simplify code in dt_init_idle_driver() The drv->state_count is assigned the total number of available states, so let's make that clear. Signed-off-by: Ulf Hansson Reviewed-by: Sudeep Holla Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/dt_idle_states.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c index 448bc796b0b4..7ca3d7d9b5ea 100644 --- a/drivers/cpuidle/dt_idle_states.c +++ b/drivers/cpuidle/dt_idle_states.c @@ -211,12 +211,9 @@ int dt_init_idle_driver(struct cpuidle_driver *drv, of_node_put(cpu_node); if (err) return err; - /* - * Update the driver state count only if some valid DT idle states - * were detected - */ - if (i) - drv->state_count = state_idx; + + /* Set the number of total supported idle states. */ + drv->state_count = state_idx; /* * Return the number of present and valid DT idle states, which can -- cgit v1.2.3 From 6e5d7300cbe7c3541bc31f16db3e9266e6027b4b Mon Sep 17 00:00:00 2001 From: xiongxin Date: Tue, 1 Nov 2022 10:28:39 +0800 Subject: PM: hibernate: Fix mistake in kerneldoc comment The actual maximum image size formula in hibernate_preallocate_memory() is as follows: max_size = (count - (size + PAGES_FOR_IO)) / 2 - 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE); but the one in the kerneldoc comment of the function is different and incorrect. Fixes: ddeb64870810 ("PM / Hibernate: Add sysfs knob to control size of memory for drivers") Signed-off-by: xiongxin [ rjw: Subject and changelog rewrite ] Signed-off-by: Rafael J. Wysocki --- kernel/power/snapshot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 2a406753af90..c20ca5fb9adc 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1723,8 +1723,8 @@ static unsigned long minimum_image_size(unsigned long saveable) * /sys/power/reserved_size, respectively). To make this happen, we compute the * total number of available page frames and allocate at least * - * ([page frames total] + PAGES_FOR_IO + [metadata pages]) / 2 - * + 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE) + * ([page frames total] - PAGES_FOR_IO - [metadata pages]) / 2 + * - 2 * DIV_ROUND_UP(reserved_size, PAGE_SIZE) * * of them, which corresponds to the maximum size of a hibernation image. * -- cgit v1.2.3 From 5616ce7b780af6103d7724f119514a6eb7b05f66 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 2 Nov 2022 22:21:01 +0800 Subject: PM: domains: Drop genpd status manipulation for hibernate restore The genpd status manipulation for hibernate restore has really never worked as intended. For example, if the genpd->status was GENPD_STATE_ON, the parent domain's `sd_count` must have been increased, so it needs to be adjusted too. So drop this status manipulation. Suggested-by: Ulf Hansson Signed-off-by: Shawn Guo Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 6471b559230e..97deae1d4e77 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1374,20 +1374,7 @@ static int genpd_restore_noirq(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - /* - * At this point suspended_count == 0 means we are being run for the - * first time for the given domain in the present cycle. - */ genpd_lock(genpd); - if (genpd->suspended_count++ == 0) { - /* - * The boot kernel might put the domain into arbitrary state, - * so make it appear as powered off to genpd_sync_power_on(), - * so that it tries to power it on in case it was really off. - */ - genpd->status = GENPD_STATE_OFF; - } - genpd_sync_power_on(genpd, true, 0); genpd_unlock(genpd); -- cgit v1.2.3 From 615db6d96c725406ae39e2822e1fbde81ecf1efd Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 2 Nov 2022 22:21:02 +0800 Subject: PM: domains: Pass generic PM noirq hooks to genpd_finish_suspend() While argument `poweroff` works fine for genpd_finish_suspend() to handle distinction between suspend and poweroff, it won't scale if we want to use it for freeze as well. Pass generic PM noirq hooks as arguments instead, so that the function can possibly cover freeze case too. Signed-off-by: Shawn Guo Reviewed-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 97deae1d4e77..f18b8b1bc17a 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1189,12 +1189,15 @@ static int genpd_prepare(struct device *dev) * genpd_finish_suspend - Completion of suspend or hibernation of device in an * I/O pm domain. * @dev: Device to suspend. - * @poweroff: Specifies if this is a poweroff_noirq or suspend_noirq callback. + * @suspend_noirq: Generic suspend_noirq callback. + * @resume_noirq: Generic resume_noirq callback. * * Stop the device and remove power from the domain if all devices in it have * been stopped. */ -static int genpd_finish_suspend(struct device *dev, bool poweroff) +static int genpd_finish_suspend(struct device *dev, + int (*suspend_noirq)(struct device *dev), + int (*resume_noirq)(struct device *dev)) { struct generic_pm_domain *genpd; int ret = 0; @@ -1203,10 +1206,7 @@ static int genpd_finish_suspend(struct device *dev, bool poweroff) if (IS_ERR(genpd)) return -EINVAL; - if (poweroff) - ret = pm_generic_poweroff_noirq(dev); - else - ret = pm_generic_suspend_noirq(dev); + ret = suspend_noirq(dev); if (ret) return ret; @@ -1217,10 +1217,7 @@ static int genpd_finish_suspend(struct device *dev, bool poweroff) !pm_runtime_status_suspended(dev)) { ret = genpd_stop_dev(genpd, dev); if (ret) { - if (poweroff) - pm_generic_restore_noirq(dev); - else - pm_generic_resume_noirq(dev); + resume_noirq(dev); return ret; } } @@ -1244,7 +1241,9 @@ static int genpd_suspend_noirq(struct device *dev) { dev_dbg(dev, "%s()\n", __func__); - return genpd_finish_suspend(dev, false); + return genpd_finish_suspend(dev, + pm_generic_suspend_noirq, + pm_generic_resume_noirq); } /** @@ -1353,7 +1352,9 @@ static int genpd_poweroff_noirq(struct device *dev) { dev_dbg(dev, "%s()\n", __func__); - return genpd_finish_suspend(dev, true); + return genpd_finish_suspend(dev, + pm_generic_poweroff_noirq, + pm_generic_restore_noirq); } /** -- cgit v1.2.3 From d9cc34fe0aae7e9df236be046a853fc63e889026 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 2 Nov 2022 22:21:03 +0800 Subject: PM: domains: Consolidate genpd_restore_noirq() and genpd_resume_noirq() Most of the logic between genpd_restore_noirq() and genpd_resume_noirq() are identical. The suspended_count decrement for restore should be the right thing to do anyway, considering there is an increment in genpd_finish_suspend() for hibernation. So consolidate these two functions into genpd_finish_resume(). Signed-off-by: Shawn Guo Reviewed-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index f18b8b1bc17a..7cee9439fd21 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1247,12 +1247,14 @@ static int genpd_suspend_noirq(struct device *dev) } /** - * genpd_resume_noirq - Start of resume of device in an I/O PM domain. + * genpd_finish_resume - Completion of resume of device in an I/O PM domain. * @dev: Device to resume. + * @resume_noirq: Generic resume_noirq callback. * * Restore power to the device's PM domain, if necessary, and start the device. */ -static int genpd_resume_noirq(struct device *dev) +static int genpd_finish_resume(struct device *dev, + int (*resume_noirq)(struct device *dev)) { struct generic_pm_domain *genpd; int ret; @@ -1264,7 +1266,7 @@ static int genpd_resume_noirq(struct device *dev) return -EINVAL; if (device_wakeup_path(dev) && genpd_is_active_wakeup(genpd)) - return pm_generic_resume_noirq(dev); + return resume_noirq(dev); genpd_lock(genpd); genpd_sync_power_on(genpd, true, 0); @@ -1281,6 +1283,19 @@ static int genpd_resume_noirq(struct device *dev) return pm_generic_resume_noirq(dev); } +/** + * genpd_resume_noirq - Start of resume of device in an I/O PM domain. + * @dev: Device to resume. + * + * Restore power to the device's PM domain, if necessary, and start the device. + */ +static int genpd_resume_noirq(struct device *dev) +{ + dev_dbg(dev, "%s()\n", __func__); + + return genpd_finish_resume(dev, pm_generic_resume_noirq); +} + /** * genpd_freeze_noirq - Completion of freezing a device in an I/O PM domain. * @dev: Device to freeze. @@ -1366,27 +1381,9 @@ static int genpd_poweroff_noirq(struct device *dev) */ static int genpd_restore_noirq(struct device *dev) { - struct generic_pm_domain *genpd; - int ret = 0; - dev_dbg(dev, "%s()\n", __func__); - genpd = dev_to_genpd(dev); - if (IS_ERR(genpd)) - return -EINVAL; - - genpd_lock(genpd); - genpd_sync_power_on(genpd, true, 0); - genpd_unlock(genpd); - - if (genpd->dev_ops.stop && genpd->dev_ops.start && - !pm_runtime_status_suspended(dev)) { - ret = genpd_start_dev(genpd, dev); - if (ret) - return ret; - } - - return pm_generic_restore_noirq(dev); + return genpd_finish_resume(dev, pm_generic_restore_noirq); } /** -- cgit v1.2.3 From ebb486bed2c36c3c4053ee9d55ef66d11030694a Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 2 Nov 2022 22:21:04 +0800 Subject: PM: domains: Power off[on] domain in hibernate .freeze[thaw]_noirq hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On platforms which use SHUTDOWN as hibernation mode, the genpd noirq hooks will be called like below. genpd_freeze_noirq() genpd_restore_noirq() ↓ ↑ Create snapshot image Restore target kernel ↓ ↑ genpd_thaw_noirq() genpd_freeze_noirq() ↓ ↑ Write snapshot image Read snapshot image ↓ ↑ power_down() Kernel boot As of today suspend hooks genpd_suspend[resume]_noirq() manages domain on/off state, but hibernate hooks genpd_freeze[thaw]_noirq() doesn't. This results in a different behavior of domain power state between suspend and hibernate freeze, i.e. domain is powered off for the former while on for the later. It causes a problem on platforms like i.MX where the domain needs to be powered on/off by calling clock and regulator interface. When the platform restores from hibernation, the domain is off in hardware and genpd_restore_noirq() tries to power it on, but will never succeed because software state of domain (clock and regulator) is left on from the last hibernate freeze, so kernel thinks that clock and regulator are enabled while they are actually not turned on in hardware. The consequence would be that devices in the power domain will access registers without clock or power, and cause hardware lockup. Power off[on] domain in hibernate .freeze[thaw]_noirq hook for reasons: - Align the behavior between suspend and hibernate freeze. - Have power state of domains stay in sync between hardware and software for hibernate freeze, and thus fix the lockup issue seen on i.MX platform. Signed-off-by: Shawn Guo Reviewed-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 7cee9439fd21..2f0787d5101b 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1307,24 +1307,11 @@ static int genpd_resume_noirq(struct device *dev) */ static int genpd_freeze_noirq(struct device *dev) { - const struct generic_pm_domain *genpd; - int ret = 0; - dev_dbg(dev, "%s()\n", __func__); - genpd = dev_to_genpd(dev); - if (IS_ERR(genpd)) - return -EINVAL; - - ret = pm_generic_freeze_noirq(dev); - if (ret) - return ret; - - if (genpd->dev_ops.stop && genpd->dev_ops.start && - !pm_runtime_status_suspended(dev)) - ret = genpd_stop_dev(genpd, dev); - - return ret; + return genpd_finish_suspend(dev, + pm_generic_freeze_noirq, + pm_generic_thaw_noirq); } /** @@ -1336,23 +1323,9 @@ static int genpd_freeze_noirq(struct device *dev) */ static int genpd_thaw_noirq(struct device *dev) { - const struct generic_pm_domain *genpd; - int ret = 0; - dev_dbg(dev, "%s()\n", __func__); - genpd = dev_to_genpd(dev); - if (IS_ERR(genpd)) - return -EINVAL; - - if (genpd->dev_ops.stop && genpd->dev_ops.start && - !pm_runtime_status_suspended(dev)) { - ret = genpd_start_dev(genpd, dev); - if (ret) - return ret; - } - - return pm_generic_thaw_noirq(dev); + return genpd_finish_resume(dev, pm_generic_thaw_noirq); } /** -- cgit v1.2.3 From ae8ac19655e0cd7ca5ac2f45837d386745aaed7f Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Tue, 15 Nov 2022 23:25:43 +0200 Subject: PM: domains: Reverse the order of performance and enabling ops The ->set_performance_state() needs to be called before ->power_on() when a genpd is powered on, and after ->power_off() when a genpd is powered off. Do this in order to let the provider know to which performance state to power on the genpd, on the power on sequence, and also to maintain the performance for that genpd until after powering off, on power off sequence. There is no scenario where a consumer would need its genpd enabled and then its performance state increased. Instead, in every scenario, the consumer needs the genpd to be enabled from the start at a specific performance state. And same logic applies to the powering down. No consumer would need its genpd performance state dropped right before powering down. Now, there are currently two vendors which use ->set_performance_state() in their genpd providers. One of them is Tegra, but the only genpd provider (PMC) that makes use of ->set_performance_state() doesn't implement the ->power_on() or ->power_off(), and so it will not be affected by the ops reversal. The other vendor that uses it is Qualcomm, in multiple genpd providers actually (RPM, RPMh and CPR). But all Qualcomm genpd providers that make use of ->set_performance_state() need the order between enabling ops and the performance setting op to be reversed. And the reason for that is that it currently translates into two different voltages in order to power on a genpd to a specific performance state. Basically, ->power_on() switches to the minimum (enabling) voltage for that genpd, and then ->set_performance_state() sets it to the voltage level required by the consumer. By reversing the call order, we rely on the provider to know what to do on each call, but most popular usecase is to cache the performance state and postpone the voltage setting until the ->power_on() gets called. As for the reason of still needing the ->power_on() and ->power_off() for a provider which could get away with just having ->set_performance_state() implemented, there are consumers that do not (nor should) provide an opp-table. For those consumers, ->set_performance_state() will not be called, and so they will enable the genpd to its minimum performance state by a ->power_on() call. Same logic goes for the disabling. Signed-off-by: Abel Vesa Reviewed-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 2f0787d5101b..b46aa490b4cd 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -939,8 +939,8 @@ static int genpd_runtime_suspend(struct device *dev) return 0; genpd_lock(genpd); - gpd_data->rpm_pstate = genpd_drop_performance_state(dev); genpd_power_off(genpd, true, 0); + gpd_data->rpm_pstate = genpd_drop_performance_state(dev); genpd_unlock(genpd); return 0; @@ -978,9 +978,8 @@ static int genpd_runtime_resume(struct device *dev) goto out; genpd_lock(genpd); + genpd_restore_performance_state(dev, gpd_data->rpm_pstate); ret = genpd_power_on(genpd, 0); - if (!ret) - genpd_restore_performance_state(dev, gpd_data->rpm_pstate); genpd_unlock(genpd); if (ret) @@ -1018,8 +1017,8 @@ err_stop: err_poweroff: if (!pm_runtime_is_irq_safe(dev) || genpd_is_irq_safe(genpd)) { genpd_lock(genpd); - gpd_data->rpm_pstate = genpd_drop_performance_state(dev); genpd_power_off(genpd, true, 0); + gpd_data->rpm_pstate = genpd_drop_performance_state(dev); genpd_unlock(genpd); } @@ -2707,17 +2706,6 @@ static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev, dev->pm_domain->detach = genpd_dev_pm_detach; dev->pm_domain->sync = genpd_dev_pm_sync; - if (power_on) { - genpd_lock(pd); - ret = genpd_power_on(pd, 0); - genpd_unlock(pd); - } - - if (ret) { - genpd_remove_device(pd, dev); - return -EPROBE_DEFER; - } - /* Set the default performance state */ pstate = of_get_required_opp_performance_state(dev->of_node, index); if (pstate < 0 && pstate != -ENODEV && pstate != -EOPNOTSUPP) { @@ -2729,6 +2717,24 @@ static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev, goto err; dev_gpd_data(dev)->default_pstate = pstate; } + + if (power_on) { + genpd_lock(pd); + ret = genpd_power_on(pd, 0); + genpd_unlock(pd); + } + + if (ret) { + /* Drop the default performance state */ + if (dev_gpd_data(dev)->default_pstate) { + dev_pm_genpd_set_performance_state(dev, 0); + dev_gpd_data(dev)->default_pstate = 0; + } + + genpd_remove_device(pd, dev); + return -EPROBE_DEFER; + } + return 1; err: -- cgit v1.2.3 From 3363e0adb3931e987caa6404327b35ea2db231d8 Mon Sep 17 00:00:00 2001 From: Xueqin Luo Date: Fri, 11 Nov 2022 13:19:49 +0800 Subject: PM: hibernate: Complain about memory map mismatches during resume The system memory map can change over a hibernation-restore cycle due to a defect in the platform firmware, and some of the page frames used by the kernel before hibernation may not be available any more during the subsequent restore which leads to the error below. [ T357] PM: Image loading progress: 0% [ T357] PM: Read 2681596 kbytes in 0.03 seconds (89386.53 MB/s) [ T357] PM: Error -14 resuming [ T357] PM: Failed to load hibernation image, recovering. [ T357] PM: Basic memory bitmaps freed [ T357] OOM killer enabled. [ T357] Restarting tasks ... done. [ T357] PM: resume from hibernation failed (-14) [ T357] PM: Hibernation image not present or could not be loaded. Add an error message to the unpack() function to allow problematic page frames to be identified and the source of the problem to be diagnosed more easily. This can save developers quite a bit of debugging time. Signed-off-by: Xueqin Luo [ rjw: New subject, edited changelog ] Signed-off-by: Rafael J. Wysocki --- kernel/power/snapshot.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index c20ca5fb9adc..cd8b7b35f1e8 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -2259,10 +2259,14 @@ static int unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm) if (unlikely(buf[j] == BM_END_OF_MAP)) break; - if (pfn_valid(buf[j]) && memory_bm_pfn_present(bm, buf[j])) + if (pfn_valid(buf[j]) && memory_bm_pfn_present(bm, buf[j])) { memory_bm_set_bit(bm, buf[j]); - else + } else { + if (!pfn_valid(buf[j])) + pr_err(FW_BUG "Memory map mismatch at 0x%llx after hibernation\n", + (unsigned long long)PFN_PHYS(buf[j])); return -EFAULT; + } } return 0; -- cgit v1.2.3 From a449dfbfc0894676ad0aa1873383265047529e3a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 1 Dec 2022 19:33:09 +0100 Subject: PM: sleep: Avoid using pr_cont() in the tasks freezing code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using pr_cont() in the tasks freezing code related to system-wide suspend and hibernation is problematic, because the continuation messages printed there are susceptible to interspersing with other unrelated messages which results in output that is hard to understand. Address this issue by modifying try_to_freeze_tasks() to print messages that don't require continuations and adjusting its callers accordingly. Reported-by: Thomas Weißschuh Signed-off-by: Rafael J. Wysocki Reviewed-by: Petr Mladek --- kernel/power/process.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/kernel/power/process.c b/kernel/power/process.c index ddd9988327fe..beeab7f9fac8 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -27,6 +27,8 @@ unsigned int __read_mostly freeze_timeout_msecs = 20 * MSEC_PER_SEC; static int try_to_freeze_tasks(bool user_only) { + const char *what = user_only ? "user space processes" : + "remaining freezable tasks"; struct task_struct *g, *p; unsigned long end_time; unsigned int todo; @@ -36,6 +38,8 @@ static int try_to_freeze_tasks(bool user_only) bool wakeup = false; int sleep_usecs = USEC_PER_MSEC; + pr_info("Freezing %s\n", what); + start = ktime_get_boottime(); end_time = jiffies + msecs_to_jiffies(freeze_timeout_msecs); @@ -82,7 +86,6 @@ static int try_to_freeze_tasks(bool user_only) elapsed_msecs = ktime_to_ms(elapsed); if (todo) { - pr_cont("\n"); pr_err("Freezing of tasks %s after %d.%03d seconds " "(%d tasks refusing to freeze, wq_busy=%d):\n", wakeup ? "aborted" : "failed", @@ -101,8 +104,8 @@ static int try_to_freeze_tasks(bool user_only) read_unlock(&tasklist_lock); } } else { - pr_cont("(elapsed %d.%03d seconds) ", elapsed_msecs / 1000, - elapsed_msecs % 1000); + pr_info("Freezing %s completed (elapsed %d.%03d seconds)\n", + what, elapsed_msecs / 1000, elapsed_msecs % 1000); } return todo ? -EBUSY : 0; @@ -130,14 +133,11 @@ int freeze_processes(void) static_branch_inc(&freezer_active); pm_wakeup_clear(0); - pr_info("Freezing user space processes ... "); pm_freezing = true; error = try_to_freeze_tasks(true); - if (!error) { + if (!error) __usermodehelper_set_disable_depth(UMH_DISABLED); - pr_cont("done."); - } - pr_cont("\n"); + BUG_ON(in_atomic()); /* @@ -166,14 +166,9 @@ int freeze_kernel_threads(void) { int error; - pr_info("Freezing remaining freezable tasks ... "); - pm_nosig_freezing = true; error = try_to_freeze_tasks(false); - if (!error) - pr_cont("done."); - pr_cont("\n"); BUG_ON(in_atomic()); if (error) -- cgit v1.2.3 From 96d4b8e1ad8a34711ef416dd61e6b60df9e12d30 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 1 Dec 2022 19:34:44 +0100 Subject: PM: sleep: Refine error message in try_to_freeze_tasks() A previous change amended try_to_freeze_tasks() with the "what" variable pointing to a string describing the group of tasks subject to the freezing which may be used in the error message in there too, so make that happen. Accordingly, update sleepgraph.py to catch the modified error message as appropriate. Signed-off-by: Rafael J. Wysocki Reviewed-by: Petr Mladek --- kernel/power/process.c | 4 ++-- tools/power/pm-graph/sleepgraph.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/power/process.c b/kernel/power/process.c index beeab7f9fac8..6c1c7e566d35 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -86,8 +86,8 @@ static int try_to_freeze_tasks(bool user_only) elapsed_msecs = ktime_to_ms(elapsed); if (todo) { - pr_err("Freezing of tasks %s after %d.%03d seconds " - "(%d tasks refusing to freeze, wq_busy=%d):\n", + pr_err("Freezing %s %s after %d.%03d seconds " + "(%d tasks refusing to freeze, wq_busy=%d):\n", what, wakeup ? "aborted" : "failed", elapsed_msecs / 1000, elapsed_msecs % 1000, todo - wq_busy, wq_busy); diff --git a/tools/power/pm-graph/sleepgraph.py b/tools/power/pm-graph/sleepgraph.py index cfe343306e08..c60c90f35d18 100755 --- a/tools/power/pm-graph/sleepgraph.py +++ b/tools/power/pm-graph/sleepgraph.py @@ -1462,7 +1462,7 @@ class Data: 'TIMEOUT' : r'(?i).*\bTIMEOUT\b.*', 'ABORT' : r'(?i).*\bABORT\b.*', 'IRQ' : r'.*\bgenirq: .*', - 'TASKFAIL': r'.*Freezing of tasks *.*', + 'TASKFAIL': r'.*Freezing .*after *.*', 'ACPI' : r'.*\bACPI *(?P[A-Za-z]*) *Error[: ].*', 'DISKFULL': r'.*\bNo space left on device.*', 'USBERR' : r'.*usb .*device .*, error [0-9-]*', -- cgit v1.2.3