Oliver Neukum 278644
From d12544fb2aa9944b180c35914031a8384ab082c1 Mon Sep 17 00:00:00 2001
Oliver Neukum 278644
From: Xiang Chen <chenxiang66@hisilicon.com>
Oliver Neukum 278644
Date: Tue, 22 Sep 2020 21:11:06 +0800
Oliver Neukum 278644
Subject: [PATCH] PM: runtime: Remove link state checks in
Oliver Neukum 278644
 rpm_get/put_supplier()
Oliver Neukum 278644
Git-commit: d12544fb2aa9944b180c35914031a8384ab082c1
Oliver Neukum 278644
References: git-fixes
Oliver Neukum 278644
Patch-mainline: v5.10-rc1
Oliver Neukum 278644
Oliver Neukum 278644
To support runtime PM for hisi SAS driver (the driver is in directory
Oliver Neukum 278644
drivers/scsi/hisi_sas), we add device link between scsi_device->sdev_gendev
Oliver Neukum 278644
(consumer device) and hisi_hba->dev(supplier device) with flags
Oliver Neukum 278644
DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE.
Oliver Neukum 278644
Oliver Neukum 278644
After runtime suspended consumers and supplier, unload the dirver which
Oliver Neukum 278644
causes a hung.
Oliver Neukum 278644
Oliver Neukum 278644
We found that it called function device_release_driver_internal() to
Oliver Neukum 278644
release the supplier device (hisi_hba->dev), as the device link was
Oliver Neukum 278644
busy, it set the device link state to DL_STATE_SUPPLIER_UNBIND, and
Oliver Neukum 278644
then it called device_release_driver_internal() to release the consumer
Oliver Neukum 278644
device (scsi_device->sdev_gendev).
Oliver Neukum 278644
Oliver Neukum 278644
Then it would try to call pm_runtime_get_sync() to resume the consumer
Oliver Neukum 278644
device, but because consumer-supplier relation existed, it would try
Oliver Neukum 278644
to resume the supplier first, but as the link state was already
Oliver Neukum 278644
DL_STATE_SUPPLIER_UNBIND, so it skipped resuming the supplier and only
Oliver Neukum 278644
resumed the consumer which hanged (it sends IOs to resume scsi_device
Oliver Neukum 278644
while the SAS controller is suspended).
Oliver Neukum 278644
Oliver Neukum 278644
Simple flow is as follows:
Oliver Neukum 278644
Oliver Neukum 278644
device_release_driver_internal -> (supplier device)
Oliver Neukum 278644
    if device_links_busy ->
Oliver Neukum 278644
	device_links_unbind_consumers ->
Oliver Neukum 278644
	    ...
Oliver Neukum 278644
	    WRITE_ONCE(link->status, DL_STATE_SUPPLIER_UNBIND)
Oliver Neukum 278644
	    device_release_driver_internal (consumer device)
Oliver Neukum 278644
    pm_runtime_get_sync -> (consumer device)
Oliver Neukum 278644
	...
Oliver Neukum 278644
	__rpm_callback ->
Oliver Neukum 278644
	    rpm_get_suppliers ->
Oliver Neukum 278644
		if link->state == DL_STATE_SUPPLIER_UNBIND -> skip the action of resuming the supplier
Oliver Neukum 278644
		...
Oliver Neukum 278644
    pm_runtime_clean_up_links
Oliver Neukum 278644
    ...
Oliver Neukum 278644
Oliver Neukum 278644
Correct suspend/resume ordering between a supplier device and its consumer
Oliver Neukum 278644
devices (resume the supplier device before resuming consumer devices, and
Oliver Neukum 278644
suspend consumer devices before suspending the supplier device) should be
Oliver Neukum 278644
guaranteed by runtime PM, but the state checks in rpm_get_supplier() and
Oliver Neukum 278644
rpm_put_supplier() break this rule, so remove them.
Oliver Neukum 278644
Oliver Neukum 278644
Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
Oliver Neukum 278644
[ rjw: Subject and changelog edits ]
Oliver Neukum 278644
Cc: All applicable <stable@vger.kernel.org>
Oliver Neukum 278644
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Oliver Neukum 278644
Signed-off-by: Oliver Neukum <oneukum@suse.com>
Oliver Neukum 278644
---
Oliver Neukum 278644
 drivers/base/power/runtime.c |    3 +--
Oliver Neukum 278644
 1 file changed, 1 insertion(+), 2 deletions(-)
Oliver Neukum 278644
Oliver Neukum 278644
--- a/drivers/base/power/runtime.c
Oliver Neukum 278644
+++ b/drivers/base/power/runtime.c
Mel Gorman 7cd982
@@ -291,8 +291,7 @@ static int rpm_get_suppliers(struct devi
Mel Gorman 7cd982
 				device_links_read_lock_held()) {
Oliver Neukum 278644
 		int retval;
Oliver Neukum 278644
 
Oliver Neukum 278644
-		if (!(link->flags & DL_FLAG_PM_RUNTIME) ||
Oliver Neukum 278644
-		    READ_ONCE(link->status) == DL_STATE_SUPPLIER_UNBIND)
Oliver Neukum 278644
+		if (!(link->flags & DL_FLAG_PM_RUNTIME))
Oliver Neukum 278644
 			continue;
Oliver Neukum 278644
 
Oliver Neukum 278644
 		retval = pm_runtime_get_sync(link->supplier);