diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2011-07-12 00:39:29 +0200 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2011-07-12 00:39:29 +0200 |
commit | 17b75eca7683d4942f4d8d00563fd15f37c39589 (patch) | |
tree | 539ee88f2c4008eec206ca98cec54263deeae708 /include/linux/pm_domain.h | |
parent | b6c10c84665912985d0bf9b6ae8ce19fc4298d9f (diff) |
PM / Domains: Do not execute device callbacks under locks
Currently, the .start_device() and .stop_device() callbacks from
struct generic_pm_domain() as well as the device drivers' runtime PM
callbacks used by the generic PM domains code are executed under
the generic PM domain lock. This, unfortunately, is prone to
deadlocks, for example if a device and its parent are boths members
of the same PM domain. For this reason, it would be better if the
PM domains code didn't execute device callbacks under the lock.
Rework the locking in the generic PM domains code so that the lock
is dropped for the execution of device callbacks. To this end,
introduce PM domains states reflecting the current status of a PM
domain and such that the PM domain lock cannot be acquired if the
status is GPD_STATE_BUSY. Make threads attempting to acquire a PM
domain's lock wait until the status changes to either
GPD_STATE_ACTIVE or GPD_STATE_POWER_OFF.
This change by itself doesn't fix the deadlock problem mentioned
above, but the mechanism introduced by it will be used for for this
purpose by a subsequent patch.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'include/linux/pm_domain.h')
-rw-r--r-- | include/linux/pm_domain.h | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 14fb0953fa4..c71457cb8a7 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -11,8 +11,11 @@ #include <linux/device.h> -#define GPD_IN_SUSPEND 1 -#define GPD_POWER_OFF 2 +enum gpd_status { + GPD_STATE_ACTIVE = 0, /* PM domain is active */ + GPD_STATE_BUSY, /* Something is happening to the PM domain */ + GPD_STATE_POWER_OFF, /* PM domain is off */ +}; struct dev_power_governor { bool (*power_down_ok)(struct dev_pm_domain *domain); @@ -29,7 +32,8 @@ struct generic_pm_domain { struct work_struct power_off_work; unsigned int in_progress; /* Number of devices being suspended now */ unsigned int sd_count; /* Number of subdomains with power "on" */ - bool power_is_off; /* Whether or not power has been removed */ + enum gpd_status status; /* Current state of the domain */ + wait_queue_head_t status_wait_queue; unsigned int device_count; /* Number of devices */ unsigned int suspended_count; /* System suspend device counter */ unsigned int prepared_count; /* Suspend counter of prepared devices */ |