diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/acpi/sleep.c | 16 | ||||
| -rw-r--r-- | drivers/amba/bus.c | 136 | ||||
| -rw-r--r-- | drivers/base/firmware_class.c | 4 | ||||
| -rw-r--r-- | drivers/base/platform.c | 115 | ||||
| -rw-r--r-- | drivers/base/power/generic_ops.c | 91 | ||||
| -rw-r--r-- | drivers/base/power/main.c | 375 | ||||
| -rw-r--r-- | drivers/base/power/runtime.c | 9 | ||||
| -rw-r--r-- | drivers/bluetooth/btmrvl_main.c | 2 | ||||
| -rw-r--r-- | drivers/dma/dmatest.c | 46 | ||||
| -rw-r--r-- | drivers/mfd/twl6030-irq.c | 2 | ||||
| -rw-r--r-- | drivers/net/irda/stir4200.c | 2 | ||||
| -rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 15 | ||||
| -rw-r--r-- | drivers/staging/rts_pstor/rtsx.c | 2 | ||||
| -rw-r--r-- | drivers/usb/storage/usb.c | 13 | 
14 files changed, 250 insertions, 578 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 6d9a3ab58db..0a7ed69546b 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -476,6 +476,22 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {  		DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW520F"),  		},  	}, +	{ +	.callback = init_nvs_nosave, +	.ident = "Asus K54C", +	.matches = { +		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), +		DMI_MATCH(DMI_PRODUCT_NAME, "K54C"), +		}, +	}, +	{ +	.callback = init_nvs_nosave, +	.ident = "Asus K54HR", +	.matches = { +		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), +		DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"), +		}, +	},  	{},  };  #endif /* CONFIG_SUSPEND */ diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index bd230e80113..0304b3fdff5 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -109,31 +109,7 @@ static int amba_legacy_resume(struct device *dev)  	return ret;  } -static int amba_pm_prepare(struct device *dev) -{ -	struct device_driver *drv = dev->driver; -	int ret = 0; - -	if (drv && drv->pm && drv->pm->prepare) -		ret = drv->pm->prepare(dev); - -	return ret; -} - -static void amba_pm_complete(struct device *dev) -{ -	struct device_driver *drv = dev->driver; - -	if (drv && drv->pm && drv->pm->complete) -		drv->pm->complete(dev); -} - -#else /* !CONFIG_PM_SLEEP */ - -#define amba_pm_prepare		NULL -#define amba_pm_complete		NULL - -#endif /* !CONFIG_PM_SLEEP */ +#endif /* CONFIG_PM_SLEEP */  #ifdef CONFIG_SUSPEND @@ -155,22 +131,6 @@ static int amba_pm_suspend(struct device *dev)  	return ret;  } -static int amba_pm_suspend_noirq(struct device *dev) -{ -	struct device_driver *drv = dev->driver; -	int ret = 0; - -	if (!drv) -		return 0; - -	if (drv->pm) { -		if (drv->pm->suspend_noirq) -			ret = drv->pm->suspend_noirq(dev); -	} - -	return ret; -} -  static int amba_pm_resume(struct device *dev)  {  	struct device_driver *drv = dev->driver; @@ -189,28 +149,10 @@ static int amba_pm_resume(struct device *dev)  	return ret;  } -static int amba_pm_resume_noirq(struct device *dev) -{ -	struct device_driver *drv = dev->driver; -	int ret = 0; - -	if (!drv) -		return 0; - -	if (drv->pm) { -		if (drv->pm->resume_noirq) -			ret = drv->pm->resume_noirq(dev); -	} - -	return ret; -} -  #else /* !CONFIG_SUSPEND */  #define amba_pm_suspend		NULL  #define amba_pm_resume		NULL -#define amba_pm_suspend_noirq	NULL -#define amba_pm_resume_noirq	NULL  #endif /* !CONFIG_SUSPEND */ @@ -234,22 +176,6 @@ static int amba_pm_freeze(struct device *dev)  	return ret;  } -static int amba_pm_freeze_noirq(struct device *dev) -{ -	struct device_driver *drv = dev->driver; -	int ret = 0; - -	if (!drv) -		return 0; - -	if (drv->pm) { -		if (drv->pm->freeze_noirq) -			ret = drv->pm->freeze_noirq(dev); -	} - -	return ret; -} -  static int amba_pm_thaw(struct device *dev)  {  	struct device_driver *drv = dev->driver; @@ -268,22 +194,6 @@ static int amba_pm_thaw(struct device *dev)  	return ret;  } -static int amba_pm_thaw_noirq(struct device *dev) -{ -	struct device_driver *drv = dev->driver; -	int ret = 0; - -	if (!drv) -		return 0; - -	if (drv->pm) { -		if (drv->pm->thaw_noirq) -			ret = drv->pm->thaw_noirq(dev); -	} - -	return ret; -} -  static int amba_pm_poweroff(struct device *dev)  {  	struct device_driver *drv = dev->driver; @@ -302,22 +212,6 @@ static int amba_pm_poweroff(struct device *dev)  	return ret;  } -static int amba_pm_poweroff_noirq(struct device *dev) -{ -	struct device_driver *drv = dev->driver; -	int ret = 0; - -	if (!drv) -		return 0; - -	if (drv->pm) { -		if (drv->pm->poweroff_noirq) -			ret = drv->pm->poweroff_noirq(dev); -	} - -	return ret; -} -  static int amba_pm_restore(struct device *dev)  {  	struct device_driver *drv = dev->driver; @@ -336,32 +230,12 @@ static int amba_pm_restore(struct device *dev)  	return ret;  } -static int amba_pm_restore_noirq(struct device *dev) -{ -	struct device_driver *drv = dev->driver; -	int ret = 0; - -	if (!drv) -		return 0; - -	if (drv->pm) { -		if (drv->pm->restore_noirq) -			ret = drv->pm->restore_noirq(dev); -	} - -	return ret; -} -  #else /* !CONFIG_HIBERNATE_CALLBACKS */  #define amba_pm_freeze		NULL  #define amba_pm_thaw		NULL  #define amba_pm_poweroff		NULL  #define amba_pm_restore		NULL -#define amba_pm_freeze_noirq	NULL -#define amba_pm_thaw_noirq		NULL -#define amba_pm_poweroff_noirq	NULL -#define amba_pm_restore_noirq	NULL  #endif /* !CONFIG_HIBERNATE_CALLBACKS */ @@ -402,20 +276,12 @@ static int amba_pm_runtime_resume(struct device *dev)  #ifdef CONFIG_PM  static const struct dev_pm_ops amba_pm = { -	.prepare	= amba_pm_prepare, -	.complete	= amba_pm_complete,  	.suspend	= amba_pm_suspend,  	.resume		= amba_pm_resume,  	.freeze		= amba_pm_freeze,  	.thaw		= amba_pm_thaw,  	.poweroff	= amba_pm_poweroff,  	.restore	= amba_pm_restore, -	.suspend_noirq	= amba_pm_suspend_noirq, -	.resume_noirq	= amba_pm_resume_noirq, -	.freeze_noirq	= amba_pm_freeze_noirq, -	.thaw_noirq	= amba_pm_thaw_noirq, -	.poweroff_noirq	= amba_pm_poweroff_noirq, -	.restore_noirq	= amba_pm_restore_noirq,  	SET_RUNTIME_PM_OPS(  		amba_pm_runtime_suspend,  		amba_pm_runtime_resume, diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 06ed6b4e7df..d5585da14c8 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -534,6 +534,8 @@ static int _request_firmware(const struct firmware **firmware_p,  		return 0;  	} +	read_lock_usermodehelper(); +  	if (WARN_ON(usermodehelper_is_disabled())) {  		dev_err(device, "firmware: %s will not be loaded\n", name);  		retval = -EBUSY; @@ -572,6 +574,8 @@ static int _request_firmware(const struct firmware **firmware_p,  	fw_destroy_instance(fw_priv);  out: +	read_unlock_usermodehelper(); +  	if (retval) {  		release_firmware(firmware);  		*firmware_p = NULL; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 7a24895543e..7d912d5675d 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -700,25 +700,6 @@ static int platform_legacy_resume(struct device *dev)  	return ret;  } -int platform_pm_prepare(struct device *dev) -{ -	struct device_driver *drv = dev->driver; -	int ret = 0; - -	if (drv && drv->pm && drv->pm->prepare) -		ret = drv->pm->prepare(dev); - -	return ret; -} - -void platform_pm_complete(struct device *dev) -{ -	struct device_driver *drv = dev->driver; - -	if (drv && drv->pm && drv->pm->complete) -		drv->pm->complete(dev); -} -  #endif /* CONFIG_PM_SLEEP */  #ifdef CONFIG_SUSPEND @@ -741,22 +722,6 @@ int platform_pm_suspend(struct device *dev)  	return ret;  } -int platform_pm_suspend_noirq(struct device *dev) -{ -	struct device_driver *drv = dev->driver; -	int ret = 0; - -	if (!drv) -		return 0; - -	if (drv->pm) { -		if (drv->pm->suspend_noirq) -			ret = drv->pm->suspend_noirq(dev); -	} - -	return ret; -} -  int platform_pm_resume(struct device *dev)  {  	struct device_driver *drv = dev->driver; @@ -775,22 +740,6 @@ int platform_pm_resume(struct device *dev)  	return ret;  } -int platform_pm_resume_noirq(struct device *dev) -{ -	struct device_driver *drv = dev->driver; -	int ret = 0; - -	if (!drv) -		return 0; - -	if (drv->pm) { -		if (drv->pm->resume_noirq) -			ret = drv->pm->resume_noirq(dev); -	} - -	return ret; -} -  #endif /* CONFIG_SUSPEND */  #ifdef CONFIG_HIBERNATE_CALLBACKS @@ -813,22 +762,6 @@ int platform_pm_freeze(struct device *dev)  	return ret;  } -int platform_pm_freeze_noirq(struct device *dev) -{ -	struct device_driver *drv = dev->driver; -	int ret = 0; - -	if (!drv) -		return 0; - -	if (drv->pm) { -		if (drv->pm->freeze_noirq) -			ret = drv->pm->freeze_noirq(dev); -	} - -	return ret; -} -  int platform_pm_thaw(struct device *dev)  {  	struct device_driver *drv = dev->driver; @@ -847,22 +780,6 @@ int platform_pm_thaw(struct device *dev)  	return ret;  } -int platform_pm_thaw_noirq(struct device *dev) -{ -	struct device_driver *drv = dev->driver; -	int ret = 0; - -	if (!drv) -		return 0; - -	if (drv->pm) { -		if (drv->pm->thaw_noirq) -			ret = drv->pm->thaw_noirq(dev); -	} - -	return ret; -} -  int platform_pm_poweroff(struct device *dev)  {  	struct device_driver *drv = dev->driver; @@ -881,22 +798,6 @@ int platform_pm_poweroff(struct device *dev)  	return ret;  } -int platform_pm_poweroff_noirq(struct device *dev) -{ -	struct device_driver *drv = dev->driver; -	int ret = 0; - -	if (!drv) -		return 0; - -	if (drv->pm) { -		if (drv->pm->poweroff_noirq) -			ret = drv->pm->poweroff_noirq(dev); -	} - -	return ret; -} -  int platform_pm_restore(struct device *dev)  {  	struct device_driver *drv = dev->driver; @@ -915,22 +816,6 @@ int platform_pm_restore(struct device *dev)  	return ret;  } -int platform_pm_restore_noirq(struct device *dev) -{ -	struct device_driver *drv = dev->driver; -	int ret = 0; - -	if (!drv) -		return 0; - -	if (drv->pm) { -		if (drv->pm->restore_noirq) -			ret = drv->pm->restore_noirq(dev); -	} - -	return ret; -} -  #endif /* CONFIG_HIBERNATE_CALLBACKS */  static const struct dev_pm_ops platform_dev_pm_ops = { diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c index 265a0ee3b49..10bdd793f0b 100644 --- a/drivers/base/power/generic_ops.c +++ b/drivers/base/power/generic_ops.c @@ -97,16 +97,16 @@ int pm_generic_prepare(struct device *dev)   * @event: PM transition of the system under way.   * @bool: Whether or not this is the "noirq" stage.   * - * If the device has not been suspended at run time, execute the - * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and - * return its error code.  Otherwise, return zero. + * Execute the PM callback corresponding to @event provided by the driver of + * @dev, if defined, and return its error code.    Return 0 if the callback is + * not present.   */  static int __pm_generic_call(struct device *dev, int event, bool noirq)  {  	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;  	int (*callback)(struct device *); -	if (!pm || pm_runtime_suspended(dev)) +	if (!pm)  		return 0;  	switch (event) { @@ -119,9 +119,15 @@ static int __pm_generic_call(struct device *dev, int event, bool noirq)  	case PM_EVENT_HIBERNATE:  		callback = noirq ? pm->poweroff_noirq : pm->poweroff;  		break; +	case PM_EVENT_RESUME: +		callback = noirq ? pm->resume_noirq : pm->resume; +		break;  	case PM_EVENT_THAW:  		callback = noirq ? pm->thaw_noirq : pm->thaw;  		break; +	case PM_EVENT_RESTORE: +		callback = noirq ? pm->restore_noirq : pm->restore; +		break;  	default:  		callback = NULL;  		break; @@ -211,56 +217,12 @@ int pm_generic_thaw(struct device *dev)  EXPORT_SYMBOL_GPL(pm_generic_thaw);  /** - * __pm_generic_resume - Generic resume/restore callback for subsystems. - * @dev: Device to handle. - * @event: PM transition of the system under way. - * @bool: Whether or not this is the "noirq" stage. - * - * Execute the resume/resotre callback provided by the @dev's driver, if - * defined.  If it returns 0, change the device's runtime PM status to 'active'. - * Return the callback's error code. - */ -static int __pm_generic_resume(struct device *dev, int event, bool noirq) -{ -	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; -	int (*callback)(struct device *); -	int ret; - -	if (!pm) -		return 0; - -	switch (event) { -	case PM_EVENT_RESUME: -		callback = noirq ? pm->resume_noirq : pm->resume; -		break; -	case PM_EVENT_RESTORE: -		callback = noirq ? pm->restore_noirq : pm->restore; -		break; -	default: -		callback = NULL; -		break; -	} - -	if (!callback) -		return 0; - -	ret = callback(dev); -	if (!ret && !noirq && pm_runtime_enabled(dev)) { -		pm_runtime_disable(dev); -		pm_runtime_set_active(dev); -		pm_runtime_enable(dev); -	} - -	return ret; -} - -/**   * pm_generic_resume_noirq - Generic resume_noirq callback for subsystems.   * @dev: Device to resume.   */  int pm_generic_resume_noirq(struct device *dev)  { -	return __pm_generic_resume(dev, PM_EVENT_RESUME, true); +	return __pm_generic_call(dev, PM_EVENT_RESUME, true);  }  EXPORT_SYMBOL_GPL(pm_generic_resume_noirq); @@ -270,7 +232,7 @@ EXPORT_SYMBOL_GPL(pm_generic_resume_noirq);   */  int pm_generic_resume(struct device *dev)  { -	return __pm_generic_resume(dev, PM_EVENT_RESUME, false); +	return __pm_generic_call(dev, PM_EVENT_RESUME, false);  }  EXPORT_SYMBOL_GPL(pm_generic_resume); @@ -280,7 +242,7 @@ EXPORT_SYMBOL_GPL(pm_generic_resume);   */  int pm_generic_restore_noirq(struct device *dev)  { -	return __pm_generic_resume(dev, PM_EVENT_RESTORE, true); +	return __pm_generic_call(dev, PM_EVENT_RESTORE, true);  }  EXPORT_SYMBOL_GPL(pm_generic_restore_noirq); @@ -290,7 +252,7 @@ EXPORT_SYMBOL_GPL(pm_generic_restore_noirq);   */  int pm_generic_restore(struct device *dev)  { -	return __pm_generic_resume(dev, PM_EVENT_RESTORE, false); +	return __pm_generic_call(dev, PM_EVENT_RESTORE, false);  }  EXPORT_SYMBOL_GPL(pm_generic_restore); @@ -314,28 +276,3 @@ void pm_generic_complete(struct device *dev)  	pm_runtime_idle(dev);  }  #endif /* CONFIG_PM_SLEEP */ - -struct dev_pm_ops generic_subsys_pm_ops = { -#ifdef CONFIG_PM_SLEEP -	.prepare = pm_generic_prepare, -	.suspend = pm_generic_suspend, -	.suspend_noirq = pm_generic_suspend_noirq, -	.resume = pm_generic_resume, -	.resume_noirq = pm_generic_resume_noirq, -	.freeze = pm_generic_freeze, -	.freeze_noirq = pm_generic_freeze_noirq, -	.thaw = pm_generic_thaw, -	.thaw_noirq = pm_generic_thaw_noirq, -	.poweroff = pm_generic_poweroff, -	.poweroff_noirq = pm_generic_poweroff_noirq, -	.restore = pm_generic_restore, -	.restore_noirq = pm_generic_restore_noirq, -	.complete = pm_generic_complete, -#endif -#ifdef CONFIG_PM_RUNTIME -	.runtime_suspend = pm_generic_runtime_suspend, -	.runtime_resume = pm_generic_runtime_resume, -	.runtime_idle = pm_generic_runtime_idle, -#endif -}; -EXPORT_SYMBOL_GPL(generic_subsys_pm_ops); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index c3d2dfcf438..e2cc3d2e0ec 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -32,6 +32,8 @@  #include "../base.h"  #include "power.h" +typedef int (*pm_callback_t)(struct device *); +  /*   * The entries in the dpm_list list are in a depth first order, simply   * because children are guaranteed to be discovered after parents, and @@ -164,8 +166,9 @@ static ktime_t initcall_debug_start(struct device *dev)  	ktime_t calltime = ktime_set(0, 0);  	if (initcall_debug) { -		pr_info("calling  %s+ @ %i\n", -				dev_name(dev), task_pid_nr(current)); +		pr_info("calling  %s+ @ %i, parent: %s\n", +			dev_name(dev), task_pid_nr(current), +			dev->parent ? dev_name(dev->parent) : "none");  		calltime = ktime_get();  	} @@ -211,151 +214,69 @@ static void dpm_wait_for_children(struct device *dev, bool async)  }  /** - * pm_op - Execute the PM operation appropriate for given PM event. - * @dev: Device to handle. + * pm_op - Return the PM operation appropriate for given PM event.   * @ops: PM operations to choose from.   * @state: PM transition of the system being carried out.   */ -static int pm_op(struct device *dev, -		 const struct dev_pm_ops *ops, -		 pm_message_t state) +static pm_callback_t pm_op(const struct dev_pm_ops *ops, pm_message_t state)  { -	int error = 0; -	ktime_t calltime; - -	calltime = initcall_debug_start(dev); -  	switch (state.event) {  #ifdef CONFIG_SUSPEND  	case PM_EVENT_SUSPEND: -		if (ops->suspend) { -			error = ops->suspend(dev); -			suspend_report_result(ops->suspend, error); -		} -		break; +		return ops->suspend;  	case PM_EVENT_RESUME: -		if (ops->resume) { -			error = ops->resume(dev); -			suspend_report_result(ops->resume, error); -		} -		break; +		return ops->resume;  #endif /* CONFIG_SUSPEND */  #ifdef CONFIG_HIBERNATE_CALLBACKS  	case PM_EVENT_FREEZE:  	case PM_EVENT_QUIESCE: -		if (ops->freeze) { -			error = ops->freeze(dev); -			suspend_report_result(ops->freeze, error); -		} -		break; +		return ops->freeze;  	case PM_EVENT_HIBERNATE: -		if (ops->poweroff) { -			error = ops->poweroff(dev); -			suspend_report_result(ops->poweroff, error); -		} -		break; +		return ops->poweroff;  	case PM_EVENT_THAW:  	case PM_EVENT_RECOVER: -		if (ops->thaw) { -			error = ops->thaw(dev); -			suspend_report_result(ops->thaw, error); -		} +		return ops->thaw;  		break;  	case PM_EVENT_RESTORE: -		if (ops->restore) { -			error = ops->restore(dev); -			suspend_report_result(ops->restore, error); -		} -		break; +		return ops->restore;  #endif /* CONFIG_HIBERNATE_CALLBACKS */ -	default: -		error = -EINVAL;  	} -	initcall_debug_report(dev, calltime, error); - -	return error; +	return NULL;  }  /** - * pm_noirq_op - Execute the PM operation appropriate for given PM event. - * @dev: Device to handle. + * pm_noirq_op - Return the PM operation appropriate for given PM event.   * @ops: PM operations to choose from.   * @state: PM transition of the system being carried out.   *   * The driver of @dev will not receive interrupts while this function is being   * executed.   */ -static int pm_noirq_op(struct device *dev, -			const struct dev_pm_ops *ops, -			pm_message_t state) +static pm_callback_t pm_noirq_op(const struct dev_pm_ops *ops, pm_message_t state)  { -	int error = 0; -	ktime_t calltime = ktime_set(0, 0), delta, rettime; - -	if (initcall_debug) { -		pr_info("calling  %s+ @ %i, parent: %s\n", -				dev_name(dev), task_pid_nr(current), -				dev->parent ? dev_name(dev->parent) : "none"); -		calltime = ktime_get(); -	} -  	switch (state.event) {  #ifdef CONFIG_SUSPEND  	case PM_EVENT_SUSPEND: -		if (ops->suspend_noirq) { -			error = ops->suspend_noirq(dev); -			suspend_report_result(ops->suspend_noirq, error); -		} -		break; +		return ops->suspend_noirq;  	case PM_EVENT_RESUME: -		if (ops->resume_noirq) { -			error = ops->resume_noirq(dev); -			suspend_report_result(ops->resume_noirq, error); -		} -		break; +		return ops->resume_noirq;  #endif /* CONFIG_SUSPEND */  #ifdef CONFIG_HIBERNATE_CALLBACKS  	case PM_EVENT_FREEZE:  	case PM_EVENT_QUIESCE: -		if (ops->freeze_noirq) { -			error = ops->freeze_noirq(dev); -			suspend_report_result(ops->freeze_noirq, error); -		} -		break; +		return ops->freeze_noirq;  	case PM_EVENT_HIBERNATE: -		if (ops->poweroff_noirq) { -			error = ops->poweroff_noirq(dev); -			suspend_report_result(ops->poweroff_noirq, error); -		} -		break; +		return ops->poweroff_noirq;  	case PM_EVENT_THAW:  	case PM_EVENT_RECOVER: -		if (ops->thaw_noirq) { -			error = ops->thaw_noirq(dev); -			suspend_report_result(ops->thaw_noirq, error); -		} -		break; +		return ops->thaw_noirq;  	case PM_EVENT_RESTORE: -		if (ops->restore_noirq) { -			error = ops->restore_noirq(dev); -			suspend_report_result(ops->restore_noirq, error); -		} -		break; +		return ops->restore_noirq;  #endif /* CONFIG_HIBERNATE_CALLBACKS */ -	default: -		error = -EINVAL; -	} - -	if (initcall_debug) { -		rettime = ktime_get(); -		delta = ktime_sub(rettime, calltime); -		printk("initcall %s_i+ returned %d after %Ld usecs\n", -			dev_name(dev), error, -			(unsigned long long)ktime_to_ns(delta) >> 10);  	} -	return error; +	return NULL;  }  static char *pm_verb(int event) @@ -413,6 +334,26 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info)  		usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC);  } +static int dpm_run_callback(pm_callback_t cb, struct device *dev, +			    pm_message_t state, char *info) +{ +	ktime_t calltime; +	int error; + +	if (!cb) +		return 0; + +	calltime = initcall_debug_start(dev); + +	pm_dev_dbg(dev, state, info); +	error = cb(dev); +	suspend_report_result(cb, error); + +	initcall_debug_report(dev, calltime, error); + +	return error; +} +  /*------------------------- Resume routines -------------------------*/  /** @@ -425,25 +366,34 @@ static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info)   */  static int device_resume_noirq(struct device *dev, pm_message_t state)  { +	pm_callback_t callback = NULL; +	char *info = NULL;  	int error = 0;  	TRACE_DEVICE(dev);  	TRACE_RESUME(0);  	if (dev->pm_domain) { -		pm_dev_dbg(dev, state, "EARLY power domain "); -		error = pm_noirq_op(dev, &dev->pm_domain->ops, state); +		info = "EARLY power domain "; +		callback = pm_noirq_op(&dev->pm_domain->ops, state);  	} else if (dev->type && dev->type->pm) { -		pm_dev_dbg(dev, state, "EARLY type "); -		error = pm_noirq_op(dev, dev->type->pm, state); +		info = "EARLY type "; +		callback = pm_noirq_op(dev->type->pm, state);  	} else if (dev->class && dev->class->pm) { -		pm_dev_dbg(dev, state, "EARLY class "); -		error = pm_noirq_op(dev, dev->class->pm, state); +		info = "EARLY class "; +		callback = pm_noirq_op(dev->class->pm, state);  	} else if (dev->bus && dev->bus->pm) { -		pm_dev_dbg(dev, state, "EARLY "); -		error = pm_noirq_op(dev, dev->bus->pm, state); +		info = "EARLY bus "; +		callback = pm_noirq_op(dev->bus->pm, state);  	} +	if (!callback && dev->driver && dev->driver->pm) { +		info = "EARLY driver "; +		callback = pm_noirq_op(dev->driver->pm, state); +	} + +	error = dpm_run_callback(callback, dev, state, info); +  	TRACE_RESUME(error);  	return error;  } @@ -486,26 +436,6 @@ void dpm_resume_noirq(pm_message_t state)  EXPORT_SYMBOL_GPL(dpm_resume_noirq);  /** - * legacy_resume - Execute a legacy (bus or class) resume callback for device. - * @dev: Device to resume. - * @cb: Resume callback to execute. - */ -static int legacy_resume(struct device *dev, int (*cb)(struct device *dev)) -{ -	int error; -	ktime_t calltime; - -	calltime = initcall_debug_start(dev); - -	error = cb(dev); -	suspend_report_result(cb, error); - -	initcall_debug_report(dev, calltime, error); - -	return error; -} - -/**   * device_resume - Execute "resume" callbacks for given device.   * @dev: Device to handle.   * @state: PM transition of the system being carried out. @@ -513,6 +443,8 @@ static int legacy_resume(struct device *dev, int (*cb)(struct device *dev))   */  static int device_resume(struct device *dev, pm_message_t state, bool async)  { +	pm_callback_t callback = NULL; +	char *info = NULL;  	int error = 0;  	bool put = false; @@ -535,40 +467,48 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)  	put = true;  	if (dev->pm_domain) { -		pm_dev_dbg(dev, state, "power domain "); -		error = pm_op(dev, &dev->pm_domain->ops, state); -		goto End; +		info = "power domain "; +		callback = pm_op(&dev->pm_domain->ops, state); +		goto Driver;  	}  	if (dev->type && dev->type->pm) { -		pm_dev_dbg(dev, state, "type "); -		error = pm_op(dev, dev->type->pm, state); -		goto End; +		info = "type "; +		callback = pm_op(dev->type->pm, state); +		goto Driver;  	}  	if (dev->class) {  		if (dev->class->pm) { -			pm_dev_dbg(dev, state, "class "); -			error = pm_op(dev, dev->class->pm, state); -			goto End; +			info = "class "; +			callback = pm_op(dev->class->pm, state); +			goto Driver;  		} else if (dev->class->resume) { -			pm_dev_dbg(dev, state, "legacy class "); -			error = legacy_resume(dev, dev->class->resume); +			info = "legacy class "; +			callback = dev->class->resume;  			goto End;  		}  	}  	if (dev->bus) {  		if (dev->bus->pm) { -			pm_dev_dbg(dev, state, ""); -			error = pm_op(dev, dev->bus->pm, state); +			info = "bus "; +			callback = pm_op(dev->bus->pm, state);  		} else if (dev->bus->resume) { -			pm_dev_dbg(dev, state, "legacy "); -			error = legacy_resume(dev, dev->bus->resume); +			info = "legacy bus "; +			callback = dev->bus->resume; +			goto End;  		}  	} + Driver: +	if (!callback && dev->driver && dev->driver->pm) { +		info = "driver "; +		callback = pm_op(dev->driver->pm, state); +	} +   End: +	error = dpm_run_callback(callback, dev, state, info);  	dev->power.is_suspended = false;   Unlock: @@ -660,24 +600,33 @@ void dpm_resume(pm_message_t state)   */  static void device_complete(struct device *dev, pm_message_t state)  { +	void (*callback)(struct device *) = NULL; +	char *info = NULL; +  	device_lock(dev);  	if (dev->pm_domain) { -		pm_dev_dbg(dev, state, "completing power domain "); -		if (dev->pm_domain->ops.complete) -			dev->pm_domain->ops.complete(dev); +		info = "completing power domain "; +		callback = dev->pm_domain->ops.complete;  	} else if (dev->type && dev->type->pm) { -		pm_dev_dbg(dev, state, "completing type "); -		if (dev->type->pm->complete) -			dev->type->pm->complete(dev); +		info = "completing type "; +		callback = dev->type->pm->complete;  	} else if (dev->class && dev->class->pm) { -		pm_dev_dbg(dev, state, "completing class "); -		if (dev->class->pm->complete) -			dev->class->pm->complete(dev); +		info = "completing class "; +		callback = dev->class->pm->complete;  	} else if (dev->bus && dev->bus->pm) { -		pm_dev_dbg(dev, state, "completing "); -		if (dev->bus->pm->complete) -			dev->bus->pm->complete(dev); +		info = "completing bus "; +		callback = dev->bus->pm->complete; +	} + +	if (!callback && dev->driver && dev->driver->pm) { +		info = "completing driver "; +		callback = dev->driver->pm->complete; +	} + +	if (callback) { +		pm_dev_dbg(dev, state, info); +		callback(dev);  	}  	device_unlock(dev); @@ -763,31 +712,29 @@ static pm_message_t resume_event(pm_message_t sleep_state)   */  static int device_suspend_noirq(struct device *dev, pm_message_t state)  { -	int error; +	pm_callback_t callback = NULL; +	char *info = NULL;  	if (dev->pm_domain) { -		pm_dev_dbg(dev, state, "LATE power domain "); -		error = pm_noirq_op(dev, &dev->pm_domain->ops, state); -		if (error) -			return error; +		info = "LATE power domain "; +		callback = pm_noirq_op(&dev->pm_domain->ops, state);  	} else if (dev->type && dev->type->pm) { -		pm_dev_dbg(dev, state, "LATE type "); -		error = pm_noirq_op(dev, dev->type->pm, state); -		if (error) -			return error; +		info = "LATE type "; +		callback = pm_noirq_op(dev->type->pm, state);  	} else if (dev->class && dev->class->pm) { -		pm_dev_dbg(dev, state, "LATE class "); -		error = pm_noirq_op(dev, dev->class->pm, state); -		if (error) -			return error; +		info = "LATE class "; +		callback = pm_noirq_op(dev->class->pm, state);  	} else if (dev->bus && dev->bus->pm) { -		pm_dev_dbg(dev, state, "LATE "); -		error = pm_noirq_op(dev, dev->bus->pm, state); -		if (error) -			return error; +		info = "LATE bus "; +		callback = pm_noirq_op(dev->bus->pm, state);  	} -	return 0; +	if (!callback && dev->driver && dev->driver->pm) { +		info = "LATE driver "; +		callback = pm_noirq_op(dev->driver->pm, state); +	} + +	return dpm_run_callback(callback, dev, state, info);  }  /** @@ -864,6 +811,8 @@ static int legacy_suspend(struct device *dev, pm_message_t state,   */  static int __device_suspend(struct device *dev, pm_message_t state, bool async)  { +	pm_callback_t callback = NULL; +	char *info = NULL;  	int error = 0;  	dpm_wait_for_children(dev, async); @@ -884,22 +833,22 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)  	device_lock(dev);  	if (dev->pm_domain) { -		pm_dev_dbg(dev, state, "power domain "); -		error = pm_op(dev, &dev->pm_domain->ops, state); -		goto End; +		info = "power domain "; +		callback = pm_op(&dev->pm_domain->ops, state); +		goto Run;  	}  	if (dev->type && dev->type->pm) { -		pm_dev_dbg(dev, state, "type "); -		error = pm_op(dev, dev->type->pm, state); -		goto End; +		info = "type "; +		callback = pm_op(dev->type->pm, state); +		goto Run;  	}  	if (dev->class) {  		if (dev->class->pm) { -			pm_dev_dbg(dev, state, "class "); -			error = pm_op(dev, dev->class->pm, state); -			goto End; +			info = "class "; +			callback = pm_op(dev->class->pm, state); +			goto Run;  		} else if (dev->class->suspend) {  			pm_dev_dbg(dev, state, "legacy class ");  			error = legacy_suspend(dev, state, dev->class->suspend); @@ -909,14 +858,23 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)  	if (dev->bus) {  		if (dev->bus->pm) { -			pm_dev_dbg(dev, state, ""); -			error = pm_op(dev, dev->bus->pm, state); +			info = "bus "; +			callback = pm_op(dev->bus->pm, state);  		} else if (dev->bus->suspend) { -			pm_dev_dbg(dev, state, "legacy "); +			pm_dev_dbg(dev, state, "legacy bus ");  			error = legacy_suspend(dev, state, dev->bus->suspend); +			goto End;  		}  	} + Run: +	if (!callback && dev->driver && dev->driver->pm) { +		info = "driver "; +		callback = pm_op(dev->driver->pm, state); +	} + +	error = dpm_run_callback(callback, dev, state, info); +   End:  	if (!error) {  		dev->power.is_suspended = true; @@ -1022,6 +980,8 @@ int dpm_suspend(pm_message_t state)   */  static int device_prepare(struct device *dev, pm_message_t state)  { +	int (*callback)(struct device *) = NULL; +	char *info = NULL;  	int error = 0;  	device_lock(dev); @@ -1029,34 +989,29 @@ static int device_prepare(struct device *dev, pm_message_t state)  	dev->power.wakeup_path = device_may_wakeup(dev);  	if (dev->pm_domain) { -		pm_dev_dbg(dev, state, "preparing power domain "); -		if (dev->pm_domain->ops.prepare) -			error = dev->pm_domain->ops.prepare(dev); -		suspend_report_result(dev->pm_domain->ops.prepare, error); -		if (error) -			goto End; +		info = "preparing power domain "; +		callback = dev->pm_domain->ops.prepare;  	} else if (dev->type && dev->type->pm) { -		pm_dev_dbg(dev, state, "preparing type "); -		if (dev->type->pm->prepare) -			error = dev->type->pm->prepare(dev); -		suspend_report_result(dev->type->pm->prepare, error); -		if (error) -			goto End; +		info = "preparing type "; +		callback = dev->type->pm->prepare;  	} else if (dev->class && dev->class->pm) { -		pm_dev_dbg(dev, state, "preparing class "); -		if (dev->class->pm->prepare) -			error = dev->class->pm->prepare(dev); -		suspend_report_result(dev->class->pm->prepare, error); -		if (error) -			goto End; +		info = "preparing class "; +		callback = dev->class->pm->prepare;  	} else if (dev->bus && dev->bus->pm) { -		pm_dev_dbg(dev, state, "preparing "); -		if (dev->bus->pm->prepare) -			error = dev->bus->pm->prepare(dev); -		suspend_report_result(dev->bus->pm->prepare, error); +		info = "preparing bus "; +		callback = dev->bus->pm->prepare; +	} + +	if (!callback && dev->driver && dev->driver->pm) { +		info = "preparing driver "; +		callback = dev->driver->pm->prepare; +	} + +	if (callback) { +		error = callback(dev); +		suspend_report_result(callback, error);  	} - End:  	device_unlock(dev);  	return error; diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 8c78443bca8..c56efd75653 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -250,6 +250,9 @@ static int rpm_idle(struct device *dev, int rpmflags)  	else  		callback = NULL; +	if (!callback && dev->driver && dev->driver->pm) +		callback = dev->driver->pm->runtime_idle; +  	if (callback)  		__rpm_callback(callback, dev); @@ -413,6 +416,9 @@ static int rpm_suspend(struct device *dev, int rpmflags)  	else  		callback = NULL; +	if (!callback && dev->driver && dev->driver->pm) +		callback = dev->driver->pm->runtime_suspend; +  	retval = rpm_callback(callback, dev);  	if (retval) {  		__update_runtime_status(dev, RPM_ACTIVE); @@ -633,6 +639,9 @@ static int rpm_resume(struct device *dev, int rpmflags)  	else  		callback = NULL; +	if (!callback && dev->driver && dev->driver->pm) +		callback = dev->driver->pm->runtime_resume; +  	retval = rpm_callback(callback, dev);  	if (retval) {  		__update_runtime_status(dev, RPM_SUSPENDED); diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index a88a78c8616..6c3defa5084 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -475,8 +475,6 @@ static int btmrvl_service_main_thread(void *data)  	init_waitqueue_entry(&wait, current); -	current->flags |= PF_NOFREEZE; -  	for (;;) {  		add_wait_queue(&thread->wait_q, &wait); diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index eb1d8641cf5..2b8661b54ea 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -214,9 +214,18 @@ static unsigned int dmatest_verify(u8 **bufs, unsigned int start,  	return error_count;  } -static void dmatest_callback(void *completion) +/* poor man's completion - we want to use wait_event_freezable() on it */ +struct dmatest_done { +	bool			done; +	wait_queue_head_t	*wait; +}; + +static void dmatest_callback(void *arg)  { -	complete(completion); +	struct dmatest_done *done = arg; + +	done->done = true; +	wake_up_all(done->wait);  }  /* @@ -235,7 +244,9 @@ static void dmatest_callback(void *completion)   */  static int dmatest_func(void *data)  { +	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_wait);  	struct dmatest_thread	*thread = data; +	struct dmatest_done	done = { .wait = &done_wait };  	struct dma_chan		*chan;  	const char		*thread_name;  	unsigned int		src_off, dst_off, len; @@ -252,7 +263,7 @@ static int dmatest_func(void *data)  	int			i;  	thread_name = current->comm; -	set_freezable_with_signal(); +	set_freezable();  	ret = -ENOMEM; @@ -306,9 +317,6 @@ static int dmatest_func(void *data)  		struct dma_async_tx_descriptor *tx = NULL;  		dma_addr_t dma_srcs[src_cnt];  		dma_addr_t dma_dsts[dst_cnt]; -		struct completion cmp; -		unsigned long start, tmo, end = 0 /* compiler... */; -		bool reload = true;  		u8 align = 0;  		total_tests++; @@ -391,9 +399,9 @@ static int dmatest_func(void *data)  			continue;  		} -		init_completion(&cmp); +		done.done = false;  		tx->callback = dmatest_callback; -		tx->callback_param = &cmp; +		tx->callback_param = &done;  		cookie = tx->tx_submit(tx);  		if (dma_submit_error(cookie)) { @@ -407,20 +415,20 @@ static int dmatest_func(void *data)  		}  		dma_async_issue_pending(chan); -		do { -			start = jiffies; -			if (reload) -				end = start + msecs_to_jiffies(timeout); -			else if (end <= start) -				end = start + 1; -			tmo = wait_for_completion_interruptible_timeout(&cmp, -								end - start); -			reload = try_to_freeze(); -		} while (tmo == -ERESTARTSYS); +		wait_event_freezable_timeout(done_wait, done.done, +					     msecs_to_jiffies(timeout));  		status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); -		if (tmo == 0) { +		if (!done.done) { +			/* +			 * We're leaving the timed out dma operation with +			 * dangling pointer to done_wait.  To make this +			 * correct, we'll need to allocate wait_done for +			 * each test iteration and perform "who's gonna +			 * free it this time?" dancing.  For now, just +			 * leave it dangling. +			 */  			pr_warning("%s: #%u: test timed out\n",  				   thread_name, total_tests - 1);  			failed_tests++; diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 3eee45ffb09..c6b456ad734 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -138,8 +138,6 @@ static int twl6030_irq_thread(void *data)  	static const unsigned max_i2c_errors = 100;  	int ret; -	current->flags |= PF_NOFREEZE; -  	while (!kthread_should_stop()) {  		int i;  		union { diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 41c96b3d815..e880c79d7bd 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -750,7 +750,7 @@ static int stir_transmit_thread(void *arg)  			write_reg(stir, REG_CTRL1, CTRL1_TXPWD|CTRL1_RXPWD); -			refrigerator(); +			try_to_freeze();  			if (change_speed(stir, stir->speed))  				break; diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 7b828680b21..4b11fc91fa7 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2456,8 +2456,9 @@ static int hotkey_kthread(void *data)  	u32 poll_mask, event_mask;  	unsigned int si, so;  	unsigned long t; -	unsigned int change_detector, must_reset; +	unsigned int change_detector;  	unsigned int poll_freq; +	bool was_frozen;  	mutex_lock(&hotkey_thread_mutex); @@ -2488,14 +2489,14 @@ static int hotkey_kthread(void *data)  				t = 100;	/* should never happen... */  		}  		t = msleep_interruptible(t); -		if (unlikely(kthread_should_stop())) +		if (unlikely(kthread_freezable_should_stop(&was_frozen)))  			break; -		must_reset = try_to_freeze(); -		if (t > 0 && !must_reset) + +		if (t > 0 && !was_frozen)  			continue;  		mutex_lock(&hotkey_thread_data_mutex); -		if (must_reset || hotkey_config_change != change_detector) { +		if (was_frozen || hotkey_config_change != change_detector) {  			/* forget old state on thaw or config change */  			si = so;  			t = 0; @@ -2528,10 +2529,6 @@ exit:  static void hotkey_poll_stop_sync(void)  {  	if (tpacpi_hotkey_task) { -		if (frozen(tpacpi_hotkey_task) || -		    freezing(tpacpi_hotkey_task)) -			thaw_process(tpacpi_hotkey_task); -  		kthread_stop(tpacpi_hotkey_task);  		tpacpi_hotkey_task = NULL;  		mutex_lock(&hotkey_thread_mutex); diff --git a/drivers/staging/rts_pstor/rtsx.c b/drivers/staging/rts_pstor/rtsx.c index 115635f9502..a7feb3e328a 100644 --- a/drivers/staging/rts_pstor/rtsx.c +++ b/drivers/staging/rts_pstor/rtsx.c @@ -466,8 +466,6 @@ static int rtsx_control_thread(void *__dev)  	struct rtsx_chip *chip = dev->chip;  	struct Scsi_Host *host = rtsx_to_host(dev); -	current->flags |= PF_NOFREEZE; -  	for (;;) {  		if (wait_for_completion_interruptible(&dev->cmnd_ready))  			break; diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index c325e69415a..aa84b3d7727 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -831,7 +831,8 @@ static int usb_stor_scan_thread(void * __us)  	dev_dbg(dev, "device found\n"); -	set_freezable_with_signal(); +	set_freezable(); +  	/*  	 * Wait for the timeout to expire or for a disconnect  	 * @@ -839,16 +840,16 @@ static int usb_stor_scan_thread(void * __us)  	 * fail to freeze, but we can't be non-freezable either. Nor can  	 * khubd freeze while waiting for scanning to complete as it may  	 * hold the device lock, causing a hang when suspending devices. -	 * So we request a fake signal when freezing and use -	 * interruptible sleep to kick us out of our wait early when -	 * freezing happens. +	 * So instead of using wait_event_freezable(), explicitly test +	 * for (DONT_SCAN || freezing) in interruptible wait and proceed +	 * if any of DONT_SCAN, freezing or timeout has happened.  	 */  	if (delay_use > 0) {  		dev_dbg(dev, "waiting for device to settle "  				"before scanning\n");  		wait_event_interruptible_timeout(us->delay_wait, -				test_bit(US_FLIDX_DONT_SCAN, &us->dflags), -				delay_use * HZ); +				test_bit(US_FLIDX_DONT_SCAN, &us->dflags) || +				freezing(current), delay_use * HZ);  	}  	/* If the device is still connected, perform the scanning */  |