diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 3ef70f1..48862bc 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -434,7 +434,7 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info) * The driver of @dev will not receive interrupts while this function is being * executed. */ -static int device_resume_noirq(struct device *dev, pm_message_t state) +int device_resume_noirq(struct device *dev, pm_message_t state) { int error = 0; ktime_t starttime = ktime_get(); @@ -467,6 +467,15 @@ End: return error; } +#define to_dev(obj) container_of(obj, struct device, kobj) + +struct device *my_get_device(struct device *dev) +{ + if (!dev || atomic_read(&dev->kobj.kref.refcount) == 0) + return NULL; + return to_dev(kobject_get(&dev->kobj)); +} + /** * dpm_resume_noirq - Execute "early resume" callbacks for non-sysdev devices. * @state: PM transition of the system being carried out. @@ -483,16 +492,18 @@ void dpm_resume_noirq(pm_message_t state) struct device *dev = to_device(dpm_noirq_list.next); int error; - get_device(dev); list_move_tail(&dev->power.entry, &dpm_suspended_list); - mutex_unlock(&dpm_list_mtx); + if (my_get_device(dev)) { + mutex_unlock(&dpm_list_mtx); - error = device_resume_noirq(dev, state); - if (error) - pm_dev_err(dev, state, " early", error); + error = device_resume_noirq(dev, state); + if (error) + pm_dev_err(dev, state, " early", error); - mutex_lock(&dpm_list_mtx); - put_device(dev); + mutex_lock(&dpm_list_mtx); + put_device(dev); + } else + printk("dpm_resume_noirq: kref_get %s %s\n", dev_driver_string(dev), dev_name(dev)); } mutex_unlock(&dpm_list_mtx); dpm_show_time(starttime, state, "early"); @@ -526,7 +537,7 @@ static int legacy_resume(struct device *dev, int (*cb)(struct device *dev)) * @state: PM transition of the system being carried out. * @async: If true, the device is being resumed asynchronously. */ -static int device_resume(struct device *dev, pm_message_t state, bool async) +int device_resume(struct device *dev, pm_message_t state, bool async) { int error = 0; ktime_t starttime = ktime_get(); @@ -578,7 +589,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) return error; } -static void async_resume(void *data, async_cookie_t cookie) +void async_resume(void *data, async_cookie_t cookie) { struct device *dev = (struct device *)data; int error; @@ -589,7 +600,7 @@ static void async_resume(void *data, async_cookie_t cookie) put_device(dev); } -static bool is_async(struct device *dev) +bool is_async(struct device *dev) { return dev->power.async_suspend && pm_async_enabled && !pm_trace_is_enabled(); @@ -602,7 +613,7 @@ static bool is_async(struct device *dev) * Execute the appropriate "resume" callback for all devices whose status * indicates that they are suspended. */ -static void dpm_resume(pm_message_t state) +void dpm_resume(pm_message_t state) { struct device *dev; ktime_t starttime = ktime_get(); @@ -614,28 +625,32 @@ static void dpm_resume(pm_message_t state) list_for_each_entry(dev, &dpm_suspended_list, power.entry) { INIT_COMPLETION(dev->power.completion); if (is_async(dev)) { - get_device(dev); - async_schedule(async_resume, dev); + if (my_get_device(dev)) + async_schedule(async_resume, dev); + else + printk("dpm_resume: 1 kref_get %s %s\n", dev_driver_string(dev), dev_name(dev)); } } while (!list_empty(&dpm_suspended_list)) { dev = to_device(dpm_suspended_list.next); - get_device(dev); - if (!is_async(dev)) { - int error; + if (my_get_device(dev)) { + if (!is_async(dev)) { + int error; - mutex_unlock(&dpm_list_mtx); + mutex_unlock(&dpm_list_mtx); - error = device_resume(dev, state, false); - if (error) - pm_dev_err(dev, state, "", error); + error = device_resume(dev, state, false); + if (error) + pm_dev_err(dev, state, "", error); - mutex_lock(&dpm_list_mtx); - } + mutex_lock(&dpm_list_mtx); + } + put_device(dev); + } else + printk("dpm_resume: 2 kref_get %s %s\n", dev_driver_string(dev), dev_name(dev)); if (!list_empty(&dev->power.entry)) list_move_tail(&dev->power.entry, &dpm_prepared_list); - put_device(dev); } mutex_unlock(&dpm_list_mtx); async_synchronize_full(); @@ -647,7 +662,7 @@ static void dpm_resume(pm_message_t state) * @dev: Device to handle. * @state: PM transition of the system being carried out. */ -static void device_complete(struct device *dev, pm_message_t state) +void device_complete(struct device *dev, pm_message_t state) { device_lock(dev); @@ -676,25 +691,34 @@ static void device_complete(struct device *dev, pm_message_t state) * Execute the ->complete() callbacks for all devices whose PM status is not * DPM_ON (this allows new devices to be registered). */ -static void dpm_complete(pm_message_t state) +void dpm_complete(pm_message_t state) { struct list_head list; + int got; INIT_LIST_HEAD(&list); mutex_lock(&dpm_list_mtx); while (!list_empty(&dpm_prepared_list)) { struct device *dev = to_device(dpm_prepared_list.prev); - get_device(dev); + if (my_get_device(dev)) + got = 1; + else { + got = 0; + printk("dpm_complete: %s %s\n", dev_driver_string(dev), dev_name(dev)); + } dev->power.in_suspend = false; list_move(&dev->power.entry, &list); mutex_unlock(&dpm_list_mtx); - device_complete(dev, state); - pm_runtime_put_sync(dev); + if (got) { + device_complete(dev, state); + pm_runtime_put_sync(dev); + } mutex_lock(&dpm_list_mtx); - put_device(dev); + if (got) + put_device(dev); } list_splice(&list, &dpm_list); mutex_unlock(&dpm_list_mtx); @@ -747,7 +771,7 @@ static pm_message_t resume_event(pm_message_t sleep_state) * The driver of @dev will not receive interrupts while this function is being * executed. */ -static int device_suspend_noirq(struct device *dev, pm_message_t state) +int device_suspend_noirq(struct device *dev, pm_message_t state) { int error = 0; ktime_t starttime = ktime_get(); @@ -977,7 +1001,7 @@ static int dpm_suspend(pm_message_t state) * Execute the ->prepare() callback(s) for given device. No new children of the * device may be registered after this function has returned. */ -static int device_prepare(struct device *dev, pm_message_t state) +int device_prepare(struct device *dev, pm_message_t state) { int error = 0; @@ -1016,7 +1040,7 @@ static int device_prepare(struct device *dev, pm_message_t state) * * Execute the ->prepare() callback(s) for all devices. */ -static int dpm_prepare(pm_message_t state) +int dpm_prepare(pm_message_t state) { int error = 0;