18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * drivers/base/core.c - core driver model code (device registration, etc) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2002-3 Patrick Mochel 68c2ecf20Sopenharmony_ci * Copyright (c) 2002-3 Open Source Development Labs 78c2ecf20Sopenharmony_ci * Copyright (c) 2006 Greg Kroah-Hartman <gregkh@suse.de> 88c2ecf20Sopenharmony_ci * Copyright (c) 2006 Novell, Inc. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/acpi.h> 128c2ecf20Sopenharmony_ci#include <linux/cpufreq.h> 138c2ecf20Sopenharmony_ci#include <linux/device.h> 148c2ecf20Sopenharmony_ci#include <linux/err.h> 158c2ecf20Sopenharmony_ci#include <linux/fwnode.h> 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/string.h> 208c2ecf20Sopenharmony_ci#include <linux/kdev_t.h> 218c2ecf20Sopenharmony_ci#include <linux/notifier.h> 228c2ecf20Sopenharmony_ci#include <linux/of.h> 238c2ecf20Sopenharmony_ci#include <linux/of_device.h> 248c2ecf20Sopenharmony_ci#include <linux/genhd.h> 258c2ecf20Sopenharmony_ci#include <linux/mutex.h> 268c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 278c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 288c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 298c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 308c2ecf20Sopenharmony_ci#include <linux/sched/mm.h> 318c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include "base.h" 348c2ecf20Sopenharmony_ci#include "power/power.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#ifdef CONFIG_SYSFS_DEPRECATED 378c2ecf20Sopenharmony_ci#ifdef CONFIG_SYSFS_DEPRECATED_V2 388c2ecf20Sopenharmony_cilong sysfs_deprecated = 1; 398c2ecf20Sopenharmony_ci#else 408c2ecf20Sopenharmony_cilong sysfs_deprecated = 0; 418c2ecf20Sopenharmony_ci#endif 428c2ecf20Sopenharmony_cistatic int __init sysfs_deprecated_setup(char *arg) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci return kstrtol(arg, 10, &sysfs_deprecated); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ciearly_param("sysfs.deprecated", sysfs_deprecated_setup); 478c2ecf20Sopenharmony_ci#endif 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* Device links support. */ 508c2ecf20Sopenharmony_cistatic LIST_HEAD(wait_for_suppliers); 518c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(wfs_lock); 528c2ecf20Sopenharmony_cistatic LIST_HEAD(deferred_sync); 538c2ecf20Sopenharmony_cistatic unsigned int defer_sync_state_count = 1; 548c2ecf20Sopenharmony_cistatic unsigned int defer_fw_devlink_count; 558c2ecf20Sopenharmony_cistatic LIST_HEAD(deferred_fw_devlink); 568c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(defer_fw_devlink_lock); 578c2ecf20Sopenharmony_cistatic bool fw_devlink_is_permissive(void); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#ifdef CONFIG_SRCU 608c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(device_links_lock); 618c2ecf20Sopenharmony_ciDEFINE_STATIC_SRCU(device_links_srcu); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic inline void device_links_write_lock(void) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci mutex_lock(&device_links_lock); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic inline void device_links_write_unlock(void) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci mutex_unlock(&device_links_lock); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciint device_links_read_lock(void) __acquires(&device_links_srcu) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci return srcu_read_lock(&device_links_srcu); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_civoid device_links_read_unlock(int idx) __releases(&device_links_srcu) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci srcu_read_unlock(&device_links_srcu, idx); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ciint device_links_read_lock_held(void) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci return srcu_read_lock_held(&device_links_srcu); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void device_link_synchronize_removal(void) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci synchronize_srcu(&device_links_srcu); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci#else /* !CONFIG_SRCU */ 938c2ecf20Sopenharmony_cistatic DECLARE_RWSEM(device_links_lock); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic inline void device_links_write_lock(void) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci down_write(&device_links_lock); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic inline void device_links_write_unlock(void) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci up_write(&device_links_lock); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ciint device_links_read_lock(void) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci down_read(&device_links_lock); 1088c2ecf20Sopenharmony_ci return 0; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_civoid device_links_read_unlock(int not_used) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci up_read(&device_links_lock); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_LOCK_ALLOC 1178c2ecf20Sopenharmony_ciint device_links_read_lock_held(void) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci return lockdep_is_held(&device_links_lock); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci#endif 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic inline void device_link_synchronize_removal(void) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci#endif /* !CONFIG_SRCU */ 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic bool device_is_ancestor(struct device *dev, struct device *target) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci while (target->parent) { 1318c2ecf20Sopenharmony_ci target = target->parent; 1328c2ecf20Sopenharmony_ci if (dev == target) 1338c2ecf20Sopenharmony_ci return true; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci return false; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/** 1398c2ecf20Sopenharmony_ci * device_is_dependent - Check if one device depends on another one 1408c2ecf20Sopenharmony_ci * @dev: Device to check dependencies for. 1418c2ecf20Sopenharmony_ci * @target: Device to check against. 1428c2ecf20Sopenharmony_ci * 1438c2ecf20Sopenharmony_ci * Check if @target depends on @dev or any device dependent on it (its child or 1448c2ecf20Sopenharmony_ci * its consumer etc). Return 1 if that is the case or 0 otherwise. 1458c2ecf20Sopenharmony_ci */ 1468c2ecf20Sopenharmony_ciint device_is_dependent(struct device *dev, void *target) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci struct device_link *link; 1498c2ecf20Sopenharmony_ci int ret; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* 1528c2ecf20Sopenharmony_ci * The "ancestors" check is needed to catch the case when the target 1538c2ecf20Sopenharmony_ci * device has not been completely initialized yet and it is still 1548c2ecf20Sopenharmony_ci * missing from the list of children of its parent device. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_ci if (dev == target || device_is_ancestor(dev, target)) 1578c2ecf20Sopenharmony_ci return 1; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci ret = device_for_each_child(dev, target, device_is_dependent); 1608c2ecf20Sopenharmony_ci if (ret) 1618c2ecf20Sopenharmony_ci return ret; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci list_for_each_entry(link, &dev->links.consumers, s_node) { 1648c2ecf20Sopenharmony_ci if (link->flags == (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED)) 1658c2ecf20Sopenharmony_ci continue; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (link->consumer == target) 1688c2ecf20Sopenharmony_ci return 1; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci ret = device_is_dependent(link->consumer, target); 1718c2ecf20Sopenharmony_ci if (ret) 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci return ret; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic void device_link_init_status(struct device_link *link, 1788c2ecf20Sopenharmony_ci struct device *consumer, 1798c2ecf20Sopenharmony_ci struct device *supplier) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci switch (supplier->links.status) { 1828c2ecf20Sopenharmony_ci case DL_DEV_PROBING: 1838c2ecf20Sopenharmony_ci switch (consumer->links.status) { 1848c2ecf20Sopenharmony_ci case DL_DEV_PROBING: 1858c2ecf20Sopenharmony_ci /* 1868c2ecf20Sopenharmony_ci * A consumer driver can create a link to a supplier 1878c2ecf20Sopenharmony_ci * that has not completed its probing yet as long as it 1888c2ecf20Sopenharmony_ci * knows that the supplier is already functional (for 1898c2ecf20Sopenharmony_ci * example, it has just acquired some resources from the 1908c2ecf20Sopenharmony_ci * supplier). 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci link->status = DL_STATE_CONSUMER_PROBE; 1938c2ecf20Sopenharmony_ci break; 1948c2ecf20Sopenharmony_ci default: 1958c2ecf20Sopenharmony_ci link->status = DL_STATE_DORMANT; 1968c2ecf20Sopenharmony_ci break; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci case DL_DEV_DRIVER_BOUND: 2008c2ecf20Sopenharmony_ci switch (consumer->links.status) { 2018c2ecf20Sopenharmony_ci case DL_DEV_PROBING: 2028c2ecf20Sopenharmony_ci link->status = DL_STATE_CONSUMER_PROBE; 2038c2ecf20Sopenharmony_ci break; 2048c2ecf20Sopenharmony_ci case DL_DEV_DRIVER_BOUND: 2058c2ecf20Sopenharmony_ci link->status = DL_STATE_ACTIVE; 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci default: 2088c2ecf20Sopenharmony_ci link->status = DL_STATE_AVAILABLE; 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci break; 2128c2ecf20Sopenharmony_ci case DL_DEV_UNBINDING: 2138c2ecf20Sopenharmony_ci link->status = DL_STATE_SUPPLIER_UNBIND; 2148c2ecf20Sopenharmony_ci break; 2158c2ecf20Sopenharmony_ci default: 2168c2ecf20Sopenharmony_ci link->status = DL_STATE_DORMANT; 2178c2ecf20Sopenharmony_ci break; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int device_reorder_to_tail(struct device *dev, void *not_used) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct device_link *link; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* 2268c2ecf20Sopenharmony_ci * Devices that have not been registered yet will be put to the ends 2278c2ecf20Sopenharmony_ci * of the lists during the registration, so skip them here. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci if (device_is_registered(dev)) 2308c2ecf20Sopenharmony_ci devices_kset_move_last(dev); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (device_pm_initialized(dev)) 2338c2ecf20Sopenharmony_ci device_pm_move_last(dev); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci device_for_each_child(dev, NULL, device_reorder_to_tail); 2368c2ecf20Sopenharmony_ci list_for_each_entry(link, &dev->links.consumers, s_node) { 2378c2ecf20Sopenharmony_ci if (link->flags == (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED)) 2388c2ecf20Sopenharmony_ci continue; 2398c2ecf20Sopenharmony_ci device_reorder_to_tail(link->consumer, NULL); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return 0; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci/** 2468c2ecf20Sopenharmony_ci * device_pm_move_to_tail - Move set of devices to the end of device lists 2478c2ecf20Sopenharmony_ci * @dev: Device to move 2488c2ecf20Sopenharmony_ci * 2498c2ecf20Sopenharmony_ci * This is a device_reorder_to_tail() wrapper taking the requisite locks. 2508c2ecf20Sopenharmony_ci * 2518c2ecf20Sopenharmony_ci * It moves the @dev along with all of its children and all of its consumers 2528c2ecf20Sopenharmony_ci * to the ends of the device_kset and dpm_list, recursively. 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_civoid device_pm_move_to_tail(struct device *dev) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci int idx; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci idx = device_links_read_lock(); 2598c2ecf20Sopenharmony_ci device_pm_lock(); 2608c2ecf20Sopenharmony_ci device_reorder_to_tail(dev, NULL); 2618c2ecf20Sopenharmony_ci device_pm_unlock(); 2628c2ecf20Sopenharmony_ci device_links_read_unlock(idx); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci#define to_devlink(dev) container_of((dev), struct device_link, link_dev) 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic ssize_t status_show(struct device *dev, 2688c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci const char *output; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci switch (to_devlink(dev)->status) { 2738c2ecf20Sopenharmony_ci case DL_STATE_NONE: 2748c2ecf20Sopenharmony_ci output = "not tracked"; 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci case DL_STATE_DORMANT: 2778c2ecf20Sopenharmony_ci output = "dormant"; 2788c2ecf20Sopenharmony_ci break; 2798c2ecf20Sopenharmony_ci case DL_STATE_AVAILABLE: 2808c2ecf20Sopenharmony_ci output = "available"; 2818c2ecf20Sopenharmony_ci break; 2828c2ecf20Sopenharmony_ci case DL_STATE_CONSUMER_PROBE: 2838c2ecf20Sopenharmony_ci output = "consumer probing"; 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci case DL_STATE_ACTIVE: 2868c2ecf20Sopenharmony_ci output = "active"; 2878c2ecf20Sopenharmony_ci break; 2888c2ecf20Sopenharmony_ci case DL_STATE_SUPPLIER_UNBIND: 2898c2ecf20Sopenharmony_ci output = "supplier unbinding"; 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci default: 2928c2ecf20Sopenharmony_ci output = "unknown"; 2938c2ecf20Sopenharmony_ci break; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%s\n", output); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(status); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic ssize_t auto_remove_on_show(struct device *dev, 3018c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct device_link *link = to_devlink(dev); 3048c2ecf20Sopenharmony_ci const char *output; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER) 3078c2ecf20Sopenharmony_ci output = "supplier unbind"; 3088c2ecf20Sopenharmony_ci else if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER) 3098c2ecf20Sopenharmony_ci output = "consumer unbind"; 3108c2ecf20Sopenharmony_ci else 3118c2ecf20Sopenharmony_ci output = "never"; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%s\n", output); 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(auto_remove_on); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic ssize_t runtime_pm_show(struct device *dev, 3188c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct device_link *link = to_devlink(dev); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%d\n", !!(link->flags & DL_FLAG_PM_RUNTIME)); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(runtime_pm); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic ssize_t sync_state_only_show(struct device *dev, 3278c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct device_link *link = to_devlink(dev); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%d\n", 3328c2ecf20Sopenharmony_ci !!(link->flags & DL_FLAG_SYNC_STATE_ONLY)); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(sync_state_only); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic struct attribute *devlink_attrs[] = { 3378c2ecf20Sopenharmony_ci &dev_attr_status.attr, 3388c2ecf20Sopenharmony_ci &dev_attr_auto_remove_on.attr, 3398c2ecf20Sopenharmony_ci &dev_attr_runtime_pm.attr, 3408c2ecf20Sopenharmony_ci &dev_attr_sync_state_only.attr, 3418c2ecf20Sopenharmony_ci NULL, 3428c2ecf20Sopenharmony_ci}; 3438c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(devlink); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic void device_link_release_fn(struct work_struct *work) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct device_link *link = container_of(work, struct device_link, rm_work); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* Ensure that all references to the link object have been dropped. */ 3508c2ecf20Sopenharmony_ci device_link_synchronize_removal(); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci pm_runtime_release_supplier(link); 3538c2ecf20Sopenharmony_ci pm_request_idle(link->supplier); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci put_device(link->consumer); 3568c2ecf20Sopenharmony_ci put_device(link->supplier); 3578c2ecf20Sopenharmony_ci kfree(link); 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic void devlink_dev_release(struct device *dev) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct device_link *link = to_devlink(dev); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci INIT_WORK(&link->rm_work, device_link_release_fn); 3658c2ecf20Sopenharmony_ci /* 3668c2ecf20Sopenharmony_ci * It may take a while to complete this work because of the SRCU 3678c2ecf20Sopenharmony_ci * synchronization in device_link_release_fn() and if the consumer or 3688c2ecf20Sopenharmony_ci * supplier devices get deleted when it runs, so put it into the "long" 3698c2ecf20Sopenharmony_ci * workqueue. 3708c2ecf20Sopenharmony_ci */ 3718c2ecf20Sopenharmony_ci queue_work(system_long_wq, &link->rm_work); 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic struct class devlink_class = { 3758c2ecf20Sopenharmony_ci .name = "devlink", 3768c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3778c2ecf20Sopenharmony_ci .dev_groups = devlink_groups, 3788c2ecf20Sopenharmony_ci .dev_release = devlink_dev_release, 3798c2ecf20Sopenharmony_ci}; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic int devlink_add_symlinks(struct device *dev, 3828c2ecf20Sopenharmony_ci struct class_interface *class_intf) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci int ret; 3858c2ecf20Sopenharmony_ci size_t len; 3868c2ecf20Sopenharmony_ci struct device_link *link = to_devlink(dev); 3878c2ecf20Sopenharmony_ci struct device *sup = link->supplier; 3888c2ecf20Sopenharmony_ci struct device *con = link->consumer; 3898c2ecf20Sopenharmony_ci char *buf; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci len = max(strlen(dev_bus_name(sup)) + strlen(dev_name(sup)), 3928c2ecf20Sopenharmony_ci strlen(dev_bus_name(con)) + strlen(dev_name(con))); 3938c2ecf20Sopenharmony_ci len += strlen(":"); 3948c2ecf20Sopenharmony_ci len += strlen("supplier:") + 1; 3958c2ecf20Sopenharmony_ci buf = kzalloc(len, GFP_KERNEL); 3968c2ecf20Sopenharmony_ci if (!buf) 3978c2ecf20Sopenharmony_ci return -ENOMEM; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci ret = sysfs_create_link(&link->link_dev.kobj, &sup->kobj, "supplier"); 4008c2ecf20Sopenharmony_ci if (ret) 4018c2ecf20Sopenharmony_ci goto out; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci ret = sysfs_create_link(&link->link_dev.kobj, &con->kobj, "consumer"); 4048c2ecf20Sopenharmony_ci if (ret) 4058c2ecf20Sopenharmony_ci goto err_con; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con)); 4088c2ecf20Sopenharmony_ci ret = sysfs_create_link(&sup->kobj, &link->link_dev.kobj, buf); 4098c2ecf20Sopenharmony_ci if (ret) 4108c2ecf20Sopenharmony_ci goto err_con_dev; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci snprintf(buf, len, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup)); 4138c2ecf20Sopenharmony_ci ret = sysfs_create_link(&con->kobj, &link->link_dev.kobj, buf); 4148c2ecf20Sopenharmony_ci if (ret) 4158c2ecf20Sopenharmony_ci goto err_sup_dev; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci goto out; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cierr_sup_dev: 4208c2ecf20Sopenharmony_ci snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con)); 4218c2ecf20Sopenharmony_ci sysfs_remove_link(&sup->kobj, buf); 4228c2ecf20Sopenharmony_cierr_con_dev: 4238c2ecf20Sopenharmony_ci sysfs_remove_link(&link->link_dev.kobj, "consumer"); 4248c2ecf20Sopenharmony_cierr_con: 4258c2ecf20Sopenharmony_ci sysfs_remove_link(&link->link_dev.kobj, "supplier"); 4268c2ecf20Sopenharmony_ciout: 4278c2ecf20Sopenharmony_ci kfree(buf); 4288c2ecf20Sopenharmony_ci return ret; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic void devlink_remove_symlinks(struct device *dev, 4328c2ecf20Sopenharmony_ci struct class_interface *class_intf) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct device_link *link = to_devlink(dev); 4358c2ecf20Sopenharmony_ci size_t len; 4368c2ecf20Sopenharmony_ci struct device *sup = link->supplier; 4378c2ecf20Sopenharmony_ci struct device *con = link->consumer; 4388c2ecf20Sopenharmony_ci char *buf; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci sysfs_remove_link(&link->link_dev.kobj, "consumer"); 4418c2ecf20Sopenharmony_ci sysfs_remove_link(&link->link_dev.kobj, "supplier"); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci len = max(strlen(dev_bus_name(sup)) + strlen(dev_name(sup)), 4448c2ecf20Sopenharmony_ci strlen(dev_bus_name(con)) + strlen(dev_name(con))); 4458c2ecf20Sopenharmony_ci len += strlen(":"); 4468c2ecf20Sopenharmony_ci len += strlen("supplier:") + 1; 4478c2ecf20Sopenharmony_ci buf = kzalloc(len, GFP_KERNEL); 4488c2ecf20Sopenharmony_ci if (!buf) { 4498c2ecf20Sopenharmony_ci WARN(1, "Unable to properly free device link symlinks!\n"); 4508c2ecf20Sopenharmony_ci return; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (device_is_registered(con)) { 4548c2ecf20Sopenharmony_ci snprintf(buf, len, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup)); 4558c2ecf20Sopenharmony_ci sysfs_remove_link(&con->kobj, buf); 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con)); 4588c2ecf20Sopenharmony_ci sysfs_remove_link(&sup->kobj, buf); 4598c2ecf20Sopenharmony_ci kfree(buf); 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic struct class_interface devlink_class_intf = { 4638c2ecf20Sopenharmony_ci .class = &devlink_class, 4648c2ecf20Sopenharmony_ci .add_dev = devlink_add_symlinks, 4658c2ecf20Sopenharmony_ci .remove_dev = devlink_remove_symlinks, 4668c2ecf20Sopenharmony_ci}; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic int __init devlink_class_init(void) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci int ret; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci ret = class_register(&devlink_class); 4738c2ecf20Sopenharmony_ci if (ret) 4748c2ecf20Sopenharmony_ci return ret; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci ret = class_interface_register(&devlink_class_intf); 4778c2ecf20Sopenharmony_ci if (ret) 4788c2ecf20Sopenharmony_ci class_unregister(&devlink_class); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci return ret; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_cipostcore_initcall(devlink_class_init); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci#define DL_MANAGED_LINK_FLAGS (DL_FLAG_AUTOREMOVE_CONSUMER | \ 4858c2ecf20Sopenharmony_ci DL_FLAG_AUTOREMOVE_SUPPLIER | \ 4868c2ecf20Sopenharmony_ci DL_FLAG_AUTOPROBE_CONSUMER | \ 4878c2ecf20Sopenharmony_ci DL_FLAG_SYNC_STATE_ONLY) 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci#define DL_ADD_VALID_FLAGS (DL_MANAGED_LINK_FLAGS | DL_FLAG_STATELESS | \ 4908c2ecf20Sopenharmony_ci DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE) 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci/** 4938c2ecf20Sopenharmony_ci * device_link_add - Create a link between two devices. 4948c2ecf20Sopenharmony_ci * @consumer: Consumer end of the link. 4958c2ecf20Sopenharmony_ci * @supplier: Supplier end of the link. 4968c2ecf20Sopenharmony_ci * @flags: Link flags. 4978c2ecf20Sopenharmony_ci * 4988c2ecf20Sopenharmony_ci * The caller is responsible for the proper synchronization of the link creation 4998c2ecf20Sopenharmony_ci * with runtime PM. First, setting the DL_FLAG_PM_RUNTIME flag will cause the 5008c2ecf20Sopenharmony_ci * runtime PM framework to take the link into account. Second, if the 5018c2ecf20Sopenharmony_ci * DL_FLAG_RPM_ACTIVE flag is set in addition to it, the supplier devices will 5028c2ecf20Sopenharmony_ci * be forced into the active metastate and reference-counted upon the creation 5038c2ecf20Sopenharmony_ci * of the link. If DL_FLAG_PM_RUNTIME is not set, DL_FLAG_RPM_ACTIVE will be 5048c2ecf20Sopenharmony_ci * ignored. 5058c2ecf20Sopenharmony_ci * 5068c2ecf20Sopenharmony_ci * If DL_FLAG_STATELESS is set in @flags, the caller of this function is 5078c2ecf20Sopenharmony_ci * expected to release the link returned by it directly with the help of either 5088c2ecf20Sopenharmony_ci * device_link_del() or device_link_remove(). 5098c2ecf20Sopenharmony_ci * 5108c2ecf20Sopenharmony_ci * If that flag is not set, however, the caller of this function is handing the 5118c2ecf20Sopenharmony_ci * management of the link over to the driver core entirely and its return value 5128c2ecf20Sopenharmony_ci * can only be used to check whether or not the link is present. In that case, 5138c2ecf20Sopenharmony_ci * the DL_FLAG_AUTOREMOVE_CONSUMER and DL_FLAG_AUTOREMOVE_SUPPLIER device link 5148c2ecf20Sopenharmony_ci * flags can be used to indicate to the driver core when the link can be safely 5158c2ecf20Sopenharmony_ci * deleted. Namely, setting one of them in @flags indicates to the driver core 5168c2ecf20Sopenharmony_ci * that the link is not going to be used (by the given caller of this function) 5178c2ecf20Sopenharmony_ci * after unbinding the consumer or supplier driver, respectively, from its 5188c2ecf20Sopenharmony_ci * device, so the link can be deleted at that point. If none of them is set, 5198c2ecf20Sopenharmony_ci * the link will be maintained until one of the devices pointed to by it (either 5208c2ecf20Sopenharmony_ci * the consumer or the supplier) is unregistered. 5218c2ecf20Sopenharmony_ci * 5228c2ecf20Sopenharmony_ci * Also, if DL_FLAG_STATELESS, DL_FLAG_AUTOREMOVE_CONSUMER and 5238c2ecf20Sopenharmony_ci * DL_FLAG_AUTOREMOVE_SUPPLIER are not set in @flags (that is, a persistent 5248c2ecf20Sopenharmony_ci * managed device link is being added), the DL_FLAG_AUTOPROBE_CONSUMER flag can 5258c2ecf20Sopenharmony_ci * be used to request the driver core to automaticall probe for a consmer 5268c2ecf20Sopenharmony_ci * driver after successfully binding a driver to the supplier device. 5278c2ecf20Sopenharmony_ci * 5288c2ecf20Sopenharmony_ci * The combination of DL_FLAG_STATELESS and one of DL_FLAG_AUTOREMOVE_CONSUMER, 5298c2ecf20Sopenharmony_ci * DL_FLAG_AUTOREMOVE_SUPPLIER, or DL_FLAG_AUTOPROBE_CONSUMER set in @flags at 5308c2ecf20Sopenharmony_ci * the same time is invalid and will cause NULL to be returned upfront. 5318c2ecf20Sopenharmony_ci * However, if a device link between the given @consumer and @supplier pair 5328c2ecf20Sopenharmony_ci * exists already when this function is called for them, the existing link will 5338c2ecf20Sopenharmony_ci * be returned regardless of its current type and status (the link's flags may 5348c2ecf20Sopenharmony_ci * be modified then). The caller of this function is then expected to treat 5358c2ecf20Sopenharmony_ci * the link as though it has just been created, so (in particular) if 5368c2ecf20Sopenharmony_ci * DL_FLAG_STATELESS was passed in @flags, the link needs to be released 5378c2ecf20Sopenharmony_ci * explicitly when not needed any more (as stated above). 5388c2ecf20Sopenharmony_ci * 5398c2ecf20Sopenharmony_ci * A side effect of the link creation is re-ordering of dpm_list and the 5408c2ecf20Sopenharmony_ci * devices_kset list by moving the consumer device and all devices depending 5418c2ecf20Sopenharmony_ci * on it to the ends of these lists (that does not happen to devices that have 5428c2ecf20Sopenharmony_ci * not been registered when this function is called). 5438c2ecf20Sopenharmony_ci * 5448c2ecf20Sopenharmony_ci * The supplier device is required to be registered when this function is called 5458c2ecf20Sopenharmony_ci * and NULL will be returned if that is not the case. The consumer device need 5468c2ecf20Sopenharmony_ci * not be registered, however. 5478c2ecf20Sopenharmony_ci */ 5488c2ecf20Sopenharmony_cistruct device_link *device_link_add(struct device *consumer, 5498c2ecf20Sopenharmony_ci struct device *supplier, u32 flags) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct device_link *link; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (!consumer || !supplier || consumer == supplier || 5548c2ecf20Sopenharmony_ci flags & ~DL_ADD_VALID_FLAGS || 5558c2ecf20Sopenharmony_ci (flags & DL_FLAG_STATELESS && flags & DL_MANAGED_LINK_FLAGS) || 5568c2ecf20Sopenharmony_ci (flags & DL_FLAG_SYNC_STATE_ONLY && 5578c2ecf20Sopenharmony_ci flags != DL_FLAG_SYNC_STATE_ONLY) || 5588c2ecf20Sopenharmony_ci (flags & DL_FLAG_AUTOPROBE_CONSUMER && 5598c2ecf20Sopenharmony_ci flags & (DL_FLAG_AUTOREMOVE_CONSUMER | 5608c2ecf20Sopenharmony_ci DL_FLAG_AUTOREMOVE_SUPPLIER))) 5618c2ecf20Sopenharmony_ci return NULL; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (flags & DL_FLAG_PM_RUNTIME && flags & DL_FLAG_RPM_ACTIVE) { 5648c2ecf20Sopenharmony_ci if (pm_runtime_get_sync(supplier) < 0) { 5658c2ecf20Sopenharmony_ci pm_runtime_put_noidle(supplier); 5668c2ecf20Sopenharmony_ci return NULL; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (!(flags & DL_FLAG_STATELESS)) 5718c2ecf20Sopenharmony_ci flags |= DL_FLAG_MANAGED; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci device_links_write_lock(); 5748c2ecf20Sopenharmony_ci device_pm_lock(); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci /* 5778c2ecf20Sopenharmony_ci * If the supplier has not been fully registered yet or there is a 5788c2ecf20Sopenharmony_ci * reverse (non-SYNC_STATE_ONLY) dependency between the consumer and 5798c2ecf20Sopenharmony_ci * the supplier already in the graph, return NULL. If the link is a 5808c2ecf20Sopenharmony_ci * SYNC_STATE_ONLY link, we don't check for reverse dependencies 5818c2ecf20Sopenharmony_ci * because it only affects sync_state() callbacks. 5828c2ecf20Sopenharmony_ci */ 5838c2ecf20Sopenharmony_ci if (!device_pm_initialized(supplier) 5848c2ecf20Sopenharmony_ci || (!(flags & DL_FLAG_SYNC_STATE_ONLY) && 5858c2ecf20Sopenharmony_ci device_is_dependent(consumer, supplier))) { 5868c2ecf20Sopenharmony_ci link = NULL; 5878c2ecf20Sopenharmony_ci goto out; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci /* 5918c2ecf20Sopenharmony_ci * DL_FLAG_AUTOREMOVE_SUPPLIER indicates that the link will be needed 5928c2ecf20Sopenharmony_ci * longer than for DL_FLAG_AUTOREMOVE_CONSUMER and setting them both 5938c2ecf20Sopenharmony_ci * together doesn't make sense, so prefer DL_FLAG_AUTOREMOVE_SUPPLIER. 5948c2ecf20Sopenharmony_ci */ 5958c2ecf20Sopenharmony_ci if (flags & DL_FLAG_AUTOREMOVE_SUPPLIER) 5968c2ecf20Sopenharmony_ci flags &= ~DL_FLAG_AUTOREMOVE_CONSUMER; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci list_for_each_entry(link, &supplier->links.consumers, s_node) { 5998c2ecf20Sopenharmony_ci if (link->consumer != consumer) 6008c2ecf20Sopenharmony_ci continue; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (flags & DL_FLAG_PM_RUNTIME) { 6038c2ecf20Sopenharmony_ci if (!(link->flags & DL_FLAG_PM_RUNTIME)) { 6048c2ecf20Sopenharmony_ci pm_runtime_new_link(consumer); 6058c2ecf20Sopenharmony_ci link->flags |= DL_FLAG_PM_RUNTIME; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci if (flags & DL_FLAG_RPM_ACTIVE) 6088c2ecf20Sopenharmony_ci refcount_inc(&link->rpm_active); 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (flags & DL_FLAG_STATELESS) { 6128c2ecf20Sopenharmony_ci kref_get(&link->kref); 6138c2ecf20Sopenharmony_ci if (link->flags & DL_FLAG_SYNC_STATE_ONLY && 6148c2ecf20Sopenharmony_ci !(link->flags & DL_FLAG_STATELESS)) { 6158c2ecf20Sopenharmony_ci link->flags |= DL_FLAG_STATELESS; 6168c2ecf20Sopenharmony_ci goto reorder; 6178c2ecf20Sopenharmony_ci } else { 6188c2ecf20Sopenharmony_ci link->flags |= DL_FLAG_STATELESS; 6198c2ecf20Sopenharmony_ci goto out; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci /* 6248c2ecf20Sopenharmony_ci * If the life time of the link following from the new flags is 6258c2ecf20Sopenharmony_ci * longer than indicated by the flags of the existing link, 6268c2ecf20Sopenharmony_ci * update the existing link to stay around longer. 6278c2ecf20Sopenharmony_ci */ 6288c2ecf20Sopenharmony_ci if (flags & DL_FLAG_AUTOREMOVE_SUPPLIER) { 6298c2ecf20Sopenharmony_ci if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER) { 6308c2ecf20Sopenharmony_ci link->flags &= ~DL_FLAG_AUTOREMOVE_CONSUMER; 6318c2ecf20Sopenharmony_ci link->flags |= DL_FLAG_AUTOREMOVE_SUPPLIER; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci } else if (!(flags & DL_FLAG_AUTOREMOVE_CONSUMER)) { 6348c2ecf20Sopenharmony_ci link->flags &= ~(DL_FLAG_AUTOREMOVE_CONSUMER | 6358c2ecf20Sopenharmony_ci DL_FLAG_AUTOREMOVE_SUPPLIER); 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci if (!(link->flags & DL_FLAG_MANAGED)) { 6388c2ecf20Sopenharmony_ci kref_get(&link->kref); 6398c2ecf20Sopenharmony_ci link->flags |= DL_FLAG_MANAGED; 6408c2ecf20Sopenharmony_ci device_link_init_status(link, consumer, supplier); 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci if (link->flags & DL_FLAG_SYNC_STATE_ONLY && 6438c2ecf20Sopenharmony_ci !(flags & DL_FLAG_SYNC_STATE_ONLY)) { 6448c2ecf20Sopenharmony_ci link->flags &= ~DL_FLAG_SYNC_STATE_ONLY; 6458c2ecf20Sopenharmony_ci goto reorder; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci goto out; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci link = kzalloc(sizeof(*link), GFP_KERNEL); 6528c2ecf20Sopenharmony_ci if (!link) 6538c2ecf20Sopenharmony_ci goto out; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci refcount_set(&link->rpm_active, 1); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci get_device(supplier); 6588c2ecf20Sopenharmony_ci link->supplier = supplier; 6598c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&link->s_node); 6608c2ecf20Sopenharmony_ci get_device(consumer); 6618c2ecf20Sopenharmony_ci link->consumer = consumer; 6628c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&link->c_node); 6638c2ecf20Sopenharmony_ci link->flags = flags; 6648c2ecf20Sopenharmony_ci kref_init(&link->kref); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci link->link_dev.class = &devlink_class; 6678c2ecf20Sopenharmony_ci device_set_pm_not_required(&link->link_dev); 6688c2ecf20Sopenharmony_ci dev_set_name(&link->link_dev, "%s:%s--%s:%s", 6698c2ecf20Sopenharmony_ci dev_bus_name(supplier), dev_name(supplier), 6708c2ecf20Sopenharmony_ci dev_bus_name(consumer), dev_name(consumer)); 6718c2ecf20Sopenharmony_ci if (device_register(&link->link_dev)) { 6728c2ecf20Sopenharmony_ci put_device(&link->link_dev); 6738c2ecf20Sopenharmony_ci link = NULL; 6748c2ecf20Sopenharmony_ci goto out; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (flags & DL_FLAG_PM_RUNTIME) { 6788c2ecf20Sopenharmony_ci if (flags & DL_FLAG_RPM_ACTIVE) 6798c2ecf20Sopenharmony_ci refcount_inc(&link->rpm_active); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci pm_runtime_new_link(consumer); 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* Determine the initial link state. */ 6858c2ecf20Sopenharmony_ci if (flags & DL_FLAG_STATELESS) 6868c2ecf20Sopenharmony_ci link->status = DL_STATE_NONE; 6878c2ecf20Sopenharmony_ci else 6888c2ecf20Sopenharmony_ci device_link_init_status(link, consumer, supplier); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* 6918c2ecf20Sopenharmony_ci * Some callers expect the link creation during consumer driver probe to 6928c2ecf20Sopenharmony_ci * resume the supplier even without DL_FLAG_RPM_ACTIVE. 6938c2ecf20Sopenharmony_ci */ 6948c2ecf20Sopenharmony_ci if (link->status == DL_STATE_CONSUMER_PROBE && 6958c2ecf20Sopenharmony_ci flags & DL_FLAG_PM_RUNTIME) 6968c2ecf20Sopenharmony_ci pm_runtime_resume(supplier); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci list_add_tail_rcu(&link->s_node, &supplier->links.consumers); 6998c2ecf20Sopenharmony_ci list_add_tail_rcu(&link->c_node, &consumer->links.suppliers); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (flags & DL_FLAG_SYNC_STATE_ONLY) { 7028c2ecf20Sopenharmony_ci dev_dbg(consumer, 7038c2ecf20Sopenharmony_ci "Linked as a sync state only consumer to %s\n", 7048c2ecf20Sopenharmony_ci dev_name(supplier)); 7058c2ecf20Sopenharmony_ci goto out; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cireorder: 7098c2ecf20Sopenharmony_ci /* 7108c2ecf20Sopenharmony_ci * Move the consumer and all of the devices depending on it to the end 7118c2ecf20Sopenharmony_ci * of dpm_list and the devices_kset list. 7128c2ecf20Sopenharmony_ci * 7138c2ecf20Sopenharmony_ci * It is necessary to hold dpm_list locked throughout all that or else 7148c2ecf20Sopenharmony_ci * we may end up suspending with a wrong ordering of it. 7158c2ecf20Sopenharmony_ci */ 7168c2ecf20Sopenharmony_ci device_reorder_to_tail(consumer, NULL); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci dev_dbg(consumer, "Linked as a consumer to %s\n", dev_name(supplier)); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ciout: 7218c2ecf20Sopenharmony_ci device_pm_unlock(); 7228c2ecf20Sopenharmony_ci device_links_write_unlock(); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if ((flags & DL_FLAG_PM_RUNTIME && flags & DL_FLAG_RPM_ACTIVE) && !link) 7258c2ecf20Sopenharmony_ci pm_runtime_put(supplier); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return link; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_link_add); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci/** 7328c2ecf20Sopenharmony_ci * device_link_wait_for_supplier - Add device to wait_for_suppliers list 7338c2ecf20Sopenharmony_ci * @consumer: Consumer device 7348c2ecf20Sopenharmony_ci * 7358c2ecf20Sopenharmony_ci * Marks the @consumer device as waiting for suppliers to become available by 7368c2ecf20Sopenharmony_ci * adding it to the wait_for_suppliers list. The consumer device will never be 7378c2ecf20Sopenharmony_ci * probed until it's removed from the wait_for_suppliers list. 7388c2ecf20Sopenharmony_ci * 7398c2ecf20Sopenharmony_ci * The caller is responsible for adding the links to the supplier devices once 7408c2ecf20Sopenharmony_ci * they are available and removing the @consumer device from the 7418c2ecf20Sopenharmony_ci * wait_for_suppliers list once links to all the suppliers have been created. 7428c2ecf20Sopenharmony_ci * 7438c2ecf20Sopenharmony_ci * This function is NOT meant to be called from the probe function of the 7448c2ecf20Sopenharmony_ci * consumer but rather from code that creates/adds the consumer device. 7458c2ecf20Sopenharmony_ci */ 7468c2ecf20Sopenharmony_cistatic void device_link_wait_for_supplier(struct device *consumer, 7478c2ecf20Sopenharmony_ci bool need_for_probe) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci mutex_lock(&wfs_lock); 7508c2ecf20Sopenharmony_ci list_add_tail(&consumer->links.needs_suppliers, &wait_for_suppliers); 7518c2ecf20Sopenharmony_ci consumer->links.need_for_probe = need_for_probe; 7528c2ecf20Sopenharmony_ci mutex_unlock(&wfs_lock); 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic void device_link_wait_for_mandatory_supplier(struct device *consumer) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci device_link_wait_for_supplier(consumer, true); 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic void device_link_wait_for_optional_supplier(struct device *consumer) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci device_link_wait_for_supplier(consumer, false); 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci/** 7668c2ecf20Sopenharmony_ci * device_link_add_missing_supplier_links - Add links from consumer devices to 7678c2ecf20Sopenharmony_ci * supplier devices, leaving any 7688c2ecf20Sopenharmony_ci * consumer with inactive suppliers on 7698c2ecf20Sopenharmony_ci * the wait_for_suppliers list 7708c2ecf20Sopenharmony_ci * 7718c2ecf20Sopenharmony_ci * Loops through all consumers waiting on suppliers and tries to add all their 7728c2ecf20Sopenharmony_ci * supplier links. If that succeeds, the consumer device is removed from 7738c2ecf20Sopenharmony_ci * wait_for_suppliers list. Otherwise, they are left in the wait_for_suppliers 7748c2ecf20Sopenharmony_ci * list. Devices left on the wait_for_suppliers list will not be probed. 7758c2ecf20Sopenharmony_ci * 7768c2ecf20Sopenharmony_ci * The fwnode add_links callback is expected to return 0 if it has found and 7778c2ecf20Sopenharmony_ci * added all the supplier links for the consumer device. It should return an 7788c2ecf20Sopenharmony_ci * error if it isn't able to do so. 7798c2ecf20Sopenharmony_ci * 7808c2ecf20Sopenharmony_ci * The caller of device_link_wait_for_supplier() is expected to call this once 7818c2ecf20Sopenharmony_ci * it's aware of potential suppliers becoming available. 7828c2ecf20Sopenharmony_ci */ 7838c2ecf20Sopenharmony_cistatic void device_link_add_missing_supplier_links(void) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci struct device *dev, *tmp; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci mutex_lock(&wfs_lock); 7888c2ecf20Sopenharmony_ci list_for_each_entry_safe(dev, tmp, &wait_for_suppliers, 7898c2ecf20Sopenharmony_ci links.needs_suppliers) { 7908c2ecf20Sopenharmony_ci int ret = fwnode_call_int_op(dev->fwnode, add_links, dev); 7918c2ecf20Sopenharmony_ci if (!ret) 7928c2ecf20Sopenharmony_ci list_del_init(&dev->links.needs_suppliers); 7938c2ecf20Sopenharmony_ci else if (ret != -ENODEV || fw_devlink_is_permissive()) 7948c2ecf20Sopenharmony_ci dev->links.need_for_probe = false; 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci mutex_unlock(&wfs_lock); 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci#ifdef CONFIG_SRCU 8008c2ecf20Sopenharmony_cistatic void __device_link_del(struct kref *kref) 8018c2ecf20Sopenharmony_ci{ 8028c2ecf20Sopenharmony_ci struct device_link *link = container_of(kref, struct device_link, kref); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci dev_dbg(link->consumer, "Dropping the link to %s\n", 8058c2ecf20Sopenharmony_ci dev_name(link->supplier)); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci pm_runtime_drop_link(link); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci list_del_rcu(&link->s_node); 8108c2ecf20Sopenharmony_ci list_del_rcu(&link->c_node); 8118c2ecf20Sopenharmony_ci device_unregister(&link->link_dev); 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci#else /* !CONFIG_SRCU */ 8148c2ecf20Sopenharmony_cistatic void __device_link_del(struct kref *kref) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci struct device_link *link = container_of(kref, struct device_link, kref); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci dev_info(link->consumer, "Dropping the link to %s\n", 8198c2ecf20Sopenharmony_ci dev_name(link->supplier)); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci pm_runtime_drop_link(link); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci list_del(&link->s_node); 8248c2ecf20Sopenharmony_ci list_del(&link->c_node); 8258c2ecf20Sopenharmony_ci device_unregister(&link->link_dev); 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci#endif /* !CONFIG_SRCU */ 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_cistatic void device_link_put_kref(struct device_link *link) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci if (link->flags & DL_FLAG_STATELESS) 8328c2ecf20Sopenharmony_ci kref_put(&link->kref, __device_link_del); 8338c2ecf20Sopenharmony_ci else 8348c2ecf20Sopenharmony_ci WARN(1, "Unable to drop a managed device link reference\n"); 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci/** 8388c2ecf20Sopenharmony_ci * device_link_del - Delete a stateless link between two devices. 8398c2ecf20Sopenharmony_ci * @link: Device link to delete. 8408c2ecf20Sopenharmony_ci * 8418c2ecf20Sopenharmony_ci * The caller must ensure proper synchronization of this function with runtime 8428c2ecf20Sopenharmony_ci * PM. If the link was added multiple times, it needs to be deleted as often. 8438c2ecf20Sopenharmony_ci * Care is required for hotplugged devices: Their links are purged on removal 8448c2ecf20Sopenharmony_ci * and calling device_link_del() is then no longer allowed. 8458c2ecf20Sopenharmony_ci */ 8468c2ecf20Sopenharmony_civoid device_link_del(struct device_link *link) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci device_links_write_lock(); 8498c2ecf20Sopenharmony_ci device_link_put_kref(link); 8508c2ecf20Sopenharmony_ci device_links_write_unlock(); 8518c2ecf20Sopenharmony_ci} 8528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_link_del); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci/** 8558c2ecf20Sopenharmony_ci * device_link_remove - Delete a stateless link between two devices. 8568c2ecf20Sopenharmony_ci * @consumer: Consumer end of the link. 8578c2ecf20Sopenharmony_ci * @supplier: Supplier end of the link. 8588c2ecf20Sopenharmony_ci * 8598c2ecf20Sopenharmony_ci * The caller must ensure proper synchronization of this function with runtime 8608c2ecf20Sopenharmony_ci * PM. 8618c2ecf20Sopenharmony_ci */ 8628c2ecf20Sopenharmony_civoid device_link_remove(void *consumer, struct device *supplier) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci struct device_link *link; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (WARN_ON(consumer == supplier)) 8678c2ecf20Sopenharmony_ci return; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci device_links_write_lock(); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci list_for_each_entry(link, &supplier->links.consumers, s_node) { 8728c2ecf20Sopenharmony_ci if (link->consumer == consumer) { 8738c2ecf20Sopenharmony_ci device_link_put_kref(link); 8748c2ecf20Sopenharmony_ci break; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci device_links_write_unlock(); 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_link_remove); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic void device_links_missing_supplier(struct device *dev) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci struct device_link *link; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci list_for_each_entry(link, &dev->links.suppliers, c_node) { 8878c2ecf20Sopenharmony_ci if (link->status != DL_STATE_CONSUMER_PROBE) 8888c2ecf20Sopenharmony_ci continue; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) { 8918c2ecf20Sopenharmony_ci WRITE_ONCE(link->status, DL_STATE_AVAILABLE); 8928c2ecf20Sopenharmony_ci } else { 8938c2ecf20Sopenharmony_ci WARN_ON(!(link->flags & DL_FLAG_SYNC_STATE_ONLY)); 8948c2ecf20Sopenharmony_ci WRITE_ONCE(link->status, DL_STATE_DORMANT); 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci/** 9008c2ecf20Sopenharmony_ci * device_links_check_suppliers - Check presence of supplier drivers. 9018c2ecf20Sopenharmony_ci * @dev: Consumer device. 9028c2ecf20Sopenharmony_ci * 9038c2ecf20Sopenharmony_ci * Check links from this device to any suppliers. Walk the list of the device's 9048c2ecf20Sopenharmony_ci * links to suppliers and see if all of them are available. If not, simply 9058c2ecf20Sopenharmony_ci * return -EPROBE_DEFER. 9068c2ecf20Sopenharmony_ci * 9078c2ecf20Sopenharmony_ci * We need to guarantee that the supplier will not go away after the check has 9088c2ecf20Sopenharmony_ci * been positive here. It only can go away in __device_release_driver() and 9098c2ecf20Sopenharmony_ci * that function checks the device's links to consumers. This means we need to 9108c2ecf20Sopenharmony_ci * mark the link as "consumer probe in progress" to make the supplier removal 9118c2ecf20Sopenharmony_ci * wait for us to complete (or bad things may happen). 9128c2ecf20Sopenharmony_ci * 9138c2ecf20Sopenharmony_ci * Links without the DL_FLAG_MANAGED flag set are ignored. 9148c2ecf20Sopenharmony_ci */ 9158c2ecf20Sopenharmony_ciint device_links_check_suppliers(struct device *dev) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci struct device_link *link; 9188c2ecf20Sopenharmony_ci int ret = 0; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* 9218c2ecf20Sopenharmony_ci * Device waiting for supplier to become available is not allowed to 9228c2ecf20Sopenharmony_ci * probe. 9238c2ecf20Sopenharmony_ci */ 9248c2ecf20Sopenharmony_ci mutex_lock(&wfs_lock); 9258c2ecf20Sopenharmony_ci if (!list_empty(&dev->links.needs_suppliers) && 9268c2ecf20Sopenharmony_ci dev->links.need_for_probe) { 9278c2ecf20Sopenharmony_ci mutex_unlock(&wfs_lock); 9288c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci mutex_unlock(&wfs_lock); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci device_links_write_lock(); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci list_for_each_entry(link, &dev->links.suppliers, c_node) { 9358c2ecf20Sopenharmony_ci if (!(link->flags & DL_FLAG_MANAGED)) 9368c2ecf20Sopenharmony_ci continue; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci if (link->status != DL_STATE_AVAILABLE && 9398c2ecf20Sopenharmony_ci !(link->flags & DL_FLAG_SYNC_STATE_ONLY)) { 9408c2ecf20Sopenharmony_ci device_links_missing_supplier(dev); 9418c2ecf20Sopenharmony_ci ret = -EPROBE_DEFER; 9428c2ecf20Sopenharmony_ci break; 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci WRITE_ONCE(link->status, DL_STATE_CONSUMER_PROBE); 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci dev->links.status = DL_DEV_PROBING; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci device_links_write_unlock(); 9498c2ecf20Sopenharmony_ci return ret; 9508c2ecf20Sopenharmony_ci} 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci/** 9538c2ecf20Sopenharmony_ci * __device_links_queue_sync_state - Queue a device for sync_state() callback 9548c2ecf20Sopenharmony_ci * @dev: Device to call sync_state() on 9558c2ecf20Sopenharmony_ci * @list: List head to queue the @dev on 9568c2ecf20Sopenharmony_ci * 9578c2ecf20Sopenharmony_ci * Queues a device for a sync_state() callback when the device links write lock 9588c2ecf20Sopenharmony_ci * isn't held. This allows the sync_state() execution flow to use device links 9598c2ecf20Sopenharmony_ci * APIs. The caller must ensure this function is called with 9608c2ecf20Sopenharmony_ci * device_links_write_lock() held. 9618c2ecf20Sopenharmony_ci * 9628c2ecf20Sopenharmony_ci * This function does a get_device() to make sure the device is not freed while 9638c2ecf20Sopenharmony_ci * on this list. 9648c2ecf20Sopenharmony_ci * 9658c2ecf20Sopenharmony_ci * So the caller must also ensure that device_links_flush_sync_list() is called 9668c2ecf20Sopenharmony_ci * as soon as the caller releases device_links_write_lock(). This is necessary 9678c2ecf20Sopenharmony_ci * to make sure the sync_state() is called in a timely fashion and the 9688c2ecf20Sopenharmony_ci * put_device() is called on this device. 9698c2ecf20Sopenharmony_ci */ 9708c2ecf20Sopenharmony_cistatic void __device_links_queue_sync_state(struct device *dev, 9718c2ecf20Sopenharmony_ci struct list_head *list) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci struct device_link *link; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if (!dev_has_sync_state(dev)) 9768c2ecf20Sopenharmony_ci return; 9778c2ecf20Sopenharmony_ci if (dev->state_synced) 9788c2ecf20Sopenharmony_ci return; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci list_for_each_entry(link, &dev->links.consumers, s_node) { 9818c2ecf20Sopenharmony_ci if (!(link->flags & DL_FLAG_MANAGED)) 9828c2ecf20Sopenharmony_ci continue; 9838c2ecf20Sopenharmony_ci if (link->status != DL_STATE_ACTIVE) 9848c2ecf20Sopenharmony_ci return; 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci /* 9888c2ecf20Sopenharmony_ci * Set the flag here to avoid adding the same device to a list more 9898c2ecf20Sopenharmony_ci * than once. This can happen if new consumers get added to the device 9908c2ecf20Sopenharmony_ci * and probed before the list is flushed. 9918c2ecf20Sopenharmony_ci */ 9928c2ecf20Sopenharmony_ci dev->state_synced = true; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci if (WARN_ON(!list_empty(&dev->links.defer_hook))) 9958c2ecf20Sopenharmony_ci return; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci get_device(dev); 9988c2ecf20Sopenharmony_ci list_add_tail(&dev->links.defer_hook, list); 9998c2ecf20Sopenharmony_ci} 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci/** 10028c2ecf20Sopenharmony_ci * device_links_flush_sync_list - Call sync_state() on a list of devices 10038c2ecf20Sopenharmony_ci * @list: List of devices to call sync_state() on 10048c2ecf20Sopenharmony_ci * @dont_lock_dev: Device for which lock is already held by the caller 10058c2ecf20Sopenharmony_ci * 10068c2ecf20Sopenharmony_ci * Calls sync_state() on all the devices that have been queued for it. This 10078c2ecf20Sopenharmony_ci * function is used in conjunction with __device_links_queue_sync_state(). The 10088c2ecf20Sopenharmony_ci * @dont_lock_dev parameter is useful when this function is called from a 10098c2ecf20Sopenharmony_ci * context where a device lock is already held. 10108c2ecf20Sopenharmony_ci */ 10118c2ecf20Sopenharmony_cistatic void device_links_flush_sync_list(struct list_head *list, 10128c2ecf20Sopenharmony_ci struct device *dont_lock_dev) 10138c2ecf20Sopenharmony_ci{ 10148c2ecf20Sopenharmony_ci struct device *dev, *tmp; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci list_for_each_entry_safe(dev, tmp, list, links.defer_hook) { 10178c2ecf20Sopenharmony_ci list_del_init(&dev->links.defer_hook); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci if (dev != dont_lock_dev) 10208c2ecf20Sopenharmony_ci device_lock(dev); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if (dev->bus->sync_state) 10238c2ecf20Sopenharmony_ci dev->bus->sync_state(dev); 10248c2ecf20Sopenharmony_ci else if (dev->driver && dev->driver->sync_state) 10258c2ecf20Sopenharmony_ci dev->driver->sync_state(dev); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci if (dev != dont_lock_dev) 10288c2ecf20Sopenharmony_ci device_unlock(dev); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci put_device(dev); 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_civoid device_links_supplier_sync_state_pause(void) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci device_links_write_lock(); 10378c2ecf20Sopenharmony_ci defer_sync_state_count++; 10388c2ecf20Sopenharmony_ci device_links_write_unlock(); 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_civoid device_links_supplier_sync_state_resume(void) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci struct device *dev, *tmp; 10448c2ecf20Sopenharmony_ci LIST_HEAD(sync_list); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci device_links_write_lock(); 10478c2ecf20Sopenharmony_ci if (!defer_sync_state_count) { 10488c2ecf20Sopenharmony_ci WARN(true, "Unmatched sync_state pause/resume!"); 10498c2ecf20Sopenharmony_ci goto out; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci defer_sync_state_count--; 10528c2ecf20Sopenharmony_ci if (defer_sync_state_count) 10538c2ecf20Sopenharmony_ci goto out; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci list_for_each_entry_safe(dev, tmp, &deferred_sync, links.defer_hook) { 10568c2ecf20Sopenharmony_ci /* 10578c2ecf20Sopenharmony_ci * Delete from deferred_sync list before queuing it to 10588c2ecf20Sopenharmony_ci * sync_list because defer_hook is used for both lists. 10598c2ecf20Sopenharmony_ci */ 10608c2ecf20Sopenharmony_ci list_del_init(&dev->links.defer_hook); 10618c2ecf20Sopenharmony_ci __device_links_queue_sync_state(dev, &sync_list); 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ciout: 10648c2ecf20Sopenharmony_ci device_links_write_unlock(); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci device_links_flush_sync_list(&sync_list, NULL); 10678c2ecf20Sopenharmony_ci} 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_cistatic int sync_state_resume_initcall(void) 10708c2ecf20Sopenharmony_ci{ 10718c2ecf20Sopenharmony_ci device_links_supplier_sync_state_resume(); 10728c2ecf20Sopenharmony_ci return 0; 10738c2ecf20Sopenharmony_ci} 10748c2ecf20Sopenharmony_cilate_initcall(sync_state_resume_initcall); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_cistatic void __device_links_supplier_defer_sync(struct device *sup) 10778c2ecf20Sopenharmony_ci{ 10788c2ecf20Sopenharmony_ci if (list_empty(&sup->links.defer_hook) && dev_has_sync_state(sup)) 10798c2ecf20Sopenharmony_ci list_add_tail(&sup->links.defer_hook, &deferred_sync); 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_cistatic void device_link_drop_managed(struct device_link *link) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci link->flags &= ~DL_FLAG_MANAGED; 10858c2ecf20Sopenharmony_ci WRITE_ONCE(link->status, DL_STATE_NONE); 10868c2ecf20Sopenharmony_ci kref_put(&link->kref, __device_link_del); 10878c2ecf20Sopenharmony_ci} 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_cistatic ssize_t waiting_for_supplier_show(struct device *dev, 10908c2ecf20Sopenharmony_ci struct device_attribute *attr, 10918c2ecf20Sopenharmony_ci char *buf) 10928c2ecf20Sopenharmony_ci{ 10938c2ecf20Sopenharmony_ci bool val; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci device_lock(dev); 10968c2ecf20Sopenharmony_ci mutex_lock(&wfs_lock); 10978c2ecf20Sopenharmony_ci val = !list_empty(&dev->links.needs_suppliers) 10988c2ecf20Sopenharmony_ci && dev->links.need_for_probe; 10998c2ecf20Sopenharmony_ci mutex_unlock(&wfs_lock); 11008c2ecf20Sopenharmony_ci device_unlock(dev); 11018c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%u\n", val); 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(waiting_for_supplier); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci/** 11068c2ecf20Sopenharmony_ci * device_links_driver_bound - Update device links after probing its driver. 11078c2ecf20Sopenharmony_ci * @dev: Device to update the links for. 11088c2ecf20Sopenharmony_ci * 11098c2ecf20Sopenharmony_ci * The probe has been successful, so update links from this device to any 11108c2ecf20Sopenharmony_ci * consumers by changing their status to "available". 11118c2ecf20Sopenharmony_ci * 11128c2ecf20Sopenharmony_ci * Also change the status of @dev's links to suppliers to "active". 11138c2ecf20Sopenharmony_ci * 11148c2ecf20Sopenharmony_ci * Links without the DL_FLAG_MANAGED flag set are ignored. 11158c2ecf20Sopenharmony_ci */ 11168c2ecf20Sopenharmony_civoid device_links_driver_bound(struct device *dev) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci struct device_link *link, *ln; 11198c2ecf20Sopenharmony_ci LIST_HEAD(sync_list); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* 11228c2ecf20Sopenharmony_ci * If a device probes successfully, it's expected to have created all 11238c2ecf20Sopenharmony_ci * the device links it needs to or make new device links as it needs 11248c2ecf20Sopenharmony_ci * them. So, it no longer needs to wait on any suppliers. 11258c2ecf20Sopenharmony_ci */ 11268c2ecf20Sopenharmony_ci mutex_lock(&wfs_lock); 11278c2ecf20Sopenharmony_ci list_del_init(&dev->links.needs_suppliers); 11288c2ecf20Sopenharmony_ci mutex_unlock(&wfs_lock); 11298c2ecf20Sopenharmony_ci device_remove_file(dev, &dev_attr_waiting_for_supplier); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci device_links_write_lock(); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci list_for_each_entry(link, &dev->links.consumers, s_node) { 11348c2ecf20Sopenharmony_ci if (!(link->flags & DL_FLAG_MANAGED)) 11358c2ecf20Sopenharmony_ci continue; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci /* 11388c2ecf20Sopenharmony_ci * Links created during consumer probe may be in the "consumer 11398c2ecf20Sopenharmony_ci * probe" state to start with if the supplier is still probing 11408c2ecf20Sopenharmony_ci * when they are created and they may become "active" if the 11418c2ecf20Sopenharmony_ci * consumer probe returns first. Skip them here. 11428c2ecf20Sopenharmony_ci */ 11438c2ecf20Sopenharmony_ci if (link->status == DL_STATE_CONSUMER_PROBE || 11448c2ecf20Sopenharmony_ci link->status == DL_STATE_ACTIVE) 11458c2ecf20Sopenharmony_ci continue; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci WARN_ON(link->status != DL_STATE_DORMANT); 11488c2ecf20Sopenharmony_ci WRITE_ONCE(link->status, DL_STATE_AVAILABLE); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci if (link->flags & DL_FLAG_AUTOPROBE_CONSUMER) 11518c2ecf20Sopenharmony_ci driver_deferred_probe_add(link->consumer); 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci if (defer_sync_state_count) 11558c2ecf20Sopenharmony_ci __device_links_supplier_defer_sync(dev); 11568c2ecf20Sopenharmony_ci else 11578c2ecf20Sopenharmony_ci __device_links_queue_sync_state(dev, &sync_list); 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci list_for_each_entry_safe(link, ln, &dev->links.suppliers, c_node) { 11608c2ecf20Sopenharmony_ci struct device *supplier; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci if (!(link->flags & DL_FLAG_MANAGED)) 11638c2ecf20Sopenharmony_ci continue; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci supplier = link->supplier; 11668c2ecf20Sopenharmony_ci if (link->flags & DL_FLAG_SYNC_STATE_ONLY) { 11678c2ecf20Sopenharmony_ci /* 11688c2ecf20Sopenharmony_ci * When DL_FLAG_SYNC_STATE_ONLY is set, it means no 11698c2ecf20Sopenharmony_ci * other DL_MANAGED_LINK_FLAGS have been set. So, it's 11708c2ecf20Sopenharmony_ci * save to drop the managed link completely. 11718c2ecf20Sopenharmony_ci */ 11728c2ecf20Sopenharmony_ci device_link_drop_managed(link); 11738c2ecf20Sopenharmony_ci } else { 11748c2ecf20Sopenharmony_ci WARN_ON(link->status != DL_STATE_CONSUMER_PROBE); 11758c2ecf20Sopenharmony_ci WRITE_ONCE(link->status, DL_STATE_ACTIVE); 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci /* 11798c2ecf20Sopenharmony_ci * This needs to be done even for the deleted 11808c2ecf20Sopenharmony_ci * DL_FLAG_SYNC_STATE_ONLY device link in case it was the last 11818c2ecf20Sopenharmony_ci * device link that was preventing the supplier from getting a 11828c2ecf20Sopenharmony_ci * sync_state() call. 11838c2ecf20Sopenharmony_ci */ 11848c2ecf20Sopenharmony_ci if (defer_sync_state_count) 11858c2ecf20Sopenharmony_ci __device_links_supplier_defer_sync(supplier); 11868c2ecf20Sopenharmony_ci else 11878c2ecf20Sopenharmony_ci __device_links_queue_sync_state(supplier, &sync_list); 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci dev->links.status = DL_DEV_DRIVER_BOUND; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci device_links_write_unlock(); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci device_links_flush_sync_list(&sync_list, dev); 11958c2ecf20Sopenharmony_ci} 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci/** 11988c2ecf20Sopenharmony_ci * __device_links_no_driver - Update links of a device without a driver. 11998c2ecf20Sopenharmony_ci * @dev: Device without a drvier. 12008c2ecf20Sopenharmony_ci * 12018c2ecf20Sopenharmony_ci * Delete all non-persistent links from this device to any suppliers. 12028c2ecf20Sopenharmony_ci * 12038c2ecf20Sopenharmony_ci * Persistent links stay around, but their status is changed to "available", 12048c2ecf20Sopenharmony_ci * unless they already are in the "supplier unbind in progress" state in which 12058c2ecf20Sopenharmony_ci * case they need not be updated. 12068c2ecf20Sopenharmony_ci * 12078c2ecf20Sopenharmony_ci * Links without the DL_FLAG_MANAGED flag set are ignored. 12088c2ecf20Sopenharmony_ci */ 12098c2ecf20Sopenharmony_cistatic void __device_links_no_driver(struct device *dev) 12108c2ecf20Sopenharmony_ci{ 12118c2ecf20Sopenharmony_ci struct device_link *link, *ln; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci list_for_each_entry_safe_reverse(link, ln, &dev->links.suppliers, c_node) { 12148c2ecf20Sopenharmony_ci if (!(link->flags & DL_FLAG_MANAGED)) 12158c2ecf20Sopenharmony_ci continue; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER) { 12188c2ecf20Sopenharmony_ci device_link_drop_managed(link); 12198c2ecf20Sopenharmony_ci continue; 12208c2ecf20Sopenharmony_ci } 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (link->status != DL_STATE_CONSUMER_PROBE && 12238c2ecf20Sopenharmony_ci link->status != DL_STATE_ACTIVE) 12248c2ecf20Sopenharmony_ci continue; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) { 12278c2ecf20Sopenharmony_ci WRITE_ONCE(link->status, DL_STATE_AVAILABLE); 12288c2ecf20Sopenharmony_ci } else { 12298c2ecf20Sopenharmony_ci WARN_ON(!(link->flags & DL_FLAG_SYNC_STATE_ONLY)); 12308c2ecf20Sopenharmony_ci WRITE_ONCE(link->status, DL_STATE_DORMANT); 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci dev->links.status = DL_DEV_NO_DRIVER; 12358c2ecf20Sopenharmony_ci} 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci/** 12388c2ecf20Sopenharmony_ci * device_links_no_driver - Update links after failing driver probe. 12398c2ecf20Sopenharmony_ci * @dev: Device whose driver has just failed to probe. 12408c2ecf20Sopenharmony_ci * 12418c2ecf20Sopenharmony_ci * Clean up leftover links to consumers for @dev and invoke 12428c2ecf20Sopenharmony_ci * %__device_links_no_driver() to update links to suppliers for it as 12438c2ecf20Sopenharmony_ci * appropriate. 12448c2ecf20Sopenharmony_ci * 12458c2ecf20Sopenharmony_ci * Links without the DL_FLAG_MANAGED flag set are ignored. 12468c2ecf20Sopenharmony_ci */ 12478c2ecf20Sopenharmony_civoid device_links_no_driver(struct device *dev) 12488c2ecf20Sopenharmony_ci{ 12498c2ecf20Sopenharmony_ci struct device_link *link; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci device_links_write_lock(); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci list_for_each_entry(link, &dev->links.consumers, s_node) { 12548c2ecf20Sopenharmony_ci if (!(link->flags & DL_FLAG_MANAGED)) 12558c2ecf20Sopenharmony_ci continue; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci /* 12588c2ecf20Sopenharmony_ci * The probe has failed, so if the status of the link is 12598c2ecf20Sopenharmony_ci * "consumer probe" or "active", it must have been added by 12608c2ecf20Sopenharmony_ci * a probing consumer while this device was still probing. 12618c2ecf20Sopenharmony_ci * Change its state to "dormant", as it represents a valid 12628c2ecf20Sopenharmony_ci * relationship, but it is not functionally meaningful. 12638c2ecf20Sopenharmony_ci */ 12648c2ecf20Sopenharmony_ci if (link->status == DL_STATE_CONSUMER_PROBE || 12658c2ecf20Sopenharmony_ci link->status == DL_STATE_ACTIVE) 12668c2ecf20Sopenharmony_ci WRITE_ONCE(link->status, DL_STATE_DORMANT); 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci __device_links_no_driver(dev); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci device_links_write_unlock(); 12728c2ecf20Sopenharmony_ci} 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci/** 12758c2ecf20Sopenharmony_ci * device_links_driver_cleanup - Update links after driver removal. 12768c2ecf20Sopenharmony_ci * @dev: Device whose driver has just gone away. 12778c2ecf20Sopenharmony_ci * 12788c2ecf20Sopenharmony_ci * Update links to consumers for @dev by changing their status to "dormant" and 12798c2ecf20Sopenharmony_ci * invoke %__device_links_no_driver() to update links to suppliers for it as 12808c2ecf20Sopenharmony_ci * appropriate. 12818c2ecf20Sopenharmony_ci * 12828c2ecf20Sopenharmony_ci * Links without the DL_FLAG_MANAGED flag set are ignored. 12838c2ecf20Sopenharmony_ci */ 12848c2ecf20Sopenharmony_civoid device_links_driver_cleanup(struct device *dev) 12858c2ecf20Sopenharmony_ci{ 12868c2ecf20Sopenharmony_ci struct device_link *link, *ln; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci device_links_write_lock(); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci list_for_each_entry_safe(link, ln, &dev->links.consumers, s_node) { 12918c2ecf20Sopenharmony_ci if (!(link->flags & DL_FLAG_MANAGED)) 12928c2ecf20Sopenharmony_ci continue; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci WARN_ON(link->flags & DL_FLAG_AUTOREMOVE_CONSUMER); 12958c2ecf20Sopenharmony_ci WARN_ON(link->status != DL_STATE_SUPPLIER_UNBIND); 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci /* 12988c2ecf20Sopenharmony_ci * autoremove the links between this @dev and its consumer 12998c2ecf20Sopenharmony_ci * devices that are not active, i.e. where the link state 13008c2ecf20Sopenharmony_ci * has moved to DL_STATE_SUPPLIER_UNBIND. 13018c2ecf20Sopenharmony_ci */ 13028c2ecf20Sopenharmony_ci if (link->status == DL_STATE_SUPPLIER_UNBIND && 13038c2ecf20Sopenharmony_ci link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER) 13048c2ecf20Sopenharmony_ci device_link_drop_managed(link); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci WRITE_ONCE(link->status, DL_STATE_DORMANT); 13078c2ecf20Sopenharmony_ci } 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci list_del_init(&dev->links.defer_hook); 13108c2ecf20Sopenharmony_ci __device_links_no_driver(dev); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci device_links_write_unlock(); 13138c2ecf20Sopenharmony_ci} 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci/** 13168c2ecf20Sopenharmony_ci * device_links_busy - Check if there are any busy links to consumers. 13178c2ecf20Sopenharmony_ci * @dev: Device to check. 13188c2ecf20Sopenharmony_ci * 13198c2ecf20Sopenharmony_ci * Check each consumer of the device and return 'true' if its link's status 13208c2ecf20Sopenharmony_ci * is one of "consumer probe" or "active" (meaning that the given consumer is 13218c2ecf20Sopenharmony_ci * probing right now or its driver is present). Otherwise, change the link 13228c2ecf20Sopenharmony_ci * state to "supplier unbind" to prevent the consumer from being probed 13238c2ecf20Sopenharmony_ci * successfully going forward. 13248c2ecf20Sopenharmony_ci * 13258c2ecf20Sopenharmony_ci * Return 'false' if there are no probing or active consumers. 13268c2ecf20Sopenharmony_ci * 13278c2ecf20Sopenharmony_ci * Links without the DL_FLAG_MANAGED flag set are ignored. 13288c2ecf20Sopenharmony_ci */ 13298c2ecf20Sopenharmony_cibool device_links_busy(struct device *dev) 13308c2ecf20Sopenharmony_ci{ 13318c2ecf20Sopenharmony_ci struct device_link *link; 13328c2ecf20Sopenharmony_ci bool ret = false; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci device_links_write_lock(); 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci list_for_each_entry(link, &dev->links.consumers, s_node) { 13378c2ecf20Sopenharmony_ci if (!(link->flags & DL_FLAG_MANAGED)) 13388c2ecf20Sopenharmony_ci continue; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci if (link->status == DL_STATE_CONSUMER_PROBE 13418c2ecf20Sopenharmony_ci || link->status == DL_STATE_ACTIVE) { 13428c2ecf20Sopenharmony_ci ret = true; 13438c2ecf20Sopenharmony_ci break; 13448c2ecf20Sopenharmony_ci } 13458c2ecf20Sopenharmony_ci WRITE_ONCE(link->status, DL_STATE_SUPPLIER_UNBIND); 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci dev->links.status = DL_DEV_UNBINDING; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci device_links_write_unlock(); 13518c2ecf20Sopenharmony_ci return ret; 13528c2ecf20Sopenharmony_ci} 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci/** 13558c2ecf20Sopenharmony_ci * device_links_unbind_consumers - Force unbind consumers of the given device. 13568c2ecf20Sopenharmony_ci * @dev: Device to unbind the consumers of. 13578c2ecf20Sopenharmony_ci * 13588c2ecf20Sopenharmony_ci * Walk the list of links to consumers for @dev and if any of them is in the 13598c2ecf20Sopenharmony_ci * "consumer probe" state, wait for all device probes in progress to complete 13608c2ecf20Sopenharmony_ci * and start over. 13618c2ecf20Sopenharmony_ci * 13628c2ecf20Sopenharmony_ci * If that's not the case, change the status of the link to "supplier unbind" 13638c2ecf20Sopenharmony_ci * and check if the link was in the "active" state. If so, force the consumer 13648c2ecf20Sopenharmony_ci * driver to unbind and start over (the consumer will not re-probe as we have 13658c2ecf20Sopenharmony_ci * changed the state of the link already). 13668c2ecf20Sopenharmony_ci * 13678c2ecf20Sopenharmony_ci * Links without the DL_FLAG_MANAGED flag set are ignored. 13688c2ecf20Sopenharmony_ci */ 13698c2ecf20Sopenharmony_civoid device_links_unbind_consumers(struct device *dev) 13708c2ecf20Sopenharmony_ci{ 13718c2ecf20Sopenharmony_ci struct device_link *link; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci start: 13748c2ecf20Sopenharmony_ci device_links_write_lock(); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci list_for_each_entry(link, &dev->links.consumers, s_node) { 13778c2ecf20Sopenharmony_ci enum device_link_state status; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (!(link->flags & DL_FLAG_MANAGED) || 13808c2ecf20Sopenharmony_ci link->flags & DL_FLAG_SYNC_STATE_ONLY) 13818c2ecf20Sopenharmony_ci continue; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci status = link->status; 13848c2ecf20Sopenharmony_ci if (status == DL_STATE_CONSUMER_PROBE) { 13858c2ecf20Sopenharmony_ci device_links_write_unlock(); 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci wait_for_device_probe(); 13888c2ecf20Sopenharmony_ci goto start; 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci WRITE_ONCE(link->status, DL_STATE_SUPPLIER_UNBIND); 13918c2ecf20Sopenharmony_ci if (status == DL_STATE_ACTIVE) { 13928c2ecf20Sopenharmony_ci struct device *consumer = link->consumer; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci get_device(consumer); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci device_links_write_unlock(); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci device_release_driver_internal(consumer, NULL, 13998c2ecf20Sopenharmony_ci consumer->parent); 14008c2ecf20Sopenharmony_ci put_device(consumer); 14018c2ecf20Sopenharmony_ci goto start; 14028c2ecf20Sopenharmony_ci } 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci device_links_write_unlock(); 14068c2ecf20Sopenharmony_ci} 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci/** 14098c2ecf20Sopenharmony_ci * device_links_purge - Delete existing links to other devices. 14108c2ecf20Sopenharmony_ci * @dev: Target device. 14118c2ecf20Sopenharmony_ci */ 14128c2ecf20Sopenharmony_cistatic void device_links_purge(struct device *dev) 14138c2ecf20Sopenharmony_ci{ 14148c2ecf20Sopenharmony_ci struct device_link *link, *ln; 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci if (dev->class == &devlink_class) 14178c2ecf20Sopenharmony_ci return; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci mutex_lock(&wfs_lock); 14208c2ecf20Sopenharmony_ci list_del_init(&dev->links.needs_suppliers); 14218c2ecf20Sopenharmony_ci mutex_unlock(&wfs_lock); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci /* 14248c2ecf20Sopenharmony_ci * Delete all of the remaining links from this device to any other 14258c2ecf20Sopenharmony_ci * devices (either consumers or suppliers). 14268c2ecf20Sopenharmony_ci */ 14278c2ecf20Sopenharmony_ci device_links_write_lock(); 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci list_for_each_entry_safe_reverse(link, ln, &dev->links.suppliers, c_node) { 14308c2ecf20Sopenharmony_ci WARN_ON(link->status == DL_STATE_ACTIVE); 14318c2ecf20Sopenharmony_ci __device_link_del(&link->kref); 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci list_for_each_entry_safe_reverse(link, ln, &dev->links.consumers, s_node) { 14358c2ecf20Sopenharmony_ci WARN_ON(link->status != DL_STATE_DORMANT && 14368c2ecf20Sopenharmony_ci link->status != DL_STATE_NONE); 14378c2ecf20Sopenharmony_ci __device_link_del(&link->kref); 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci device_links_write_unlock(); 14418c2ecf20Sopenharmony_ci} 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_cistatic u32 fw_devlink_flags = DL_FLAG_SYNC_STATE_ONLY; 14448c2ecf20Sopenharmony_cistatic int __init fw_devlink_setup(char *arg) 14458c2ecf20Sopenharmony_ci{ 14468c2ecf20Sopenharmony_ci if (!arg) 14478c2ecf20Sopenharmony_ci return -EINVAL; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci if (strcmp(arg, "off") == 0) { 14508c2ecf20Sopenharmony_ci fw_devlink_flags = 0; 14518c2ecf20Sopenharmony_ci } else if (strcmp(arg, "permissive") == 0) { 14528c2ecf20Sopenharmony_ci fw_devlink_flags = DL_FLAG_SYNC_STATE_ONLY; 14538c2ecf20Sopenharmony_ci } else if (strcmp(arg, "on") == 0) { 14548c2ecf20Sopenharmony_ci fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER; 14558c2ecf20Sopenharmony_ci } else if (strcmp(arg, "rpm") == 0) { 14568c2ecf20Sopenharmony_ci fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER | 14578c2ecf20Sopenharmony_ci DL_FLAG_PM_RUNTIME; 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci return 0; 14608c2ecf20Sopenharmony_ci} 14618c2ecf20Sopenharmony_ciearly_param("fw_devlink", fw_devlink_setup); 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ciu32 fw_devlink_get_flags(void) 14648c2ecf20Sopenharmony_ci{ 14658c2ecf20Sopenharmony_ci return fw_devlink_flags; 14668c2ecf20Sopenharmony_ci} 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_cistatic bool fw_devlink_is_permissive(void) 14698c2ecf20Sopenharmony_ci{ 14708c2ecf20Sopenharmony_ci return fw_devlink_flags == DL_FLAG_SYNC_STATE_ONLY; 14718c2ecf20Sopenharmony_ci} 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_cistatic void fw_devlink_link_device(struct device *dev) 14748c2ecf20Sopenharmony_ci{ 14758c2ecf20Sopenharmony_ci int fw_ret; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci if (!fw_devlink_flags) 14788c2ecf20Sopenharmony_ci return; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci mutex_lock(&defer_fw_devlink_lock); 14818c2ecf20Sopenharmony_ci if (!defer_fw_devlink_count) 14828c2ecf20Sopenharmony_ci device_link_add_missing_supplier_links(); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci /* 14858c2ecf20Sopenharmony_ci * The device's fwnode not having add_links() doesn't affect if other 14868c2ecf20Sopenharmony_ci * consumers can find this device as a supplier. So, this check is 14878c2ecf20Sopenharmony_ci * intentionally placed after device_link_add_missing_supplier_links(). 14888c2ecf20Sopenharmony_ci */ 14898c2ecf20Sopenharmony_ci if (!fwnode_has_op(dev->fwnode, add_links)) 14908c2ecf20Sopenharmony_ci goto out; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci /* 14938c2ecf20Sopenharmony_ci * If fw_devlink is being deferred, assume all devices have mandatory 14948c2ecf20Sopenharmony_ci * suppliers they need to link to later. Then, when the fw_devlink is 14958c2ecf20Sopenharmony_ci * resumed, all these devices will get a chance to try and link to any 14968c2ecf20Sopenharmony_ci * suppliers they have. 14978c2ecf20Sopenharmony_ci */ 14988c2ecf20Sopenharmony_ci if (!defer_fw_devlink_count) { 14998c2ecf20Sopenharmony_ci fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev); 15008c2ecf20Sopenharmony_ci if (fw_ret == -ENODEV && fw_devlink_is_permissive()) 15018c2ecf20Sopenharmony_ci fw_ret = -EAGAIN; 15028c2ecf20Sopenharmony_ci } else { 15038c2ecf20Sopenharmony_ci fw_ret = -ENODEV; 15048c2ecf20Sopenharmony_ci /* 15058c2ecf20Sopenharmony_ci * defer_hook is not used to add device to deferred_sync list 15068c2ecf20Sopenharmony_ci * until device is bound. Since deferred fw devlink also blocks 15078c2ecf20Sopenharmony_ci * probing, same list hook can be used for deferred_fw_devlink. 15088c2ecf20Sopenharmony_ci */ 15098c2ecf20Sopenharmony_ci list_add_tail(&dev->links.defer_hook, &deferred_fw_devlink); 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci if (fw_ret == -ENODEV) 15138c2ecf20Sopenharmony_ci device_link_wait_for_mandatory_supplier(dev); 15148c2ecf20Sopenharmony_ci else if (fw_ret) 15158c2ecf20Sopenharmony_ci device_link_wait_for_optional_supplier(dev); 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ciout: 15188c2ecf20Sopenharmony_ci mutex_unlock(&defer_fw_devlink_lock); 15198c2ecf20Sopenharmony_ci} 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci/** 15228c2ecf20Sopenharmony_ci * fw_devlink_pause - Pause parsing of fwnode to create device links 15238c2ecf20Sopenharmony_ci * 15248c2ecf20Sopenharmony_ci * Calling this function defers any fwnode parsing to create device links until 15258c2ecf20Sopenharmony_ci * fw_devlink_resume() is called. Both these functions are ref counted and the 15268c2ecf20Sopenharmony_ci * caller needs to match the calls. 15278c2ecf20Sopenharmony_ci * 15288c2ecf20Sopenharmony_ci * While fw_devlink is paused: 15298c2ecf20Sopenharmony_ci * - Any device that is added won't have its fwnode parsed to create device 15308c2ecf20Sopenharmony_ci * links. 15318c2ecf20Sopenharmony_ci * - The probe of the device will also be deferred during this period. 15328c2ecf20Sopenharmony_ci * - Any devices that were already added, but waiting for suppliers won't be 15338c2ecf20Sopenharmony_ci * able to link to newly added devices. 15348c2ecf20Sopenharmony_ci * 15358c2ecf20Sopenharmony_ci * Once fw_devlink_resume(): 15368c2ecf20Sopenharmony_ci * - All the fwnodes that was not parsed will be parsed. 15378c2ecf20Sopenharmony_ci * - All the devices that were deferred probing will be reattempted if they 15388c2ecf20Sopenharmony_ci * aren't waiting for any more suppliers. 15398c2ecf20Sopenharmony_ci * 15408c2ecf20Sopenharmony_ci * This pair of functions, is mainly meant to optimize the parsing of fwnodes 15418c2ecf20Sopenharmony_ci * when a lot of devices that need to link to each other are added in a short 15428c2ecf20Sopenharmony_ci * interval of time. For example, adding all the top level devices in a system. 15438c2ecf20Sopenharmony_ci * 15448c2ecf20Sopenharmony_ci * For example, if N devices are added and: 15458c2ecf20Sopenharmony_ci * - All the consumers are added before their suppliers 15468c2ecf20Sopenharmony_ci * - All the suppliers of the N devices are part of the N devices 15478c2ecf20Sopenharmony_ci * 15488c2ecf20Sopenharmony_ci * Then: 15498c2ecf20Sopenharmony_ci * 15508c2ecf20Sopenharmony_ci * - With the use of fw_devlink_pause() and fw_devlink_resume(), each device 15518c2ecf20Sopenharmony_ci * will only need one parsing of its fwnode because it is guaranteed to find 15528c2ecf20Sopenharmony_ci * all the supplier devices already registered and ready to link to. It won't 15538c2ecf20Sopenharmony_ci * have to do another pass later to find one or more suppliers it couldn't 15548c2ecf20Sopenharmony_ci * find in the first parse of the fwnode. So, we'll only need O(N) fwnode 15558c2ecf20Sopenharmony_ci * parses. 15568c2ecf20Sopenharmony_ci * 15578c2ecf20Sopenharmony_ci * - Without the use of fw_devlink_pause() and fw_devlink_resume(), we would 15588c2ecf20Sopenharmony_ci * end up doing O(N^2) parses of fwnodes because every device that's added is 15598c2ecf20Sopenharmony_ci * guaranteed to trigger a parse of the fwnode of every device added before 15608c2ecf20Sopenharmony_ci * it. This O(N^2) parse is made worse by the fact that when a fwnode of a 15618c2ecf20Sopenharmony_ci * device is parsed, all it descendant devices might need to have their 15628c2ecf20Sopenharmony_ci * fwnodes parsed too (even if the devices themselves aren't added). 15638c2ecf20Sopenharmony_ci */ 15648c2ecf20Sopenharmony_civoid fw_devlink_pause(void) 15658c2ecf20Sopenharmony_ci{ 15668c2ecf20Sopenharmony_ci mutex_lock(&defer_fw_devlink_lock); 15678c2ecf20Sopenharmony_ci defer_fw_devlink_count++; 15688c2ecf20Sopenharmony_ci mutex_unlock(&defer_fw_devlink_lock); 15698c2ecf20Sopenharmony_ci} 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci/** fw_devlink_resume - Resume parsing of fwnode to create device links 15728c2ecf20Sopenharmony_ci * 15738c2ecf20Sopenharmony_ci * This function is used in conjunction with fw_devlink_pause() and is ref 15748c2ecf20Sopenharmony_ci * counted. See documentation for fw_devlink_pause() for more details. 15758c2ecf20Sopenharmony_ci */ 15768c2ecf20Sopenharmony_civoid fw_devlink_resume(void) 15778c2ecf20Sopenharmony_ci{ 15788c2ecf20Sopenharmony_ci struct device *dev, *tmp; 15798c2ecf20Sopenharmony_ci LIST_HEAD(probe_list); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci mutex_lock(&defer_fw_devlink_lock); 15828c2ecf20Sopenharmony_ci if (!defer_fw_devlink_count) { 15838c2ecf20Sopenharmony_ci WARN(true, "Unmatched fw_devlink pause/resume!"); 15848c2ecf20Sopenharmony_ci goto out; 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci defer_fw_devlink_count--; 15888c2ecf20Sopenharmony_ci if (defer_fw_devlink_count) 15898c2ecf20Sopenharmony_ci goto out; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci device_link_add_missing_supplier_links(); 15928c2ecf20Sopenharmony_ci list_splice_tail_init(&deferred_fw_devlink, &probe_list); 15938c2ecf20Sopenharmony_ciout: 15948c2ecf20Sopenharmony_ci mutex_unlock(&defer_fw_devlink_lock); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci /* 15978c2ecf20Sopenharmony_ci * bus_probe_device() can cause new devices to get added and they'll 15988c2ecf20Sopenharmony_ci * try to grab defer_fw_devlink_lock. So, this needs to be done outside 15998c2ecf20Sopenharmony_ci * the defer_fw_devlink_lock. 16008c2ecf20Sopenharmony_ci */ 16018c2ecf20Sopenharmony_ci list_for_each_entry_safe(dev, tmp, &probe_list, links.defer_hook) { 16028c2ecf20Sopenharmony_ci list_del_init(&dev->links.defer_hook); 16038c2ecf20Sopenharmony_ci bus_probe_device(dev); 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci} 16068c2ecf20Sopenharmony_ci/* Device links support end. */ 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ciint (*platform_notify)(struct device *dev) = NULL; 16098c2ecf20Sopenharmony_ciint (*platform_notify_remove)(struct device *dev) = NULL; 16108c2ecf20Sopenharmony_cistatic struct kobject *dev_kobj; 16118c2ecf20Sopenharmony_cistruct kobject *sysfs_dev_char_kobj; 16128c2ecf20Sopenharmony_cistruct kobject *sysfs_dev_block_kobj; 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(device_hotplug_lock); 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_civoid lock_device_hotplug(void) 16178c2ecf20Sopenharmony_ci{ 16188c2ecf20Sopenharmony_ci mutex_lock(&device_hotplug_lock); 16198c2ecf20Sopenharmony_ci} 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_civoid unlock_device_hotplug(void) 16228c2ecf20Sopenharmony_ci{ 16238c2ecf20Sopenharmony_ci mutex_unlock(&device_hotplug_lock); 16248c2ecf20Sopenharmony_ci} 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ciint lock_device_hotplug_sysfs(void) 16278c2ecf20Sopenharmony_ci{ 16288c2ecf20Sopenharmony_ci if (mutex_trylock(&device_hotplug_lock)) 16298c2ecf20Sopenharmony_ci return 0; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci /* Avoid busy looping (5 ms of sleep should do). */ 16328c2ecf20Sopenharmony_ci msleep(5); 16338c2ecf20Sopenharmony_ci return restart_syscall(); 16348c2ecf20Sopenharmony_ci} 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci#ifdef CONFIG_BLOCK 16378c2ecf20Sopenharmony_cistatic inline int device_is_not_partition(struct device *dev) 16388c2ecf20Sopenharmony_ci{ 16398c2ecf20Sopenharmony_ci return !(dev->type == &part_type); 16408c2ecf20Sopenharmony_ci} 16418c2ecf20Sopenharmony_ci#else 16428c2ecf20Sopenharmony_cistatic inline int device_is_not_partition(struct device *dev) 16438c2ecf20Sopenharmony_ci{ 16448c2ecf20Sopenharmony_ci return 1; 16458c2ecf20Sopenharmony_ci} 16468c2ecf20Sopenharmony_ci#endif 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_cistatic int 16498c2ecf20Sopenharmony_cidevice_platform_notify(struct device *dev, enum kobject_action action) 16508c2ecf20Sopenharmony_ci{ 16518c2ecf20Sopenharmony_ci int ret; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci ret = acpi_platform_notify(dev, action); 16548c2ecf20Sopenharmony_ci if (ret) 16558c2ecf20Sopenharmony_ci return ret; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci ret = software_node_notify(dev, action); 16588c2ecf20Sopenharmony_ci if (ret) 16598c2ecf20Sopenharmony_ci return ret; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci if (platform_notify && action == KOBJ_ADD) 16628c2ecf20Sopenharmony_ci platform_notify(dev); 16638c2ecf20Sopenharmony_ci else if (platform_notify_remove && action == KOBJ_REMOVE) 16648c2ecf20Sopenharmony_ci platform_notify_remove(dev); 16658c2ecf20Sopenharmony_ci return 0; 16668c2ecf20Sopenharmony_ci} 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci/** 16698c2ecf20Sopenharmony_ci * dev_driver_string - Return a device's driver name, if at all possible 16708c2ecf20Sopenharmony_ci * @dev: struct device to get the name of 16718c2ecf20Sopenharmony_ci * 16728c2ecf20Sopenharmony_ci * Will return the device's driver's name if it is bound to a device. If 16738c2ecf20Sopenharmony_ci * the device is not bound to a driver, it will return the name of the bus 16748c2ecf20Sopenharmony_ci * it is attached to. If it is not attached to a bus either, an empty 16758c2ecf20Sopenharmony_ci * string will be returned. 16768c2ecf20Sopenharmony_ci */ 16778c2ecf20Sopenharmony_ciconst char *dev_driver_string(const struct device *dev) 16788c2ecf20Sopenharmony_ci{ 16798c2ecf20Sopenharmony_ci struct device_driver *drv; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci /* dev->driver can change to NULL underneath us because of unbinding, 16828c2ecf20Sopenharmony_ci * so be careful about accessing it. dev->bus and dev->class should 16838c2ecf20Sopenharmony_ci * never change once they are set, so they don't need special care. 16848c2ecf20Sopenharmony_ci */ 16858c2ecf20Sopenharmony_ci drv = READ_ONCE(dev->driver); 16868c2ecf20Sopenharmony_ci return drv ? drv->name : dev_bus_name(dev); 16878c2ecf20Sopenharmony_ci} 16888c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dev_driver_string); 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_cistatic ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, 16938c2ecf20Sopenharmony_ci char *buf) 16948c2ecf20Sopenharmony_ci{ 16958c2ecf20Sopenharmony_ci struct device_attribute *dev_attr = to_dev_attr(attr); 16968c2ecf20Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 16978c2ecf20Sopenharmony_ci ssize_t ret = -EIO; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci if (dev_attr->show) 17008c2ecf20Sopenharmony_ci ret = dev_attr->show(dev, dev_attr, buf); 17018c2ecf20Sopenharmony_ci if (ret >= (ssize_t)PAGE_SIZE) { 17028c2ecf20Sopenharmony_ci printk("dev_attr_show: %pS returned bad count\n", 17038c2ecf20Sopenharmony_ci dev_attr->show); 17048c2ecf20Sopenharmony_ci } 17058c2ecf20Sopenharmony_ci return ret; 17068c2ecf20Sopenharmony_ci} 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_cistatic ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr, 17098c2ecf20Sopenharmony_ci const char *buf, size_t count) 17108c2ecf20Sopenharmony_ci{ 17118c2ecf20Sopenharmony_ci struct device_attribute *dev_attr = to_dev_attr(attr); 17128c2ecf20Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 17138c2ecf20Sopenharmony_ci ssize_t ret = -EIO; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci if (dev_attr->store) 17168c2ecf20Sopenharmony_ci ret = dev_attr->store(dev, dev_attr, buf, count); 17178c2ecf20Sopenharmony_ci return ret; 17188c2ecf20Sopenharmony_ci} 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_cistatic const struct sysfs_ops dev_sysfs_ops = { 17218c2ecf20Sopenharmony_ci .show = dev_attr_show, 17228c2ecf20Sopenharmony_ci .store = dev_attr_store, 17238c2ecf20Sopenharmony_ci}; 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci#define to_ext_attr(x) container_of(x, struct dev_ext_attribute, attr) 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_cissize_t device_store_ulong(struct device *dev, 17288c2ecf20Sopenharmony_ci struct device_attribute *attr, 17298c2ecf20Sopenharmony_ci const char *buf, size_t size) 17308c2ecf20Sopenharmony_ci{ 17318c2ecf20Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 17328c2ecf20Sopenharmony_ci int ret; 17338c2ecf20Sopenharmony_ci unsigned long new; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci ret = kstrtoul(buf, 0, &new); 17368c2ecf20Sopenharmony_ci if (ret) 17378c2ecf20Sopenharmony_ci return ret; 17388c2ecf20Sopenharmony_ci *(unsigned long *)(ea->var) = new; 17398c2ecf20Sopenharmony_ci /* Always return full write size even if we didn't consume all */ 17408c2ecf20Sopenharmony_ci return size; 17418c2ecf20Sopenharmony_ci} 17428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_store_ulong); 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_cissize_t device_show_ulong(struct device *dev, 17458c2ecf20Sopenharmony_ci struct device_attribute *attr, 17468c2ecf20Sopenharmony_ci char *buf) 17478c2ecf20Sopenharmony_ci{ 17488c2ecf20Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 17498c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%lx\n", *(unsigned long *)(ea->var)); 17508c2ecf20Sopenharmony_ci} 17518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_show_ulong); 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_cissize_t device_store_int(struct device *dev, 17548c2ecf20Sopenharmony_ci struct device_attribute *attr, 17558c2ecf20Sopenharmony_ci const char *buf, size_t size) 17568c2ecf20Sopenharmony_ci{ 17578c2ecf20Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 17588c2ecf20Sopenharmony_ci int ret; 17598c2ecf20Sopenharmony_ci long new; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci ret = kstrtol(buf, 0, &new); 17628c2ecf20Sopenharmony_ci if (ret) 17638c2ecf20Sopenharmony_ci return ret; 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci if (new > INT_MAX || new < INT_MIN) 17668c2ecf20Sopenharmony_ci return -EINVAL; 17678c2ecf20Sopenharmony_ci *(int *)(ea->var) = new; 17688c2ecf20Sopenharmony_ci /* Always return full write size even if we didn't consume all */ 17698c2ecf20Sopenharmony_ci return size; 17708c2ecf20Sopenharmony_ci} 17718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_store_int); 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_cissize_t device_show_int(struct device *dev, 17748c2ecf20Sopenharmony_ci struct device_attribute *attr, 17758c2ecf20Sopenharmony_ci char *buf) 17768c2ecf20Sopenharmony_ci{ 17778c2ecf20Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%d\n", *(int *)(ea->var)); 17808c2ecf20Sopenharmony_ci} 17818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_show_int); 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_cissize_t device_store_bool(struct device *dev, struct device_attribute *attr, 17848c2ecf20Sopenharmony_ci const char *buf, size_t size) 17858c2ecf20Sopenharmony_ci{ 17868c2ecf20Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci if (strtobool(buf, ea->var) < 0) 17898c2ecf20Sopenharmony_ci return -EINVAL; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci return size; 17928c2ecf20Sopenharmony_ci} 17938c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_store_bool); 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_cissize_t device_show_bool(struct device *dev, struct device_attribute *attr, 17968c2ecf20Sopenharmony_ci char *buf) 17978c2ecf20Sopenharmony_ci{ 17988c2ecf20Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%d\n", *(bool *)(ea->var)); 18018c2ecf20Sopenharmony_ci} 18028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_show_bool); 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci/** 18058c2ecf20Sopenharmony_ci * device_release - free device structure. 18068c2ecf20Sopenharmony_ci * @kobj: device's kobject. 18078c2ecf20Sopenharmony_ci * 18088c2ecf20Sopenharmony_ci * This is called once the reference count for the object 18098c2ecf20Sopenharmony_ci * reaches 0. We forward the call to the device's release 18108c2ecf20Sopenharmony_ci * method, which should handle actually freeing the structure. 18118c2ecf20Sopenharmony_ci */ 18128c2ecf20Sopenharmony_cistatic void device_release(struct kobject *kobj) 18138c2ecf20Sopenharmony_ci{ 18148c2ecf20Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 18158c2ecf20Sopenharmony_ci struct device_private *p = dev->p; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci /* 18188c2ecf20Sopenharmony_ci * Some platform devices are driven without driver attached 18198c2ecf20Sopenharmony_ci * and managed resources may have been acquired. Make sure 18208c2ecf20Sopenharmony_ci * all resources are released. 18218c2ecf20Sopenharmony_ci * 18228c2ecf20Sopenharmony_ci * Drivers still can add resources into device after device 18238c2ecf20Sopenharmony_ci * is deleted but alive, so release devres here to avoid 18248c2ecf20Sopenharmony_ci * possible memory leak. 18258c2ecf20Sopenharmony_ci */ 18268c2ecf20Sopenharmony_ci devres_release_all(dev); 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci kfree(dev->dma_range_map); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci if (dev->release) 18318c2ecf20Sopenharmony_ci dev->release(dev); 18328c2ecf20Sopenharmony_ci else if (dev->type && dev->type->release) 18338c2ecf20Sopenharmony_ci dev->type->release(dev); 18348c2ecf20Sopenharmony_ci else if (dev->class && dev->class->dev_release) 18358c2ecf20Sopenharmony_ci dev->class->dev_release(dev); 18368c2ecf20Sopenharmony_ci else 18378c2ecf20Sopenharmony_ci WARN(1, KERN_ERR "Device '%s' does not have a release() function, it is broken and must be fixed. See Documentation/core-api/kobject.rst.\n", 18388c2ecf20Sopenharmony_ci dev_name(dev)); 18398c2ecf20Sopenharmony_ci kfree(p); 18408c2ecf20Sopenharmony_ci} 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_cistatic const void *device_namespace(struct kobject *kobj) 18438c2ecf20Sopenharmony_ci{ 18448c2ecf20Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 18458c2ecf20Sopenharmony_ci const void *ns = NULL; 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci if (dev->class && dev->class->ns_type) 18488c2ecf20Sopenharmony_ci ns = dev->class->namespace(dev); 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci return ns; 18518c2ecf20Sopenharmony_ci} 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_cistatic void device_get_ownership(struct kobject *kobj, kuid_t *uid, kgid_t *gid) 18548c2ecf20Sopenharmony_ci{ 18558c2ecf20Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci if (dev->class && dev->class->get_ownership) 18588c2ecf20Sopenharmony_ci dev->class->get_ownership(dev, uid, gid); 18598c2ecf20Sopenharmony_ci} 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_cistatic struct kobj_type device_ktype = { 18628c2ecf20Sopenharmony_ci .release = device_release, 18638c2ecf20Sopenharmony_ci .sysfs_ops = &dev_sysfs_ops, 18648c2ecf20Sopenharmony_ci .namespace = device_namespace, 18658c2ecf20Sopenharmony_ci .get_ownership = device_get_ownership, 18668c2ecf20Sopenharmony_ci}; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_cistatic int dev_uevent_filter(struct kset *kset, struct kobject *kobj) 18708c2ecf20Sopenharmony_ci{ 18718c2ecf20Sopenharmony_ci struct kobj_type *ktype = get_ktype(kobj); 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci if (ktype == &device_ktype) { 18748c2ecf20Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 18758c2ecf20Sopenharmony_ci if (dev->bus) 18768c2ecf20Sopenharmony_ci return 1; 18778c2ecf20Sopenharmony_ci if (dev->class) 18788c2ecf20Sopenharmony_ci return 1; 18798c2ecf20Sopenharmony_ci } 18808c2ecf20Sopenharmony_ci return 0; 18818c2ecf20Sopenharmony_ci} 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_cistatic const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) 18848c2ecf20Sopenharmony_ci{ 18858c2ecf20Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci if (dev->bus) 18888c2ecf20Sopenharmony_ci return dev->bus->name; 18898c2ecf20Sopenharmony_ci if (dev->class) 18908c2ecf20Sopenharmony_ci return dev->class->name; 18918c2ecf20Sopenharmony_ci return NULL; 18928c2ecf20Sopenharmony_ci} 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_cistatic int dev_uevent(struct kset *kset, struct kobject *kobj, 18958c2ecf20Sopenharmony_ci struct kobj_uevent_env *env) 18968c2ecf20Sopenharmony_ci{ 18978c2ecf20Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 18988c2ecf20Sopenharmony_ci struct device_driver *driver; 18998c2ecf20Sopenharmony_ci int retval = 0; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci /* add device node properties if present */ 19028c2ecf20Sopenharmony_ci if (MAJOR(dev->devt)) { 19038c2ecf20Sopenharmony_ci const char *tmp; 19048c2ecf20Sopenharmony_ci const char *name; 19058c2ecf20Sopenharmony_ci umode_t mode = 0; 19068c2ecf20Sopenharmony_ci kuid_t uid = GLOBAL_ROOT_UID; 19078c2ecf20Sopenharmony_ci kgid_t gid = GLOBAL_ROOT_GID; 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); 19108c2ecf20Sopenharmony_ci add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); 19118c2ecf20Sopenharmony_ci name = device_get_devnode(dev, &mode, &uid, &gid, &tmp); 19128c2ecf20Sopenharmony_ci if (name) { 19138c2ecf20Sopenharmony_ci add_uevent_var(env, "DEVNAME=%s", name); 19148c2ecf20Sopenharmony_ci if (mode) 19158c2ecf20Sopenharmony_ci add_uevent_var(env, "DEVMODE=%#o", mode & 0777); 19168c2ecf20Sopenharmony_ci if (!uid_eq(uid, GLOBAL_ROOT_UID)) 19178c2ecf20Sopenharmony_ci add_uevent_var(env, "DEVUID=%u", from_kuid(&init_user_ns, uid)); 19188c2ecf20Sopenharmony_ci if (!gid_eq(gid, GLOBAL_ROOT_GID)) 19198c2ecf20Sopenharmony_ci add_uevent_var(env, "DEVGID=%u", from_kgid(&init_user_ns, gid)); 19208c2ecf20Sopenharmony_ci kfree(tmp); 19218c2ecf20Sopenharmony_ci } 19228c2ecf20Sopenharmony_ci } 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci if (dev->type && dev->type->name) 19258c2ecf20Sopenharmony_ci add_uevent_var(env, "DEVTYPE=%s", dev->type->name); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci /* Synchronize with module_remove_driver() */ 19288c2ecf20Sopenharmony_ci rcu_read_lock(); 19298c2ecf20Sopenharmony_ci driver = READ_ONCE(dev->driver); 19308c2ecf20Sopenharmony_ci if (driver) 19318c2ecf20Sopenharmony_ci add_uevent_var(env, "DRIVER=%s", driver->name); 19328c2ecf20Sopenharmony_ci rcu_read_unlock(); 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci /* Add common DT information about the device */ 19358c2ecf20Sopenharmony_ci of_device_uevent(dev, env); 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci /* have the bus specific function add its stuff */ 19388c2ecf20Sopenharmony_ci if (dev->bus && dev->bus->uevent) { 19398c2ecf20Sopenharmony_ci retval = dev->bus->uevent(dev, env); 19408c2ecf20Sopenharmony_ci if (retval) 19418c2ecf20Sopenharmony_ci pr_debug("device: '%s': %s: bus uevent() returned %d\n", 19428c2ecf20Sopenharmony_ci dev_name(dev), __func__, retval); 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci /* have the class specific function add its stuff */ 19468c2ecf20Sopenharmony_ci if (dev->class && dev->class->dev_uevent) { 19478c2ecf20Sopenharmony_ci retval = dev->class->dev_uevent(dev, env); 19488c2ecf20Sopenharmony_ci if (retval) 19498c2ecf20Sopenharmony_ci pr_debug("device: '%s': %s: class uevent() " 19508c2ecf20Sopenharmony_ci "returned %d\n", dev_name(dev), 19518c2ecf20Sopenharmony_ci __func__, retval); 19528c2ecf20Sopenharmony_ci } 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci /* have the device type specific function add its stuff */ 19558c2ecf20Sopenharmony_ci if (dev->type && dev->type->uevent) { 19568c2ecf20Sopenharmony_ci retval = dev->type->uevent(dev, env); 19578c2ecf20Sopenharmony_ci if (retval) 19588c2ecf20Sopenharmony_ci pr_debug("device: '%s': %s: dev_type uevent() " 19598c2ecf20Sopenharmony_ci "returned %d\n", dev_name(dev), 19608c2ecf20Sopenharmony_ci __func__, retval); 19618c2ecf20Sopenharmony_ci } 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci return retval; 19648c2ecf20Sopenharmony_ci} 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_cistatic const struct kset_uevent_ops device_uevent_ops = { 19678c2ecf20Sopenharmony_ci .filter = dev_uevent_filter, 19688c2ecf20Sopenharmony_ci .name = dev_uevent_name, 19698c2ecf20Sopenharmony_ci .uevent = dev_uevent, 19708c2ecf20Sopenharmony_ci}; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_cistatic ssize_t uevent_show(struct device *dev, struct device_attribute *attr, 19738c2ecf20Sopenharmony_ci char *buf) 19748c2ecf20Sopenharmony_ci{ 19758c2ecf20Sopenharmony_ci struct kobject *top_kobj; 19768c2ecf20Sopenharmony_ci struct kset *kset; 19778c2ecf20Sopenharmony_ci struct kobj_uevent_env *env = NULL; 19788c2ecf20Sopenharmony_ci int i; 19798c2ecf20Sopenharmony_ci int len = 0; 19808c2ecf20Sopenharmony_ci int retval; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci /* search the kset, the device belongs to */ 19838c2ecf20Sopenharmony_ci top_kobj = &dev->kobj; 19848c2ecf20Sopenharmony_ci while (!top_kobj->kset && top_kobj->parent) 19858c2ecf20Sopenharmony_ci top_kobj = top_kobj->parent; 19868c2ecf20Sopenharmony_ci if (!top_kobj->kset) 19878c2ecf20Sopenharmony_ci goto out; 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci kset = top_kobj->kset; 19908c2ecf20Sopenharmony_ci if (!kset->uevent_ops || !kset->uevent_ops->uevent) 19918c2ecf20Sopenharmony_ci goto out; 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci /* respect filter */ 19948c2ecf20Sopenharmony_ci if (kset->uevent_ops && kset->uevent_ops->filter) 19958c2ecf20Sopenharmony_ci if (!kset->uevent_ops->filter(kset, &dev->kobj)) 19968c2ecf20Sopenharmony_ci goto out; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); 19998c2ecf20Sopenharmony_ci if (!env) 20008c2ecf20Sopenharmony_ci return -ENOMEM; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci /* let the kset specific function add its keys */ 20038c2ecf20Sopenharmony_ci retval = kset->uevent_ops->uevent(kset, &dev->kobj, env); 20048c2ecf20Sopenharmony_ci if (retval) 20058c2ecf20Sopenharmony_ci goto out; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci /* copy keys to file */ 20088c2ecf20Sopenharmony_ci for (i = 0; i < env->envp_idx; i++) 20098c2ecf20Sopenharmony_ci len += sysfs_emit_at(buf, len, "%s\n", env->envp[i]); 20108c2ecf20Sopenharmony_ciout: 20118c2ecf20Sopenharmony_ci kfree(env); 20128c2ecf20Sopenharmony_ci return len; 20138c2ecf20Sopenharmony_ci} 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_cistatic ssize_t uevent_store(struct device *dev, struct device_attribute *attr, 20168c2ecf20Sopenharmony_ci const char *buf, size_t count) 20178c2ecf20Sopenharmony_ci{ 20188c2ecf20Sopenharmony_ci int rc; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci rc = kobject_synth_uevent(&dev->kobj, buf, count); 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci if (rc) { 20238c2ecf20Sopenharmony_ci dev_err(dev, "uevent: failed to send synthetic uevent\n"); 20248c2ecf20Sopenharmony_ci return rc; 20258c2ecf20Sopenharmony_ci } 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci return count; 20288c2ecf20Sopenharmony_ci} 20298c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(uevent); 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_cistatic ssize_t online_show(struct device *dev, struct device_attribute *attr, 20328c2ecf20Sopenharmony_ci char *buf) 20338c2ecf20Sopenharmony_ci{ 20348c2ecf20Sopenharmony_ci bool val; 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci device_lock(dev); 20378c2ecf20Sopenharmony_ci val = !dev->offline; 20388c2ecf20Sopenharmony_ci device_unlock(dev); 20398c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%u\n", val); 20408c2ecf20Sopenharmony_ci} 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_cistatic ssize_t online_store(struct device *dev, struct device_attribute *attr, 20438c2ecf20Sopenharmony_ci const char *buf, size_t count) 20448c2ecf20Sopenharmony_ci{ 20458c2ecf20Sopenharmony_ci bool val; 20468c2ecf20Sopenharmony_ci int ret; 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci ret = strtobool(buf, &val); 20498c2ecf20Sopenharmony_ci if (ret < 0) 20508c2ecf20Sopenharmony_ci return ret; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci ret = lock_device_hotplug_sysfs(); 20538c2ecf20Sopenharmony_ci if (ret) 20548c2ecf20Sopenharmony_ci return ret; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci ret = val ? device_online(dev) : device_offline(dev); 20578c2ecf20Sopenharmony_ci unlock_device_hotplug(); 20588c2ecf20Sopenharmony_ci return ret < 0 ? ret : count; 20598c2ecf20Sopenharmony_ci} 20608c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(online); 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_cistatic ssize_t removable_show(struct device *dev, struct device_attribute *attr, 20638c2ecf20Sopenharmony_ci char *buf) 20648c2ecf20Sopenharmony_ci{ 20658c2ecf20Sopenharmony_ci const char *loc; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci switch (dev->removable) { 20688c2ecf20Sopenharmony_ci case DEVICE_REMOVABLE: 20698c2ecf20Sopenharmony_ci loc = "removable"; 20708c2ecf20Sopenharmony_ci break; 20718c2ecf20Sopenharmony_ci case DEVICE_FIXED: 20728c2ecf20Sopenharmony_ci loc = "fixed"; 20738c2ecf20Sopenharmony_ci break; 20748c2ecf20Sopenharmony_ci default: 20758c2ecf20Sopenharmony_ci loc = "unknown"; 20768c2ecf20Sopenharmony_ci } 20778c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%s\n", loc); 20788c2ecf20Sopenharmony_ci} 20798c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(removable); 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ciint device_add_groups(struct device *dev, const struct attribute_group **groups) 20828c2ecf20Sopenharmony_ci{ 20838c2ecf20Sopenharmony_ci return sysfs_create_groups(&dev->kobj, groups); 20848c2ecf20Sopenharmony_ci} 20858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_add_groups); 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_civoid device_remove_groups(struct device *dev, 20888c2ecf20Sopenharmony_ci const struct attribute_group **groups) 20898c2ecf20Sopenharmony_ci{ 20908c2ecf20Sopenharmony_ci sysfs_remove_groups(&dev->kobj, groups); 20918c2ecf20Sopenharmony_ci} 20928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_remove_groups); 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ciunion device_attr_group_devres { 20958c2ecf20Sopenharmony_ci const struct attribute_group *group; 20968c2ecf20Sopenharmony_ci const struct attribute_group **groups; 20978c2ecf20Sopenharmony_ci}; 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_cistatic int devm_attr_group_match(struct device *dev, void *res, void *data) 21008c2ecf20Sopenharmony_ci{ 21018c2ecf20Sopenharmony_ci return ((union device_attr_group_devres *)res)->group == data; 21028c2ecf20Sopenharmony_ci} 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_cistatic void devm_attr_group_remove(struct device *dev, void *res) 21058c2ecf20Sopenharmony_ci{ 21068c2ecf20Sopenharmony_ci union device_attr_group_devres *devres = res; 21078c2ecf20Sopenharmony_ci const struct attribute_group *group = devres->group; 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: removing group %p\n", __func__, group); 21108c2ecf20Sopenharmony_ci sysfs_remove_group(&dev->kobj, group); 21118c2ecf20Sopenharmony_ci} 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_cistatic void devm_attr_groups_remove(struct device *dev, void *res) 21148c2ecf20Sopenharmony_ci{ 21158c2ecf20Sopenharmony_ci union device_attr_group_devres *devres = res; 21168c2ecf20Sopenharmony_ci const struct attribute_group **groups = devres->groups; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: removing groups %p\n", __func__, groups); 21198c2ecf20Sopenharmony_ci sysfs_remove_groups(&dev->kobj, groups); 21208c2ecf20Sopenharmony_ci} 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci/** 21238c2ecf20Sopenharmony_ci * devm_device_add_group - given a device, create a managed attribute group 21248c2ecf20Sopenharmony_ci * @dev: The device to create the group for 21258c2ecf20Sopenharmony_ci * @grp: The attribute group to create 21268c2ecf20Sopenharmony_ci * 21278c2ecf20Sopenharmony_ci * This function creates a group for the first time. It will explicitly 21288c2ecf20Sopenharmony_ci * warn and error if any of the attribute files being created already exist. 21298c2ecf20Sopenharmony_ci * 21308c2ecf20Sopenharmony_ci * Returns 0 on success or error code on failure. 21318c2ecf20Sopenharmony_ci */ 21328c2ecf20Sopenharmony_ciint devm_device_add_group(struct device *dev, const struct attribute_group *grp) 21338c2ecf20Sopenharmony_ci{ 21348c2ecf20Sopenharmony_ci union device_attr_group_devres *devres; 21358c2ecf20Sopenharmony_ci int error; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci devres = devres_alloc(devm_attr_group_remove, 21388c2ecf20Sopenharmony_ci sizeof(*devres), GFP_KERNEL); 21398c2ecf20Sopenharmony_ci if (!devres) 21408c2ecf20Sopenharmony_ci return -ENOMEM; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci error = sysfs_create_group(&dev->kobj, grp); 21438c2ecf20Sopenharmony_ci if (error) { 21448c2ecf20Sopenharmony_ci devres_free(devres); 21458c2ecf20Sopenharmony_ci return error; 21468c2ecf20Sopenharmony_ci } 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci devres->group = grp; 21498c2ecf20Sopenharmony_ci devres_add(dev, devres); 21508c2ecf20Sopenharmony_ci return 0; 21518c2ecf20Sopenharmony_ci} 21528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_device_add_group); 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci/** 21558c2ecf20Sopenharmony_ci * devm_device_remove_group: remove a managed group from a device 21568c2ecf20Sopenharmony_ci * @dev: device to remove the group from 21578c2ecf20Sopenharmony_ci * @grp: group to remove 21588c2ecf20Sopenharmony_ci * 21598c2ecf20Sopenharmony_ci * This function removes a group of attributes from a device. The attributes 21608c2ecf20Sopenharmony_ci * previously have to have been created for this group, otherwise it will fail. 21618c2ecf20Sopenharmony_ci */ 21628c2ecf20Sopenharmony_civoid devm_device_remove_group(struct device *dev, 21638c2ecf20Sopenharmony_ci const struct attribute_group *grp) 21648c2ecf20Sopenharmony_ci{ 21658c2ecf20Sopenharmony_ci WARN_ON(devres_release(dev, devm_attr_group_remove, 21668c2ecf20Sopenharmony_ci devm_attr_group_match, 21678c2ecf20Sopenharmony_ci /* cast away const */ (void *)grp)); 21688c2ecf20Sopenharmony_ci} 21698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_device_remove_group); 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci/** 21728c2ecf20Sopenharmony_ci * devm_device_add_groups - create a bunch of managed attribute groups 21738c2ecf20Sopenharmony_ci * @dev: The device to create the group for 21748c2ecf20Sopenharmony_ci * @groups: The attribute groups to create, NULL terminated 21758c2ecf20Sopenharmony_ci * 21768c2ecf20Sopenharmony_ci * This function creates a bunch of managed attribute groups. If an error 21778c2ecf20Sopenharmony_ci * occurs when creating a group, all previously created groups will be 21788c2ecf20Sopenharmony_ci * removed, unwinding everything back to the original state when this 21798c2ecf20Sopenharmony_ci * function was called. It will explicitly warn and error if any of the 21808c2ecf20Sopenharmony_ci * attribute files being created already exist. 21818c2ecf20Sopenharmony_ci * 21828c2ecf20Sopenharmony_ci * Returns 0 on success or error code from sysfs_create_group on failure. 21838c2ecf20Sopenharmony_ci */ 21848c2ecf20Sopenharmony_ciint devm_device_add_groups(struct device *dev, 21858c2ecf20Sopenharmony_ci const struct attribute_group **groups) 21868c2ecf20Sopenharmony_ci{ 21878c2ecf20Sopenharmony_ci union device_attr_group_devres *devres; 21888c2ecf20Sopenharmony_ci int error; 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci devres = devres_alloc(devm_attr_groups_remove, 21918c2ecf20Sopenharmony_ci sizeof(*devres), GFP_KERNEL); 21928c2ecf20Sopenharmony_ci if (!devres) 21938c2ecf20Sopenharmony_ci return -ENOMEM; 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci error = sysfs_create_groups(&dev->kobj, groups); 21968c2ecf20Sopenharmony_ci if (error) { 21978c2ecf20Sopenharmony_ci devres_free(devres); 21988c2ecf20Sopenharmony_ci return error; 21998c2ecf20Sopenharmony_ci } 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci devres->groups = groups; 22028c2ecf20Sopenharmony_ci devres_add(dev, devres); 22038c2ecf20Sopenharmony_ci return 0; 22048c2ecf20Sopenharmony_ci} 22058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_device_add_groups); 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci/** 22088c2ecf20Sopenharmony_ci * devm_device_remove_groups - remove a list of managed groups 22098c2ecf20Sopenharmony_ci * 22108c2ecf20Sopenharmony_ci * @dev: The device for the groups to be removed from 22118c2ecf20Sopenharmony_ci * @groups: NULL terminated list of groups to be removed 22128c2ecf20Sopenharmony_ci * 22138c2ecf20Sopenharmony_ci * If groups is not NULL, remove the specified groups from the device. 22148c2ecf20Sopenharmony_ci */ 22158c2ecf20Sopenharmony_civoid devm_device_remove_groups(struct device *dev, 22168c2ecf20Sopenharmony_ci const struct attribute_group **groups) 22178c2ecf20Sopenharmony_ci{ 22188c2ecf20Sopenharmony_ci WARN_ON(devres_release(dev, devm_attr_groups_remove, 22198c2ecf20Sopenharmony_ci devm_attr_group_match, 22208c2ecf20Sopenharmony_ci /* cast away const */ (void *)groups)); 22218c2ecf20Sopenharmony_ci} 22228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_device_remove_groups); 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_cistatic int device_add_attrs(struct device *dev) 22258c2ecf20Sopenharmony_ci{ 22268c2ecf20Sopenharmony_ci struct class *class = dev->class; 22278c2ecf20Sopenharmony_ci const struct device_type *type = dev->type; 22288c2ecf20Sopenharmony_ci int error; 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci if (class) { 22318c2ecf20Sopenharmony_ci error = device_add_groups(dev, class->dev_groups); 22328c2ecf20Sopenharmony_ci if (error) 22338c2ecf20Sopenharmony_ci return error; 22348c2ecf20Sopenharmony_ci } 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci if (type) { 22378c2ecf20Sopenharmony_ci error = device_add_groups(dev, type->groups); 22388c2ecf20Sopenharmony_ci if (error) 22398c2ecf20Sopenharmony_ci goto err_remove_class_groups; 22408c2ecf20Sopenharmony_ci } 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci error = device_add_groups(dev, dev->groups); 22438c2ecf20Sopenharmony_ci if (error) 22448c2ecf20Sopenharmony_ci goto err_remove_type_groups; 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci if (device_supports_offline(dev) && !dev->offline_disabled) { 22478c2ecf20Sopenharmony_ci error = device_create_file(dev, &dev_attr_online); 22488c2ecf20Sopenharmony_ci if (error) 22498c2ecf20Sopenharmony_ci goto err_remove_dev_groups; 22508c2ecf20Sopenharmony_ci } 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci if (fw_devlink_flags && !fw_devlink_is_permissive()) { 22538c2ecf20Sopenharmony_ci error = device_create_file(dev, &dev_attr_waiting_for_supplier); 22548c2ecf20Sopenharmony_ci if (error) 22558c2ecf20Sopenharmony_ci goto err_remove_dev_online; 22568c2ecf20Sopenharmony_ci } 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci if (dev_removable_is_valid(dev)) { 22598c2ecf20Sopenharmony_ci error = device_create_file(dev, &dev_attr_removable); 22608c2ecf20Sopenharmony_ci if (error) 22618c2ecf20Sopenharmony_ci goto err_remove_dev_waiting_for_supplier; 22628c2ecf20Sopenharmony_ci } 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci return 0; 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci err_remove_dev_waiting_for_supplier: 22678c2ecf20Sopenharmony_ci device_remove_file(dev, &dev_attr_waiting_for_supplier); 22688c2ecf20Sopenharmony_ci err_remove_dev_online: 22698c2ecf20Sopenharmony_ci device_remove_file(dev, &dev_attr_online); 22708c2ecf20Sopenharmony_ci err_remove_dev_groups: 22718c2ecf20Sopenharmony_ci device_remove_groups(dev, dev->groups); 22728c2ecf20Sopenharmony_ci err_remove_type_groups: 22738c2ecf20Sopenharmony_ci if (type) 22748c2ecf20Sopenharmony_ci device_remove_groups(dev, type->groups); 22758c2ecf20Sopenharmony_ci err_remove_class_groups: 22768c2ecf20Sopenharmony_ci if (class) 22778c2ecf20Sopenharmony_ci device_remove_groups(dev, class->dev_groups); 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci return error; 22808c2ecf20Sopenharmony_ci} 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_cistatic void device_remove_attrs(struct device *dev) 22838c2ecf20Sopenharmony_ci{ 22848c2ecf20Sopenharmony_ci struct class *class = dev->class; 22858c2ecf20Sopenharmony_ci const struct device_type *type = dev->type; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci device_remove_file(dev, &dev_attr_removable); 22888c2ecf20Sopenharmony_ci device_remove_file(dev, &dev_attr_waiting_for_supplier); 22898c2ecf20Sopenharmony_ci device_remove_file(dev, &dev_attr_online); 22908c2ecf20Sopenharmony_ci device_remove_groups(dev, dev->groups); 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci if (type) 22938c2ecf20Sopenharmony_ci device_remove_groups(dev, type->groups); 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci if (class) 22968c2ecf20Sopenharmony_ci device_remove_groups(dev, class->dev_groups); 22978c2ecf20Sopenharmony_ci} 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_cistatic ssize_t dev_show(struct device *dev, struct device_attribute *attr, 23008c2ecf20Sopenharmony_ci char *buf) 23018c2ecf20Sopenharmony_ci{ 23028c2ecf20Sopenharmony_ci return print_dev_t(buf, dev->devt); 23038c2ecf20Sopenharmony_ci} 23048c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(dev); 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci/* /sys/devices/ */ 23078c2ecf20Sopenharmony_cistruct kset *devices_kset; 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci/** 23108c2ecf20Sopenharmony_ci * devices_kset_move_before - Move device in the devices_kset's list. 23118c2ecf20Sopenharmony_ci * @deva: Device to move. 23128c2ecf20Sopenharmony_ci * @devb: Device @deva should come before. 23138c2ecf20Sopenharmony_ci */ 23148c2ecf20Sopenharmony_cistatic void devices_kset_move_before(struct device *deva, struct device *devb) 23158c2ecf20Sopenharmony_ci{ 23168c2ecf20Sopenharmony_ci if (!devices_kset) 23178c2ecf20Sopenharmony_ci return; 23188c2ecf20Sopenharmony_ci pr_debug("devices_kset: Moving %s before %s\n", 23198c2ecf20Sopenharmony_ci dev_name(deva), dev_name(devb)); 23208c2ecf20Sopenharmony_ci spin_lock(&devices_kset->list_lock); 23218c2ecf20Sopenharmony_ci list_move_tail(&deva->kobj.entry, &devb->kobj.entry); 23228c2ecf20Sopenharmony_ci spin_unlock(&devices_kset->list_lock); 23238c2ecf20Sopenharmony_ci} 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci/** 23268c2ecf20Sopenharmony_ci * devices_kset_move_after - Move device in the devices_kset's list. 23278c2ecf20Sopenharmony_ci * @deva: Device to move 23288c2ecf20Sopenharmony_ci * @devb: Device @deva should come after. 23298c2ecf20Sopenharmony_ci */ 23308c2ecf20Sopenharmony_cistatic void devices_kset_move_after(struct device *deva, struct device *devb) 23318c2ecf20Sopenharmony_ci{ 23328c2ecf20Sopenharmony_ci if (!devices_kset) 23338c2ecf20Sopenharmony_ci return; 23348c2ecf20Sopenharmony_ci pr_debug("devices_kset: Moving %s after %s\n", 23358c2ecf20Sopenharmony_ci dev_name(deva), dev_name(devb)); 23368c2ecf20Sopenharmony_ci spin_lock(&devices_kset->list_lock); 23378c2ecf20Sopenharmony_ci list_move(&deva->kobj.entry, &devb->kobj.entry); 23388c2ecf20Sopenharmony_ci spin_unlock(&devices_kset->list_lock); 23398c2ecf20Sopenharmony_ci} 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_ci/** 23428c2ecf20Sopenharmony_ci * devices_kset_move_last - move the device to the end of devices_kset's list. 23438c2ecf20Sopenharmony_ci * @dev: device to move 23448c2ecf20Sopenharmony_ci */ 23458c2ecf20Sopenharmony_civoid devices_kset_move_last(struct device *dev) 23468c2ecf20Sopenharmony_ci{ 23478c2ecf20Sopenharmony_ci if (!devices_kset) 23488c2ecf20Sopenharmony_ci return; 23498c2ecf20Sopenharmony_ci pr_debug("devices_kset: Moving %s to end of list\n", dev_name(dev)); 23508c2ecf20Sopenharmony_ci spin_lock(&devices_kset->list_lock); 23518c2ecf20Sopenharmony_ci list_move_tail(&dev->kobj.entry, &devices_kset->list); 23528c2ecf20Sopenharmony_ci spin_unlock(&devices_kset->list_lock); 23538c2ecf20Sopenharmony_ci} 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_ci/** 23568c2ecf20Sopenharmony_ci * device_create_file - create sysfs attribute file for device. 23578c2ecf20Sopenharmony_ci * @dev: device. 23588c2ecf20Sopenharmony_ci * @attr: device attribute descriptor. 23598c2ecf20Sopenharmony_ci */ 23608c2ecf20Sopenharmony_ciint device_create_file(struct device *dev, 23618c2ecf20Sopenharmony_ci const struct device_attribute *attr) 23628c2ecf20Sopenharmony_ci{ 23638c2ecf20Sopenharmony_ci int error = 0; 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci if (dev) { 23668c2ecf20Sopenharmony_ci WARN(((attr->attr.mode & S_IWUGO) && !attr->store), 23678c2ecf20Sopenharmony_ci "Attribute %s: write permission without 'store'\n", 23688c2ecf20Sopenharmony_ci attr->attr.name); 23698c2ecf20Sopenharmony_ci WARN(((attr->attr.mode & S_IRUGO) && !attr->show), 23708c2ecf20Sopenharmony_ci "Attribute %s: read permission without 'show'\n", 23718c2ecf20Sopenharmony_ci attr->attr.name); 23728c2ecf20Sopenharmony_ci error = sysfs_create_file(&dev->kobj, &attr->attr); 23738c2ecf20Sopenharmony_ci } 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci return error; 23768c2ecf20Sopenharmony_ci} 23778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_create_file); 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci/** 23808c2ecf20Sopenharmony_ci * device_remove_file - remove sysfs attribute file. 23818c2ecf20Sopenharmony_ci * @dev: device. 23828c2ecf20Sopenharmony_ci * @attr: device attribute descriptor. 23838c2ecf20Sopenharmony_ci */ 23848c2ecf20Sopenharmony_civoid device_remove_file(struct device *dev, 23858c2ecf20Sopenharmony_ci const struct device_attribute *attr) 23868c2ecf20Sopenharmony_ci{ 23878c2ecf20Sopenharmony_ci if (dev) 23888c2ecf20Sopenharmony_ci sysfs_remove_file(&dev->kobj, &attr->attr); 23898c2ecf20Sopenharmony_ci} 23908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_remove_file); 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci/** 23938c2ecf20Sopenharmony_ci * device_remove_file_self - remove sysfs attribute file from its own method. 23948c2ecf20Sopenharmony_ci * @dev: device. 23958c2ecf20Sopenharmony_ci * @attr: device attribute descriptor. 23968c2ecf20Sopenharmony_ci * 23978c2ecf20Sopenharmony_ci * See kernfs_remove_self() for details. 23988c2ecf20Sopenharmony_ci */ 23998c2ecf20Sopenharmony_cibool device_remove_file_self(struct device *dev, 24008c2ecf20Sopenharmony_ci const struct device_attribute *attr) 24018c2ecf20Sopenharmony_ci{ 24028c2ecf20Sopenharmony_ci if (dev) 24038c2ecf20Sopenharmony_ci return sysfs_remove_file_self(&dev->kobj, &attr->attr); 24048c2ecf20Sopenharmony_ci else 24058c2ecf20Sopenharmony_ci return false; 24068c2ecf20Sopenharmony_ci} 24078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_remove_file_self); 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci/** 24108c2ecf20Sopenharmony_ci * device_create_bin_file - create sysfs binary attribute file for device. 24118c2ecf20Sopenharmony_ci * @dev: device. 24128c2ecf20Sopenharmony_ci * @attr: device binary attribute descriptor. 24138c2ecf20Sopenharmony_ci */ 24148c2ecf20Sopenharmony_ciint device_create_bin_file(struct device *dev, 24158c2ecf20Sopenharmony_ci const struct bin_attribute *attr) 24168c2ecf20Sopenharmony_ci{ 24178c2ecf20Sopenharmony_ci int error = -EINVAL; 24188c2ecf20Sopenharmony_ci if (dev) 24198c2ecf20Sopenharmony_ci error = sysfs_create_bin_file(&dev->kobj, attr); 24208c2ecf20Sopenharmony_ci return error; 24218c2ecf20Sopenharmony_ci} 24228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_create_bin_file); 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci/** 24258c2ecf20Sopenharmony_ci * device_remove_bin_file - remove sysfs binary attribute file 24268c2ecf20Sopenharmony_ci * @dev: device. 24278c2ecf20Sopenharmony_ci * @attr: device binary attribute descriptor. 24288c2ecf20Sopenharmony_ci */ 24298c2ecf20Sopenharmony_civoid device_remove_bin_file(struct device *dev, 24308c2ecf20Sopenharmony_ci const struct bin_attribute *attr) 24318c2ecf20Sopenharmony_ci{ 24328c2ecf20Sopenharmony_ci if (dev) 24338c2ecf20Sopenharmony_ci sysfs_remove_bin_file(&dev->kobj, attr); 24348c2ecf20Sopenharmony_ci} 24358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_remove_bin_file); 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_cistatic void klist_children_get(struct klist_node *n) 24388c2ecf20Sopenharmony_ci{ 24398c2ecf20Sopenharmony_ci struct device_private *p = to_device_private_parent(n); 24408c2ecf20Sopenharmony_ci struct device *dev = p->device; 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci get_device(dev); 24438c2ecf20Sopenharmony_ci} 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_cistatic void klist_children_put(struct klist_node *n) 24468c2ecf20Sopenharmony_ci{ 24478c2ecf20Sopenharmony_ci struct device_private *p = to_device_private_parent(n); 24488c2ecf20Sopenharmony_ci struct device *dev = p->device; 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci put_device(dev); 24518c2ecf20Sopenharmony_ci} 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci/** 24548c2ecf20Sopenharmony_ci * device_initialize - init device structure. 24558c2ecf20Sopenharmony_ci * @dev: device. 24568c2ecf20Sopenharmony_ci * 24578c2ecf20Sopenharmony_ci * This prepares the device for use by other layers by initializing 24588c2ecf20Sopenharmony_ci * its fields. 24598c2ecf20Sopenharmony_ci * It is the first half of device_register(), if called by 24608c2ecf20Sopenharmony_ci * that function, though it can also be called separately, so one 24618c2ecf20Sopenharmony_ci * may use @dev's fields. In particular, get_device()/put_device() 24628c2ecf20Sopenharmony_ci * may be used for reference counting of @dev after calling this 24638c2ecf20Sopenharmony_ci * function. 24648c2ecf20Sopenharmony_ci * 24658c2ecf20Sopenharmony_ci * All fields in @dev must be initialized by the caller to 0, except 24668c2ecf20Sopenharmony_ci * for those explicitly set to some other value. The simplest 24678c2ecf20Sopenharmony_ci * approach is to use kzalloc() to allocate the structure containing 24688c2ecf20Sopenharmony_ci * @dev. 24698c2ecf20Sopenharmony_ci * 24708c2ecf20Sopenharmony_ci * NOTE: Use put_device() to give up your reference instead of freeing 24718c2ecf20Sopenharmony_ci * @dev directly once you have called this function. 24728c2ecf20Sopenharmony_ci */ 24738c2ecf20Sopenharmony_civoid device_initialize(struct device *dev) 24748c2ecf20Sopenharmony_ci{ 24758c2ecf20Sopenharmony_ci dev->kobj.kset = devices_kset; 24768c2ecf20Sopenharmony_ci kobject_init(&dev->kobj, &device_ktype); 24778c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dev->dma_pools); 24788c2ecf20Sopenharmony_ci mutex_init(&dev->mutex); 24798c2ecf20Sopenharmony_ci#ifdef CONFIG_PROVE_LOCKING 24808c2ecf20Sopenharmony_ci mutex_init(&dev->lockdep_mutex); 24818c2ecf20Sopenharmony_ci#endif 24828c2ecf20Sopenharmony_ci lockdep_set_novalidate_class(&dev->mutex); 24838c2ecf20Sopenharmony_ci spin_lock_init(&dev->devres_lock); 24848c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dev->devres_head); 24858c2ecf20Sopenharmony_ci device_pm_init(dev); 24868c2ecf20Sopenharmony_ci set_dev_node(dev, -1); 24878c2ecf20Sopenharmony_ci#ifdef CONFIG_GENERIC_MSI_IRQ 24888c2ecf20Sopenharmony_ci raw_spin_lock_init(&dev->msi_lock); 24898c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dev->msi_list); 24908c2ecf20Sopenharmony_ci#endif 24918c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dev->links.consumers); 24928c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dev->links.suppliers); 24938c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dev->links.needs_suppliers); 24948c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dev->links.defer_hook); 24958c2ecf20Sopenharmony_ci dev->links.status = DL_DEV_NO_DRIVER; 24968c2ecf20Sopenharmony_ci} 24978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_initialize); 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_cistruct kobject *virtual_device_parent(struct device *dev) 25008c2ecf20Sopenharmony_ci{ 25018c2ecf20Sopenharmony_ci static struct kobject *virtual_dir = NULL; 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci if (!virtual_dir) 25048c2ecf20Sopenharmony_ci virtual_dir = kobject_create_and_add("virtual", 25058c2ecf20Sopenharmony_ci &devices_kset->kobj); 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci return virtual_dir; 25088c2ecf20Sopenharmony_ci} 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_cistruct class_dir { 25118c2ecf20Sopenharmony_ci struct kobject kobj; 25128c2ecf20Sopenharmony_ci struct class *class; 25138c2ecf20Sopenharmony_ci}; 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci#define to_class_dir(obj) container_of(obj, struct class_dir, kobj) 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_cistatic void class_dir_release(struct kobject *kobj) 25188c2ecf20Sopenharmony_ci{ 25198c2ecf20Sopenharmony_ci struct class_dir *dir = to_class_dir(kobj); 25208c2ecf20Sopenharmony_ci kfree(dir); 25218c2ecf20Sopenharmony_ci} 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_cistatic const 25248c2ecf20Sopenharmony_cistruct kobj_ns_type_operations *class_dir_child_ns_type(struct kobject *kobj) 25258c2ecf20Sopenharmony_ci{ 25268c2ecf20Sopenharmony_ci struct class_dir *dir = to_class_dir(kobj); 25278c2ecf20Sopenharmony_ci return dir->class->ns_type; 25288c2ecf20Sopenharmony_ci} 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_cistatic struct kobj_type class_dir_ktype = { 25318c2ecf20Sopenharmony_ci .release = class_dir_release, 25328c2ecf20Sopenharmony_ci .sysfs_ops = &kobj_sysfs_ops, 25338c2ecf20Sopenharmony_ci .child_ns_type = class_dir_child_ns_type 25348c2ecf20Sopenharmony_ci}; 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_cistatic struct kobject * 25378c2ecf20Sopenharmony_ciclass_dir_create_and_add(struct class *class, struct kobject *parent_kobj) 25388c2ecf20Sopenharmony_ci{ 25398c2ecf20Sopenharmony_ci struct class_dir *dir; 25408c2ecf20Sopenharmony_ci int retval; 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci dir = kzalloc(sizeof(*dir), GFP_KERNEL); 25438c2ecf20Sopenharmony_ci if (!dir) 25448c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci dir->class = class; 25478c2ecf20Sopenharmony_ci kobject_init(&dir->kobj, &class_dir_ktype); 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci dir->kobj.kset = &class->p->glue_dirs; 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name); 25528c2ecf20Sopenharmony_ci if (retval < 0) { 25538c2ecf20Sopenharmony_ci kobject_put(&dir->kobj); 25548c2ecf20Sopenharmony_ci return ERR_PTR(retval); 25558c2ecf20Sopenharmony_ci } 25568c2ecf20Sopenharmony_ci return &dir->kobj; 25578c2ecf20Sopenharmony_ci} 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(gdp_mutex); 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_cistatic struct kobject *get_device_parent(struct device *dev, 25628c2ecf20Sopenharmony_ci struct device *parent) 25638c2ecf20Sopenharmony_ci{ 25648c2ecf20Sopenharmony_ci if (dev->class) { 25658c2ecf20Sopenharmony_ci struct kobject *kobj = NULL; 25668c2ecf20Sopenharmony_ci struct kobject *parent_kobj; 25678c2ecf20Sopenharmony_ci struct kobject *k; 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci#ifdef CONFIG_BLOCK 25708c2ecf20Sopenharmony_ci /* block disks show up in /sys/block */ 25718c2ecf20Sopenharmony_ci if (sysfs_deprecated && dev->class == &block_class) { 25728c2ecf20Sopenharmony_ci if (parent && parent->class == &block_class) 25738c2ecf20Sopenharmony_ci return &parent->kobj; 25748c2ecf20Sopenharmony_ci return &block_class.p->subsys.kobj; 25758c2ecf20Sopenharmony_ci } 25768c2ecf20Sopenharmony_ci#endif 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci /* 25798c2ecf20Sopenharmony_ci * If we have no parent, we live in "virtual". 25808c2ecf20Sopenharmony_ci * Class-devices with a non class-device as parent, live 25818c2ecf20Sopenharmony_ci * in a "glue" directory to prevent namespace collisions. 25828c2ecf20Sopenharmony_ci */ 25838c2ecf20Sopenharmony_ci if (parent == NULL) 25848c2ecf20Sopenharmony_ci parent_kobj = virtual_device_parent(dev); 25858c2ecf20Sopenharmony_ci else if (parent->class && !dev->class->ns_type) 25868c2ecf20Sopenharmony_ci return &parent->kobj; 25878c2ecf20Sopenharmony_ci else 25888c2ecf20Sopenharmony_ci parent_kobj = &parent->kobj; 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci mutex_lock(&gdp_mutex); 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci /* find our class-directory at the parent and reference it */ 25938c2ecf20Sopenharmony_ci spin_lock(&dev->class->p->glue_dirs.list_lock); 25948c2ecf20Sopenharmony_ci list_for_each_entry(k, &dev->class->p->glue_dirs.list, entry) 25958c2ecf20Sopenharmony_ci if (k->parent == parent_kobj) { 25968c2ecf20Sopenharmony_ci kobj = kobject_get(k); 25978c2ecf20Sopenharmony_ci break; 25988c2ecf20Sopenharmony_ci } 25998c2ecf20Sopenharmony_ci spin_unlock(&dev->class->p->glue_dirs.list_lock); 26008c2ecf20Sopenharmony_ci if (kobj) { 26018c2ecf20Sopenharmony_ci mutex_unlock(&gdp_mutex); 26028c2ecf20Sopenharmony_ci return kobj; 26038c2ecf20Sopenharmony_ci } 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci /* or create a new class-directory at the parent device */ 26068c2ecf20Sopenharmony_ci k = class_dir_create_and_add(dev->class, parent_kobj); 26078c2ecf20Sopenharmony_ci /* do not emit an uevent for this simple "glue" directory */ 26088c2ecf20Sopenharmony_ci mutex_unlock(&gdp_mutex); 26098c2ecf20Sopenharmony_ci return k; 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci /* subsystems can specify a default root directory for their devices */ 26138c2ecf20Sopenharmony_ci if (!parent && dev->bus && dev->bus->dev_root) 26148c2ecf20Sopenharmony_ci return &dev->bus->dev_root->kobj; 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci if (parent) 26178c2ecf20Sopenharmony_ci return &parent->kobj; 26188c2ecf20Sopenharmony_ci return NULL; 26198c2ecf20Sopenharmony_ci} 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_cistatic inline bool live_in_glue_dir(struct kobject *kobj, 26228c2ecf20Sopenharmony_ci struct device *dev) 26238c2ecf20Sopenharmony_ci{ 26248c2ecf20Sopenharmony_ci if (!kobj || !dev->class || 26258c2ecf20Sopenharmony_ci kobj->kset != &dev->class->p->glue_dirs) 26268c2ecf20Sopenharmony_ci return false; 26278c2ecf20Sopenharmony_ci return true; 26288c2ecf20Sopenharmony_ci} 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_cistatic inline struct kobject *get_glue_dir(struct device *dev) 26318c2ecf20Sopenharmony_ci{ 26328c2ecf20Sopenharmony_ci return dev->kobj.parent; 26338c2ecf20Sopenharmony_ci} 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci/* 26368c2ecf20Sopenharmony_ci * make sure cleaning up dir as the last step, we need to make 26378c2ecf20Sopenharmony_ci * sure .release handler of kobject is run with holding the 26388c2ecf20Sopenharmony_ci * global lock 26398c2ecf20Sopenharmony_ci */ 26408c2ecf20Sopenharmony_cistatic void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) 26418c2ecf20Sopenharmony_ci{ 26428c2ecf20Sopenharmony_ci unsigned int ref; 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_ci /* see if we live in a "glue" directory */ 26458c2ecf20Sopenharmony_ci if (!live_in_glue_dir(glue_dir, dev)) 26468c2ecf20Sopenharmony_ci return; 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci mutex_lock(&gdp_mutex); 26498c2ecf20Sopenharmony_ci /** 26508c2ecf20Sopenharmony_ci * There is a race condition between removing glue directory 26518c2ecf20Sopenharmony_ci * and adding a new device under the glue directory. 26528c2ecf20Sopenharmony_ci * 26538c2ecf20Sopenharmony_ci * CPU1: CPU2: 26548c2ecf20Sopenharmony_ci * 26558c2ecf20Sopenharmony_ci * device_add() 26568c2ecf20Sopenharmony_ci * get_device_parent() 26578c2ecf20Sopenharmony_ci * class_dir_create_and_add() 26588c2ecf20Sopenharmony_ci * kobject_add_internal() 26598c2ecf20Sopenharmony_ci * create_dir() // create glue_dir 26608c2ecf20Sopenharmony_ci * 26618c2ecf20Sopenharmony_ci * device_add() 26628c2ecf20Sopenharmony_ci * get_device_parent() 26638c2ecf20Sopenharmony_ci * kobject_get() // get glue_dir 26648c2ecf20Sopenharmony_ci * 26658c2ecf20Sopenharmony_ci * device_del() 26668c2ecf20Sopenharmony_ci * cleanup_glue_dir() 26678c2ecf20Sopenharmony_ci * kobject_del(glue_dir) 26688c2ecf20Sopenharmony_ci * 26698c2ecf20Sopenharmony_ci * kobject_add() 26708c2ecf20Sopenharmony_ci * kobject_add_internal() 26718c2ecf20Sopenharmony_ci * create_dir() // in glue_dir 26728c2ecf20Sopenharmony_ci * sysfs_create_dir_ns() 26738c2ecf20Sopenharmony_ci * kernfs_create_dir_ns(sd) 26748c2ecf20Sopenharmony_ci * 26758c2ecf20Sopenharmony_ci * sysfs_remove_dir() // glue_dir->sd=NULL 26768c2ecf20Sopenharmony_ci * sysfs_put() // free glue_dir->sd 26778c2ecf20Sopenharmony_ci * 26788c2ecf20Sopenharmony_ci * // sd is freed 26798c2ecf20Sopenharmony_ci * kernfs_new_node(sd) 26808c2ecf20Sopenharmony_ci * kernfs_get(glue_dir) 26818c2ecf20Sopenharmony_ci * kernfs_add_one() 26828c2ecf20Sopenharmony_ci * kernfs_put() 26838c2ecf20Sopenharmony_ci * 26848c2ecf20Sopenharmony_ci * Before CPU1 remove last child device under glue dir, if CPU2 add 26858c2ecf20Sopenharmony_ci * a new device under glue dir, the glue_dir kobject reference count 26868c2ecf20Sopenharmony_ci * will be increase to 2 in kobject_get(k). And CPU2 has been called 26878c2ecf20Sopenharmony_ci * kernfs_create_dir_ns(). Meanwhile, CPU1 call sysfs_remove_dir() 26888c2ecf20Sopenharmony_ci * and sysfs_put(). This result in glue_dir->sd is freed. 26898c2ecf20Sopenharmony_ci * 26908c2ecf20Sopenharmony_ci * Then the CPU2 will see a stale "empty" but still potentially used 26918c2ecf20Sopenharmony_ci * glue dir around in kernfs_new_node(). 26928c2ecf20Sopenharmony_ci * 26938c2ecf20Sopenharmony_ci * In order to avoid this happening, we also should make sure that 26948c2ecf20Sopenharmony_ci * kernfs_node for glue_dir is released in CPU1 only when refcount 26958c2ecf20Sopenharmony_ci * for glue_dir kobj is 1. 26968c2ecf20Sopenharmony_ci */ 26978c2ecf20Sopenharmony_ci ref = kref_read(&glue_dir->kref); 26988c2ecf20Sopenharmony_ci if (!kobject_has_children(glue_dir) && !--ref) 26998c2ecf20Sopenharmony_ci kobject_del(glue_dir); 27008c2ecf20Sopenharmony_ci kobject_put(glue_dir); 27018c2ecf20Sopenharmony_ci mutex_unlock(&gdp_mutex); 27028c2ecf20Sopenharmony_ci} 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_cistatic int device_add_class_symlinks(struct device *dev) 27058c2ecf20Sopenharmony_ci{ 27068c2ecf20Sopenharmony_ci struct device_node *of_node = dev_of_node(dev); 27078c2ecf20Sopenharmony_ci int error; 27088c2ecf20Sopenharmony_ci 27098c2ecf20Sopenharmony_ci if (of_node) { 27108c2ecf20Sopenharmony_ci error = sysfs_create_link(&dev->kobj, of_node_kobj(of_node), "of_node"); 27118c2ecf20Sopenharmony_ci if (error) 27128c2ecf20Sopenharmony_ci dev_warn(dev, "Error %d creating of_node link\n",error); 27138c2ecf20Sopenharmony_ci /* An error here doesn't warrant bringing down the device */ 27148c2ecf20Sopenharmony_ci } 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_ci if (!dev->class) 27178c2ecf20Sopenharmony_ci return 0; 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci error = sysfs_create_link(&dev->kobj, 27208c2ecf20Sopenharmony_ci &dev->class->p->subsys.kobj, 27218c2ecf20Sopenharmony_ci "subsystem"); 27228c2ecf20Sopenharmony_ci if (error) 27238c2ecf20Sopenharmony_ci goto out_devnode; 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci if (dev->parent && device_is_not_partition(dev)) { 27268c2ecf20Sopenharmony_ci error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, 27278c2ecf20Sopenharmony_ci "device"); 27288c2ecf20Sopenharmony_ci if (error) 27298c2ecf20Sopenharmony_ci goto out_subsys; 27308c2ecf20Sopenharmony_ci } 27318c2ecf20Sopenharmony_ci 27328c2ecf20Sopenharmony_ci#ifdef CONFIG_BLOCK 27338c2ecf20Sopenharmony_ci /* /sys/block has directories and does not need symlinks */ 27348c2ecf20Sopenharmony_ci if (sysfs_deprecated && dev->class == &block_class) 27358c2ecf20Sopenharmony_ci return 0; 27368c2ecf20Sopenharmony_ci#endif 27378c2ecf20Sopenharmony_ci 27388c2ecf20Sopenharmony_ci /* link in the class directory pointing to the device */ 27398c2ecf20Sopenharmony_ci error = sysfs_create_link(&dev->class->p->subsys.kobj, 27408c2ecf20Sopenharmony_ci &dev->kobj, dev_name(dev)); 27418c2ecf20Sopenharmony_ci if (error) 27428c2ecf20Sopenharmony_ci goto out_device; 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci return 0; 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ciout_device: 27478c2ecf20Sopenharmony_ci sysfs_remove_link(&dev->kobj, "device"); 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ciout_subsys: 27508c2ecf20Sopenharmony_ci sysfs_remove_link(&dev->kobj, "subsystem"); 27518c2ecf20Sopenharmony_ciout_devnode: 27528c2ecf20Sopenharmony_ci sysfs_remove_link(&dev->kobj, "of_node"); 27538c2ecf20Sopenharmony_ci return error; 27548c2ecf20Sopenharmony_ci} 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_cistatic void device_remove_class_symlinks(struct device *dev) 27578c2ecf20Sopenharmony_ci{ 27588c2ecf20Sopenharmony_ci if (dev_of_node(dev)) 27598c2ecf20Sopenharmony_ci sysfs_remove_link(&dev->kobj, "of_node"); 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci if (!dev->class) 27628c2ecf20Sopenharmony_ci return; 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci if (dev->parent && device_is_not_partition(dev)) 27658c2ecf20Sopenharmony_ci sysfs_remove_link(&dev->kobj, "device"); 27668c2ecf20Sopenharmony_ci sysfs_remove_link(&dev->kobj, "subsystem"); 27678c2ecf20Sopenharmony_ci#ifdef CONFIG_BLOCK 27688c2ecf20Sopenharmony_ci if (sysfs_deprecated && dev->class == &block_class) 27698c2ecf20Sopenharmony_ci return; 27708c2ecf20Sopenharmony_ci#endif 27718c2ecf20Sopenharmony_ci sysfs_delete_link(&dev->class->p->subsys.kobj, &dev->kobj, dev_name(dev)); 27728c2ecf20Sopenharmony_ci} 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci/** 27758c2ecf20Sopenharmony_ci * dev_set_name - set a device name 27768c2ecf20Sopenharmony_ci * @dev: device 27778c2ecf20Sopenharmony_ci * @fmt: format string for the device's name 27788c2ecf20Sopenharmony_ci */ 27798c2ecf20Sopenharmony_ciint dev_set_name(struct device *dev, const char *fmt, ...) 27808c2ecf20Sopenharmony_ci{ 27818c2ecf20Sopenharmony_ci va_list vargs; 27828c2ecf20Sopenharmony_ci int err; 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci va_start(vargs, fmt); 27858c2ecf20Sopenharmony_ci err = kobject_set_name_vargs(&dev->kobj, fmt, vargs); 27868c2ecf20Sopenharmony_ci va_end(vargs); 27878c2ecf20Sopenharmony_ci return err; 27888c2ecf20Sopenharmony_ci} 27898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_set_name); 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci/** 27928c2ecf20Sopenharmony_ci * device_to_dev_kobj - select a /sys/dev/ directory for the device 27938c2ecf20Sopenharmony_ci * @dev: device 27948c2ecf20Sopenharmony_ci * 27958c2ecf20Sopenharmony_ci * By default we select char/ for new entries. Setting class->dev_obj 27968c2ecf20Sopenharmony_ci * to NULL prevents an entry from being created. class->dev_kobj must 27978c2ecf20Sopenharmony_ci * be set (or cleared) before any devices are registered to the class 27988c2ecf20Sopenharmony_ci * otherwise device_create_sys_dev_entry() and 27998c2ecf20Sopenharmony_ci * device_remove_sys_dev_entry() will disagree about the presence of 28008c2ecf20Sopenharmony_ci * the link. 28018c2ecf20Sopenharmony_ci */ 28028c2ecf20Sopenharmony_cistatic struct kobject *device_to_dev_kobj(struct device *dev) 28038c2ecf20Sopenharmony_ci{ 28048c2ecf20Sopenharmony_ci struct kobject *kobj; 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci if (dev->class) 28078c2ecf20Sopenharmony_ci kobj = dev->class->dev_kobj; 28088c2ecf20Sopenharmony_ci else 28098c2ecf20Sopenharmony_ci kobj = sysfs_dev_char_kobj; 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci return kobj; 28128c2ecf20Sopenharmony_ci} 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_cistatic int device_create_sys_dev_entry(struct device *dev) 28158c2ecf20Sopenharmony_ci{ 28168c2ecf20Sopenharmony_ci struct kobject *kobj = device_to_dev_kobj(dev); 28178c2ecf20Sopenharmony_ci int error = 0; 28188c2ecf20Sopenharmony_ci char devt_str[15]; 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci if (kobj) { 28218c2ecf20Sopenharmony_ci format_dev_t(devt_str, dev->devt); 28228c2ecf20Sopenharmony_ci error = sysfs_create_link(kobj, &dev->kobj, devt_str); 28238c2ecf20Sopenharmony_ci } 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci return error; 28268c2ecf20Sopenharmony_ci} 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_cistatic void device_remove_sys_dev_entry(struct device *dev) 28298c2ecf20Sopenharmony_ci{ 28308c2ecf20Sopenharmony_ci struct kobject *kobj = device_to_dev_kobj(dev); 28318c2ecf20Sopenharmony_ci char devt_str[15]; 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci if (kobj) { 28348c2ecf20Sopenharmony_ci format_dev_t(devt_str, dev->devt); 28358c2ecf20Sopenharmony_ci sysfs_remove_link(kobj, devt_str); 28368c2ecf20Sopenharmony_ci } 28378c2ecf20Sopenharmony_ci} 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_cistatic int device_private_init(struct device *dev) 28408c2ecf20Sopenharmony_ci{ 28418c2ecf20Sopenharmony_ci dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL); 28428c2ecf20Sopenharmony_ci if (!dev->p) 28438c2ecf20Sopenharmony_ci return -ENOMEM; 28448c2ecf20Sopenharmony_ci dev->p->device = dev; 28458c2ecf20Sopenharmony_ci klist_init(&dev->p->klist_children, klist_children_get, 28468c2ecf20Sopenharmony_ci klist_children_put); 28478c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dev->p->deferred_probe); 28488c2ecf20Sopenharmony_ci return 0; 28498c2ecf20Sopenharmony_ci} 28508c2ecf20Sopenharmony_ci 28518c2ecf20Sopenharmony_ci/** 28528c2ecf20Sopenharmony_ci * device_add - add device to device hierarchy. 28538c2ecf20Sopenharmony_ci * @dev: device. 28548c2ecf20Sopenharmony_ci * 28558c2ecf20Sopenharmony_ci * This is part 2 of device_register(), though may be called 28568c2ecf20Sopenharmony_ci * separately _iff_ device_initialize() has been called separately. 28578c2ecf20Sopenharmony_ci * 28588c2ecf20Sopenharmony_ci * This adds @dev to the kobject hierarchy via kobject_add(), adds it 28598c2ecf20Sopenharmony_ci * to the global and sibling lists for the device, then 28608c2ecf20Sopenharmony_ci * adds it to the other relevant subsystems of the driver model. 28618c2ecf20Sopenharmony_ci * 28628c2ecf20Sopenharmony_ci * Do not call this routine or device_register() more than once for 28638c2ecf20Sopenharmony_ci * any device structure. The driver model core is not designed to work 28648c2ecf20Sopenharmony_ci * with devices that get unregistered and then spring back to life. 28658c2ecf20Sopenharmony_ci * (Among other things, it's very hard to guarantee that all references 28668c2ecf20Sopenharmony_ci * to the previous incarnation of @dev have been dropped.) Allocate 28678c2ecf20Sopenharmony_ci * and register a fresh new struct device instead. 28688c2ecf20Sopenharmony_ci * 28698c2ecf20Sopenharmony_ci * NOTE: _Never_ directly free @dev after calling this function, even 28708c2ecf20Sopenharmony_ci * if it returned an error! Always use put_device() to give up your 28718c2ecf20Sopenharmony_ci * reference instead. 28728c2ecf20Sopenharmony_ci * 28738c2ecf20Sopenharmony_ci * Rule of thumb is: if device_add() succeeds, you should call 28748c2ecf20Sopenharmony_ci * device_del() when you want to get rid of it. If device_add() has 28758c2ecf20Sopenharmony_ci * *not* succeeded, use *only* put_device() to drop the reference 28768c2ecf20Sopenharmony_ci * count. 28778c2ecf20Sopenharmony_ci */ 28788c2ecf20Sopenharmony_ciint device_add(struct device *dev) 28798c2ecf20Sopenharmony_ci{ 28808c2ecf20Sopenharmony_ci struct device *parent; 28818c2ecf20Sopenharmony_ci struct kobject *kobj; 28828c2ecf20Sopenharmony_ci struct class_interface *class_intf; 28838c2ecf20Sopenharmony_ci int error = -EINVAL; 28848c2ecf20Sopenharmony_ci struct kobject *glue_dir = NULL; 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci dev = get_device(dev); 28878c2ecf20Sopenharmony_ci if (!dev) 28888c2ecf20Sopenharmony_ci goto done; 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ci if (!dev->p) { 28918c2ecf20Sopenharmony_ci error = device_private_init(dev); 28928c2ecf20Sopenharmony_ci if (error) 28938c2ecf20Sopenharmony_ci goto done; 28948c2ecf20Sopenharmony_ci } 28958c2ecf20Sopenharmony_ci 28968c2ecf20Sopenharmony_ci /* 28978c2ecf20Sopenharmony_ci * for statically allocated devices, which should all be converted 28988c2ecf20Sopenharmony_ci * some day, we need to initialize the name. We prevent reading back 28998c2ecf20Sopenharmony_ci * the name, and force the use of dev_name() 29008c2ecf20Sopenharmony_ci */ 29018c2ecf20Sopenharmony_ci if (dev->init_name) { 29028c2ecf20Sopenharmony_ci dev_set_name(dev, "%s", dev->init_name); 29038c2ecf20Sopenharmony_ci dev->init_name = NULL; 29048c2ecf20Sopenharmony_ci } 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_ci /* subsystems can specify simple device enumeration */ 29078c2ecf20Sopenharmony_ci if (!dev_name(dev) && dev->bus && dev->bus->dev_name) 29088c2ecf20Sopenharmony_ci dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id); 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci if (!dev_name(dev)) { 29118c2ecf20Sopenharmony_ci error = -EINVAL; 29128c2ecf20Sopenharmony_ci goto name_error; 29138c2ecf20Sopenharmony_ci } 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci pr_debug("device: '%s': %s\n", dev_name(dev), __func__); 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci parent = get_device(dev->parent); 29188c2ecf20Sopenharmony_ci kobj = get_device_parent(dev, parent); 29198c2ecf20Sopenharmony_ci if (IS_ERR(kobj)) { 29208c2ecf20Sopenharmony_ci error = PTR_ERR(kobj); 29218c2ecf20Sopenharmony_ci goto parent_error; 29228c2ecf20Sopenharmony_ci } 29238c2ecf20Sopenharmony_ci if (kobj) 29248c2ecf20Sopenharmony_ci dev->kobj.parent = kobj; 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci /* use parent numa_node */ 29278c2ecf20Sopenharmony_ci if (parent && (dev_to_node(dev) == NUMA_NO_NODE)) 29288c2ecf20Sopenharmony_ci set_dev_node(dev, dev_to_node(parent)); 29298c2ecf20Sopenharmony_ci 29308c2ecf20Sopenharmony_ci /* first, register with generic layer. */ 29318c2ecf20Sopenharmony_ci /* we require the name to be set before, and pass NULL */ 29328c2ecf20Sopenharmony_ci error = kobject_add(&dev->kobj, dev->kobj.parent, NULL); 29338c2ecf20Sopenharmony_ci if (error) { 29348c2ecf20Sopenharmony_ci glue_dir = get_glue_dir(dev); 29358c2ecf20Sopenharmony_ci goto Error; 29368c2ecf20Sopenharmony_ci } 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci /* notify platform of device entry */ 29398c2ecf20Sopenharmony_ci error = device_platform_notify(dev, KOBJ_ADD); 29408c2ecf20Sopenharmony_ci if (error) 29418c2ecf20Sopenharmony_ci goto platform_error; 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci error = device_create_file(dev, &dev_attr_uevent); 29448c2ecf20Sopenharmony_ci if (error) 29458c2ecf20Sopenharmony_ci goto attrError; 29468c2ecf20Sopenharmony_ci 29478c2ecf20Sopenharmony_ci error = device_add_class_symlinks(dev); 29488c2ecf20Sopenharmony_ci if (error) 29498c2ecf20Sopenharmony_ci goto SymlinkError; 29508c2ecf20Sopenharmony_ci error = device_add_attrs(dev); 29518c2ecf20Sopenharmony_ci if (error) 29528c2ecf20Sopenharmony_ci goto AttrsError; 29538c2ecf20Sopenharmony_ci error = bus_add_device(dev); 29548c2ecf20Sopenharmony_ci if (error) 29558c2ecf20Sopenharmony_ci goto BusError; 29568c2ecf20Sopenharmony_ci error = dpm_sysfs_add(dev); 29578c2ecf20Sopenharmony_ci if (error) 29588c2ecf20Sopenharmony_ci goto DPMError; 29598c2ecf20Sopenharmony_ci device_pm_add(dev); 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci if (MAJOR(dev->devt)) { 29628c2ecf20Sopenharmony_ci error = device_create_file(dev, &dev_attr_dev); 29638c2ecf20Sopenharmony_ci if (error) 29648c2ecf20Sopenharmony_ci goto DevAttrError; 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_ci error = device_create_sys_dev_entry(dev); 29678c2ecf20Sopenharmony_ci if (error) 29688c2ecf20Sopenharmony_ci goto SysEntryError; 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci devtmpfs_create_node(dev); 29718c2ecf20Sopenharmony_ci } 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci /* Notify clients of device addition. This call must come 29748c2ecf20Sopenharmony_ci * after dpm_sysfs_add() and before kobject_uevent(). 29758c2ecf20Sopenharmony_ci */ 29768c2ecf20Sopenharmony_ci if (dev->bus) 29778c2ecf20Sopenharmony_ci blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 29788c2ecf20Sopenharmony_ci BUS_NOTIFY_ADD_DEVICE, dev); 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci kobject_uevent(&dev->kobj, KOBJ_ADD); 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci /* 29838c2ecf20Sopenharmony_ci * Check if any of the other devices (consumers) have been waiting for 29848c2ecf20Sopenharmony_ci * this device (supplier) to be added so that they can create a device 29858c2ecf20Sopenharmony_ci * link to it. 29868c2ecf20Sopenharmony_ci * 29878c2ecf20Sopenharmony_ci * This needs to happen after device_pm_add() because device_link_add() 29888c2ecf20Sopenharmony_ci * requires the supplier be registered before it's called. 29898c2ecf20Sopenharmony_ci * 29908c2ecf20Sopenharmony_ci * But this also needs to happen before bus_probe_device() to make sure 29918c2ecf20Sopenharmony_ci * waiting consumers can link to it before the driver is bound to the 29928c2ecf20Sopenharmony_ci * device and the driver sync_state callback is called for this device. 29938c2ecf20Sopenharmony_ci */ 29948c2ecf20Sopenharmony_ci if (dev->fwnode && !dev->fwnode->dev) { 29958c2ecf20Sopenharmony_ci dev->fwnode->dev = dev; 29968c2ecf20Sopenharmony_ci fw_devlink_link_device(dev); 29978c2ecf20Sopenharmony_ci } 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ci bus_probe_device(dev); 30008c2ecf20Sopenharmony_ci if (parent) 30018c2ecf20Sopenharmony_ci klist_add_tail(&dev->p->knode_parent, 30028c2ecf20Sopenharmony_ci &parent->p->klist_children); 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci if (dev->class) { 30058c2ecf20Sopenharmony_ci mutex_lock(&dev->class->p->mutex); 30068c2ecf20Sopenharmony_ci /* tie the class to the device */ 30078c2ecf20Sopenharmony_ci klist_add_tail(&dev->p->knode_class, 30088c2ecf20Sopenharmony_ci &dev->class->p->klist_devices); 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci /* notify any interfaces that the device is here */ 30118c2ecf20Sopenharmony_ci list_for_each_entry(class_intf, 30128c2ecf20Sopenharmony_ci &dev->class->p->interfaces, node) 30138c2ecf20Sopenharmony_ci if (class_intf->add_dev) 30148c2ecf20Sopenharmony_ci class_intf->add_dev(dev, class_intf); 30158c2ecf20Sopenharmony_ci mutex_unlock(&dev->class->p->mutex); 30168c2ecf20Sopenharmony_ci } 30178c2ecf20Sopenharmony_cidone: 30188c2ecf20Sopenharmony_ci put_device(dev); 30198c2ecf20Sopenharmony_ci return error; 30208c2ecf20Sopenharmony_ci SysEntryError: 30218c2ecf20Sopenharmony_ci if (MAJOR(dev->devt)) 30228c2ecf20Sopenharmony_ci device_remove_file(dev, &dev_attr_dev); 30238c2ecf20Sopenharmony_ci DevAttrError: 30248c2ecf20Sopenharmony_ci device_pm_remove(dev); 30258c2ecf20Sopenharmony_ci dpm_sysfs_remove(dev); 30268c2ecf20Sopenharmony_ci DPMError: 30278c2ecf20Sopenharmony_ci bus_remove_device(dev); 30288c2ecf20Sopenharmony_ci BusError: 30298c2ecf20Sopenharmony_ci device_remove_attrs(dev); 30308c2ecf20Sopenharmony_ci AttrsError: 30318c2ecf20Sopenharmony_ci device_remove_class_symlinks(dev); 30328c2ecf20Sopenharmony_ci SymlinkError: 30338c2ecf20Sopenharmony_ci device_remove_file(dev, &dev_attr_uevent); 30348c2ecf20Sopenharmony_ci attrError: 30358c2ecf20Sopenharmony_ci device_platform_notify(dev, KOBJ_REMOVE); 30368c2ecf20Sopenharmony_ciplatform_error: 30378c2ecf20Sopenharmony_ci kobject_uevent(&dev->kobj, KOBJ_REMOVE); 30388c2ecf20Sopenharmony_ci glue_dir = get_glue_dir(dev); 30398c2ecf20Sopenharmony_ci kobject_del(&dev->kobj); 30408c2ecf20Sopenharmony_ci Error: 30418c2ecf20Sopenharmony_ci cleanup_glue_dir(dev, glue_dir); 30428c2ecf20Sopenharmony_ciparent_error: 30438c2ecf20Sopenharmony_ci put_device(parent); 30448c2ecf20Sopenharmony_ciname_error: 30458c2ecf20Sopenharmony_ci kfree(dev->p); 30468c2ecf20Sopenharmony_ci dev->p = NULL; 30478c2ecf20Sopenharmony_ci goto done; 30488c2ecf20Sopenharmony_ci} 30498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_add); 30508c2ecf20Sopenharmony_ci 30518c2ecf20Sopenharmony_ci/** 30528c2ecf20Sopenharmony_ci * device_register - register a device with the system. 30538c2ecf20Sopenharmony_ci * @dev: pointer to the device structure 30548c2ecf20Sopenharmony_ci * 30558c2ecf20Sopenharmony_ci * This happens in two clean steps - initialize the device 30568c2ecf20Sopenharmony_ci * and add it to the system. The two steps can be called 30578c2ecf20Sopenharmony_ci * separately, but this is the easiest and most common. 30588c2ecf20Sopenharmony_ci * I.e. you should only call the two helpers separately if 30598c2ecf20Sopenharmony_ci * have a clearly defined need to use and refcount the device 30608c2ecf20Sopenharmony_ci * before it is added to the hierarchy. 30618c2ecf20Sopenharmony_ci * 30628c2ecf20Sopenharmony_ci * For more information, see the kerneldoc for device_initialize() 30638c2ecf20Sopenharmony_ci * and device_add(). 30648c2ecf20Sopenharmony_ci * 30658c2ecf20Sopenharmony_ci * NOTE: _Never_ directly free @dev after calling this function, even 30668c2ecf20Sopenharmony_ci * if it returned an error! Always use put_device() to give up the 30678c2ecf20Sopenharmony_ci * reference initialized in this function instead. 30688c2ecf20Sopenharmony_ci */ 30698c2ecf20Sopenharmony_ciint device_register(struct device *dev) 30708c2ecf20Sopenharmony_ci{ 30718c2ecf20Sopenharmony_ci device_initialize(dev); 30728c2ecf20Sopenharmony_ci return device_add(dev); 30738c2ecf20Sopenharmony_ci} 30748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_register); 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_ci/** 30778c2ecf20Sopenharmony_ci * get_device - increment reference count for device. 30788c2ecf20Sopenharmony_ci * @dev: device. 30798c2ecf20Sopenharmony_ci * 30808c2ecf20Sopenharmony_ci * This simply forwards the call to kobject_get(), though 30818c2ecf20Sopenharmony_ci * we do take care to provide for the case that we get a NULL 30828c2ecf20Sopenharmony_ci * pointer passed in. 30838c2ecf20Sopenharmony_ci */ 30848c2ecf20Sopenharmony_cistruct device *get_device(struct device *dev) 30858c2ecf20Sopenharmony_ci{ 30868c2ecf20Sopenharmony_ci return dev ? kobj_to_dev(kobject_get(&dev->kobj)) : NULL; 30878c2ecf20Sopenharmony_ci} 30888c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(get_device); 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_ci/** 30918c2ecf20Sopenharmony_ci * put_device - decrement reference count. 30928c2ecf20Sopenharmony_ci * @dev: device in question. 30938c2ecf20Sopenharmony_ci */ 30948c2ecf20Sopenharmony_civoid put_device(struct device *dev) 30958c2ecf20Sopenharmony_ci{ 30968c2ecf20Sopenharmony_ci /* might_sleep(); */ 30978c2ecf20Sopenharmony_ci if (dev) 30988c2ecf20Sopenharmony_ci kobject_put(&dev->kobj); 30998c2ecf20Sopenharmony_ci} 31008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(put_device); 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_cibool kill_device(struct device *dev) 31038c2ecf20Sopenharmony_ci{ 31048c2ecf20Sopenharmony_ci /* 31058c2ecf20Sopenharmony_ci * Require the device lock and set the "dead" flag to guarantee that 31068c2ecf20Sopenharmony_ci * the update behavior is consistent with the other bitfields near 31078c2ecf20Sopenharmony_ci * it and that we cannot have an asynchronous probe routine trying 31088c2ecf20Sopenharmony_ci * to run while we are tearing out the bus/class/sysfs from 31098c2ecf20Sopenharmony_ci * underneath the device. 31108c2ecf20Sopenharmony_ci */ 31118c2ecf20Sopenharmony_ci lockdep_assert_held(&dev->mutex); 31128c2ecf20Sopenharmony_ci 31138c2ecf20Sopenharmony_ci if (dev->p->dead) 31148c2ecf20Sopenharmony_ci return false; 31158c2ecf20Sopenharmony_ci dev->p->dead = true; 31168c2ecf20Sopenharmony_ci return true; 31178c2ecf20Sopenharmony_ci} 31188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kill_device); 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci/** 31218c2ecf20Sopenharmony_ci * device_del - delete device from system. 31228c2ecf20Sopenharmony_ci * @dev: device. 31238c2ecf20Sopenharmony_ci * 31248c2ecf20Sopenharmony_ci * This is the first part of the device unregistration 31258c2ecf20Sopenharmony_ci * sequence. This removes the device from the lists we control 31268c2ecf20Sopenharmony_ci * from here, has it removed from the other driver model 31278c2ecf20Sopenharmony_ci * subsystems it was added to in device_add(), and removes it 31288c2ecf20Sopenharmony_ci * from the kobject hierarchy. 31298c2ecf20Sopenharmony_ci * 31308c2ecf20Sopenharmony_ci * NOTE: this should be called manually _iff_ device_add() was 31318c2ecf20Sopenharmony_ci * also called manually. 31328c2ecf20Sopenharmony_ci */ 31338c2ecf20Sopenharmony_civoid device_del(struct device *dev) 31348c2ecf20Sopenharmony_ci{ 31358c2ecf20Sopenharmony_ci struct device *parent = dev->parent; 31368c2ecf20Sopenharmony_ci struct kobject *glue_dir = NULL; 31378c2ecf20Sopenharmony_ci struct class_interface *class_intf; 31388c2ecf20Sopenharmony_ci unsigned int noio_flag; 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci device_lock(dev); 31418c2ecf20Sopenharmony_ci kill_device(dev); 31428c2ecf20Sopenharmony_ci device_unlock(dev); 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_ci if (dev->fwnode && dev->fwnode->dev == dev) 31458c2ecf20Sopenharmony_ci dev->fwnode->dev = NULL; 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_ci /* Notify clients of device removal. This call must come 31488c2ecf20Sopenharmony_ci * before dpm_sysfs_remove(). 31498c2ecf20Sopenharmony_ci */ 31508c2ecf20Sopenharmony_ci noio_flag = memalloc_noio_save(); 31518c2ecf20Sopenharmony_ci if (dev->bus) 31528c2ecf20Sopenharmony_ci blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 31538c2ecf20Sopenharmony_ci BUS_NOTIFY_DEL_DEVICE, dev); 31548c2ecf20Sopenharmony_ci 31558c2ecf20Sopenharmony_ci dpm_sysfs_remove(dev); 31568c2ecf20Sopenharmony_ci if (parent) 31578c2ecf20Sopenharmony_ci klist_del(&dev->p->knode_parent); 31588c2ecf20Sopenharmony_ci if (MAJOR(dev->devt)) { 31598c2ecf20Sopenharmony_ci devtmpfs_delete_node(dev); 31608c2ecf20Sopenharmony_ci device_remove_sys_dev_entry(dev); 31618c2ecf20Sopenharmony_ci device_remove_file(dev, &dev_attr_dev); 31628c2ecf20Sopenharmony_ci } 31638c2ecf20Sopenharmony_ci if (dev->class) { 31648c2ecf20Sopenharmony_ci device_remove_class_symlinks(dev); 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_ci mutex_lock(&dev->class->p->mutex); 31678c2ecf20Sopenharmony_ci /* notify any interfaces that the device is now gone */ 31688c2ecf20Sopenharmony_ci list_for_each_entry(class_intf, 31698c2ecf20Sopenharmony_ci &dev->class->p->interfaces, node) 31708c2ecf20Sopenharmony_ci if (class_intf->remove_dev) 31718c2ecf20Sopenharmony_ci class_intf->remove_dev(dev, class_intf); 31728c2ecf20Sopenharmony_ci /* remove the device from the class list */ 31738c2ecf20Sopenharmony_ci klist_del(&dev->p->knode_class); 31748c2ecf20Sopenharmony_ci mutex_unlock(&dev->class->p->mutex); 31758c2ecf20Sopenharmony_ci } 31768c2ecf20Sopenharmony_ci device_remove_file(dev, &dev_attr_uevent); 31778c2ecf20Sopenharmony_ci device_remove_attrs(dev); 31788c2ecf20Sopenharmony_ci bus_remove_device(dev); 31798c2ecf20Sopenharmony_ci device_pm_remove(dev); 31808c2ecf20Sopenharmony_ci driver_deferred_probe_del(dev); 31818c2ecf20Sopenharmony_ci device_platform_notify(dev, KOBJ_REMOVE); 31828c2ecf20Sopenharmony_ci device_remove_properties(dev); 31838c2ecf20Sopenharmony_ci device_links_purge(dev); 31848c2ecf20Sopenharmony_ci 31858c2ecf20Sopenharmony_ci if (dev->bus) 31868c2ecf20Sopenharmony_ci blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 31878c2ecf20Sopenharmony_ci BUS_NOTIFY_REMOVED_DEVICE, dev); 31888c2ecf20Sopenharmony_ci kobject_uevent(&dev->kobj, KOBJ_REMOVE); 31898c2ecf20Sopenharmony_ci glue_dir = get_glue_dir(dev); 31908c2ecf20Sopenharmony_ci kobject_del(&dev->kobj); 31918c2ecf20Sopenharmony_ci cleanup_glue_dir(dev, glue_dir); 31928c2ecf20Sopenharmony_ci memalloc_noio_restore(noio_flag); 31938c2ecf20Sopenharmony_ci put_device(parent); 31948c2ecf20Sopenharmony_ci} 31958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_del); 31968c2ecf20Sopenharmony_ci 31978c2ecf20Sopenharmony_ci/** 31988c2ecf20Sopenharmony_ci * device_unregister - unregister device from system. 31998c2ecf20Sopenharmony_ci * @dev: device going away. 32008c2ecf20Sopenharmony_ci * 32018c2ecf20Sopenharmony_ci * We do this in two parts, like we do device_register(). First, 32028c2ecf20Sopenharmony_ci * we remove it from all the subsystems with device_del(), then 32038c2ecf20Sopenharmony_ci * we decrement the reference count via put_device(). If that 32048c2ecf20Sopenharmony_ci * is the final reference count, the device will be cleaned up 32058c2ecf20Sopenharmony_ci * via device_release() above. Otherwise, the structure will 32068c2ecf20Sopenharmony_ci * stick around until the final reference to the device is dropped. 32078c2ecf20Sopenharmony_ci */ 32088c2ecf20Sopenharmony_civoid device_unregister(struct device *dev) 32098c2ecf20Sopenharmony_ci{ 32108c2ecf20Sopenharmony_ci pr_debug("device: '%s': %s\n", dev_name(dev), __func__); 32118c2ecf20Sopenharmony_ci device_del(dev); 32128c2ecf20Sopenharmony_ci put_device(dev); 32138c2ecf20Sopenharmony_ci} 32148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_unregister); 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_cistatic struct device *prev_device(struct klist_iter *i) 32178c2ecf20Sopenharmony_ci{ 32188c2ecf20Sopenharmony_ci struct klist_node *n = klist_prev(i); 32198c2ecf20Sopenharmony_ci struct device *dev = NULL; 32208c2ecf20Sopenharmony_ci struct device_private *p; 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_ci if (n) { 32238c2ecf20Sopenharmony_ci p = to_device_private_parent(n); 32248c2ecf20Sopenharmony_ci dev = p->device; 32258c2ecf20Sopenharmony_ci } 32268c2ecf20Sopenharmony_ci return dev; 32278c2ecf20Sopenharmony_ci} 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_cistatic struct device *next_device(struct klist_iter *i) 32308c2ecf20Sopenharmony_ci{ 32318c2ecf20Sopenharmony_ci struct klist_node *n = klist_next(i); 32328c2ecf20Sopenharmony_ci struct device *dev = NULL; 32338c2ecf20Sopenharmony_ci struct device_private *p; 32348c2ecf20Sopenharmony_ci 32358c2ecf20Sopenharmony_ci if (n) { 32368c2ecf20Sopenharmony_ci p = to_device_private_parent(n); 32378c2ecf20Sopenharmony_ci dev = p->device; 32388c2ecf20Sopenharmony_ci } 32398c2ecf20Sopenharmony_ci return dev; 32408c2ecf20Sopenharmony_ci} 32418c2ecf20Sopenharmony_ci 32428c2ecf20Sopenharmony_ci/** 32438c2ecf20Sopenharmony_ci * device_get_devnode - path of device node file 32448c2ecf20Sopenharmony_ci * @dev: device 32458c2ecf20Sopenharmony_ci * @mode: returned file access mode 32468c2ecf20Sopenharmony_ci * @uid: returned file owner 32478c2ecf20Sopenharmony_ci * @gid: returned file group 32488c2ecf20Sopenharmony_ci * @tmp: possibly allocated string 32498c2ecf20Sopenharmony_ci * 32508c2ecf20Sopenharmony_ci * Return the relative path of a possible device node. 32518c2ecf20Sopenharmony_ci * Non-default names may need to allocate a memory to compose 32528c2ecf20Sopenharmony_ci * a name. This memory is returned in tmp and needs to be 32538c2ecf20Sopenharmony_ci * freed by the caller. 32548c2ecf20Sopenharmony_ci */ 32558c2ecf20Sopenharmony_ciconst char *device_get_devnode(struct device *dev, 32568c2ecf20Sopenharmony_ci umode_t *mode, kuid_t *uid, kgid_t *gid, 32578c2ecf20Sopenharmony_ci const char **tmp) 32588c2ecf20Sopenharmony_ci{ 32598c2ecf20Sopenharmony_ci char *s; 32608c2ecf20Sopenharmony_ci 32618c2ecf20Sopenharmony_ci *tmp = NULL; 32628c2ecf20Sopenharmony_ci 32638c2ecf20Sopenharmony_ci /* the device type may provide a specific name */ 32648c2ecf20Sopenharmony_ci if (dev->type && dev->type->devnode) 32658c2ecf20Sopenharmony_ci *tmp = dev->type->devnode(dev, mode, uid, gid); 32668c2ecf20Sopenharmony_ci if (*tmp) 32678c2ecf20Sopenharmony_ci return *tmp; 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci /* the class may provide a specific name */ 32708c2ecf20Sopenharmony_ci if (dev->class && dev->class->devnode) 32718c2ecf20Sopenharmony_ci *tmp = dev->class->devnode(dev, mode); 32728c2ecf20Sopenharmony_ci if (*tmp) 32738c2ecf20Sopenharmony_ci return *tmp; 32748c2ecf20Sopenharmony_ci 32758c2ecf20Sopenharmony_ci /* return name without allocation, tmp == NULL */ 32768c2ecf20Sopenharmony_ci if (strchr(dev_name(dev), '!') == NULL) 32778c2ecf20Sopenharmony_ci return dev_name(dev); 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci /* replace '!' in the name with '/' */ 32808c2ecf20Sopenharmony_ci s = kstrdup(dev_name(dev), GFP_KERNEL); 32818c2ecf20Sopenharmony_ci if (!s) 32828c2ecf20Sopenharmony_ci return NULL; 32838c2ecf20Sopenharmony_ci strreplace(s, '!', '/'); 32848c2ecf20Sopenharmony_ci return *tmp = s; 32858c2ecf20Sopenharmony_ci} 32868c2ecf20Sopenharmony_ci 32878c2ecf20Sopenharmony_ci/** 32888c2ecf20Sopenharmony_ci * device_for_each_child - device child iterator. 32898c2ecf20Sopenharmony_ci * @parent: parent struct device. 32908c2ecf20Sopenharmony_ci * @fn: function to be called for each device. 32918c2ecf20Sopenharmony_ci * @data: data for the callback. 32928c2ecf20Sopenharmony_ci * 32938c2ecf20Sopenharmony_ci * Iterate over @parent's child devices, and call @fn for each, 32948c2ecf20Sopenharmony_ci * passing it @data. 32958c2ecf20Sopenharmony_ci * 32968c2ecf20Sopenharmony_ci * We check the return of @fn each time. If it returns anything 32978c2ecf20Sopenharmony_ci * other than 0, we break out and return that value. 32988c2ecf20Sopenharmony_ci */ 32998c2ecf20Sopenharmony_ciint device_for_each_child(struct device *parent, void *data, 33008c2ecf20Sopenharmony_ci int (*fn)(struct device *dev, void *data)) 33018c2ecf20Sopenharmony_ci{ 33028c2ecf20Sopenharmony_ci struct klist_iter i; 33038c2ecf20Sopenharmony_ci struct device *child; 33048c2ecf20Sopenharmony_ci int error = 0; 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci if (!parent->p) 33078c2ecf20Sopenharmony_ci return 0; 33088c2ecf20Sopenharmony_ci 33098c2ecf20Sopenharmony_ci klist_iter_init(&parent->p->klist_children, &i); 33108c2ecf20Sopenharmony_ci while (!error && (child = next_device(&i))) 33118c2ecf20Sopenharmony_ci error = fn(child, data); 33128c2ecf20Sopenharmony_ci klist_iter_exit(&i); 33138c2ecf20Sopenharmony_ci return error; 33148c2ecf20Sopenharmony_ci} 33158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_for_each_child); 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci/** 33188c2ecf20Sopenharmony_ci * device_for_each_child_reverse - device child iterator in reversed order. 33198c2ecf20Sopenharmony_ci * @parent: parent struct device. 33208c2ecf20Sopenharmony_ci * @fn: function to be called for each device. 33218c2ecf20Sopenharmony_ci * @data: data for the callback. 33228c2ecf20Sopenharmony_ci * 33238c2ecf20Sopenharmony_ci * Iterate over @parent's child devices, and call @fn for each, 33248c2ecf20Sopenharmony_ci * passing it @data. 33258c2ecf20Sopenharmony_ci * 33268c2ecf20Sopenharmony_ci * We check the return of @fn each time. If it returns anything 33278c2ecf20Sopenharmony_ci * other than 0, we break out and return that value. 33288c2ecf20Sopenharmony_ci */ 33298c2ecf20Sopenharmony_ciint device_for_each_child_reverse(struct device *parent, void *data, 33308c2ecf20Sopenharmony_ci int (*fn)(struct device *dev, void *data)) 33318c2ecf20Sopenharmony_ci{ 33328c2ecf20Sopenharmony_ci struct klist_iter i; 33338c2ecf20Sopenharmony_ci struct device *child; 33348c2ecf20Sopenharmony_ci int error = 0; 33358c2ecf20Sopenharmony_ci 33368c2ecf20Sopenharmony_ci if (!parent->p) 33378c2ecf20Sopenharmony_ci return 0; 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci klist_iter_init(&parent->p->klist_children, &i); 33408c2ecf20Sopenharmony_ci while ((child = prev_device(&i)) && !error) 33418c2ecf20Sopenharmony_ci error = fn(child, data); 33428c2ecf20Sopenharmony_ci klist_iter_exit(&i); 33438c2ecf20Sopenharmony_ci return error; 33448c2ecf20Sopenharmony_ci} 33458c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_for_each_child_reverse); 33468c2ecf20Sopenharmony_ci 33478c2ecf20Sopenharmony_ci/** 33488c2ecf20Sopenharmony_ci * device_find_child - device iterator for locating a particular device. 33498c2ecf20Sopenharmony_ci * @parent: parent struct device 33508c2ecf20Sopenharmony_ci * @match: Callback function to check device 33518c2ecf20Sopenharmony_ci * @data: Data to pass to match function 33528c2ecf20Sopenharmony_ci * 33538c2ecf20Sopenharmony_ci * This is similar to the device_for_each_child() function above, but it 33548c2ecf20Sopenharmony_ci * returns a reference to a device that is 'found' for later use, as 33558c2ecf20Sopenharmony_ci * determined by the @match callback. 33568c2ecf20Sopenharmony_ci * 33578c2ecf20Sopenharmony_ci * The callback should return 0 if the device doesn't match and non-zero 33588c2ecf20Sopenharmony_ci * if it does. If the callback returns non-zero and a reference to the 33598c2ecf20Sopenharmony_ci * current device can be obtained, this function will return to the caller 33608c2ecf20Sopenharmony_ci * and not iterate over any more devices. 33618c2ecf20Sopenharmony_ci * 33628c2ecf20Sopenharmony_ci * NOTE: you will need to drop the reference with put_device() after use. 33638c2ecf20Sopenharmony_ci */ 33648c2ecf20Sopenharmony_cistruct device *device_find_child(struct device *parent, void *data, 33658c2ecf20Sopenharmony_ci int (*match)(struct device *dev, void *data)) 33668c2ecf20Sopenharmony_ci{ 33678c2ecf20Sopenharmony_ci struct klist_iter i; 33688c2ecf20Sopenharmony_ci struct device *child; 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_ci if (!parent) 33718c2ecf20Sopenharmony_ci return NULL; 33728c2ecf20Sopenharmony_ci 33738c2ecf20Sopenharmony_ci klist_iter_init(&parent->p->klist_children, &i); 33748c2ecf20Sopenharmony_ci while ((child = next_device(&i))) 33758c2ecf20Sopenharmony_ci if (match(child, data) && get_device(child)) 33768c2ecf20Sopenharmony_ci break; 33778c2ecf20Sopenharmony_ci klist_iter_exit(&i); 33788c2ecf20Sopenharmony_ci return child; 33798c2ecf20Sopenharmony_ci} 33808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_find_child); 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_ci/** 33838c2ecf20Sopenharmony_ci * device_find_child_by_name - device iterator for locating a child device. 33848c2ecf20Sopenharmony_ci * @parent: parent struct device 33858c2ecf20Sopenharmony_ci * @name: name of the child device 33868c2ecf20Sopenharmony_ci * 33878c2ecf20Sopenharmony_ci * This is similar to the device_find_child() function above, but it 33888c2ecf20Sopenharmony_ci * returns a reference to a device that has the name @name. 33898c2ecf20Sopenharmony_ci * 33908c2ecf20Sopenharmony_ci * NOTE: you will need to drop the reference with put_device() after use. 33918c2ecf20Sopenharmony_ci */ 33928c2ecf20Sopenharmony_cistruct device *device_find_child_by_name(struct device *parent, 33938c2ecf20Sopenharmony_ci const char *name) 33948c2ecf20Sopenharmony_ci{ 33958c2ecf20Sopenharmony_ci struct klist_iter i; 33968c2ecf20Sopenharmony_ci struct device *child; 33978c2ecf20Sopenharmony_ci 33988c2ecf20Sopenharmony_ci if (!parent) 33998c2ecf20Sopenharmony_ci return NULL; 34008c2ecf20Sopenharmony_ci 34018c2ecf20Sopenharmony_ci klist_iter_init(&parent->p->klist_children, &i); 34028c2ecf20Sopenharmony_ci while ((child = next_device(&i))) 34038c2ecf20Sopenharmony_ci if (sysfs_streq(dev_name(child), name) && get_device(child)) 34048c2ecf20Sopenharmony_ci break; 34058c2ecf20Sopenharmony_ci klist_iter_exit(&i); 34068c2ecf20Sopenharmony_ci return child; 34078c2ecf20Sopenharmony_ci} 34088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_find_child_by_name); 34098c2ecf20Sopenharmony_ci 34108c2ecf20Sopenharmony_ciint __init devices_init(void) 34118c2ecf20Sopenharmony_ci{ 34128c2ecf20Sopenharmony_ci devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); 34138c2ecf20Sopenharmony_ci if (!devices_kset) 34148c2ecf20Sopenharmony_ci return -ENOMEM; 34158c2ecf20Sopenharmony_ci dev_kobj = kobject_create_and_add("dev", NULL); 34168c2ecf20Sopenharmony_ci if (!dev_kobj) 34178c2ecf20Sopenharmony_ci goto dev_kobj_err; 34188c2ecf20Sopenharmony_ci sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj); 34198c2ecf20Sopenharmony_ci if (!sysfs_dev_block_kobj) 34208c2ecf20Sopenharmony_ci goto block_kobj_err; 34218c2ecf20Sopenharmony_ci sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj); 34228c2ecf20Sopenharmony_ci if (!sysfs_dev_char_kobj) 34238c2ecf20Sopenharmony_ci goto char_kobj_err; 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_ci return 0; 34268c2ecf20Sopenharmony_ci 34278c2ecf20Sopenharmony_ci char_kobj_err: 34288c2ecf20Sopenharmony_ci kobject_put(sysfs_dev_block_kobj); 34298c2ecf20Sopenharmony_ci block_kobj_err: 34308c2ecf20Sopenharmony_ci kobject_put(dev_kobj); 34318c2ecf20Sopenharmony_ci dev_kobj_err: 34328c2ecf20Sopenharmony_ci kset_unregister(devices_kset); 34338c2ecf20Sopenharmony_ci return -ENOMEM; 34348c2ecf20Sopenharmony_ci} 34358c2ecf20Sopenharmony_ci 34368c2ecf20Sopenharmony_cistatic int device_check_offline(struct device *dev, void *not_used) 34378c2ecf20Sopenharmony_ci{ 34388c2ecf20Sopenharmony_ci int ret; 34398c2ecf20Sopenharmony_ci 34408c2ecf20Sopenharmony_ci ret = device_for_each_child(dev, NULL, device_check_offline); 34418c2ecf20Sopenharmony_ci if (ret) 34428c2ecf20Sopenharmony_ci return ret; 34438c2ecf20Sopenharmony_ci 34448c2ecf20Sopenharmony_ci return device_supports_offline(dev) && !dev->offline ? -EBUSY : 0; 34458c2ecf20Sopenharmony_ci} 34468c2ecf20Sopenharmony_ci 34478c2ecf20Sopenharmony_ci/** 34488c2ecf20Sopenharmony_ci * device_offline - Prepare the device for hot-removal. 34498c2ecf20Sopenharmony_ci * @dev: Device to be put offline. 34508c2ecf20Sopenharmony_ci * 34518c2ecf20Sopenharmony_ci * Execute the device bus type's .offline() callback, if present, to prepare 34528c2ecf20Sopenharmony_ci * the device for a subsequent hot-removal. If that succeeds, the device must 34538c2ecf20Sopenharmony_ci * not be used until either it is removed or its bus type's .online() callback 34548c2ecf20Sopenharmony_ci * is executed. 34558c2ecf20Sopenharmony_ci * 34568c2ecf20Sopenharmony_ci * Call under device_hotplug_lock. 34578c2ecf20Sopenharmony_ci */ 34588c2ecf20Sopenharmony_ciint device_offline(struct device *dev) 34598c2ecf20Sopenharmony_ci{ 34608c2ecf20Sopenharmony_ci int ret; 34618c2ecf20Sopenharmony_ci 34628c2ecf20Sopenharmony_ci if (dev->offline_disabled) 34638c2ecf20Sopenharmony_ci return -EPERM; 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci ret = device_for_each_child(dev, NULL, device_check_offline); 34668c2ecf20Sopenharmony_ci if (ret) 34678c2ecf20Sopenharmony_ci return ret; 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci device_lock(dev); 34708c2ecf20Sopenharmony_ci if (device_supports_offline(dev)) { 34718c2ecf20Sopenharmony_ci if (dev->offline) { 34728c2ecf20Sopenharmony_ci ret = 1; 34738c2ecf20Sopenharmony_ci } else { 34748c2ecf20Sopenharmony_ci ret = dev->bus->offline(dev); 34758c2ecf20Sopenharmony_ci if (!ret) { 34768c2ecf20Sopenharmony_ci kobject_uevent(&dev->kobj, KOBJ_OFFLINE); 34778c2ecf20Sopenharmony_ci dev->offline = true; 34788c2ecf20Sopenharmony_ci } 34798c2ecf20Sopenharmony_ci } 34808c2ecf20Sopenharmony_ci } 34818c2ecf20Sopenharmony_ci device_unlock(dev); 34828c2ecf20Sopenharmony_ci 34838c2ecf20Sopenharmony_ci return ret; 34848c2ecf20Sopenharmony_ci} 34858c2ecf20Sopenharmony_ci 34868c2ecf20Sopenharmony_ci/** 34878c2ecf20Sopenharmony_ci * device_online - Put the device back online after successful device_offline(). 34888c2ecf20Sopenharmony_ci * @dev: Device to be put back online. 34898c2ecf20Sopenharmony_ci * 34908c2ecf20Sopenharmony_ci * If device_offline() has been successfully executed for @dev, but the device 34918c2ecf20Sopenharmony_ci * has not been removed subsequently, execute its bus type's .online() callback 34928c2ecf20Sopenharmony_ci * to indicate that the device can be used again. 34938c2ecf20Sopenharmony_ci * 34948c2ecf20Sopenharmony_ci * Call under device_hotplug_lock. 34958c2ecf20Sopenharmony_ci */ 34968c2ecf20Sopenharmony_ciint device_online(struct device *dev) 34978c2ecf20Sopenharmony_ci{ 34988c2ecf20Sopenharmony_ci int ret = 0; 34998c2ecf20Sopenharmony_ci 35008c2ecf20Sopenharmony_ci device_lock(dev); 35018c2ecf20Sopenharmony_ci if (device_supports_offline(dev)) { 35028c2ecf20Sopenharmony_ci if (dev->offline) { 35038c2ecf20Sopenharmony_ci ret = dev->bus->online(dev); 35048c2ecf20Sopenharmony_ci if (!ret) { 35058c2ecf20Sopenharmony_ci kobject_uevent(&dev->kobj, KOBJ_ONLINE); 35068c2ecf20Sopenharmony_ci dev->offline = false; 35078c2ecf20Sopenharmony_ci } 35088c2ecf20Sopenharmony_ci } else { 35098c2ecf20Sopenharmony_ci ret = 1; 35108c2ecf20Sopenharmony_ci } 35118c2ecf20Sopenharmony_ci } 35128c2ecf20Sopenharmony_ci device_unlock(dev); 35138c2ecf20Sopenharmony_ci 35148c2ecf20Sopenharmony_ci return ret; 35158c2ecf20Sopenharmony_ci} 35168c2ecf20Sopenharmony_ci 35178c2ecf20Sopenharmony_cistruct root_device { 35188c2ecf20Sopenharmony_ci struct device dev; 35198c2ecf20Sopenharmony_ci struct module *owner; 35208c2ecf20Sopenharmony_ci}; 35218c2ecf20Sopenharmony_ci 35228c2ecf20Sopenharmony_cistatic inline struct root_device *to_root_device(struct device *d) 35238c2ecf20Sopenharmony_ci{ 35248c2ecf20Sopenharmony_ci return container_of(d, struct root_device, dev); 35258c2ecf20Sopenharmony_ci} 35268c2ecf20Sopenharmony_ci 35278c2ecf20Sopenharmony_cistatic void root_device_release(struct device *dev) 35288c2ecf20Sopenharmony_ci{ 35298c2ecf20Sopenharmony_ci kfree(to_root_device(dev)); 35308c2ecf20Sopenharmony_ci} 35318c2ecf20Sopenharmony_ci 35328c2ecf20Sopenharmony_ci/** 35338c2ecf20Sopenharmony_ci * __root_device_register - allocate and register a root device 35348c2ecf20Sopenharmony_ci * @name: root device name 35358c2ecf20Sopenharmony_ci * @owner: owner module of the root device, usually THIS_MODULE 35368c2ecf20Sopenharmony_ci * 35378c2ecf20Sopenharmony_ci * This function allocates a root device and registers it 35388c2ecf20Sopenharmony_ci * using device_register(). In order to free the returned 35398c2ecf20Sopenharmony_ci * device, use root_device_unregister(). 35408c2ecf20Sopenharmony_ci * 35418c2ecf20Sopenharmony_ci * Root devices are dummy devices which allow other devices 35428c2ecf20Sopenharmony_ci * to be grouped under /sys/devices. Use this function to 35438c2ecf20Sopenharmony_ci * allocate a root device and then use it as the parent of 35448c2ecf20Sopenharmony_ci * any device which should appear under /sys/devices/{name} 35458c2ecf20Sopenharmony_ci * 35468c2ecf20Sopenharmony_ci * The /sys/devices/{name} directory will also contain a 35478c2ecf20Sopenharmony_ci * 'module' symlink which points to the @owner directory 35488c2ecf20Sopenharmony_ci * in sysfs. 35498c2ecf20Sopenharmony_ci * 35508c2ecf20Sopenharmony_ci * Returns &struct device pointer on success, or ERR_PTR() on error. 35518c2ecf20Sopenharmony_ci * 35528c2ecf20Sopenharmony_ci * Note: You probably want to use root_device_register(). 35538c2ecf20Sopenharmony_ci */ 35548c2ecf20Sopenharmony_cistruct device *__root_device_register(const char *name, struct module *owner) 35558c2ecf20Sopenharmony_ci{ 35568c2ecf20Sopenharmony_ci struct root_device *root; 35578c2ecf20Sopenharmony_ci int err = -ENOMEM; 35588c2ecf20Sopenharmony_ci 35598c2ecf20Sopenharmony_ci root = kzalloc(sizeof(struct root_device), GFP_KERNEL); 35608c2ecf20Sopenharmony_ci if (!root) 35618c2ecf20Sopenharmony_ci return ERR_PTR(err); 35628c2ecf20Sopenharmony_ci 35638c2ecf20Sopenharmony_ci err = dev_set_name(&root->dev, "%s", name); 35648c2ecf20Sopenharmony_ci if (err) { 35658c2ecf20Sopenharmony_ci kfree(root); 35668c2ecf20Sopenharmony_ci return ERR_PTR(err); 35678c2ecf20Sopenharmony_ci } 35688c2ecf20Sopenharmony_ci 35698c2ecf20Sopenharmony_ci root->dev.release = root_device_release; 35708c2ecf20Sopenharmony_ci 35718c2ecf20Sopenharmony_ci err = device_register(&root->dev); 35728c2ecf20Sopenharmony_ci if (err) { 35738c2ecf20Sopenharmony_ci put_device(&root->dev); 35748c2ecf20Sopenharmony_ci return ERR_PTR(err); 35758c2ecf20Sopenharmony_ci } 35768c2ecf20Sopenharmony_ci 35778c2ecf20Sopenharmony_ci#ifdef CONFIG_MODULES /* gotta find a "cleaner" way to do this */ 35788c2ecf20Sopenharmony_ci if (owner) { 35798c2ecf20Sopenharmony_ci struct module_kobject *mk = &owner->mkobj; 35808c2ecf20Sopenharmony_ci 35818c2ecf20Sopenharmony_ci err = sysfs_create_link(&root->dev.kobj, &mk->kobj, "module"); 35828c2ecf20Sopenharmony_ci if (err) { 35838c2ecf20Sopenharmony_ci device_unregister(&root->dev); 35848c2ecf20Sopenharmony_ci return ERR_PTR(err); 35858c2ecf20Sopenharmony_ci } 35868c2ecf20Sopenharmony_ci root->owner = owner; 35878c2ecf20Sopenharmony_ci } 35888c2ecf20Sopenharmony_ci#endif 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_ci return &root->dev; 35918c2ecf20Sopenharmony_ci} 35928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__root_device_register); 35938c2ecf20Sopenharmony_ci 35948c2ecf20Sopenharmony_ci/** 35958c2ecf20Sopenharmony_ci * root_device_unregister - unregister and free a root device 35968c2ecf20Sopenharmony_ci * @dev: device going away 35978c2ecf20Sopenharmony_ci * 35988c2ecf20Sopenharmony_ci * This function unregisters and cleans up a device that was created by 35998c2ecf20Sopenharmony_ci * root_device_register(). 36008c2ecf20Sopenharmony_ci */ 36018c2ecf20Sopenharmony_civoid root_device_unregister(struct device *dev) 36028c2ecf20Sopenharmony_ci{ 36038c2ecf20Sopenharmony_ci struct root_device *root = to_root_device(dev); 36048c2ecf20Sopenharmony_ci 36058c2ecf20Sopenharmony_ci if (root->owner) 36068c2ecf20Sopenharmony_ci sysfs_remove_link(&root->dev.kobj, "module"); 36078c2ecf20Sopenharmony_ci 36088c2ecf20Sopenharmony_ci device_unregister(dev); 36098c2ecf20Sopenharmony_ci} 36108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(root_device_unregister); 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_ci 36138c2ecf20Sopenharmony_cistatic void device_create_release(struct device *dev) 36148c2ecf20Sopenharmony_ci{ 36158c2ecf20Sopenharmony_ci pr_debug("device: '%s': %s\n", dev_name(dev), __func__); 36168c2ecf20Sopenharmony_ci kfree(dev); 36178c2ecf20Sopenharmony_ci} 36188c2ecf20Sopenharmony_ci 36198c2ecf20Sopenharmony_cistatic __printf(6, 0) struct device * 36208c2ecf20Sopenharmony_cidevice_create_groups_vargs(struct class *class, struct device *parent, 36218c2ecf20Sopenharmony_ci dev_t devt, void *drvdata, 36228c2ecf20Sopenharmony_ci const struct attribute_group **groups, 36238c2ecf20Sopenharmony_ci const char *fmt, va_list args) 36248c2ecf20Sopenharmony_ci{ 36258c2ecf20Sopenharmony_ci struct device *dev = NULL; 36268c2ecf20Sopenharmony_ci int retval = -ENODEV; 36278c2ecf20Sopenharmony_ci 36288c2ecf20Sopenharmony_ci if (class == NULL || IS_ERR(class)) 36298c2ecf20Sopenharmony_ci goto error; 36308c2ecf20Sopenharmony_ci 36318c2ecf20Sopenharmony_ci dev = kzalloc(sizeof(*dev), GFP_KERNEL); 36328c2ecf20Sopenharmony_ci if (!dev) { 36338c2ecf20Sopenharmony_ci retval = -ENOMEM; 36348c2ecf20Sopenharmony_ci goto error; 36358c2ecf20Sopenharmony_ci } 36368c2ecf20Sopenharmony_ci 36378c2ecf20Sopenharmony_ci device_initialize(dev); 36388c2ecf20Sopenharmony_ci dev->devt = devt; 36398c2ecf20Sopenharmony_ci dev->class = class; 36408c2ecf20Sopenharmony_ci dev->parent = parent; 36418c2ecf20Sopenharmony_ci dev->groups = groups; 36428c2ecf20Sopenharmony_ci dev->release = device_create_release; 36438c2ecf20Sopenharmony_ci dev_set_drvdata(dev, drvdata); 36448c2ecf20Sopenharmony_ci 36458c2ecf20Sopenharmony_ci retval = kobject_set_name_vargs(&dev->kobj, fmt, args); 36468c2ecf20Sopenharmony_ci if (retval) 36478c2ecf20Sopenharmony_ci goto error; 36488c2ecf20Sopenharmony_ci 36498c2ecf20Sopenharmony_ci retval = device_add(dev); 36508c2ecf20Sopenharmony_ci if (retval) 36518c2ecf20Sopenharmony_ci goto error; 36528c2ecf20Sopenharmony_ci 36538c2ecf20Sopenharmony_ci return dev; 36548c2ecf20Sopenharmony_ci 36558c2ecf20Sopenharmony_cierror: 36568c2ecf20Sopenharmony_ci put_device(dev); 36578c2ecf20Sopenharmony_ci return ERR_PTR(retval); 36588c2ecf20Sopenharmony_ci} 36598c2ecf20Sopenharmony_ci 36608c2ecf20Sopenharmony_ci/** 36618c2ecf20Sopenharmony_ci * device_create - creates a device and registers it with sysfs 36628c2ecf20Sopenharmony_ci * @class: pointer to the struct class that this device should be registered to 36638c2ecf20Sopenharmony_ci * @parent: pointer to the parent struct device of this new device, if any 36648c2ecf20Sopenharmony_ci * @devt: the dev_t for the char device to be added 36658c2ecf20Sopenharmony_ci * @drvdata: the data to be added to the device for callbacks 36668c2ecf20Sopenharmony_ci * @fmt: string for the device's name 36678c2ecf20Sopenharmony_ci * 36688c2ecf20Sopenharmony_ci * This function can be used by char device classes. A struct device 36698c2ecf20Sopenharmony_ci * will be created in sysfs, registered to the specified class. 36708c2ecf20Sopenharmony_ci * 36718c2ecf20Sopenharmony_ci * A "dev" file will be created, showing the dev_t for the device, if 36728c2ecf20Sopenharmony_ci * the dev_t is not 0,0. 36738c2ecf20Sopenharmony_ci * If a pointer to a parent struct device is passed in, the newly created 36748c2ecf20Sopenharmony_ci * struct device will be a child of that device in sysfs. 36758c2ecf20Sopenharmony_ci * The pointer to the struct device will be returned from the call. 36768c2ecf20Sopenharmony_ci * Any further sysfs files that might be required can be created using this 36778c2ecf20Sopenharmony_ci * pointer. 36788c2ecf20Sopenharmony_ci * 36798c2ecf20Sopenharmony_ci * Returns &struct device pointer on success, or ERR_PTR() on error. 36808c2ecf20Sopenharmony_ci * 36818c2ecf20Sopenharmony_ci * Note: the struct class passed to this function must have previously 36828c2ecf20Sopenharmony_ci * been created with a call to class_create(). 36838c2ecf20Sopenharmony_ci */ 36848c2ecf20Sopenharmony_cistruct device *device_create(struct class *class, struct device *parent, 36858c2ecf20Sopenharmony_ci dev_t devt, void *drvdata, const char *fmt, ...) 36868c2ecf20Sopenharmony_ci{ 36878c2ecf20Sopenharmony_ci va_list vargs; 36888c2ecf20Sopenharmony_ci struct device *dev; 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_ci va_start(vargs, fmt); 36918c2ecf20Sopenharmony_ci dev = device_create_groups_vargs(class, parent, devt, drvdata, NULL, 36928c2ecf20Sopenharmony_ci fmt, vargs); 36938c2ecf20Sopenharmony_ci va_end(vargs); 36948c2ecf20Sopenharmony_ci return dev; 36958c2ecf20Sopenharmony_ci} 36968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_create); 36978c2ecf20Sopenharmony_ci 36988c2ecf20Sopenharmony_ci/** 36998c2ecf20Sopenharmony_ci * device_create_with_groups - creates a device and registers it with sysfs 37008c2ecf20Sopenharmony_ci * @class: pointer to the struct class that this device should be registered to 37018c2ecf20Sopenharmony_ci * @parent: pointer to the parent struct device of this new device, if any 37028c2ecf20Sopenharmony_ci * @devt: the dev_t for the char device to be added 37038c2ecf20Sopenharmony_ci * @drvdata: the data to be added to the device for callbacks 37048c2ecf20Sopenharmony_ci * @groups: NULL-terminated list of attribute groups to be created 37058c2ecf20Sopenharmony_ci * @fmt: string for the device's name 37068c2ecf20Sopenharmony_ci * 37078c2ecf20Sopenharmony_ci * This function can be used by char device classes. A struct device 37088c2ecf20Sopenharmony_ci * will be created in sysfs, registered to the specified class. 37098c2ecf20Sopenharmony_ci * Additional attributes specified in the groups parameter will also 37108c2ecf20Sopenharmony_ci * be created automatically. 37118c2ecf20Sopenharmony_ci * 37128c2ecf20Sopenharmony_ci * A "dev" file will be created, showing the dev_t for the device, if 37138c2ecf20Sopenharmony_ci * the dev_t is not 0,0. 37148c2ecf20Sopenharmony_ci * If a pointer to a parent struct device is passed in, the newly created 37158c2ecf20Sopenharmony_ci * struct device will be a child of that device in sysfs. 37168c2ecf20Sopenharmony_ci * The pointer to the struct device will be returned from the call. 37178c2ecf20Sopenharmony_ci * Any further sysfs files that might be required can be created using this 37188c2ecf20Sopenharmony_ci * pointer. 37198c2ecf20Sopenharmony_ci * 37208c2ecf20Sopenharmony_ci * Returns &struct device pointer on success, or ERR_PTR() on error. 37218c2ecf20Sopenharmony_ci * 37228c2ecf20Sopenharmony_ci * Note: the struct class passed to this function must have previously 37238c2ecf20Sopenharmony_ci * been created with a call to class_create(). 37248c2ecf20Sopenharmony_ci */ 37258c2ecf20Sopenharmony_cistruct device *device_create_with_groups(struct class *class, 37268c2ecf20Sopenharmony_ci struct device *parent, dev_t devt, 37278c2ecf20Sopenharmony_ci void *drvdata, 37288c2ecf20Sopenharmony_ci const struct attribute_group **groups, 37298c2ecf20Sopenharmony_ci const char *fmt, ...) 37308c2ecf20Sopenharmony_ci{ 37318c2ecf20Sopenharmony_ci va_list vargs; 37328c2ecf20Sopenharmony_ci struct device *dev; 37338c2ecf20Sopenharmony_ci 37348c2ecf20Sopenharmony_ci va_start(vargs, fmt); 37358c2ecf20Sopenharmony_ci dev = device_create_groups_vargs(class, parent, devt, drvdata, groups, 37368c2ecf20Sopenharmony_ci fmt, vargs); 37378c2ecf20Sopenharmony_ci va_end(vargs); 37388c2ecf20Sopenharmony_ci return dev; 37398c2ecf20Sopenharmony_ci} 37408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_create_with_groups); 37418c2ecf20Sopenharmony_ci 37428c2ecf20Sopenharmony_ci/** 37438c2ecf20Sopenharmony_ci * device_destroy - removes a device that was created with device_create() 37448c2ecf20Sopenharmony_ci * @class: pointer to the struct class that this device was registered with 37458c2ecf20Sopenharmony_ci * @devt: the dev_t of the device that was previously registered 37468c2ecf20Sopenharmony_ci * 37478c2ecf20Sopenharmony_ci * This call unregisters and cleans up a device that was created with a 37488c2ecf20Sopenharmony_ci * call to device_create(). 37498c2ecf20Sopenharmony_ci */ 37508c2ecf20Sopenharmony_civoid device_destroy(struct class *class, dev_t devt) 37518c2ecf20Sopenharmony_ci{ 37528c2ecf20Sopenharmony_ci struct device *dev; 37538c2ecf20Sopenharmony_ci 37548c2ecf20Sopenharmony_ci dev = class_find_device_by_devt(class, devt); 37558c2ecf20Sopenharmony_ci if (dev) { 37568c2ecf20Sopenharmony_ci put_device(dev); 37578c2ecf20Sopenharmony_ci device_unregister(dev); 37588c2ecf20Sopenharmony_ci } 37598c2ecf20Sopenharmony_ci} 37608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_destroy); 37618c2ecf20Sopenharmony_ci 37628c2ecf20Sopenharmony_ci/** 37638c2ecf20Sopenharmony_ci * device_rename - renames a device 37648c2ecf20Sopenharmony_ci * @dev: the pointer to the struct device to be renamed 37658c2ecf20Sopenharmony_ci * @new_name: the new name of the device 37668c2ecf20Sopenharmony_ci * 37678c2ecf20Sopenharmony_ci * It is the responsibility of the caller to provide mutual 37688c2ecf20Sopenharmony_ci * exclusion between two different calls of device_rename 37698c2ecf20Sopenharmony_ci * on the same device to ensure that new_name is valid and 37708c2ecf20Sopenharmony_ci * won't conflict with other devices. 37718c2ecf20Sopenharmony_ci * 37728c2ecf20Sopenharmony_ci * Note: Don't call this function. Currently, the networking layer calls this 37738c2ecf20Sopenharmony_ci * function, but that will change. The following text from Kay Sievers offers 37748c2ecf20Sopenharmony_ci * some insight: 37758c2ecf20Sopenharmony_ci * 37768c2ecf20Sopenharmony_ci * Renaming devices is racy at many levels, symlinks and other stuff are not 37778c2ecf20Sopenharmony_ci * replaced atomically, and you get a "move" uevent, but it's not easy to 37788c2ecf20Sopenharmony_ci * connect the event to the old and new device. Device nodes are not renamed at 37798c2ecf20Sopenharmony_ci * all, there isn't even support for that in the kernel now. 37808c2ecf20Sopenharmony_ci * 37818c2ecf20Sopenharmony_ci * In the meantime, during renaming, your target name might be taken by another 37828c2ecf20Sopenharmony_ci * driver, creating conflicts. Or the old name is taken directly after you 37838c2ecf20Sopenharmony_ci * renamed it -- then you get events for the same DEVPATH, before you even see 37848c2ecf20Sopenharmony_ci * the "move" event. It's just a mess, and nothing new should ever rely on 37858c2ecf20Sopenharmony_ci * kernel device renaming. Besides that, it's not even implemented now for 37868c2ecf20Sopenharmony_ci * other things than (driver-core wise very simple) network devices. 37878c2ecf20Sopenharmony_ci * 37888c2ecf20Sopenharmony_ci * We are currently about to change network renaming in udev to completely 37898c2ecf20Sopenharmony_ci * disallow renaming of devices in the same namespace as the kernel uses, 37908c2ecf20Sopenharmony_ci * because we can't solve the problems properly, that arise with swapping names 37918c2ecf20Sopenharmony_ci * of multiple interfaces without races. Means, renaming of eth[0-9]* will only 37928c2ecf20Sopenharmony_ci * be allowed to some other name than eth[0-9]*, for the aforementioned 37938c2ecf20Sopenharmony_ci * reasons. 37948c2ecf20Sopenharmony_ci * 37958c2ecf20Sopenharmony_ci * Make up a "real" name in the driver before you register anything, or add 37968c2ecf20Sopenharmony_ci * some other attributes for userspace to find the device, or use udev to add 37978c2ecf20Sopenharmony_ci * symlinks -- but never rename kernel devices later, it's a complete mess. We 37988c2ecf20Sopenharmony_ci * don't even want to get into that and try to implement the missing pieces in 37998c2ecf20Sopenharmony_ci * the core. We really have other pieces to fix in the driver core mess. :) 38008c2ecf20Sopenharmony_ci */ 38018c2ecf20Sopenharmony_ciint device_rename(struct device *dev, const char *new_name) 38028c2ecf20Sopenharmony_ci{ 38038c2ecf20Sopenharmony_ci struct kobject *kobj = &dev->kobj; 38048c2ecf20Sopenharmony_ci char *old_device_name = NULL; 38058c2ecf20Sopenharmony_ci int error; 38068c2ecf20Sopenharmony_ci 38078c2ecf20Sopenharmony_ci dev = get_device(dev); 38088c2ecf20Sopenharmony_ci if (!dev) 38098c2ecf20Sopenharmony_ci return -EINVAL; 38108c2ecf20Sopenharmony_ci 38118c2ecf20Sopenharmony_ci dev_dbg(dev, "renaming to %s\n", new_name); 38128c2ecf20Sopenharmony_ci 38138c2ecf20Sopenharmony_ci old_device_name = kstrdup(dev_name(dev), GFP_KERNEL); 38148c2ecf20Sopenharmony_ci if (!old_device_name) { 38158c2ecf20Sopenharmony_ci error = -ENOMEM; 38168c2ecf20Sopenharmony_ci goto out; 38178c2ecf20Sopenharmony_ci } 38188c2ecf20Sopenharmony_ci 38198c2ecf20Sopenharmony_ci if (dev->class) { 38208c2ecf20Sopenharmony_ci error = sysfs_rename_link_ns(&dev->class->p->subsys.kobj, 38218c2ecf20Sopenharmony_ci kobj, old_device_name, 38228c2ecf20Sopenharmony_ci new_name, kobject_namespace(kobj)); 38238c2ecf20Sopenharmony_ci if (error) 38248c2ecf20Sopenharmony_ci goto out; 38258c2ecf20Sopenharmony_ci } 38268c2ecf20Sopenharmony_ci 38278c2ecf20Sopenharmony_ci error = kobject_rename(kobj, new_name); 38288c2ecf20Sopenharmony_ci if (error) 38298c2ecf20Sopenharmony_ci goto out; 38308c2ecf20Sopenharmony_ci 38318c2ecf20Sopenharmony_ciout: 38328c2ecf20Sopenharmony_ci put_device(dev); 38338c2ecf20Sopenharmony_ci 38348c2ecf20Sopenharmony_ci kfree(old_device_name); 38358c2ecf20Sopenharmony_ci 38368c2ecf20Sopenharmony_ci return error; 38378c2ecf20Sopenharmony_ci} 38388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_rename); 38398c2ecf20Sopenharmony_ci 38408c2ecf20Sopenharmony_cistatic int device_move_class_links(struct device *dev, 38418c2ecf20Sopenharmony_ci struct device *old_parent, 38428c2ecf20Sopenharmony_ci struct device *new_parent) 38438c2ecf20Sopenharmony_ci{ 38448c2ecf20Sopenharmony_ci int error = 0; 38458c2ecf20Sopenharmony_ci 38468c2ecf20Sopenharmony_ci if (old_parent) 38478c2ecf20Sopenharmony_ci sysfs_remove_link(&dev->kobj, "device"); 38488c2ecf20Sopenharmony_ci if (new_parent) 38498c2ecf20Sopenharmony_ci error = sysfs_create_link(&dev->kobj, &new_parent->kobj, 38508c2ecf20Sopenharmony_ci "device"); 38518c2ecf20Sopenharmony_ci return error; 38528c2ecf20Sopenharmony_ci} 38538c2ecf20Sopenharmony_ci 38548c2ecf20Sopenharmony_ci/** 38558c2ecf20Sopenharmony_ci * device_move - moves a device to a new parent 38568c2ecf20Sopenharmony_ci * @dev: the pointer to the struct device to be moved 38578c2ecf20Sopenharmony_ci * @new_parent: the new parent of the device (can be NULL) 38588c2ecf20Sopenharmony_ci * @dpm_order: how to reorder the dpm_list 38598c2ecf20Sopenharmony_ci */ 38608c2ecf20Sopenharmony_ciint device_move(struct device *dev, struct device *new_parent, 38618c2ecf20Sopenharmony_ci enum dpm_order dpm_order) 38628c2ecf20Sopenharmony_ci{ 38638c2ecf20Sopenharmony_ci int error; 38648c2ecf20Sopenharmony_ci struct device *old_parent; 38658c2ecf20Sopenharmony_ci struct kobject *new_parent_kobj; 38668c2ecf20Sopenharmony_ci 38678c2ecf20Sopenharmony_ci dev = get_device(dev); 38688c2ecf20Sopenharmony_ci if (!dev) 38698c2ecf20Sopenharmony_ci return -EINVAL; 38708c2ecf20Sopenharmony_ci 38718c2ecf20Sopenharmony_ci device_pm_lock(); 38728c2ecf20Sopenharmony_ci new_parent = get_device(new_parent); 38738c2ecf20Sopenharmony_ci new_parent_kobj = get_device_parent(dev, new_parent); 38748c2ecf20Sopenharmony_ci if (IS_ERR(new_parent_kobj)) { 38758c2ecf20Sopenharmony_ci error = PTR_ERR(new_parent_kobj); 38768c2ecf20Sopenharmony_ci put_device(new_parent); 38778c2ecf20Sopenharmony_ci goto out; 38788c2ecf20Sopenharmony_ci } 38798c2ecf20Sopenharmony_ci 38808c2ecf20Sopenharmony_ci pr_debug("device: '%s': %s: moving to '%s'\n", dev_name(dev), 38818c2ecf20Sopenharmony_ci __func__, new_parent ? dev_name(new_parent) : "<NULL>"); 38828c2ecf20Sopenharmony_ci error = kobject_move(&dev->kobj, new_parent_kobj); 38838c2ecf20Sopenharmony_ci if (error) { 38848c2ecf20Sopenharmony_ci cleanup_glue_dir(dev, new_parent_kobj); 38858c2ecf20Sopenharmony_ci put_device(new_parent); 38868c2ecf20Sopenharmony_ci goto out; 38878c2ecf20Sopenharmony_ci } 38888c2ecf20Sopenharmony_ci old_parent = dev->parent; 38898c2ecf20Sopenharmony_ci dev->parent = new_parent; 38908c2ecf20Sopenharmony_ci if (old_parent) 38918c2ecf20Sopenharmony_ci klist_remove(&dev->p->knode_parent); 38928c2ecf20Sopenharmony_ci if (new_parent) { 38938c2ecf20Sopenharmony_ci klist_add_tail(&dev->p->knode_parent, 38948c2ecf20Sopenharmony_ci &new_parent->p->klist_children); 38958c2ecf20Sopenharmony_ci set_dev_node(dev, dev_to_node(new_parent)); 38968c2ecf20Sopenharmony_ci } 38978c2ecf20Sopenharmony_ci 38988c2ecf20Sopenharmony_ci if (dev->class) { 38998c2ecf20Sopenharmony_ci error = device_move_class_links(dev, old_parent, new_parent); 39008c2ecf20Sopenharmony_ci if (error) { 39018c2ecf20Sopenharmony_ci /* We ignore errors on cleanup since we're hosed anyway... */ 39028c2ecf20Sopenharmony_ci device_move_class_links(dev, new_parent, old_parent); 39038c2ecf20Sopenharmony_ci if (!kobject_move(&dev->kobj, &old_parent->kobj)) { 39048c2ecf20Sopenharmony_ci if (new_parent) 39058c2ecf20Sopenharmony_ci klist_remove(&dev->p->knode_parent); 39068c2ecf20Sopenharmony_ci dev->parent = old_parent; 39078c2ecf20Sopenharmony_ci if (old_parent) { 39088c2ecf20Sopenharmony_ci klist_add_tail(&dev->p->knode_parent, 39098c2ecf20Sopenharmony_ci &old_parent->p->klist_children); 39108c2ecf20Sopenharmony_ci set_dev_node(dev, dev_to_node(old_parent)); 39118c2ecf20Sopenharmony_ci } 39128c2ecf20Sopenharmony_ci } 39138c2ecf20Sopenharmony_ci cleanup_glue_dir(dev, new_parent_kobj); 39148c2ecf20Sopenharmony_ci put_device(new_parent); 39158c2ecf20Sopenharmony_ci goto out; 39168c2ecf20Sopenharmony_ci } 39178c2ecf20Sopenharmony_ci } 39188c2ecf20Sopenharmony_ci switch (dpm_order) { 39198c2ecf20Sopenharmony_ci case DPM_ORDER_NONE: 39208c2ecf20Sopenharmony_ci break; 39218c2ecf20Sopenharmony_ci case DPM_ORDER_DEV_AFTER_PARENT: 39228c2ecf20Sopenharmony_ci device_pm_move_after(dev, new_parent); 39238c2ecf20Sopenharmony_ci devices_kset_move_after(dev, new_parent); 39248c2ecf20Sopenharmony_ci break; 39258c2ecf20Sopenharmony_ci case DPM_ORDER_PARENT_BEFORE_DEV: 39268c2ecf20Sopenharmony_ci device_pm_move_before(new_parent, dev); 39278c2ecf20Sopenharmony_ci devices_kset_move_before(new_parent, dev); 39288c2ecf20Sopenharmony_ci break; 39298c2ecf20Sopenharmony_ci case DPM_ORDER_DEV_LAST: 39308c2ecf20Sopenharmony_ci device_pm_move_last(dev); 39318c2ecf20Sopenharmony_ci devices_kset_move_last(dev); 39328c2ecf20Sopenharmony_ci break; 39338c2ecf20Sopenharmony_ci } 39348c2ecf20Sopenharmony_ci 39358c2ecf20Sopenharmony_ci put_device(old_parent); 39368c2ecf20Sopenharmony_ciout: 39378c2ecf20Sopenharmony_ci device_pm_unlock(); 39388c2ecf20Sopenharmony_ci put_device(dev); 39398c2ecf20Sopenharmony_ci return error; 39408c2ecf20Sopenharmony_ci} 39418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_move); 39428c2ecf20Sopenharmony_ci 39438c2ecf20Sopenharmony_cistatic int device_attrs_change_owner(struct device *dev, kuid_t kuid, 39448c2ecf20Sopenharmony_ci kgid_t kgid) 39458c2ecf20Sopenharmony_ci{ 39468c2ecf20Sopenharmony_ci struct kobject *kobj = &dev->kobj; 39478c2ecf20Sopenharmony_ci struct class *class = dev->class; 39488c2ecf20Sopenharmony_ci const struct device_type *type = dev->type; 39498c2ecf20Sopenharmony_ci int error; 39508c2ecf20Sopenharmony_ci 39518c2ecf20Sopenharmony_ci if (class) { 39528c2ecf20Sopenharmony_ci /* 39538c2ecf20Sopenharmony_ci * Change the device groups of the device class for @dev to 39548c2ecf20Sopenharmony_ci * @kuid/@kgid. 39558c2ecf20Sopenharmony_ci */ 39568c2ecf20Sopenharmony_ci error = sysfs_groups_change_owner(kobj, class->dev_groups, kuid, 39578c2ecf20Sopenharmony_ci kgid); 39588c2ecf20Sopenharmony_ci if (error) 39598c2ecf20Sopenharmony_ci return error; 39608c2ecf20Sopenharmony_ci } 39618c2ecf20Sopenharmony_ci 39628c2ecf20Sopenharmony_ci if (type) { 39638c2ecf20Sopenharmony_ci /* 39648c2ecf20Sopenharmony_ci * Change the device groups of the device type for @dev to 39658c2ecf20Sopenharmony_ci * @kuid/@kgid. 39668c2ecf20Sopenharmony_ci */ 39678c2ecf20Sopenharmony_ci error = sysfs_groups_change_owner(kobj, type->groups, kuid, 39688c2ecf20Sopenharmony_ci kgid); 39698c2ecf20Sopenharmony_ci if (error) 39708c2ecf20Sopenharmony_ci return error; 39718c2ecf20Sopenharmony_ci } 39728c2ecf20Sopenharmony_ci 39738c2ecf20Sopenharmony_ci /* Change the device groups of @dev to @kuid/@kgid. */ 39748c2ecf20Sopenharmony_ci error = sysfs_groups_change_owner(kobj, dev->groups, kuid, kgid); 39758c2ecf20Sopenharmony_ci if (error) 39768c2ecf20Sopenharmony_ci return error; 39778c2ecf20Sopenharmony_ci 39788c2ecf20Sopenharmony_ci if (device_supports_offline(dev) && !dev->offline_disabled) { 39798c2ecf20Sopenharmony_ci /* Change online device attributes of @dev to @kuid/@kgid. */ 39808c2ecf20Sopenharmony_ci error = sysfs_file_change_owner(kobj, dev_attr_online.attr.name, 39818c2ecf20Sopenharmony_ci kuid, kgid); 39828c2ecf20Sopenharmony_ci if (error) 39838c2ecf20Sopenharmony_ci return error; 39848c2ecf20Sopenharmony_ci } 39858c2ecf20Sopenharmony_ci 39868c2ecf20Sopenharmony_ci return 0; 39878c2ecf20Sopenharmony_ci} 39888c2ecf20Sopenharmony_ci 39898c2ecf20Sopenharmony_ci/** 39908c2ecf20Sopenharmony_ci * device_change_owner - change the owner of an existing device. 39918c2ecf20Sopenharmony_ci * @dev: device. 39928c2ecf20Sopenharmony_ci * @kuid: new owner's kuid 39938c2ecf20Sopenharmony_ci * @kgid: new owner's kgid 39948c2ecf20Sopenharmony_ci * 39958c2ecf20Sopenharmony_ci * This changes the owner of @dev and its corresponding sysfs entries to 39968c2ecf20Sopenharmony_ci * @kuid/@kgid. This function closely mirrors how @dev was added via driver 39978c2ecf20Sopenharmony_ci * core. 39988c2ecf20Sopenharmony_ci * 39998c2ecf20Sopenharmony_ci * Returns 0 on success or error code on failure. 40008c2ecf20Sopenharmony_ci */ 40018c2ecf20Sopenharmony_ciint device_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid) 40028c2ecf20Sopenharmony_ci{ 40038c2ecf20Sopenharmony_ci int error; 40048c2ecf20Sopenharmony_ci struct kobject *kobj = &dev->kobj; 40058c2ecf20Sopenharmony_ci 40068c2ecf20Sopenharmony_ci dev = get_device(dev); 40078c2ecf20Sopenharmony_ci if (!dev) 40088c2ecf20Sopenharmony_ci return -EINVAL; 40098c2ecf20Sopenharmony_ci 40108c2ecf20Sopenharmony_ci /* 40118c2ecf20Sopenharmony_ci * Change the kobject and the default attributes and groups of the 40128c2ecf20Sopenharmony_ci * ktype associated with it to @kuid/@kgid. 40138c2ecf20Sopenharmony_ci */ 40148c2ecf20Sopenharmony_ci error = sysfs_change_owner(kobj, kuid, kgid); 40158c2ecf20Sopenharmony_ci if (error) 40168c2ecf20Sopenharmony_ci goto out; 40178c2ecf20Sopenharmony_ci 40188c2ecf20Sopenharmony_ci /* 40198c2ecf20Sopenharmony_ci * Change the uevent file for @dev to the new owner. The uevent file 40208c2ecf20Sopenharmony_ci * was created in a separate step when @dev got added and we mirror 40218c2ecf20Sopenharmony_ci * that step here. 40228c2ecf20Sopenharmony_ci */ 40238c2ecf20Sopenharmony_ci error = sysfs_file_change_owner(kobj, dev_attr_uevent.attr.name, kuid, 40248c2ecf20Sopenharmony_ci kgid); 40258c2ecf20Sopenharmony_ci if (error) 40268c2ecf20Sopenharmony_ci goto out; 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_ci /* 40298c2ecf20Sopenharmony_ci * Change the device groups, the device groups associated with the 40308c2ecf20Sopenharmony_ci * device class, and the groups associated with the device type of @dev 40318c2ecf20Sopenharmony_ci * to @kuid/@kgid. 40328c2ecf20Sopenharmony_ci */ 40338c2ecf20Sopenharmony_ci error = device_attrs_change_owner(dev, kuid, kgid); 40348c2ecf20Sopenharmony_ci if (error) 40358c2ecf20Sopenharmony_ci goto out; 40368c2ecf20Sopenharmony_ci 40378c2ecf20Sopenharmony_ci error = dpm_sysfs_change_owner(dev, kuid, kgid); 40388c2ecf20Sopenharmony_ci if (error) 40398c2ecf20Sopenharmony_ci goto out; 40408c2ecf20Sopenharmony_ci 40418c2ecf20Sopenharmony_ci#ifdef CONFIG_BLOCK 40428c2ecf20Sopenharmony_ci if (sysfs_deprecated && dev->class == &block_class) 40438c2ecf20Sopenharmony_ci goto out; 40448c2ecf20Sopenharmony_ci#endif 40458c2ecf20Sopenharmony_ci 40468c2ecf20Sopenharmony_ci /* 40478c2ecf20Sopenharmony_ci * Change the owner of the symlink located in the class directory of 40488c2ecf20Sopenharmony_ci * the device class associated with @dev which points to the actual 40498c2ecf20Sopenharmony_ci * directory entry for @dev to @kuid/@kgid. This ensures that the 40508c2ecf20Sopenharmony_ci * symlink shows the same permissions as its target. 40518c2ecf20Sopenharmony_ci */ 40528c2ecf20Sopenharmony_ci error = sysfs_link_change_owner(&dev->class->p->subsys.kobj, &dev->kobj, 40538c2ecf20Sopenharmony_ci dev_name(dev), kuid, kgid); 40548c2ecf20Sopenharmony_ci if (error) 40558c2ecf20Sopenharmony_ci goto out; 40568c2ecf20Sopenharmony_ci 40578c2ecf20Sopenharmony_ciout: 40588c2ecf20Sopenharmony_ci put_device(dev); 40598c2ecf20Sopenharmony_ci return error; 40608c2ecf20Sopenharmony_ci} 40618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_change_owner); 40628c2ecf20Sopenharmony_ci 40638c2ecf20Sopenharmony_ci/** 40648c2ecf20Sopenharmony_ci * device_shutdown - call ->shutdown() on each device to shutdown. 40658c2ecf20Sopenharmony_ci */ 40668c2ecf20Sopenharmony_civoid device_shutdown(void) 40678c2ecf20Sopenharmony_ci{ 40688c2ecf20Sopenharmony_ci struct device *dev, *parent; 40698c2ecf20Sopenharmony_ci 40708c2ecf20Sopenharmony_ci wait_for_device_probe(); 40718c2ecf20Sopenharmony_ci device_block_probing(); 40728c2ecf20Sopenharmony_ci 40738c2ecf20Sopenharmony_ci cpufreq_suspend(); 40748c2ecf20Sopenharmony_ci 40758c2ecf20Sopenharmony_ci spin_lock(&devices_kset->list_lock); 40768c2ecf20Sopenharmony_ci /* 40778c2ecf20Sopenharmony_ci * Walk the devices list backward, shutting down each in turn. 40788c2ecf20Sopenharmony_ci * Beware that device unplug events may also start pulling 40798c2ecf20Sopenharmony_ci * devices offline, even as the system is shutting down. 40808c2ecf20Sopenharmony_ci */ 40818c2ecf20Sopenharmony_ci while (!list_empty(&devices_kset->list)) { 40828c2ecf20Sopenharmony_ci dev = list_entry(devices_kset->list.prev, struct device, 40838c2ecf20Sopenharmony_ci kobj.entry); 40848c2ecf20Sopenharmony_ci 40858c2ecf20Sopenharmony_ci /* 40868c2ecf20Sopenharmony_ci * hold reference count of device's parent to 40878c2ecf20Sopenharmony_ci * prevent it from being freed because parent's 40888c2ecf20Sopenharmony_ci * lock is to be held 40898c2ecf20Sopenharmony_ci */ 40908c2ecf20Sopenharmony_ci parent = get_device(dev->parent); 40918c2ecf20Sopenharmony_ci get_device(dev); 40928c2ecf20Sopenharmony_ci /* 40938c2ecf20Sopenharmony_ci * Make sure the device is off the kset list, in the 40948c2ecf20Sopenharmony_ci * event that dev->*->shutdown() doesn't remove it. 40958c2ecf20Sopenharmony_ci */ 40968c2ecf20Sopenharmony_ci list_del_init(&dev->kobj.entry); 40978c2ecf20Sopenharmony_ci spin_unlock(&devices_kset->list_lock); 40988c2ecf20Sopenharmony_ci 40998c2ecf20Sopenharmony_ci /* hold lock to avoid race with probe/release */ 41008c2ecf20Sopenharmony_ci if (parent) 41018c2ecf20Sopenharmony_ci device_lock(parent); 41028c2ecf20Sopenharmony_ci device_lock(dev); 41038c2ecf20Sopenharmony_ci 41048c2ecf20Sopenharmony_ci /* Don't allow any more runtime suspends */ 41058c2ecf20Sopenharmony_ci pm_runtime_get_noresume(dev); 41068c2ecf20Sopenharmony_ci pm_runtime_barrier(dev); 41078c2ecf20Sopenharmony_ci 41088c2ecf20Sopenharmony_ci if (dev->class && dev->class->shutdown_pre) { 41098c2ecf20Sopenharmony_ci if (initcall_debug) 41108c2ecf20Sopenharmony_ci dev_info(dev, "shutdown_pre\n"); 41118c2ecf20Sopenharmony_ci dev->class->shutdown_pre(dev); 41128c2ecf20Sopenharmony_ci } 41138c2ecf20Sopenharmony_ci if (dev->bus && dev->bus->shutdown) { 41148c2ecf20Sopenharmony_ci if (initcall_debug) 41158c2ecf20Sopenharmony_ci dev_info(dev, "shutdown\n"); 41168c2ecf20Sopenharmony_ci dev->bus->shutdown(dev); 41178c2ecf20Sopenharmony_ci } else if (dev->driver && dev->driver->shutdown) { 41188c2ecf20Sopenharmony_ci if (initcall_debug) 41198c2ecf20Sopenharmony_ci dev_info(dev, "shutdown\n"); 41208c2ecf20Sopenharmony_ci dev->driver->shutdown(dev); 41218c2ecf20Sopenharmony_ci } 41228c2ecf20Sopenharmony_ci 41238c2ecf20Sopenharmony_ci device_unlock(dev); 41248c2ecf20Sopenharmony_ci if (parent) 41258c2ecf20Sopenharmony_ci device_unlock(parent); 41268c2ecf20Sopenharmony_ci 41278c2ecf20Sopenharmony_ci put_device(dev); 41288c2ecf20Sopenharmony_ci put_device(parent); 41298c2ecf20Sopenharmony_ci 41308c2ecf20Sopenharmony_ci spin_lock(&devices_kset->list_lock); 41318c2ecf20Sopenharmony_ci } 41328c2ecf20Sopenharmony_ci spin_unlock(&devices_kset->list_lock); 41338c2ecf20Sopenharmony_ci} 41348c2ecf20Sopenharmony_ci 41358c2ecf20Sopenharmony_ci/* 41368c2ecf20Sopenharmony_ci * Device logging functions 41378c2ecf20Sopenharmony_ci */ 41388c2ecf20Sopenharmony_ci 41398c2ecf20Sopenharmony_ci#ifdef CONFIG_PRINTK 41408c2ecf20Sopenharmony_cistatic void 41418c2ecf20Sopenharmony_ciset_dev_info(const struct device *dev, struct dev_printk_info *dev_info) 41428c2ecf20Sopenharmony_ci{ 41438c2ecf20Sopenharmony_ci const char *subsys; 41448c2ecf20Sopenharmony_ci 41458c2ecf20Sopenharmony_ci memset(dev_info, 0, sizeof(*dev_info)); 41468c2ecf20Sopenharmony_ci 41478c2ecf20Sopenharmony_ci if (dev->class) 41488c2ecf20Sopenharmony_ci subsys = dev->class->name; 41498c2ecf20Sopenharmony_ci else if (dev->bus) 41508c2ecf20Sopenharmony_ci subsys = dev->bus->name; 41518c2ecf20Sopenharmony_ci else 41528c2ecf20Sopenharmony_ci return; 41538c2ecf20Sopenharmony_ci 41548c2ecf20Sopenharmony_ci strscpy(dev_info->subsystem, subsys, sizeof(dev_info->subsystem)); 41558c2ecf20Sopenharmony_ci 41568c2ecf20Sopenharmony_ci /* 41578c2ecf20Sopenharmony_ci * Add device identifier DEVICE=: 41588c2ecf20Sopenharmony_ci * b12:8 block dev_t 41598c2ecf20Sopenharmony_ci * c127:3 char dev_t 41608c2ecf20Sopenharmony_ci * n8 netdev ifindex 41618c2ecf20Sopenharmony_ci * +sound:card0 subsystem:devname 41628c2ecf20Sopenharmony_ci */ 41638c2ecf20Sopenharmony_ci if (MAJOR(dev->devt)) { 41648c2ecf20Sopenharmony_ci char c; 41658c2ecf20Sopenharmony_ci 41668c2ecf20Sopenharmony_ci if (strcmp(subsys, "block") == 0) 41678c2ecf20Sopenharmony_ci c = 'b'; 41688c2ecf20Sopenharmony_ci else 41698c2ecf20Sopenharmony_ci c = 'c'; 41708c2ecf20Sopenharmony_ci 41718c2ecf20Sopenharmony_ci snprintf(dev_info->device, sizeof(dev_info->device), 41728c2ecf20Sopenharmony_ci "%c%u:%u", c, MAJOR(dev->devt), MINOR(dev->devt)); 41738c2ecf20Sopenharmony_ci } else if (strcmp(subsys, "net") == 0) { 41748c2ecf20Sopenharmony_ci struct net_device *net = to_net_dev(dev); 41758c2ecf20Sopenharmony_ci 41768c2ecf20Sopenharmony_ci snprintf(dev_info->device, sizeof(dev_info->device), 41778c2ecf20Sopenharmony_ci "n%u", net->ifindex); 41788c2ecf20Sopenharmony_ci } else { 41798c2ecf20Sopenharmony_ci snprintf(dev_info->device, sizeof(dev_info->device), 41808c2ecf20Sopenharmony_ci "+%s:%s", subsys, dev_name(dev)); 41818c2ecf20Sopenharmony_ci } 41828c2ecf20Sopenharmony_ci} 41838c2ecf20Sopenharmony_ci 41848c2ecf20Sopenharmony_ciint dev_vprintk_emit(int level, const struct device *dev, 41858c2ecf20Sopenharmony_ci const char *fmt, va_list args) 41868c2ecf20Sopenharmony_ci{ 41878c2ecf20Sopenharmony_ci struct dev_printk_info dev_info; 41888c2ecf20Sopenharmony_ci 41898c2ecf20Sopenharmony_ci set_dev_info(dev, &dev_info); 41908c2ecf20Sopenharmony_ci 41918c2ecf20Sopenharmony_ci return vprintk_emit(0, level, &dev_info, fmt, args); 41928c2ecf20Sopenharmony_ci} 41938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dev_vprintk_emit); 41948c2ecf20Sopenharmony_ci 41958c2ecf20Sopenharmony_ciint dev_printk_emit(int level, const struct device *dev, const char *fmt, ...) 41968c2ecf20Sopenharmony_ci{ 41978c2ecf20Sopenharmony_ci va_list args; 41988c2ecf20Sopenharmony_ci int r; 41998c2ecf20Sopenharmony_ci 42008c2ecf20Sopenharmony_ci va_start(args, fmt); 42018c2ecf20Sopenharmony_ci 42028c2ecf20Sopenharmony_ci r = dev_vprintk_emit(level, dev, fmt, args); 42038c2ecf20Sopenharmony_ci 42048c2ecf20Sopenharmony_ci va_end(args); 42058c2ecf20Sopenharmony_ci 42068c2ecf20Sopenharmony_ci return r; 42078c2ecf20Sopenharmony_ci} 42088c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dev_printk_emit); 42098c2ecf20Sopenharmony_ci 42108c2ecf20Sopenharmony_cistatic void __dev_printk(const char *level, const struct device *dev, 42118c2ecf20Sopenharmony_ci struct va_format *vaf) 42128c2ecf20Sopenharmony_ci{ 42138c2ecf20Sopenharmony_ci if (dev) 42148c2ecf20Sopenharmony_ci dev_printk_emit(level[1] - '0', dev, "%s %s: %pV", 42158c2ecf20Sopenharmony_ci dev_driver_string(dev), dev_name(dev), vaf); 42168c2ecf20Sopenharmony_ci else 42178c2ecf20Sopenharmony_ci printk("%s(NULL device *): %pV", level, vaf); 42188c2ecf20Sopenharmony_ci} 42198c2ecf20Sopenharmony_ci 42208c2ecf20Sopenharmony_civoid dev_printk(const char *level, const struct device *dev, 42218c2ecf20Sopenharmony_ci const char *fmt, ...) 42228c2ecf20Sopenharmony_ci{ 42238c2ecf20Sopenharmony_ci struct va_format vaf; 42248c2ecf20Sopenharmony_ci va_list args; 42258c2ecf20Sopenharmony_ci 42268c2ecf20Sopenharmony_ci va_start(args, fmt); 42278c2ecf20Sopenharmony_ci 42288c2ecf20Sopenharmony_ci vaf.fmt = fmt; 42298c2ecf20Sopenharmony_ci vaf.va = &args; 42308c2ecf20Sopenharmony_ci 42318c2ecf20Sopenharmony_ci __dev_printk(level, dev, &vaf); 42328c2ecf20Sopenharmony_ci 42338c2ecf20Sopenharmony_ci va_end(args); 42348c2ecf20Sopenharmony_ci} 42358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dev_printk); 42368c2ecf20Sopenharmony_ci 42378c2ecf20Sopenharmony_ci#define define_dev_printk_level(func, kern_level) \ 42388c2ecf20Sopenharmony_civoid func(const struct device *dev, const char *fmt, ...) \ 42398c2ecf20Sopenharmony_ci{ \ 42408c2ecf20Sopenharmony_ci struct va_format vaf; \ 42418c2ecf20Sopenharmony_ci va_list args; \ 42428c2ecf20Sopenharmony_ci \ 42438c2ecf20Sopenharmony_ci va_start(args, fmt); \ 42448c2ecf20Sopenharmony_ci \ 42458c2ecf20Sopenharmony_ci vaf.fmt = fmt; \ 42468c2ecf20Sopenharmony_ci vaf.va = &args; \ 42478c2ecf20Sopenharmony_ci \ 42488c2ecf20Sopenharmony_ci __dev_printk(kern_level, dev, &vaf); \ 42498c2ecf20Sopenharmony_ci \ 42508c2ecf20Sopenharmony_ci va_end(args); \ 42518c2ecf20Sopenharmony_ci} \ 42528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(func); 42538c2ecf20Sopenharmony_ci 42548c2ecf20Sopenharmony_cidefine_dev_printk_level(_dev_emerg, KERN_EMERG); 42558c2ecf20Sopenharmony_cidefine_dev_printk_level(_dev_alert, KERN_ALERT); 42568c2ecf20Sopenharmony_cidefine_dev_printk_level(_dev_crit, KERN_CRIT); 42578c2ecf20Sopenharmony_cidefine_dev_printk_level(_dev_err, KERN_ERR); 42588c2ecf20Sopenharmony_cidefine_dev_printk_level(_dev_warn, KERN_WARNING); 42598c2ecf20Sopenharmony_cidefine_dev_printk_level(_dev_notice, KERN_NOTICE); 42608c2ecf20Sopenharmony_cidefine_dev_printk_level(_dev_info, KERN_INFO); 42618c2ecf20Sopenharmony_ci 42628c2ecf20Sopenharmony_ci#endif 42638c2ecf20Sopenharmony_ci 42648c2ecf20Sopenharmony_ci/** 42658c2ecf20Sopenharmony_ci * dev_err_probe - probe error check and log helper 42668c2ecf20Sopenharmony_ci * @dev: the pointer to the struct device 42678c2ecf20Sopenharmony_ci * @err: error value to test 42688c2ecf20Sopenharmony_ci * @fmt: printf-style format string 42698c2ecf20Sopenharmony_ci * @...: arguments as specified in the format string 42708c2ecf20Sopenharmony_ci * 42718c2ecf20Sopenharmony_ci * This helper implements common pattern present in probe functions for error 42728c2ecf20Sopenharmony_ci * checking: print debug or error message depending if the error value is 42738c2ecf20Sopenharmony_ci * -EPROBE_DEFER and propagate error upwards. 42748c2ecf20Sopenharmony_ci * In case of -EPROBE_DEFER it sets also defer probe reason, which can be 42758c2ecf20Sopenharmony_ci * checked later by reading devices_deferred debugfs attribute. 42768c2ecf20Sopenharmony_ci * It replaces code sequence:: 42778c2ecf20Sopenharmony_ci * 42788c2ecf20Sopenharmony_ci * if (err != -EPROBE_DEFER) 42798c2ecf20Sopenharmony_ci * dev_err(dev, ...); 42808c2ecf20Sopenharmony_ci * else 42818c2ecf20Sopenharmony_ci * dev_dbg(dev, ...); 42828c2ecf20Sopenharmony_ci * return err; 42838c2ecf20Sopenharmony_ci * 42848c2ecf20Sopenharmony_ci * with:: 42858c2ecf20Sopenharmony_ci * 42868c2ecf20Sopenharmony_ci * return dev_err_probe(dev, err, ...); 42878c2ecf20Sopenharmony_ci * 42888c2ecf20Sopenharmony_ci * Returns @err. 42898c2ecf20Sopenharmony_ci * 42908c2ecf20Sopenharmony_ci */ 42918c2ecf20Sopenharmony_ciint dev_err_probe(const struct device *dev, int err, const char *fmt, ...) 42928c2ecf20Sopenharmony_ci{ 42938c2ecf20Sopenharmony_ci struct va_format vaf; 42948c2ecf20Sopenharmony_ci va_list args; 42958c2ecf20Sopenharmony_ci 42968c2ecf20Sopenharmony_ci va_start(args, fmt); 42978c2ecf20Sopenharmony_ci vaf.fmt = fmt; 42988c2ecf20Sopenharmony_ci vaf.va = &args; 42998c2ecf20Sopenharmony_ci 43008c2ecf20Sopenharmony_ci if (err != -EPROBE_DEFER) { 43018c2ecf20Sopenharmony_ci dev_err(dev, "error %pe: %pV", ERR_PTR(err), &vaf); 43028c2ecf20Sopenharmony_ci } else { 43038c2ecf20Sopenharmony_ci device_set_deferred_probe_reason(dev, &vaf); 43048c2ecf20Sopenharmony_ci dev_dbg(dev, "error %pe: %pV", ERR_PTR(err), &vaf); 43058c2ecf20Sopenharmony_ci } 43068c2ecf20Sopenharmony_ci 43078c2ecf20Sopenharmony_ci va_end(args); 43088c2ecf20Sopenharmony_ci 43098c2ecf20Sopenharmony_ci return err; 43108c2ecf20Sopenharmony_ci} 43118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dev_err_probe); 43128c2ecf20Sopenharmony_ci 43138c2ecf20Sopenharmony_cistatic inline bool fwnode_is_primary(struct fwnode_handle *fwnode) 43148c2ecf20Sopenharmony_ci{ 43158c2ecf20Sopenharmony_ci return fwnode && !IS_ERR(fwnode->secondary); 43168c2ecf20Sopenharmony_ci} 43178c2ecf20Sopenharmony_ci 43188c2ecf20Sopenharmony_ci/** 43198c2ecf20Sopenharmony_ci * set_primary_fwnode - Change the primary firmware node of a given device. 43208c2ecf20Sopenharmony_ci * @dev: Device to handle. 43218c2ecf20Sopenharmony_ci * @fwnode: New primary firmware node of the device. 43228c2ecf20Sopenharmony_ci * 43238c2ecf20Sopenharmony_ci * Set the device's firmware node pointer to @fwnode, but if a secondary 43248c2ecf20Sopenharmony_ci * firmware node of the device is present, preserve it. 43258c2ecf20Sopenharmony_ci */ 43268c2ecf20Sopenharmony_civoid set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode) 43278c2ecf20Sopenharmony_ci{ 43288c2ecf20Sopenharmony_ci struct device *parent = dev->parent; 43298c2ecf20Sopenharmony_ci struct fwnode_handle *fn = dev->fwnode; 43308c2ecf20Sopenharmony_ci 43318c2ecf20Sopenharmony_ci if (fwnode) { 43328c2ecf20Sopenharmony_ci if (fwnode_is_primary(fn)) 43338c2ecf20Sopenharmony_ci fn = fn->secondary; 43348c2ecf20Sopenharmony_ci 43358c2ecf20Sopenharmony_ci if (fn) { 43368c2ecf20Sopenharmony_ci WARN_ON(fwnode->secondary); 43378c2ecf20Sopenharmony_ci fwnode->secondary = fn; 43388c2ecf20Sopenharmony_ci } 43398c2ecf20Sopenharmony_ci dev->fwnode = fwnode; 43408c2ecf20Sopenharmony_ci } else { 43418c2ecf20Sopenharmony_ci if (fwnode_is_primary(fn)) { 43428c2ecf20Sopenharmony_ci dev->fwnode = fn->secondary; 43438c2ecf20Sopenharmony_ci if (!(parent && fn == parent->fwnode)) 43448c2ecf20Sopenharmony_ci fn->secondary = NULL; 43458c2ecf20Sopenharmony_ci } else { 43468c2ecf20Sopenharmony_ci dev->fwnode = NULL; 43478c2ecf20Sopenharmony_ci } 43488c2ecf20Sopenharmony_ci } 43498c2ecf20Sopenharmony_ci} 43508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(set_primary_fwnode); 43518c2ecf20Sopenharmony_ci 43528c2ecf20Sopenharmony_ci/** 43538c2ecf20Sopenharmony_ci * set_secondary_fwnode - Change the secondary firmware node of a given device. 43548c2ecf20Sopenharmony_ci * @dev: Device to handle. 43558c2ecf20Sopenharmony_ci * @fwnode: New secondary firmware node of the device. 43568c2ecf20Sopenharmony_ci * 43578c2ecf20Sopenharmony_ci * If a primary firmware node of the device is present, set its secondary 43588c2ecf20Sopenharmony_ci * pointer to @fwnode. Otherwise, set the device's firmware node pointer to 43598c2ecf20Sopenharmony_ci * @fwnode. 43608c2ecf20Sopenharmony_ci */ 43618c2ecf20Sopenharmony_civoid set_secondary_fwnode(struct device *dev, struct fwnode_handle *fwnode) 43628c2ecf20Sopenharmony_ci{ 43638c2ecf20Sopenharmony_ci if (fwnode) 43648c2ecf20Sopenharmony_ci fwnode->secondary = ERR_PTR(-ENODEV); 43658c2ecf20Sopenharmony_ci 43668c2ecf20Sopenharmony_ci if (fwnode_is_primary(dev->fwnode)) 43678c2ecf20Sopenharmony_ci dev->fwnode->secondary = fwnode; 43688c2ecf20Sopenharmony_ci else 43698c2ecf20Sopenharmony_ci dev->fwnode = fwnode; 43708c2ecf20Sopenharmony_ci} 43718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(set_secondary_fwnode); 43728c2ecf20Sopenharmony_ci 43738c2ecf20Sopenharmony_ci/** 43748c2ecf20Sopenharmony_ci * device_set_of_node_from_dev - reuse device-tree node of another device 43758c2ecf20Sopenharmony_ci * @dev: device whose device-tree node is being set 43768c2ecf20Sopenharmony_ci * @dev2: device whose device-tree node is being reused 43778c2ecf20Sopenharmony_ci * 43788c2ecf20Sopenharmony_ci * Takes another reference to the new device-tree node after first dropping 43798c2ecf20Sopenharmony_ci * any reference held to the old node. 43808c2ecf20Sopenharmony_ci */ 43818c2ecf20Sopenharmony_civoid device_set_of_node_from_dev(struct device *dev, const struct device *dev2) 43828c2ecf20Sopenharmony_ci{ 43838c2ecf20Sopenharmony_ci of_node_put(dev->of_node); 43848c2ecf20Sopenharmony_ci dev->of_node = of_node_get(dev2->of_node); 43858c2ecf20Sopenharmony_ci dev->of_node_reused = true; 43868c2ecf20Sopenharmony_ci} 43878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_set_of_node_from_dev); 43888c2ecf20Sopenharmony_ci 43898c2ecf20Sopenharmony_civoid device_set_node(struct device *dev, struct fwnode_handle *fwnode) 43908c2ecf20Sopenharmony_ci{ 43918c2ecf20Sopenharmony_ci dev->fwnode = fwnode; 43928c2ecf20Sopenharmony_ci dev->of_node = to_of_node(fwnode); 43938c2ecf20Sopenharmony_ci} 43948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_set_node); 43958c2ecf20Sopenharmony_ci 43968c2ecf20Sopenharmony_ciint device_match_name(struct device *dev, const void *name) 43978c2ecf20Sopenharmony_ci{ 43988c2ecf20Sopenharmony_ci return sysfs_streq(dev_name(dev), name); 43998c2ecf20Sopenharmony_ci} 44008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_match_name); 44018c2ecf20Sopenharmony_ci 44028c2ecf20Sopenharmony_ciint device_match_of_node(struct device *dev, const void *np) 44038c2ecf20Sopenharmony_ci{ 44048c2ecf20Sopenharmony_ci return dev->of_node == np; 44058c2ecf20Sopenharmony_ci} 44068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_match_of_node); 44078c2ecf20Sopenharmony_ci 44088c2ecf20Sopenharmony_ciint device_match_fwnode(struct device *dev, const void *fwnode) 44098c2ecf20Sopenharmony_ci{ 44108c2ecf20Sopenharmony_ci return dev_fwnode(dev) == fwnode; 44118c2ecf20Sopenharmony_ci} 44128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_match_fwnode); 44138c2ecf20Sopenharmony_ci 44148c2ecf20Sopenharmony_ciint device_match_devt(struct device *dev, const void *pdevt) 44158c2ecf20Sopenharmony_ci{ 44168c2ecf20Sopenharmony_ci return dev->devt == *(dev_t *)pdevt; 44178c2ecf20Sopenharmony_ci} 44188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_match_devt); 44198c2ecf20Sopenharmony_ci 44208c2ecf20Sopenharmony_ciint device_match_acpi_dev(struct device *dev, const void *adev) 44218c2ecf20Sopenharmony_ci{ 44228c2ecf20Sopenharmony_ci return ACPI_COMPANION(dev) == adev; 44238c2ecf20Sopenharmony_ci} 44248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(device_match_acpi_dev); 44258c2ecf20Sopenharmony_ci 44268c2ecf20Sopenharmony_ciint device_match_any(struct device *dev, const void *unused) 44278c2ecf20Sopenharmony_ci{ 44288c2ecf20Sopenharmony_ci return 1; 44298c2ecf20Sopenharmony_ci} 44308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(device_match_any); 4431