5434 lines · 147.7 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * drivers/base/core.c - core driver model code (device registration, etc) * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs * Copyright (c) 2006 Greg Kroah-Hartman <gregkh@suse.de> * Copyright (c) 2006 Novell, Inc. */ #include <linux/acpi.h>#include <linux/blkdev.h>#include <linux/cleanup.h>#include <linux/cpufreq.h>#include <linux/device.h>#include <linux/dma-map-ops.h> /* for dma_default_coherent */#include <linux/err.h>#include <linux/fwnode.h>#include <linux/init.h>#include <linux/kdev_t.h>#include <linux/kstrtox.h>#include <linux/module.h>#include <linux/mutex.h>#include <linux/netdevice.h>#include <linux/notifier.h>#include <linux/of.h>#include <linux/of_device.h>#include <linux/pm_runtime.h>#include <linux/sched/mm.h>#include <linux/sched/signal.h>#include <linux/slab.h>#include <linux/string_helpers.h>#include <linux/swiotlb.h>#include <linux/sysfs.h> #include "base.h"#include "physical_location.h"#include "power/power.h" /* Device links support. */static LIST_HEAD(deferred_sync);static unsigned int defer_sync_state_count = 1;static DEFINE_MUTEX(fwnode_link_lock);static bool fw_devlink_is_permissive(void);static void __fw_devlink_link_to_consumers(struct device *dev);static bool fw_devlink_drv_reg_done;static bool fw_devlink_best_effort;static struct workqueue_struct *device_link_wq; /** * __fwnode_link_add - Create a link between two fwnode_handles. * @con: Consumer end of the link. * @sup: Supplier end of the link. * @flags: Link flags. * * Create a fwnode link between fwnode handles @con and @sup. The fwnode link * represents the detail that the firmware lists @sup fwnode as supplying a * resource to @con. * * The driver core will use the fwnode link to create a device link between the * two device objects corresponding to @con and @sup when they are created. The * driver core will automatically delete the fwnode link between @con and @sup * after doing that. * * Attempts to create duplicate links between the same pair of fwnode handles * are ignored and there is no reference counting. */static int __fwnode_link_add(struct fwnode_handle *con,			     struct fwnode_handle *sup, u8 flags){	struct fwnode_link *link; 	list_for_each_entry(link, &sup->consumers, s_hook)		if (link->consumer == con) {			link->flags |= flags;			return 0;		} 	link = kzalloc_obj(*link);	if (!link)		return -ENOMEM; 	link->supplier = sup;	INIT_LIST_HEAD(&link->s_hook);	link->consumer = con;	INIT_LIST_HEAD(&link->c_hook);	link->flags = flags; 	list_add(&link->s_hook, &sup->consumers);	list_add(&link->c_hook, &con->suppliers);	pr_debug("%pfwf Linked as a fwnode consumer to %pfwf\n",		 con, sup); 	return 0;} int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup,		    u8 flags){	guard(mutex)(&fwnode_link_lock); 	return __fwnode_link_add(con, sup, flags);} /** * __fwnode_link_del - Delete a link between two fwnode_handles. * @link: the fwnode_link to be deleted * * The fwnode_link_lock needs to be held when this function is called. */static void __fwnode_link_del(struct fwnode_link *link){	pr_debug("%pfwf Dropping the fwnode link to %pfwf\n",		 link->consumer, link->supplier);	list_del(&link->s_hook);	list_del(&link->c_hook);	kfree(link);} /** * __fwnode_link_cycle - Mark a fwnode link as being part of a cycle. * @link: the fwnode_link to be marked * * The fwnode_link_lock needs to be held when this function is called. */static void __fwnode_link_cycle(struct fwnode_link *link){	pr_debug("%pfwf: cycle: depends on %pfwf\n",		 link->consumer, link->supplier);	link->flags |= FWLINK_FLAG_CYCLE;} /** * fwnode_links_purge_suppliers - Delete all supplier links of fwnode_handle. * @fwnode: fwnode whose supplier links need to be deleted * * Deletes all supplier links connecting directly to @fwnode. */static void fwnode_links_purge_suppliers(struct fwnode_handle *fwnode){	struct fwnode_link *link, *tmp; 	guard(mutex)(&fwnode_link_lock); 	list_for_each_entry_safe(link, tmp, &fwnode->suppliers, c_hook)		__fwnode_link_del(link);} /** * fwnode_links_purge_consumers - Delete all consumer links of fwnode_handle. * @fwnode: fwnode whose consumer links need to be deleted * * Deletes all consumer links connecting directly to @fwnode. */static void fwnode_links_purge_consumers(struct fwnode_handle *fwnode){	struct fwnode_link *link, *tmp; 	guard(mutex)(&fwnode_link_lock); 	list_for_each_entry_safe(link, tmp, &fwnode->consumers, s_hook)		__fwnode_link_del(link);} /** * fwnode_links_purge - Delete all links connected to a fwnode_handle. * @fwnode: fwnode whose links needs to be deleted * * Deletes all links connecting directly to a fwnode. */void fwnode_links_purge(struct fwnode_handle *fwnode){	fwnode_links_purge_suppliers(fwnode);	fwnode_links_purge_consumers(fwnode);} void fw_devlink_purge_absent_suppliers(struct fwnode_handle *fwnode){	struct fwnode_handle *child; 	/* Don't purge consumer links of an added child */	if (fwnode->dev)		return; 	fwnode_set_flag(fwnode, FWNODE_FLAG_NOT_DEVICE);	fwnode_links_purge_consumers(fwnode); 	fwnode_for_each_available_child_node(fwnode, child)		fw_devlink_purge_absent_suppliers(child);}EXPORT_SYMBOL_GPL(fw_devlink_purge_absent_suppliers); /** * __fwnode_links_move_consumers - Move consumer from @from to @to fwnode_handle * @from: move consumers away from this fwnode * @to: move consumers to this fwnode * * Move all consumer links from @from fwnode to @to fwnode. */static void __fwnode_links_move_consumers(struct fwnode_handle *from,					  struct fwnode_handle *to){	struct fwnode_link *link, *tmp; 	list_for_each_entry_safe(link, tmp, &from->consumers, s_hook) {		__fwnode_link_add(link->consumer, to, link->flags);		__fwnode_link_del(link);	}} /** * __fw_devlink_pickup_dangling_consumers - Pick up dangling consumers * @fwnode: fwnode from which to pick up dangling consumers * @new_sup: fwnode of new supplier * * If the @fwnode has a corresponding struct device and the device supports * probing (that is, added to a bus), then we want to let fw_devlink create * MANAGED device links to this device, so leave @fwnode and its descendant's * fwnode links alone. * * Otherwise, move its consumers to the new supplier @new_sup. */static void __fw_devlink_pickup_dangling_consumers(struct fwnode_handle *fwnode,						   struct fwnode_handle *new_sup){	struct fwnode_handle *child; 	if (fwnode->dev && fwnode->dev->bus)		return; 	fwnode_set_flag(fwnode, FWNODE_FLAG_NOT_DEVICE);	__fwnode_links_move_consumers(fwnode, new_sup); 	fwnode_for_each_available_child_node(fwnode, child)		__fw_devlink_pickup_dangling_consumers(child, new_sup);} static void fw_devlink_pickup_dangling_consumers(struct device *dev){	struct fwnode_handle *child; 	guard(mutex)(&fwnode_link_lock); 	fwnode_for_each_available_child_node(dev->fwnode, child)		__fw_devlink_pickup_dangling_consumers(child, dev->fwnode);	__fw_devlink_link_to_consumers(dev);} /** * fw_devlink_refresh_fwnode - Recheck the tree under this firmware node * @fwnode: The fwnode under which the fwnode tree has changed * * This function is mainly meant to adjust the supplier/consumer dependencies * after a fwnode tree overlay has occurred. */void fw_devlink_refresh_fwnode(struct fwnode_handle *fwnode){	struct device *dev; 	/*	 * Find the closest ancestor fwnode that has been converted to a device	 * that can bind to a driver (bus device).	 */	fwnode_handle_get(fwnode);	do {		if (fwnode_test_flag(fwnode, FWNODE_FLAG_NOT_DEVICE))			continue; 		dev = get_dev_from_fwnode(fwnode);		if (!dev)			continue; 		if (dev->bus)			break; 		put_device(dev);	} while ((fwnode = fwnode_get_next_parent(fwnode))); 	/*	 * If none of the ancestor fwnodes have (yet) been converted to a device	 * that can bind to a driver, there's nothing to fix up.	 */	if (!fwnode)		return; 	WARN(device_is_bound(dev) && dev->links.status != DL_DEV_DRIVER_BOUND,	     "Don't multithread overlaying and probing the same device!\n"); 	/*	 * If the device has already bound to a driver, then we need to redo	 * some of the work that was done after the device was bound to a	 * driver. If the device hasn't bound to a driver, running things too	 * soon would incorrectly pick up consumers that it shouldn't.	 */	if (dev->links.status == DL_DEV_DRIVER_BOUND) {		fw_devlink_pickup_dangling_consumers(dev);		/*		 * Some of dangling consumers could have been put previously in		 * the deferred probe list due to the unavailability of their		 * suppliers. Those consumers have been picked up and some of		 * their suppliers links have been updated. Time to re-try their		 * probe sequence.		 */		driver_deferred_probe_trigger();	} 	put_device(dev);	fwnode_handle_put(fwnode);} static DEFINE_MUTEX(device_links_lock);DEFINE_STATIC_SRCU(device_links_srcu); static inline void device_links_write_lock(void){	mutex_lock(&device_links_lock);} static inline void device_links_write_unlock(void){	mutex_unlock(&device_links_lock);} int device_links_read_lock(void) __acquires(&device_links_srcu){	return srcu_read_lock(&device_links_srcu);} void device_links_read_unlock(int idx) __releases(&device_links_srcu){	srcu_read_unlock(&device_links_srcu, idx);} int device_links_read_lock_held(void){	return srcu_read_lock_held(&device_links_srcu);} static void device_link_synchronize_removal(void){	synchronize_srcu(&device_links_srcu);} static void device_link_remove_from_lists(struct device_link *link){	list_del_rcu(&link->s_node);	list_del_rcu(&link->c_node);} static bool device_is_ancestor(struct device *dev, struct device *target){	while (target->parent) {		target = target->parent;		if (dev == target)			return true;	}	return false;} #define DL_MARKER_FLAGS		(DL_FLAG_INFERRED | \				 DL_FLAG_CYCLE | \				 DL_FLAG_MANAGED)bool device_link_flag_is_sync_state_only(u32 flags){	return (flags & ~DL_MARKER_FLAGS) == DL_FLAG_SYNC_STATE_ONLY;} /** * device_is_dependent - Check if one device depends on another one * @dev: Device to check dependencies for. * @target: Device to check against. * * Check if @target depends on @dev or any device dependent on it (its child or * its consumer etc).  Return 1 if that is the case or 0 otherwise. */static int device_is_dependent(struct device *dev, void *target){	struct device_link *link;	int ret; 	/*	 * The "ancestors" check is needed to catch the case when the target	 * device has not been completely initialized yet and it is still	 * missing from the list of children of its parent device.	 */	if (dev == target || device_is_ancestor(dev, target))		return 1; 	ret = device_for_each_child(dev, target, device_is_dependent);	if (ret)		return ret; 	list_for_each_entry(link, &dev->links.consumers, s_node) {		if (device_link_flag_is_sync_state_only(link->flags))			continue; 		if (link->consumer == target)			return 1; 		ret = device_is_dependent(link->consumer, target);		if (ret)			break;	}	return ret;} static void device_link_init_status(struct device_link *link,				    struct device *consumer,				    struct device *supplier){	switch (supplier->links.status) {	case DL_DEV_PROBING:		switch (consumer->links.status) {		case DL_DEV_PROBING:			/*			 * A consumer driver can create a link to a supplier			 * that has not completed its probing yet as long as it			 * knows that the supplier is already functional (for			 * example, it has just acquired some resources from the			 * supplier).			 */			link->status = DL_STATE_CONSUMER_PROBE;			break;		default:			link->status = DL_STATE_DORMANT;			break;		}		break;	case DL_DEV_DRIVER_BOUND:		switch (consumer->links.status) {		case DL_DEV_PROBING:			link->status = DL_STATE_CONSUMER_PROBE;			break;		case DL_DEV_DRIVER_BOUND:			link->status = DL_STATE_ACTIVE;			break;		default:			link->status = DL_STATE_AVAILABLE;			break;		}		break;	case DL_DEV_UNBINDING:		link->status = DL_STATE_SUPPLIER_UNBIND;		break;	default:		link->status = DL_STATE_DORMANT;		break;	}} static int device_reorder_to_tail(struct device *dev, void *not_used){	struct device_link *link; 	/*	 * Devices that have not been registered yet will be put to the ends	 * of the lists during the registration, so skip them here.	 */	if (device_is_registered(dev))		devices_kset_move_last(dev); 	if (device_pm_initialized(dev))		device_pm_move_last(dev); 	device_for_each_child(dev, NULL, device_reorder_to_tail);	list_for_each_entry(link, &dev->links.consumers, s_node) {		if (device_link_flag_is_sync_state_only(link->flags))			continue;		device_reorder_to_tail(link->consumer, NULL);	} 	return 0;} /** * device_pm_move_to_tail - Move set of devices to the end of device lists * @dev: Device to move * * This is a device_reorder_to_tail() wrapper taking the requisite locks. * * It moves the @dev along with all of its children and all of its consumers * to the ends of the device_kset and dpm_list, recursively. */void device_pm_move_to_tail(struct device *dev){	int idx; 	idx = device_links_read_lock();	device_pm_lock();	device_reorder_to_tail(dev, NULL);	device_pm_unlock();	device_links_read_unlock(idx);} #define to_devlink(dev)	container_of((dev), struct device_link, link_dev) static ssize_t status_show(struct device *dev,			   const struct device_attribute *attr, char *buf){	const char *output;

Lines 1–500 of 5434.