• Xiang Chen's avatar
    PM: runtime: Remove link state checks in rpm_get/put_supplier() · d12544fb
    Xiang Chen authored
    To support runtime PM for hisi SAS driver (the driver is in directory
    drivers/scsi/hisi_sas), we add device link between scsi_device->sdev_gendev
    (consumer device) and hisi_hba->dev(supplier device) with flags
    DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE.
    
    After runtime suspended consumers and supplier, unload the dirver which
    causes a hung.
    
    We found that it called function device_release_driver_internal() to
    release the supplier device (hisi_hba->dev), as the device link was
    busy, it set the device link state to DL_STATE_SUPPLIER_UNBIND, and
    then it called device_release_driver_internal() to release the consumer
    device (scsi_device->sdev_gendev).
    
    Then it would try to call pm_runtime_get_sync() to resume the consumer
    device, but because consumer-supplier relation existed, it would try
    to resume the supplier first, but as the link state was already
    DL_STATE_SUPPLIER_UNBIND, so it skipped resuming the supplier and only
    resumed the consumer which hanged (it sends IOs to resume scsi_device
    while the SAS controller is suspended).
    
    Simple flow is as follows:
    
    device_release_driver_internal -> (supplier device)
        if device_links_busy ->
    	device_links_unbind_consumers ->
    	    ...
    	    WRITE_ONCE(link->status, DL_STATE_SUPPLIER_UNBIND)
    	    device_release_driver_internal (consumer device)
        pm_runtime_get_sync -> (consumer device)
    	...
    	__rpm_callback ->
    	    rpm_get_suppliers ->
    		if link->state == DL_STATE_SUPPLIER_UNBIND -> skip the action of resuming the supplier
    		...
        pm_runtime_clean_up_links
        ...
    
    Correct suspend/resume ordering between a supplier device and its consumer
    devices (resume the supplier device before resuming consumer devices, and
    suspend consumer devices before suspending the supplier device) should be
    guaranteed by runtime PM, but the state checks in rpm_get_supplier() and
    rpm_put_supplier() break this rule, so remove them.
    Signed-off-by: default avatarXiang Chen <chenxiang66@hisilicon.com>
    [ rjw: Subject and changelog edits ]
    Cc: All applicable <stable@vger.kernel.org>
    Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
    d12544fb
runtime.c 50.5 KB