4764 lines · 127.8 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/cpufreq.h>#include <linux/device.h>#include <linux/err.h>#include <linux/fwnode.h>#include <linux/init.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/kdev_t.h>#include <linux/notifier.h>#include <linux/of.h>#include <linux/of_device.h>#include <linux/genhd.h>#include <linux/mutex.h>#include <linux/pm_runtime.h>#include <linux/netdevice.h>#include <linux/sched/signal.h>#include <linux/sched/mm.h>#include <linux/sysfs.h>#include <linux/dma-map-ops.h> /* for dma_default_coherent */ #include "base.h"#include "power/power.h" #ifdef CONFIG_SYSFS_DEPRECATED#ifdef CONFIG_SYSFS_DEPRECATED_V2long sysfs_deprecated = 1;#elselong sysfs_deprecated = 0;#endifstatic int __init sysfs_deprecated_setup(char *arg){	return kstrtol(arg, 10, &sysfs_deprecated);}early_param("sysfs.deprecated", sysfs_deprecated_setup);#endif /* 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 bool fw_devlink_drv_reg_done; /** * fwnode_link_add - Create a link between two fwnode_handles. * @con: Consumer end of the link. * @sup: Supplier end of the link. * * 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. */int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup){	struct fwnode_link *link;	int ret = 0; 	mutex_lock(&fwnode_link_lock); 	list_for_each_entry(link, &sup->consumers, s_hook)		if (link->consumer == con)			goto out; 	link = kzalloc(sizeof(*link), GFP_KERNEL);	if (!link) {		ret = -ENOMEM;		goto out;	} 	link->supplier = sup;	INIT_LIST_HEAD(&link->s_hook);	link->consumer = con;	INIT_LIST_HEAD(&link->c_hook); 	list_add(&link->s_hook, &sup->consumers);	list_add(&link->c_hook, &con->suppliers);out:	mutex_unlock(&fwnode_link_lock); 	return ret;} /** * 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; 	mutex_lock(&fwnode_link_lock);	list_for_each_entry_safe(link, tmp, &fwnode->suppliers, c_hook) {		list_del(&link->s_hook);		list_del(&link->c_hook);		kfree(link);	}	mutex_unlock(&fwnode_link_lock);} /** * 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; 	mutex_lock(&fwnode_link_lock);	list_for_each_entry_safe(link, tmp, &fwnode->consumers, s_hook) {		list_del(&link->s_hook);		list_del(&link->c_hook);		kfree(link);	}	mutex_unlock(&fwnode_link_lock);} /** * 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->flags |= 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); #ifdef CONFIG_SRCUstatic 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);}#else /* !CONFIG_SRCU */static DECLARE_RWSEM(device_links_lock); static inline void device_links_write_lock(void){	down_write(&device_links_lock);} static inline void device_links_write_unlock(void){	up_write(&device_links_lock);} int device_links_read_lock(void){	down_read(&device_links_lock);	return 0;} void device_links_read_unlock(int not_used){	up_read(&device_links_lock);} #ifdef CONFIG_DEBUG_LOCK_ALLOCint device_links_read_lock_held(void){	return lockdep_is_held(&device_links_lock);}#endif static inline void device_link_synchronize_removal(void){} static void device_link_remove_from_lists(struct device_link *link){	list_del(&link->s_node);	list_del(&link->c_node);}#endif /* !CONFIG_SRCU */ static bool device_is_ancestor(struct device *dev, struct device *target){	while (target->parent) {		target = target->parent;		if (dev == target)			return true;	}	return false;} /** * 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. */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 ((link->flags & ~DL_FLAG_INFERRED) ==		    (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED))			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 ((link->flags & ~DL_FLAG_INFERRED) ==		    (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED))			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,			   struct device_attribute *attr, char *buf){	const char *output; 	switch (to_devlink(dev)->status) {	case DL_STATE_NONE:		output = "not tracked";		break;	case DL_STATE_DORMANT:		output = "dormant";		break;	case DL_STATE_AVAILABLE:		output = "available";		break;	case DL_STATE_CONSUMER_PROBE:		output = "consumer probing";		break;	case DL_STATE_ACTIVE:		output = "active";		break;	case DL_STATE_SUPPLIER_UNBIND:		output = "supplier unbinding";		break;	default:		output = "unknown";		break;	} 	return sysfs_emit(buf, "%s\n", output);}static DEVICE_ATTR_RO(status); static ssize_t auto_remove_on_show(struct device *dev,				   struct device_attribute *attr, char *buf){	struct device_link *link = to_devlink(dev);	const char *output; 	if (link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER)		output = "supplier unbind";	else if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER)		output = "consumer unbind";	else		output = "never"; 	return sysfs_emit(buf, "%s\n", output);}static DEVICE_ATTR_RO(auto_remove_on); static ssize_t runtime_pm_show(struct device *dev,			       struct device_attribute *attr, char *buf){	struct device_link *link = to_devlink(dev); 	return sysfs_emit(buf, "%d\n", !!(link->flags & DL_FLAG_PM_RUNTIME));}static DEVICE_ATTR_RO(runtime_pm); static ssize_t sync_state_only_show(struct device *dev,				    struct device_attribute *attr, char *buf){	struct device_link *link = to_devlink(dev); 	return sysfs_emit(buf, "%d\n",			  !!(link->flags & DL_FLAG_SYNC_STATE_ONLY));}static DEVICE_ATTR_RO(sync_state_only); static struct attribute *devlink_attrs[] = {	&dev_attr_status.attr,	&dev_attr_auto_remove_on.attr,	&dev_attr_runtime_pm.attr,	&dev_attr_sync_state_only.attr,	NULL,};ATTRIBUTE_GROUPS(devlink); static void device_link_release_fn(struct work_struct *work){	struct device_link *link = container_of(work, struct device_link, rm_work); 	/* Ensure that all references to the link object have been dropped. */	device_link_synchronize_removal(); 	while (refcount_dec_not_one(&link->rpm_active))		pm_runtime_put(link->supplier); 	put_device(link->consumer);	put_device(link->supplier);	kfree(link);} static void devlink_dev_release(struct device *dev){	struct device_link *link = to_devlink(dev); 	INIT_WORK(&link->rm_work, device_link_release_fn);	/*	 * It may take a while to complete this work because of the SRCU	 * synchronization in device_link_release_fn() and if the consumer or	 * supplier devices get deleted when it runs, so put it into the "long"	 * workqueue.	 */	queue_work(system_long_wq, &link->rm_work);} static struct class devlink_class = {	.name = "devlink",	.owner = THIS_MODULE,

Lines 1–500 of 4764.