Skip to content

Commit d3f2c40

Browse files
committed
Merge branches 'pm-core', 'pm-sleep', 'pm-opp' and 'pm-tools'
Merge PM core changes, updates related to system sleep support, operating performance points (OPP) changes and power management utilities changes for 6.4-rc1: - Drop unnecessary (void *) conversions from the PM core (Li zeming). - Add sysfs files to represent time spent in a platform sleep state during suspend-to-idle and make AMD and Intel PMC drivers use them (Mario Limonciello). - Use of_property_present() for testing DT property presence (Rob Herring). - Add set_required_opps() callback to the 'struct opp_table', to make the code paths cleaner (Viresh Kumar). - Update the pm-graph siute of utilities to v5.11 with the following changes: * New script which allows users to install the latest pm-graph from the upstream github repo. * Update all the dmesg suspend/resume PM print formats to be able to process recent timelines using dmesg only. * Add ethtool output to the log for the system's ethernet device if ethtool exists. * Make the tool more robustly handle events where mangled dmesg or ftrace outputs do not include all the requisite data. - Make the sleepgraph utility recognize "CPU killed" messages (Xueqin Luo). * pm-core: PM: core: Remove unnecessary (void *) conversions * pm-sleep: platform/x86/intel/pmc: core: Report duration of time in HW sleep state platform/x86/intel/pmc: core: Always capture counters on suspend platform/x86/amd: pmc: Report duration of time in hw sleep state PM: Add sysfs files to represent time spent in hardware sleep state * pm-opp: OPP: Move required opps configuration to specialized callback OPP: Handle all genpd cases together in _set_required_opps() opp: Use of_property_present() for testing DT property presence * pm-tools: PM: tools: sleepgraph: Recognize "CPU killed" messages pm-graph: Update to v5.11
5 parents 21def61 + 73d73f5 + ddd66d6 + 0ba4962 + 34ea427 commit d3f2c40

13 files changed

Lines changed: 236 additions & 86 deletions

File tree

Documentation/ABI/testing/sysfs-power

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,35 @@ Description:
413413
The /sys/power/suspend_stats/last_failed_step file contains
414414
the last failed step in the suspend/resume path.
415415

416+
What: /sys/power/suspend_stats/last_hw_sleep
417+
Date: June 2023
418+
Contact: Mario Limonciello <mario.limonciello@amd.com>
419+
Description:
420+
The /sys/power/suspend_stats/last_hw_sleep file
421+
contains the duration of time spent in a hardware sleep
422+
state in the most recent system suspend-resume cycle.
423+
This number is measured in microseconds.
424+
425+
What: /sys/power/suspend_stats/total_hw_sleep
426+
Date: June 2023
427+
Contact: Mario Limonciello <mario.limonciello@amd.com>
428+
Description:
429+
The /sys/power/suspend_stats/total_hw_sleep file
430+
contains the aggregate of time spent in a hardware sleep
431+
state since the kernel was booted. This number
432+
is measured in microseconds.
433+
434+
What: /sys/power/suspend_stats/max_hw_sleep
435+
Date: June 2023
436+
Contact: Mario Limonciello <mario.limonciello@amd.com>
437+
Description:
438+
The /sys/power/suspend_stats/max_hw_sleep file
439+
contains the maximum amount of time that the hardware can
440+
report for time spent in a hardware sleep state. When sleep
441+
cycles are longer than this time, the values for
442+
'total_hw_sleep' and 'last_hw_sleep' may not be accurate.
443+
This number is measured in microseconds.
444+
416445
What: /sys/power/sync_on_suspend
417446
Date: October 2019
418447
Contact: Jonas Meurer <jonas@freesources.org>

drivers/base/power/main.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ static bool dpm_async_fn(struct device *dev, async_func_t func)
679679

