Commit d3f2c402 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

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
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -413,6 +413,35 @@ Description:
		The /sys/power/suspend_stats/last_failed_step file contains
		the last failed step in the suspend/resume path.

What:		/sys/power/suspend_stats/last_hw_sleep
Date:		June 2023
Contact:	Mario Limonciello <mario.limonciello@amd.com>
Description:
		The /sys/power/suspend_stats/last_hw_sleep file
		contains the duration of time spent in a hardware sleep
		state in the most recent system suspend-resume cycle.
		This number is measured in microseconds.

What:		/sys/power/suspend_stats/total_hw_sleep
Date:		June 2023
Contact:	Mario Limonciello <mario.limonciello@amd.com>
Description:
		The /sys/power/suspend_stats/total_hw_sleep file
		contains the aggregate of time spent in a hardware sleep
		state since the kernel was booted. This number
		is measured in microseconds.

What:		/sys/power/suspend_stats/max_hw_sleep
Date:		June 2023
Contact:	Mario Limonciello <mario.limonciello@amd.com>
Description:
		The /sys/power/suspend_stats/max_hw_sleep file
		contains the maximum amount of time that the hardware can
		report for time spent in a hardware sleep state. When sleep
		cycles are longer than this time, the values for
		'total_hw_sleep' and 'last_hw_sleep' may not be accurate.
		This number is measured in microseconds.

What:		/sys/power/sync_on_suspend
Date:		October 2019
Contact:	Jonas Meurer <jonas@freesources.org>
+6 −6
Original line number Diff line number Diff line
@@ -679,7 +679,7 @@ static bool dpm_async_fn(struct device *dev, async_func_t func)

static void async_resume_noirq(void *data, async_cookie_t cookie)
{
	struct device *dev = (struct device *)data;
	struct device *dev = data;
	int error;

	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

static void async_resume_early(void *data, async_cookie_t cookie)
{
	struct device *dev = (struct device *)data;
	struct device *dev = data;
	int error;

	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)

static void async_resume(void *data, async_cookie_t cookie)
{
	struct device *dev = (struct device *)data;
	struct device *dev = data;
	int error;

	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

static void async_suspend_noirq(void *data, async_cookie_t cookie)
{
	struct device *dev = (struct device *)data;
	struct device *dev = data;
	int error;

	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

static void async_suspend_late(void *data, async_cookie_t cookie)
{
	struct device *dev = (struct device *)data;
	struct device *dev = data;
	int error;

	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)

static void async_suspend(void *data, async_cookie_t cookie)
{
	struct device *dev = (struct device *)data;
	struct device *dev = data;
	int error;

	error = __device_suspend(dev, pm_transition, true);
+44 −34
Original line number Diff line number Diff line
@@ -935,7 +935,7 @@ static int _set_opp_bw(const struct opp_table *opp_table,
	return 0;
}

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

/* This is only called for PM domain for now */
static int _set_required_opps(struct device *dev,
			      struct opp_table *opp_table,
			      struct dev_pm_opp *opp, bool up)
static int _opp_set_required_opps_generic(struct device *dev,
	struct opp_table *opp_table, struct dev_pm_opp *opp, bool scaling_down)
{
	struct opp_table **required_opp_tables = opp_table->required_opp_tables;
	struct device **genpd_virt_devs = opp_table->genpd_virt_devs;
	int i, ret = 0;

	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
	 * doesn't belong to a genpd.
	 */
	if (unlikely(!required_opp_tables[0]->is_genpd)) {
		dev_err(dev, "required-opps don't belong to a genpd\n");
	dev_err(dev, "setting required-opps isn't supported for non-genpd devices\n");
	return -ENOENT;
}

	/* Single genpd case */
	if (!genpd_virt_devs)
		return _set_required_opp(dev, dev, opp, 0);

	/* Multiple genpd case */
static int _opp_set_required_opps_genpd(struct device *dev,
	struct opp_table *opp_table, struct dev_pm_opp *opp, bool scaling_down)
{
	struct device **genpd_virt_devs =
		opp_table->genpd_virt_devs ? opp_table->genpd_virt_devs : &dev;
	int i, ret = 0;

	/*
	 * 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,
	mutex_lock(&opp_table->genpd_virt_dev_lock);

	/* Scaling up? Set required OPPs in normal order, else reverse */
	if (up) {
	if (!scaling_down) {
		for (i = 0; i < opp_table->required_opp_count; i++) {
			ret = _set_required_opp(dev, genpd_virt_devs[i], opp, i);
			ret = _set_performance_state(dev, genpd_virt_devs[i], opp, i);
			if (ret)
				break;
		}
	} else {
		for (i = opp_table->required_opp_count - 1; i >= 0; i--) {
			ret = _set_required_opp(dev, genpd_virt_devs[i], opp, i);
			ret = _set_performance_state(dev, genpd_virt_devs[i], opp, i);
			if (ret)
				break;
		}
@@ -1011,6 +993,34 @@ static int _set_required_opps(struct device *dev,
	return ret;
}

/* This is only called for PM domain for now */
static int _set_required_opps(struct device *dev, struct opp_table *opp_table,
			      struct dev_pm_opp *opp, bool up)
{
	/* required-opps not fully initialized yet */
	if (lazy_linking_pending(opp_table))
		return -EBUSY;

	if (opp_table->set_required_opps)
		return opp_table->set_required_opps(dev, opp_table, opp, up);

	return 0;
}

/* Update set_required_opps handler */
void _update_set_required_opps(struct opp_table *opp_table)
{
	/* Already set */
	if (opp_table->set_required_opps)
		return;

	/* All required OPPs will belong to genpd or none */
	if (opp_table->required_opp_tables[0]->is_genpd)
		opp_table->set_required_opps = _opp_set_required_opps_genpd;
	else
		opp_table->set_required_opps = _opp_set_required_opps_generic;
}

static void _find_current_opp(struct device *dev, struct opp_table *opp_table)
{
	struct dev_pm_opp *opp = ERR_PTR(-ENODEV);
+5 −2
Original line number Diff line number Diff line
@@ -196,6 +196,8 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
	/* Let's do the linking later on */
	if (lazy)
		list_add(&opp_table->lazy, &lazy_opp_tables);
	else
		_update_set_required_opps(opp_table);

	goto put_np;

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

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

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

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

			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,
		 * an OPP then the OPP should not be enabled as there is
		 * no way to see if the hardware supports it.
		 */
		if (of_find_property(np, "opp-supported-hw", NULL))
		if (of_property_present(np, "opp-supported-hw"))
			return false;
		else
			return true;
+4 −0
Original line number Diff line number Diff line
@@ -184,6 +184,7 @@ enum opp_table_access {
 * @enabled: Set to true if the device's resources are enabled/configured.
 * @genpd_performance_state: Device's power domain support performance state.
 * @is_genpd: Marks if the OPP table belongs to a genpd.
 * @set_required_opps: Helper responsible to set required OPPs.
 * @dentry:	debugfs dentry pointer of the real device directory (not links).
 * @dentry_name: Name of the real dentry.
 *
@@ -234,6 +235,8 @@ struct opp_table {
	bool enabled;
	bool genpd_performance_state;
	bool is_genpd;
	int (*set_required_opps)(struct device *dev,
		struct opp_table *opp_table, struct dev_pm_opp *opp, bool scaling_down);

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

static inline bool lazy_linking_pending(struct opp_table *opp_table)
{
Loading