drivers/base/power/runtime.c

Source file repositories/reference/linux-study-clean/drivers/base/power/runtime.c

File Facts

System
Linux kernel
Corpus path
drivers/base/power/runtime.c
Extension
.c
Size
59259 bytes
Lines
2119
Domain
Driver Families
Bucket
drivers/base
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

* 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))
		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 (!device_link_test(link, 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;
}

Annotation

Implementation Notes