680680
static void async_resume_noirq(void *data, async_cookie_t cookie)
681681
{
682-
struct device *dev = (struct device *)data;
682+
struct device *dev = data;
683683
int error;
684684

685685
error = device_resume_noirq(dev, pm_transition, true);
@@ -816,7 +816,7 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn
816816

817817
static void async_resume_early(void *data, async_cookie_t cookie)
818818
{
819-
struct device *dev = (struct device *)data;
819+
struct device *dev = data;
820820
int error;
821821

822822
error = device_resume_early(dev, pm_transition, true);
@@ -980,7 +980,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
980980

981981
static void async_resume(void *data, async_cookie_t cookie)
982982
{
983-
struct device *dev = (struct device *)data;
983+
struct device *dev = data;
984984
int error;
985985

986986
error = device_resume(dev, pm_transition, true);
@@ -1269,7 +1269,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
12691269

12701270
static void async_suspend_noirq(void *data, async_cookie_t cookie)
12711271
{
1272-
struct device *dev = (struct device *)data;
1272+
struct device *dev = data;
12731273
int error;
12741274

12751275
error = __device_suspend_noirq(dev, pm_transition, true);
@@ -1450,7 +1450,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
14501450

14511451
static void async_suspend_late(void *data, async_cookie_t cookie)
14521452
{
1453-
struct device *dev = (struct device *)data;
1453+
struct device *dev = data;
14541454
int error;
14551455

14561456
error = __device_suspend_late(dev, pm_transition, true);
@@ -1727,7 +1727,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
17271727

17281728
static void async_suspend(void *data, async_cookie_t cookie)
17291729
{
1730-
struct device *dev = (struct device *)data;
1730+
struct device *dev = data;
17311731
int error;
17321732

17331733
error = __device_suspend(dev, pm_transition, true);

drivers/opp/core.c

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -935,8 +935,8 @@ static int _set_opp_bw(const struct opp_table *opp_table,
935935
return 0;
936936
}
937937

938-
static int _set_required_opp(struct device *dev, struct device *pd_dev,
939-
struct dev_pm_opp *opp, int i)
938+
static int _set_performance_state(struct device *dev, struct device *pd_dev,
939+
struct dev_pm_opp *opp, int i)
940940
{
941941
unsigned int pstate = likely(opp) ? opp->required_opps[i]->pstate : 0;
942942
int ret;
@@ -953,37 +953,19 @@ static int _set_required_opp(struct device *dev, struct device *pd_dev,
953953
return ret;
954954
}
955955

956-
/* This is only called for PM domain for now */
957-
static int _set_required_opps(struct device *dev,
958-
struct opp_table *opp_table,
959-
struct dev_pm_opp *opp, bool up)
956+
static int _opp_set_required_opps_generic(struct device *dev,
957+
struct opp_table *opp_table, struct dev_pm_opp *opp, bool scaling_down)
960958
{
961-
struct opp_table **required_opp_tables = opp_table->required_opp_tables;
962-
struct device **genpd_virt_devs = opp_table->genpd_virt_devs;
963-
int i, ret = 0;
964-
965-
if (!required_opp_tables)
966-
return 0;
967-
968-
/* required-opps not fully initialized yet */
969-
if (lazy_linking_pending(opp_table))
970-
return -EBUSY;
971-
972-
/*
973-
* We only support genpd's OPPs in the "required-opps" for now, as we
974-
* don't know much about other use cases. Error out if the required OPP
975-
* doesn't belong to a genpd.
976-
*/
977-
if (unlikely(!required_opp_tables[0]->is_genpd)) {
978-
dev_err(dev, "required-opps don't belong to a genpd\n");
979-
return -ENOENT;
980-
}
981-
982-
/* Single genpd case */
983-
if (!genpd_virt_devs)
984-
return _set_required_opp(dev, dev, opp, 0);
959+
dev_err(dev, "setting required-opps isn't supported for non-genpd devices\n");
960+
return -ENOENT;
961+
}
985962

986-
/* Multiple genpd case */
963+
static int _opp_set_required_opps_genpd(struct device *dev,
964+
struct opp_table *opp_table, struct dev_pm_opp *opp, bool scaling_down)
965+
{
966+
struct device **genpd_virt_devs =
967+
opp_table->genpd_virt_devs ? opp_table->genpd_virt_devs : &dev;
968+
int i, ret = 0;
987969

988970
/*
989971
* Acquire genpd_virt_dev_lock to make sure we don't use a genpd_dev
@@ -992,15 +974,15 @@ static int _set_required_opps(struct device *dev,
992974
mutex_lock(&opp_table->genpd_virt_dev_lock);
993975

994976
/* Scaling up? Set required OPPs in normal order, else reverse */
995-
if (up) {
977+
if (!scaling_down) {
996978
for (i = 0; i < opp_table->required_opp_count; i++) {
997-
ret = _set_required_opp(dev, genpd_virt_devs[i], opp, i);
979+
ret = _set_performance_state(dev, genpd_virt_devs[i], opp, i);
998980
if (ret)
999981
break;
1000982
}
1001983
} else {
1002984
for (i = opp_table->required_opp_count - 1; i >= 0; i--) {
1003-
ret = _set_required_opp(dev, genpd_virt_devs[i], opp, i);
985+
ret = _set_performance_state(dev, genpd_virt_devs[i], opp, i);
1004986
if (ret)
1005987
break;
1006988
}
@@ -1011,6 +993,34 @@ static int _set_required_opps(struct device *dev,
1011993
return ret;
1012994
}
1013995

996+
/* This is only called for PM domain for now */
997+
static int _set_required_opps(struct device *dev, struct opp_table *opp_table,
998+
struct dev_pm_opp *opp, bool up)
999+
{
1000+
/* required-opps not fully initialized yet */
1001+
if (lazy_linking_pending(opp_table))
1002+
return -EBUSY;
1003+
1004+
if (opp_table->set_required_opps)
1005+
return opp_table->set_required_opps(dev, opp_table, opp, up);
1006+
1007+
return 0;
1008+
}
1009+
1010+
/* Update set_required_opps handler */
1011+
void _update_set_required_opps(struct opp_table *opp_table)
1012+
{
1013+
/* Already set */
1014+
if (opp_table->set_required_opps)
1015+
return;
1016+
1017+
/* All required OPPs will belong to genpd or none */
1018+
if (opp_table->required_opp_tables[0]->is_genpd)
1019+
opp_table->set_required_opps = _opp_set_required_opps_genpd;
1020+
else
1021+
opp_table->set_required_opps = _opp_set_required_opps_generic;
1022+
}
1023+
10141024
static void _find_current_opp(struct device *dev, struct opp_table *opp_table)
10151025
{
10161026
struct dev_pm_opp *opp = ERR_PTR(-ENODEV);

drivers/opp/of.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
196196
/* Let's do the linking later on */
197197
if (lazy)
198198
list_add(&opp_table->lazy, &lazy_opp_tables);
199+
else
200+
_update_set_required_opps(opp_table);
199201

200202
goto put_np;
201203

@@ -224,7 +226,7 @@ void _of_init_opp_table(struct opp_table *opp_table, struct device *dev,
224226
of_property_read_u32(np, "voltage-tolerance",
225227
&opp_table->voltage_tolerance_v1);
226228

227-
if (of_find_property(np, "#power-domain-cells", NULL))
229+
if (of_property_present(np, "#power-domain-cells"))
228230
opp_table->is_genpd = true;
229231

230232
/* Get OPP table node */
@@ -411,6 +413,7 @@ static void lazy_link_required_opp_table(struct opp_table *new_table)
411413

412414
/* All required opp-tables found, remove from lazy list */
413415
if (!lazy) {
416+
_update_set_required_opps(opp_table);
414417
list_del_init(&opp_table->lazy);
415418

416419
list_for_each_entry(opp, &opp_table->opp_list, node)
@@ -536,7 +539,7 @@ static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
536539
* an OPP then the OPP should not be enabled as there is
537540
* no way to see if the hardware supports it.
538541
*/
539-
if (of_find_property(np, "opp-supported-hw", NULL))
542+
if (of_property_present(np, "opp-supported-hw"))
540543
return false;
541544
else
542545
return true;

drivers/opp/opp.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ enum opp_table_access {
184184
* @enabled: Set to true if the device's resources are enabled/configured.
185185
* @genpd_performance_state: Device's power domain support performance state.
186186
* @is_genpd: Marks if the OPP table belongs to a genpd.
187+
* @set_required_opps: Helper responsible to set required OPPs.
187188
* @dentry: debugfs dentry pointer of the real device directory (not links).
188189
* @dentry_name: Name of the real dentry.
189190
*
@@ -234,6 +235,8 @@ struct opp_table {
234235
bool enabled;
235236
bool genpd_performance_state;
236237
bool is_genpd;
238+
int (*set_required_opps)(struct device *dev,
239+
struct opp_table *opp_table, struct dev_pm_opp *opp, bool scaling_down);
237240

238241
#ifdef CONFIG_DEBUG_FS
239242
struct dentry *dentry;
@@ -257,6 +260,7 @@ void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cp
257260
struct opp_table *_add_opp_table_indexed(struct device *dev, int index, bool getclk);
258261
void _put_opp_list_kref(struct opp_table *opp_table);
259262
void _required_opps_available(struct dev_pm_opp *opp, int count);
263+
void _update_set_required_opps(struct opp_table *opp_table);
260264

261265
static inline bool lazy_linking_pending(struct opp_table *opp_table)
262266
{

drivers/platform/x86/amd/pmc.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,9 +393,8 @@ static void amd_pmc_validate_deepest(struct amd_pmc_dev *pdev)
393393

394394
if (!table.s0i3_last_entry_status)
395395
dev_warn(pdev->dev, "Last suspend didn't reach deepest state\n");
396-
else
397-
dev_dbg(pdev->dev, "Last suspend in deepest state for %lluus\n",
398-
table.timein_s0i3_lastcapture);
396+
pm_report_hw_sleep_time(table.s0i3_last_entry_status ?
397+
table.timein_s0i3_lastcapture : 0);
399398
}
400399

401400
static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev)
@@ -1015,6 +1014,7 @@ static int amd_pmc_probe(struct platform_device *pdev)
10151014
}
10161015

10171016
amd_pmc_dbgfs_register(dev);
1017+
pm_report_max_hw_sleep(U64_MAX);
10181018
return 0;
10191019

10201020
err_pci_dev_put:

drivers/platform/x86/intel/pmc/core.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,8 @@ static int pmc_core_probe(struct platform_device *pdev)
11531153
pmc_core_do_dmi_quirks(pmcdev);
11541154

11551155
pmc_core_dbgfs_register(pmcdev);
1156+
pm_report_max_hw_sleep(FIELD_MAX(SLP_S0_RES_COUNTER_MASK) *
1157+
pmc_core_adjust_slp_s0_step(pmcdev, 1));
11561158

11571159
device_initialized = true;
11581160
dev_info(&pdev->dev, " initialized\n");
@@ -1179,12 +1181,6 @@ static __maybe_unused int pmc_core_suspend(struct device *dev)
11791181
{
11801182
struct pmc_dev *pmcdev = dev_get_drvdata(dev);
11811183

1182-
pmcdev->check_counters = false;
1183-
1184-
/* No warnings on S0ix failures */
1185-
if (!warn_on_s0ix_failures)
1186-
return 0;
1187-
11881184
/* Check if the syspend will actually use S0ix */
11891185
if (pm_suspend_via_firmware())
11901186
return 0;
@@ -1197,7 +1193,6 @@ static __maybe_unused int pmc_core_suspend(struct device *dev)
11971193
if (pmc_core_dev_state_get(pmcdev, &pmcdev->s0ix_counter))
11981194
return -EIO;
11991195

1200-
pmcdev->check_counters = true;
12011196
return 0;
12021197
}
12031198

@@ -1221,6 +1216,8 @@ static inline bool pmc_core_is_s0ix_failed(struct pmc_dev *pmcdev)
12211216
if (pmc_core_dev_state_get(pmcdev, &s0ix_counter))
12221217
return false;
12231218

1219+
pm_report_hw_sleep_time((u32)(s0ix_counter - pmcdev->s0ix_counter));
1220+
12241221
if (s0ix_counter == pmcdev->s0ix_counter)
12251222
return true;
12261223

@@ -1233,12 +1230,16 @@ static __maybe_unused int pmc_core_resume(struct device *dev)
12331230
const struct pmc_bit_map **maps = pmcdev->map->lpm_sts;
12341231
int offset = pmcdev->map->lpm_status_offset;
12351232

1236-
if (!pmcdev->check_counters)
1233+
/* Check if the syspend used S0ix */
1234+
if (pm_suspend_via_firmware())
12371235
return 0;
12381236

12391237
if (!pmc_core_is_s0ix_failed(pmcdev))
12401238
return 0;
12411239

1240+
if (!warn_on_s0ix_failures)
1241+
return 0;
1242+
12421243
if (pmc_core_is_pc10_failed(pmcdev)) {
12431244
/* S0ix failed because of PC10 entry failure */
12441245
dev_info(dev, "CPU did not enter PC10!!! (PC10 cnt=0x%llx)\n",

drivers/platform/x86/intel/pmc/core.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include <linux/bits.h>
1717
#include <linux/platform_device.h>
1818

19+
#define SLP_S0_RES_COUNTER_MASK GENMASK(31, 0)
20+
1921
#define PMC_BASE_ADDR_DEFAULT 0xFE000000
2022

2123
/* Sunrise Point Power Management Controller PCI Device ID */
@@ -319,7 +321,6 @@ struct pmc_reg_map {
319321
* @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers
320322
* used to read MPHY PG and PLL status are available
321323
* @mutex_lock: mutex to complete one transcation
322-
* @check_counters: On resume, check if counters are getting incremented
323324
* @pc10_counter: PC10 residency counter
324325
* @s0ix_counter: S0ix residency (step adjusted)
325326
* @num_lpm_modes: Count of enabled modes
@@ -338,7 +339,6 @@ struct pmc_dev {
338339
int pmc_xram_read_bit;
339340
struct mutex lock; /* generic mutex lock for PMC Core */
340341

341-
bool check_counters; /* Check for counter increments on resume */
342342
u64 pc10_counter;
343343
u64 s0ix_counter;
344344
int num_lpm_modes;

include/linux/suspend.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ struct suspend_stats {
6868
int last_failed_errno;
6969
int errno[REC_FAILED_NUM];
7070
int last_failed_step;
71+
u64 last_hw_sleep;
72+
u64 total_hw_sleep;
73+
u64 max_hw_sleep;
7174
enum suspend_stat_step failed_steps[REC_FAILED_NUM];
7275
};
7376

@@ -489,6 +492,8 @@ void restore_processor_state(void);
489492
extern int register_pm_notifier(struct notifier_block *nb);
490493
extern int unregister_pm_notifier(struct notifier_block *nb);
491494
extern void ksys_sync_helper(void);
495+
extern void pm_report_hw_sleep_time(u64 t);
496+
extern void pm_report_max_hw_sleep(u64 t);
492497

493498
#define pm_notifier(fn, pri) { \
494499
static struct notifier_block fn##_nb = \
@@ -526,6 +531,9 @@ static inline int unregister_pm_notifier(struct notifier_block *nb)
526531
return 0;
527532
}
528533

534+
static inline void pm_report_hw_sleep_time(u64 t) {};
535+
static inline void pm_report_max_hw_sleep(u64 t) {};
536+
529537
static inline void ksys_sync_helper(void) {}
530538

531539
#define pm_notifier(fn, pri) do { (void)(fn); } while (0)

0 commit comments

Comments
 (0)