1863 lines · 51.0 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * drivers/base/power/runtime.c - Helper functions for device runtime PM * * Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. * Copyright (C) 2010 Alan Stern <stern@rowland.harvard.edu> */#include <linux/sched/mm.h>#include <linux/ktime.h>#include <linux/hrtimer.h>#include <linux/export.h>#include <linux/pm_runtime.h>#include <linux/pm_wakeirq.h>#include <trace/events/rpm.h> #include "../base.h"#include "power.h" typedef int (*pm_callback_t)(struct device *); static pm_callback_t __rpm_get_callback(struct device *dev, size_t cb_offset){	pm_callback_t cb;	const struct dev_pm_ops *ops; 	if (dev->pm_domain)		ops = &dev->pm_domain->ops;	else if (dev->type && dev->type->pm)		ops = dev->type->pm;	else if (dev->class && dev->class->pm)		ops = dev->class->pm;	else if (dev->bus && dev->bus->pm)		ops = dev->bus->pm;	else		ops = NULL; 	if (ops)		cb = *(pm_callback_t *)((void *)ops + cb_offset);	else		cb = NULL; 	if (!cb && dev->driver && dev->driver->pm)		cb = *(pm_callback_t *)((void *)dev->driver->pm + cb_offset); 	return cb;} #define RPM_GET_CALLBACK(dev, callback) \		__rpm_get_callback(dev, offsetof(struct dev_pm_ops, callback)) static int rpm_resume(struct device *dev, int rpmflags);static int rpm_suspend(struct device *dev, int rpmflags); /** * update_pm_runtime_accounting - Update the time accounting of power states * @dev: Device to update the accounting for * * In order to be able to have time accounting of the various power states * (as used by programs such as PowerTOP to show the effectiveness of runtime * PM), we need to track the time spent in each state. * update_pm_runtime_accounting must be called each time before the * runtime_status field is updated, to account the time in the old state * correctly. */static void update_pm_runtime_accounting(struct device *dev){	u64 now, last, delta; 	if (dev->power.disable_depth > 0)		return; 	last = dev->power.accounting_timestamp; 	now = ktime_get_mono_fast_ns();	dev->power.accounting_timestamp = now; 	/*	 * Because ktime_get_mono_fast_ns() is not monotonic during	 * timekeeping updates, ensure that 'now' is after the last saved	 * timesptamp.	 */	if (now < last)		return; 	delta = now - last; 	if (dev->power.runtime_status == RPM_SUSPENDED)		dev->power.suspended_time += delta;	else		dev->power.active_time += delta;} static void __update_runtime_status(struct device *dev, enum rpm_status status){	update_pm_runtime_accounting(dev);	dev->power.runtime_status = status;} static u64 rpm_get_accounted_time(struct device *dev, bool suspended){	u64 time;	unsigned long flags; 	spin_lock_irqsave(&dev->power.lock, flags); 	update_pm_runtime_accounting(dev);	time = suspended ? dev->power.suspended_time : dev->power.active_time; 	spin_unlock_irqrestore(&dev->power.lock, flags); 	return time;} u64 pm_runtime_active_time(struct device *dev){	return rpm_get_accounted_time(dev, false);} u64 pm_runtime_suspended_time(struct device *dev){	return rpm_get_accounted_time(dev, true);}EXPORT_SYMBOL_GPL(pm_runtime_suspended_time); /** * pm_runtime_deactivate_timer - Deactivate given device's suspend timer. * @dev: Device to handle. */static void pm_runtime_deactivate_timer(struct device *dev){	if (dev->power.timer_expires > 0) {		hrtimer_try_to_cancel(&dev->power.suspend_timer);		dev->power.timer_expires = 0;	}} /** * pm_runtime_cancel_pending - Deactivate suspend timer and cancel requests. * @dev: Device to handle. */static void pm_runtime_cancel_pending(struct device *dev){	pm_runtime_deactivate_timer(dev);	/*	 * In case there's a request pending, make sure its work function will	 * return without doing anything.	 */	dev->power.request = RPM_REQ_NONE;} /* * pm_runtime_autosuspend_expiration - Get a device's autosuspend-delay expiration time. * @dev: Device to handle. * * Compute the autosuspend-delay expiration time based on the device's * power.last_busy time.  If the delay has already expired or is disabled * (negative) or the power.use_autosuspend flag isn't set, return 0. * Otherwise return the expiration time in nanoseconds (adjusted to be nonzero). * * This function may be called either with or without dev->power.lock held. * Either way it can be racy, since power.last_busy may be updated at any time. */u64 pm_runtime_autosuspend_expiration(struct device *dev){	int autosuspend_delay;	u64 expires; 	if (!dev->power.use_autosuspend)		return 0; 	autosuspend_delay = READ_ONCE(dev->power.autosuspend_delay);	if (autosuspend_delay < 0)		return 0; 	expires  = READ_ONCE(dev->power.last_busy);	expires += (u64)autosuspend_delay * NSEC_PER_MSEC;	if (expires > ktime_get_mono_fast_ns())		return expires;	/* Expires in the future */ 	return 0;}EXPORT_SYMBOL_GPL(pm_runtime_autosuspend_expiration); static int dev_memalloc_noio(struct device *dev, void *data){	return dev->power.memalloc_noio;} /* * pm_runtime_set_memalloc_noio - Set a device's memalloc_noio flag. * @dev: Device to handle. * @enable: True for setting the flag and False for clearing the flag. * * Set the flag for all devices in the path from the device to the * root device in the device tree if @enable is true, otherwise clear * the flag for devices in the path whose siblings don't set the flag. * * The function should only be called by block device, or network * device driver for solving the deadlock problem during runtime * resume/suspend: * *     If memory allocation with GFP_KERNEL is called inside runtime *     resume/suspend callback of any one of its ancestors(or the *     block device itself), the deadlock may be triggered inside the *     memory allocation since it might not complete until the block *     device becomes active and the involed page I/O finishes. The *     situation is pointed out first by Alan Stern. Network device *     are involved in iSCSI kind of situation. * * The lock of dev_hotplug_mutex is held in the function for handling * hotplug race because pm_runtime_set_memalloc_noio() may be called * in async probe(). * * The function should be called between device_add() and device_del() * on the affected device(block/network device). */void pm_runtime_set_memalloc_noio(struct device *dev, bool enable){	static DEFINE_MUTEX(dev_hotplug_mutex); 	mutex_lock(&dev_hotplug_mutex);	for (;;) {		bool enabled; 		/* hold power lock since bitfield is not SMP-safe. */		spin_lock_irq(&dev->power.lock);		enabled = dev->power.memalloc_noio;		dev->power.memalloc_noio = enable;		spin_unlock_irq(&dev->power.lock); 		/*		 * not need to enable ancestors any more if the device		 * has been enabled.		 */		if (enabled && enable)			break; 		dev = dev->parent; 		/*		 * clear flag of the parent device only if all the		 * children don't set the flag because ancestor's		 * flag was set by any one of the descendants.		 */		if (!dev || (!enable &&			     device_for_each_child(dev, NULL,						   dev_memalloc_noio)))			break;	}	mutex_unlock(&dev_hotplug_mutex);}EXPORT_SYMBOL_GPL(pm_runtime_set_memalloc_noio); /** * rpm_check_suspend_allowed - Test whether a device may be suspended. * @dev: Device to test. */static int rpm_check_suspend_allowed(struct device *dev){	int retval = 0; 	if (dev->power.runtime_error)		retval = -EINVAL;	else if (dev->power.disable_depth > 0)		retval = -EACCES;	else if (atomic_read(&dev->power.usage_count) > 0)		retval = -EAGAIN;	else if (!dev->power.ignore_children &&			atomic_read(&dev->power.child_count))		retval = -EBUSY; 	/* Pending resume requests take precedence over suspends. */	else if ((dev->power.deferred_resume			&& dev->power.runtime_status == RPM_SUSPENDING)	    || (dev->power.request_pending			&& dev->power.request == RPM_REQ_RESUME))		retval = -EAGAIN;	else if (__dev_pm_qos_resume_latency(dev) == 0)		retval = -EPERM;	else if (dev->power.runtime_status == RPM_SUSPENDED)		retval = 1; 	return retval;} static int rpm_get_suppliers(struct device *dev){	struct device_link *link; 	list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,				device_links_read_lock_held()) {		int retval; 		if (!(link->flags & DL_FLAG_PM_RUNTIME))			continue; 		retval = pm_runtime_get_sync(link->supplier);		/* Ignore suppliers with disabled runtime PM. */		if (retval < 0 && retval != -EACCES) {			pm_runtime_put_noidle(link->supplier);			return retval;		}		refcount_inc(&link->rpm_active);	}	return 0;} static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend){	struct device_link *link; 	list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,				device_links_read_lock_held()) { 		while (refcount_dec_not_one(&link->rpm_active))			pm_runtime_put_noidle(link->supplier); 		if (try_to_suspend)			pm_request_idle(link->supplier);	}} static void rpm_put_suppliers(struct device *dev){	__rpm_put_suppliers(dev, true);} static void rpm_suspend_suppliers(struct device *dev){	struct device_link *link;	int idx = device_links_read_lock(); 	list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,				device_links_read_lock_held())		pm_request_idle(link->supplier); 	device_links_read_unlock(idx);} /** * __rpm_callback - Run a given runtime PM callback for a given device. * @cb: Runtime PM callback to run. * @dev: Device to run the callback for. */static int __rpm_callback(int (*cb)(struct device *), struct device *dev)	__releases(&dev->power.lock) __acquires(&dev->power.lock){	int retval, idx;	bool use_links = dev->power.links_count > 0; 	if (dev->power.irq_safe) {		spin_unlock(&dev->power.lock);	} else {		spin_unlock_irq(&dev->power.lock); 		/*		 * Resume suppliers if necessary.		 *		 * The device's runtime PM status cannot change until this		 * routine returns, so it is safe to read the status outside of		 * the lock.		 */		if (use_links && dev->power.runtime_status == RPM_RESUMING) {			idx = device_links_read_lock(); 			retval = rpm_get_suppliers(dev);			if (retval) {				rpm_put_suppliers(dev);				goto fail;			} 			device_links_read_unlock(idx);		}	} 	retval = cb(dev); 	if (dev->power.irq_safe) {		spin_lock(&dev->power.lock);	} else {		/*		 * If the device is suspending and the callback has returned		 * success, drop the usage counters of the suppliers that have		 * been reference counted on its resume.		 *		 * Do that if resume fails too.		 */		if (use_links		    && ((dev->power.runtime_status == RPM_SUSPENDING && !retval)		    || (dev->power.runtime_status == RPM_RESUMING && retval))) {			idx = device_links_read_lock(); 			__rpm_put_suppliers(dev, false); fail:			device_links_read_unlock(idx);		} 		spin_lock_irq(&dev->power.lock);	} 	return retval;} /** * rpm_idle - Notify device bus type if the device can be suspended. * @dev: Device to notify the bus type about. * @rpmflags: Flag bits. * * Check if the device's runtime PM status allows it to be suspended.  If * another idle notification has been started earlier, return immediately.  If * the RPM_ASYNC flag is set then queue an idle-notification request; otherwise * run the ->runtime_idle() callback directly. If the ->runtime_idle callback * doesn't exist or if it returns 0, call rpm_suspend with the RPM_AUTO flag. * * This function must be called under dev->power.lock with interrupts disabled. */static int rpm_idle(struct device *dev, int rpmflags){	int (*callback)(struct device *);	int retval; 	trace_rpm_idle_rcuidle(dev, rpmflags);	retval = rpm_check_suspend_allowed(dev);	if (retval < 0)		;	/* Conditions are wrong. */ 	/* Idle notifications are allowed only in the RPM_ACTIVE state. */	else if (dev->power.runtime_status != RPM_ACTIVE)		retval = -EAGAIN; 	/*	 * Any pending request other than an idle notification takes	 * precedence over us, except that the timer may be running.	 */	else if (dev->power.request_pending &&	    dev->power.request > RPM_REQ_IDLE)		retval = -EAGAIN; 	/* Act as though RPM_NOWAIT is always set. */	else if (dev->power.idle_notification)		retval = -EINPROGRESS;	if (retval)		goto out; 	/* Pending requests need to be canceled. */	dev->power.request = RPM_REQ_NONE; 	if (dev->power.no_callbacks)		goto out; 	/* Carry out an asynchronous or a synchronous idle notification. */	if (rpmflags & RPM_ASYNC) {		dev->power.request = RPM_REQ_IDLE;		if (!dev->power.request_pending) {			dev->power.request_pending = true;			queue_work(pm_wq, &dev->power.work);		}		trace_rpm_return_int_rcuidle(dev, _THIS_IP_, 0);		return 0;	} 	dev->power.idle_notification = true; 	callback = RPM_GET_CALLBACK(dev, runtime_idle); 	if (callback)		retval = __rpm_callback(callback, dev); 	dev->power.idle_notification = false;	wake_up_all(&dev->power.wait_queue);  out:	trace_rpm_return_int_rcuidle(dev, _THIS_IP_, retval);	return retval ? retval : rpm_suspend(dev, rpmflags | RPM_AUTO);} /** * rpm_callback - Run a given runtime PM callback for a given device. * @cb: Runtime PM callback to run. * @dev: Device to run the callback for. */static int rpm_callback(int (*cb)(struct device *), struct device *dev){	int retval; 	if (!cb)		return -ENOSYS; 	if (dev->power.memalloc_noio) {		unsigned int noio_flag; 		/*		 * Deadlock might be caused if memory allocation with		 * GFP_KERNEL happens inside runtime_suspend and		 * runtime_resume callbacks of one block device's		 * ancestor or the block device itself. Network		 * device might be thought as part of iSCSI block		 * device, so network device and its ancestor should		 * be marked as memalloc_noio too.

Lines 1–500 of 1863.