linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Rafael J. Wysocki" <rjw@rjwysocki.net>
To: Linux ACPI <linux-acpi@vger.kernel.org>
Cc: Linux PM <linux-pm@vger.kernel.org>,
	LKML <linux-kernel@vger.kernel.org>,
	Zhang Rui <rui.zhang@intel.com>,
	David Box <david.e.box@linux.intel.com>,
	"Rafael J. Wysocki" <rafael@kernel.org>,
	Dave Olsthoorn <dave@bewaar.me>, Shujun Wang <wsj20369@163.com>
Subject: [PATCH v1 3/3] ACPI: power: Rework turning off unused power resources
Date: Mon, 24 May 2021 17:26:16 +0200	[thread overview]
Message-ID: <9903404.nUPlyArG6x@kreacher> (raw)
In-Reply-To: <2074778.irdbgypaU6@kreacher>

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Make turning off unused power resources (after the enumeration of
devices and during system-wide resume from S3) more straightforward
by using the observation that the power resource state stored in
struct acpi_power_resource can be used to determine whether or not
the give power resource has any users.

Namely, when the state of the power resource is unknown, its _STA
method has never been evaluated (or the evaluation of it has failed)
and its _ON and _OFF methods have never been executed (or they have
failed to execute), so for all practical purposes it can be assumed
to have no users (or to be unusable).  Therefore, instead of checking
the number of power resource users, it is sufficient to check if its
state is known.

Moreover, if the last known state of a given power resource is "off",
it is not necessary to turn it off, because it has been used to
initialize the power state or the wakeup power resources list of at
least one device and either its _STA method has returned 0 ("off"),
or its _OFF method has been successfully executed already.

Accordingly, modify acpi_turn_off_unused_power_resources() to do the
above checks (which are suitable for both uses of it) instead of
using the number of power resource users or evaluating its _STA
method, drop its argument (which is not useful any more) and update
its callers.

Also drop the users field from struct acpi_power_resource as it is
not useful any more.

Tested-by: Dave Olsthoorn <dave@bewaar.me>
Tested-by: Shujun Wang <wsj20369@163.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/internal.h |    2 +-
 drivers/acpi/power.c    |   45 +++++++++++----------------------------------
 drivers/acpi/scan.c     |    2 +-
 drivers/acpi/sleep.c    |    2 +-
 4 files changed, 14 insertions(+), 37 deletions(-)

Index: linux-pm/drivers/acpi/power.c
===================================================================
--- linux-pm.orig/drivers/acpi/power.c
+++ linux-pm/drivers/acpi/power.c
@@ -52,7 +52,6 @@ struct acpi_power_resource {
 	u32 system_level;
 	u32 order;
 	unsigned int ref_count;
-	unsigned int users;
 	u8 state;
 	bool wakeup_enabled;
 	struct mutex resource_lock;
@@ -174,8 +173,6 @@ int acpi_extract_power_resources(union a
 		err = acpi_power_resources_list_add(rhandle, list);
 		if (err)
 			break;
-
-		to_power_resource(rdev)->users++;
 	}
 	if (err)
 		acpi_power_resources_list_free(list);
@@ -1018,39 +1015,10 @@ void acpi_resume_power_resources(void)
 }
 #endif
 
-static void acpi_power_turn_off_if_unused(struct acpi_power_resource *resource,
-				       bool init)
-{
-	if (resource->ref_count > 0)
-		return;
-
-	if (init) {
-		if (resource->users > 0)
-			return;
-	} else {
-		int result;
-		u8 state;
-
-		result = acpi_power_get_state(resource->device.handle, &state);
-		if (result || state == ACPI_POWER_RESOURCE_STATE_OFF)
-			return;
-	}
-
-	dev_info(&resource->device.dev, "Turning OFF\n");
-	__acpi_power_off(resource);
-}
-
 /**
  * acpi_turn_off_unused_power_resources - Turn off power resources not in use.
- * @init: Control switch.
- *
- * If @ainit is set, unconditionally turn off all of the ACPI power resources
- * without any users.
- *
- * Otherwise, turn off all ACPI power resources without active references (that
- * is, the ones that should be "off" at the moment) that are "on".
  */
-void acpi_turn_off_unused_power_resources(bool init)
+void acpi_turn_off_unused_power_resources(void)
 {
 	struct acpi_power_resource *resource;
 
@@ -1059,7 +1027,16 @@ void acpi_turn_off_unused_power_resource
 	list_for_each_entry_reverse(resource, &acpi_power_resource_list, list_node) {
 		mutex_lock(&resource->resource_lock);
 
-		acpi_power_turn_off_if_unused(resource, init);
+		/*
+		 * Turn off power resources in an unknown state too, because the
+		 * platform firmware on some system expects the OS to turn off
+		 * power resources without any users unconditionally.
+		 */
+		if (!resource->ref_count &&
+		    resource->state != ACPI_POWER_RESOURCE_STATE_OFF) {
+			dev_info(&resource->device.dev, "Turning OFF\n");
+			__acpi_power_off(resource);
+		}
 
 		mutex_unlock(&resource->resource_lock);
 	}
Index: linux-pm/drivers/acpi/internal.h
===================================================================
--- linux-pm.orig/drivers/acpi/internal.h
+++ linux-pm/drivers/acpi/internal.h
@@ -142,7 +142,7 @@ int acpi_device_sleep_wake(struct acpi_d
 int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
 int acpi_power_on_resources(struct acpi_device *device, int state);
 int acpi_power_transition(struct acpi_device *device, int state);
-void acpi_turn_off_unused_power_resources(bool init);
+void acpi_turn_off_unused_power_resources(void);
 
 /* --------------------------------------------------------------------------
                               Device Power Management
Index: linux-pm/drivers/acpi/scan.c
===================================================================
--- linux-pm.orig/drivers/acpi/scan.c
+++ linux-pm/drivers/acpi/scan.c
@@ -2356,7 +2356,7 @@ int __init acpi_scan_init(void)
 		}
 	}
 
-	acpi_turn_off_unused_power_resources(true);
+	acpi_turn_off_unused_power_resources();
 
 	acpi_scan_initialized = true;
 
Index: linux-pm/drivers/acpi/sleep.c
===================================================================
--- linux-pm.orig/drivers/acpi/sleep.c
+++ linux-pm/drivers/acpi/sleep.c
@@ -504,7 +504,7 @@ static void acpi_pm_start(u32 acpi_state
  */
 static void acpi_pm_end(void)
 {
-	acpi_turn_off_unused_power_resources(false);
+	acpi_turn_off_unused_power_resources();
 	acpi_scan_lock_release();
 	/*
 	 * This is necessary in case acpi_pm_finish() is not called during a




      parent reply	other threads:[~2021-05-24 15:29 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-24 15:23 [PATCH v1 0/3] ACPI: power: Keep track of power resource states Rafael J. Wysocki
2021-05-24 15:24 ` [PATCH v1 1/3] ACPI: power: Use u8 as the power resource state data type Rafael J. Wysocki
2021-05-24 15:25 ` [PATCH v1 2/3] ACPI: power: Save the last known state of each power resource Rafael J. Wysocki
2021-05-24 15:26 ` Rafael J. Wysocki [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9903404.nUPlyArG6x@kreacher \
    --to=rjw@rjwysocki.net \
    --cc=dave@bewaar.me \
    --cc=david.e.box@linux.intel.com \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=rafael@kernel.org \
    --cc=rui.zhang@intel.com \
    --cc=wsj20369@163.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).