diff options
author | Linus Torvalds | 2023-04-27 11:53:57 -0700 |
---|---|---|
committer | Linus Torvalds | 2023-04-27 11:53:57 -0700 |
commit | 556eb8b79190151506187bf0b16dda423c34d9a8 (patch) | |
tree | 76fe79cf977e03be1b70059eef3195b89fe39948 /drivers/base | |
parent | 97b2ff294381d05e59294a931c4db55276470cb5 (diff) | |
parent | 046b6a171009e1ed9ede02194025e9ccd709beb2 (diff) |
Merge tag 'driver-core-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core updates from Greg KH:
"Here is the large set of driver core changes for 6.4-rc1.
Once again, a busy development cycle, with lots of changes happening
in the driver core in the quest to be able to move "struct bus" and
"struct class" into read-only memory, a task now complete with these
changes.
This will make the future rust interactions with the driver core more
"provably correct" as well as providing more obvious lifetime rules
for all busses and classes in the kernel.
The changes required for this did touch many individual classes and
busses as many callbacks were changed to take const * parameters
instead. All of these changes have been submitted to the various
subsystem maintainers, giving them plenty of time to review, and most
of them actually did so.
Other than those changes, included in here are a small set of other
things:
- kobject logging improvements
- cacheinfo improvements and updates
- obligatory fw_devlink updates and fixes
- documentation updates
- device property cleanups and const * changes
- firwmare loader dependency fixes.
All of these have been in linux-next for a while with no reported
problems"
* tag 'driver-core-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (120 commits)
device property: make device_property functions take const device *
driver core: update comments in device_rename()
driver core: Don't require dynamic_debug for initcall_debug probe timing
firmware_loader: rework crypto dependencies
firmware_loader: Strip off \n from customized path
zram: fix up permission for the hot_add sysfs file
cacheinfo: Add use_arch[|_cache]_info field/function
arch_topology: Remove early cacheinfo error message if -ENOENT
cacheinfo: Check cache properties are present in DT
cacheinfo: Check sib_leaf in cache_leaves_are_shared()
cacheinfo: Allow early level detection when DT/ACPI info is missing/broken
cacheinfo: Add arm64 early level initializer implementation
cacheinfo: Add arch specific early level initializer
tty: make tty_class a static const structure
driver core: class: remove struct class_interface * from callbacks
driver core: class: mark the struct class in struct class_interface constant
driver core: class: make class_register() take a const *
driver core: class: mark class_release() as taking a const *
driver core: remove incorrect comment for device_create*
MIPS: vpe-cmp: remove module owner pointer from struct class usage.
...
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/Kconfig | 12 | ||||
-rw-r--r-- | drivers/base/arch_topology.c | 11 | ||||
-rw-r--r-- | drivers/base/base.h | 114 | ||||
-rw-r--r-- | drivers/base/bus.c | 48 | ||||
-rw-r--r-- | drivers/base/cacheinfo.c | 124 | ||||
-rw-r--r-- | drivers/base/class.c | 247 | ||||
-rw-r--r-- | drivers/base/core.c | 313 | ||||
-rw-r--r-- | drivers/base/dd.c | 36 | ||||
-rw-r--r-- | drivers/base/devcoredump.c | 5 | ||||
-rw-r--r-- | drivers/base/devres.c | 11 | ||||
-rw-r--r-- | drivers/base/devtmpfs.c | 9 | ||||
-rw-r--r-- | drivers/base/firmware_loader/Kconfig | 13 | ||||
-rw-r--r-- | drivers/base/firmware_loader/main.c | 65 | ||||
-rw-r--r-- | drivers/base/firmware_loader/sysfs.c | 4 | ||||
-rw-r--r-- | drivers/base/physical_location.h | 2 | ||||
-rw-r--r-- | drivers/base/power/wakeup_stats.c | 2 | ||||
-rw-r--r-- | drivers/base/property.c | 148 | ||||
-rw-r--r-- | drivers/base/soc.c | 15 |
18 files changed, 782 insertions, 397 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 6f04b831a5c0..2b8fd6bb7da0 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -230,4 +230,16 @@ config GENERIC_ARCH_NUMA Enable support for generic NUMA implementation. Currently, RISC-V and ARM64 use it. +config FW_DEVLINK_SYNC_STATE_TIMEOUT + bool "sync_state() behavior defaults to timeout instead of strict" + help + This is build time equivalent of adding kernel command line parameter + "fw_devlink.sync_state=timeout". Give up waiting on consumers and + call sync_state() on any devices that haven't yet received their + sync_state() calls after deferred_probe_timeout has expired or by + late_initcall() if !CONFIG_MODULES. You should almost always want to + select N here unless you have already successfully tested with the + command line option on every system/board your kernel is expected to + work on. + endmenu diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index b1c1dd38ab01..b741b5ba82bd 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -835,18 +835,19 @@ void __init init_cpu_topology(void) if (ret) { /* * Discard anything that was parsed if we hit an error so we - * don't use partial information. + * don't use partial information. But do not return yet to give + * arch-specific early cache level detection a chance to run. */ reset_cpu_topology(); - return; } for_each_possible_cpu(cpu) { ret = fetch_cache_info(cpu); - if (ret) { + if (!ret) + continue; + else if (ret != -ENOENT) pr_err("Early cacheinfo failed, ret = %d\n", ret); - break; - } + return; } } diff --git a/drivers/base/base.h b/drivers/base/base.h index 726a12a244c0..eb4c0ace9242 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -27,11 +27,13 @@ * on this bus. * @bus - pointer back to the struct bus_type that this structure is associated * with. + * @dev_root: Default device to use as the parent. * * @glue_dirs - "glue" directory to put in-between the parent device to * avoid namespace conflicts * @class - pointer back to the struct class that this structure is associated * with. + * @lock_key: Lock class key for use by the lock validator * * This structure is the one that is the actual kobject allowing struct * bus_type/class to be statically allocated safely. Nothing outside of the @@ -48,10 +50,11 @@ struct subsys_private { struct klist klist_drivers; struct blocking_notifier_head bus_notifier; unsigned int drivers_autoprobe:1; - struct bus_type *bus; + const struct bus_type *bus; + struct device *dev_root; struct kset glue_dirs; - struct class *class; + const struct class *class; struct lock_class_key lock_key; }; @@ -70,6 +73,8 @@ static inline void subsys_put(struct subsys_private *sp) kset_put(&sp->subsys); } +struct subsys_private *class_to_subsys(const struct class *class); + struct driver_private { struct kobject kobj; struct klist klist_devices; @@ -122,69 +127,73 @@ struct device_private { container_of(obj, struct device_private, knode_class) /* initialisation functions */ -extern int devices_init(void); -extern int buses_init(void); -extern int classes_init(void); -extern int firmware_init(void); +int devices_init(void); +int buses_init(void); +int classes_init(void); +int firmware_init(void); #ifdef CONFIG_SYS_HYPERVISOR -extern int hypervisor_init(void); +int hypervisor_init(void); #else static inline int hypervisor_init(void) { return 0; } #endif -extern int platform_bus_init(void); -extern void cpu_dev_init(void); -extern void container_dev_init(void); +int platform_bus_init(void); +void cpu_dev_init(void); +void container_dev_init(void); #ifdef CONFIG_AUXILIARY_BUS -extern void auxiliary_bus_init(void); +void auxiliary_bus_init(void); #else static inline void auxiliary_bus_init(void) { } #endif struct kobject *virtual_device_parent(struct device *dev); -extern int bus_add_device(struct device *dev); -extern void bus_probe_device(struct device *dev); -extern void bus_remove_device(struct device *dev); +int bus_add_device(struct device *dev); +void bus_probe_device(struct device *dev); +void bus_remove_device(struct device *dev); void bus_notify(struct device *dev, enum bus_notifier_event value); bool bus_is_registered(const struct bus_type *bus); -extern int bus_add_driver(struct device_driver *drv); -extern void bus_remove_driver(struct device_driver *drv); -extern void device_release_driver_internal(struct device *dev, - struct device_driver *drv, - struct device *parent); +int bus_add_driver(struct device_driver *drv); +void bus_remove_driver(struct device_driver *drv); +void device_release_driver_internal(struct device *dev, struct device_driver *drv, + struct device *parent); -extern void driver_detach(struct device_driver *drv); -extern void driver_deferred_probe_del(struct device *dev); -extern void device_set_deferred_probe_reason(const struct device *dev, - struct va_format *vaf); +void driver_detach(struct device_driver *drv); +void driver_deferred_probe_del(struct device *dev); +void device_set_deferred_probe_reason(const struct device *dev, struct va_format *vaf); static inline int driver_match_device(struct device_driver *drv, struct device *dev) { return drv->bus->match ? drv->bus->match(dev, drv) : 1; } -extern int driver_add_groups(struct device_driver *drv, - const struct attribute_group **groups); -extern void driver_remove_groups(struct device_driver *drv, - const struct attribute_group **groups); +static inline void dev_sync_state(struct device *dev) +{ + if (dev->bus->sync_state) + dev->bus->sync_state(dev); + else if (dev->driver && dev->driver->sync_state) + dev->driver->sync_state(dev); +} + +int driver_add_groups(struct device_driver *drv, const struct attribute_group **groups); +void driver_remove_groups(struct device_driver *drv, const struct attribute_group **groups); void device_driver_detach(struct device *dev); -extern int devres_release_all(struct device *dev); -extern void device_block_probing(void); -extern void device_unblock_probing(void); -extern void deferred_probe_extend_timeout(void); -extern void driver_deferred_probe_trigger(void); +int devres_release_all(struct device *dev); +void device_block_probing(void); +void device_unblock_probing(void); +void deferred_probe_extend_timeout(void); +void driver_deferred_probe_trigger(void); const char *device_get_devnode(const struct device *dev, umode_t *mode, kuid_t *uid, kgid_t *gid, const char **tmp); /* /sys/devices directory */ extern struct kset *devices_kset; -extern void devices_kset_move_last(struct device *dev); +void devices_kset_move_last(struct device *dev); #if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS) -extern void module_add_driver(struct module *mod, struct device_driver *drv); -extern void module_remove_driver(struct device_driver *drv); +void module_add_driver(struct module *mod, struct device_driver *drv); +void module_remove_driver(struct device_driver *drv); #else static inline void module_add_driver(struct module *mod, struct device_driver *drv) { } @@ -192,23 +201,34 @@ static inline void module_remove_driver(struct device_driver *drv) { } #endif #ifdef CONFIG_DEVTMPFS -extern int devtmpfs_init(void); +int devtmpfs_init(void); #else static inline int devtmpfs_init(void) { return 0; } #endif +#ifdef CONFIG_BLOCK +extern struct class block_class; +static inline bool is_blockdev(struct device *dev) +{ + return dev->class == &block_class; +} +#else +static inline bool is_blockdev(struct device *dev) { return false; } +#endif + /* Device links support */ -extern int device_links_read_lock(void); -extern void device_links_read_unlock(int idx); -extern int device_links_read_lock_held(void); -extern int device_links_check_suppliers(struct device *dev); -extern void device_links_force_bind(struct device *dev); -extern void device_links_driver_bound(struct device *dev); -extern void device_links_driver_cleanup(struct device *dev); -extern void device_links_no_driver(struct device *dev); -extern bool device_links_busy(struct device *dev); -extern void device_links_unbind_consumers(struct device *dev); -extern void fw_devlink_drivers_done(void); +int device_links_read_lock(void); +void device_links_read_unlock(int idx); +int device_links_read_lock_held(void); +int device_links_check_suppliers(struct device *dev); +void device_links_force_bind(struct device *dev); +void device_links_driver_bound(struct device *dev); +void device_links_driver_cleanup(struct device *dev); +void device_links_no_driver(struct device *dev); +bool device_links_busy(struct device *dev); +void device_links_unbind_consumers(struct device *dev); +void fw_devlink_drivers_done(void); +void fw_devlink_probing_done(void); /* device pm support */ void device_pm_move_to_tail(struct device *dev); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index dd4b82d7510f..84a21084d67d 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -84,7 +84,7 @@ done: return sp; } -static struct bus_type *bus_get(struct bus_type *bus) +static const struct bus_type *bus_get(const struct bus_type *bus) { struct subsys_private *sp = bus_to_subsys(bus); @@ -233,7 +233,7 @@ static const struct kset_uevent_ops bus_uevent_ops = { static ssize_t unbind_store(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = bus_get(drv->bus); + const struct bus_type *bus = bus_get(drv->bus); struct device *dev; int err = -ENODEV; @@ -256,7 +256,7 @@ static DRIVER_ATTR_IGNORE_LOCKDEP(unbind, 0200, NULL, unbind_store); static ssize_t bind_store(struct device_driver *drv, const char *buf, size_t count) { - struct bus_type *bus = bus_get(drv->bus); + const struct bus_type *bus = bus_get(drv->bus); struct device *dev; int err = -ENODEV; @@ -274,7 +274,7 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf, } static DRIVER_ATTR_IGNORE_LOCKDEP(bind, 0200, NULL, bind_store); -static ssize_t drivers_autoprobe_show(struct bus_type *bus, char *buf) +static ssize_t drivers_autoprobe_show(const struct bus_type *bus, char *buf) { struct subsys_private *sp = bus_to_subsys(bus); int ret; @@ -287,7 +287,7 @@ static ssize_t drivers_autoprobe_show(struct bus_type *bus, char *buf) return ret; } -static ssize_t drivers_autoprobe_store(struct bus_type *bus, +static ssize_t drivers_autoprobe_store(const struct bus_type *bus, const char *buf, size_t count) { struct subsys_private *sp = bus_to_subsys(bus); @@ -304,7 +304,7 @@ static ssize_t drivers_autoprobe_store(struct bus_type *bus, return count; } -static ssize_t drivers_probe_store(struct bus_type *bus, +static ssize_t drivers_probe_store(const struct bus_type *bus, const char *buf, size_t count) { struct device *dev; @@ -769,7 +769,7 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, * attached and rescan it against existing drivers to see if it matches * any by calling device_attach() for the unbound devices. */ -int bus_rescan_devices(struct bus_type *bus) +int bus_rescan_devices(const struct bus_type *bus) { return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper); } @@ -808,7 +808,7 @@ static void klist_devices_put(struct klist_node *n) put_device(dev); } -static ssize_t bus_uevent_store(struct bus_type *bus, +static ssize_t bus_uevent_store(const struct bus_type *bus, const char *buf, size_t count) { struct subsys_private *sp = bus_to_subsys(bus); @@ -841,7 +841,7 @@ static struct bus_attribute bus_attr_uevent = __ATTR(uevent, 0200, NULL, * infrastructure, then register the children subsystems it has: * the devices and drivers that belong to the subsystem. */ -int bus_register(struct bus_type *bus) +int bus_register(const struct bus_type *bus) { int retval; struct subsys_private *priv; @@ -935,8 +935,8 @@ void bus_unregister(const struct bus_type *bus) return; pr_debug("bus: '%s': unregistering\n", bus->name); - if (bus->dev_root) - device_unregister(bus->dev_root); + if (sp->dev_root) + device_unregister(sp->dev_root); bus_kobj = &sp->subsys.kobj; sysfs_remove_groups(bus_kobj, bus->bus_groups); @@ -1198,6 +1198,7 @@ static int subsys_register(struct bus_type *subsys, const struct attribute_group **groups, struct kobject *parent_of_root) { + struct subsys_private *sp; struct device *dev; int err; @@ -1205,6 +1206,12 @@ static int subsys_register(struct bus_type *subsys, if (err < 0) return err; + sp = bus_to_subsys(subsys); + if (!sp) { + err = -EINVAL; + goto err_sp; + } + dev = kzalloc(sizeof(struct device), GFP_KERNEL); if (!dev) { err = -ENOMEM; @@ -1223,7 +1230,8 @@ static int subsys_register(struct bus_type *subsys, if (err < 0) goto err_dev_reg; - subsys->dev_root = dev; + sp->dev_root = dev; + subsys_put(sp); return 0; err_dev_reg: @@ -1232,6 +1240,8 @@ err_dev_reg: err_name: kfree(dev); err_dev: + subsys_put(sp); +err_sp: bus_unregister(subsys); return err; } @@ -1297,7 +1307,7 @@ EXPORT_SYMBOL_GPL(subsys_virtual_register); * from being unregistered or unloaded while the caller is using it. * The caller is responsible for preventing this. */ -struct device_driver *driver_find(const char *name, struct bus_type *bus) +struct device_driver *driver_find(const char *name, const struct bus_type *bus) { struct subsys_private *sp = bus_to_subsys(bus); struct kobject *k; @@ -1349,9 +1359,15 @@ bool bus_is_registered(const struct bus_type *bus) */ struct device *bus_get_dev_root(const struct bus_type *bus) { - if (bus) - return get_device(bus->dev_root); - return NULL; + struct subsys_private *sp = bus_to_subsys(bus); + struct device *dev_root; + + if (!sp) + return NULL; + + dev_root = get_device(sp->dev_root); + subsys_put(sp); + return dev_root; } EXPORT_SYMBOL_GPL(bus_get_dev_root); diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index 41f0eadf1931..bba3482ddeb8 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -28,6 +28,9 @@ static DEFINE_PER_CPU(struct cpu_cacheinfo, ci_cpu_cacheinfo); #define per_cpu_cacheinfo_idx(cpu, idx) \ (per_cpu_cacheinfo(cpu) + (idx)) +/* Set if no cache information is found in DT/ACPI. */ +static bool use_arch_info; + struct cpu_cacheinfo *get_cpu_cacheinfo(unsigned int cpu) { return ci_cacheinfo(cpu); @@ -38,11 +41,11 @@ static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf, { /* * For non DT/ACPI systems, assume unique level 1 caches, - * system-wide shared caches for all other levels. This will be used - * only if arch specific code has not populated shared_cpu_map + * system-wide shared caches for all other levels. */ - if (!(IS_ENABLED(CONFIG_OF) || IS_ENABLED(CONFIG_ACPI))) - return !(this_leaf->level == 1); + if (!(IS_ENABLED(CONFIG_OF) || IS_ENABLED(CONFIG_ACPI)) || + use_arch_info) + return (this_leaf->level != 1) && (sib_leaf->level != 1); if ((sib_leaf->attributes & CACHE_ID) && (this_leaf->attributes & CACHE_ID)) @@ -79,6 +82,9 @@ bool last_level_cache_is_shared(unsigned int cpu_x, unsigned int cpu_y) } #ifdef CONFIG_OF + +static bool of_check_cache_nodes(struct device_node *np); + /* OF properties to query for a given cache type */ struct cache_type_info { const char *size_prop; @@ -206,6 +212,11 @@ static int cache_setup_of_node(unsigned int cpu) return -ENOENT; } + if (!of_check_cache_nodes(np)) { + of_node_put(np); + return -ENOENT; + } + prev = np; while (index < cache_leaves(cpu)) { @@ -230,6 +241,25 @@ static int cache_setup_of_node(unsigned int cpu) return 0; } +static bool of_check_cache_nodes(struct device_node *np) +{ + struct device_node *next; + + if (of_property_present(np, "cache-size") || + of_property_present(np, "i-cache-size") || + of_property_present(np, "d-cache-size") || + of_property_present(np, "cache-unified")) + return true; + + next = of_find_next_cache_node(np); + if (next) { + of_node_put(next); + return true; + } + + return false; +} + static int of_count_cache_leaves(struct device_node *np) { unsigned int leaves = 0; @@ -261,6 +291,11 @@ int init_of_cache_level(unsigned int cpu) struct device_node *prev = NULL; unsigned int levels = 0, leaves, level; + if (!of_check_cache_nodes(np)) { + of_node_put(np); + return -ENOENT; + } + leaves = of_count_cache_leaves(np); if (leaves > 0) levels = 1; @@ -312,6 +347,10 @@ static int cache_setup_properties(unsigned int cpu) else if (!acpi_disabled) ret = cache_setup_acpi(cpu); + // Assume there is no cache information available in DT/ACPI from now. + if (ret && use_arch_cache_info()) + use_arch_info = true; + return ret; } @@ -330,7 +369,7 @@ static int cache_shared_cpu_map_setup(unsigned int cpu) * to update the shared cpu_map if the cache attributes were * populated early before all the cpus are brought online */ - if (!last_level_cache_is_valid(cpu)) { + if (!last_level_cache_is_valid(cpu) && !use_arch_info) { ret = cache_setup_properties(cpu); if (ret) return ret; @@ -398,6 +437,11 @@ static void free_cache_attributes(unsigned int cpu) cache_shared_cpu_map_remove(cpu); } +int __weak early_cache_level(unsigned int cpu) +{ + return -ENOENT; +} + int __weak init_cache_level(unsigned int cpu) { return -ENOENT; @@ -423,56 +467,82 @@ int allocate_cache_info(int cpu) int fetch_cache_info(unsigned int cpu) { - struct cpu_cacheinfo *this_cpu_ci; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); unsigned int levels = 0, split_levels = 0; int ret; if (acpi_disabled) { ret = init_of_cache_level(cpu); - if (ret < 0) - return ret; } else { ret = acpi_get_cache_info(cpu, &levels, &split_levels); - if (ret < 0) + if (!ret) { + this_cpu_ci->num_levels = levels; + /* + * This assumes that: + * - there cannot be any split caches (data/instruction) + * above a unified cache + * - data/instruction caches come by pair + */ + this_cpu_ci->num_leaves = levels + split_levels; + } + } + + if (ret || !cache_leaves(cpu)) { + ret = early_cache_level(cpu); + if (ret) return ret; - this_cpu_ci = get_cpu_cacheinfo(cpu); - this_cpu_ci->num_levels = levels; - /* - * This assumes that: - * - there cannot be any split caches (data/instruction) - * above a unified cache - * - data/instruction caches come by pair - */ - this_cpu_ci->num_leaves = levels + split_levels; + if (!cache_leaves(cpu)) + return -ENOENT; + + this_cpu_ci->early_ci_levels = true; } - if (!cache_leaves(cpu)) - return -ENOENT; return allocate_cache_info(cpu); } -int detect_cache_attributes(unsigned int cpu) +static inline int init_level_allocate_ci(unsigned int cpu) { - int ret; + unsigned int early_leaves = cache_leaves(cpu); /* Since early initialization/allocation of the cacheinfo is allowed * via fetch_cache_info() and this also gets called as CPU hotplug * callbacks via cacheinfo_cpu_online, the init/alloc can be skipped * as it will happen only once (the cacheinfo memory is never freed). - * Just populate the cacheinfo. + * Just populate the cacheinfo. However, if the cacheinfo has been + * allocated early through the arch-specific early_cache_level() call, + * there is a chance the info is wrong (this can happen on arm64). In + * that case, call init_cache_level() anyway to give the arch-specific + * code a chance to make things right. */ - if (per_cpu_cacheinfo(cpu)) - goto populate_leaves; + if (per_cpu_cacheinfo(cpu) && !ci_cacheinfo(cpu)->early_ci_levels) + return 0; if (init_cache_level(cpu) || !cache_leaves(cpu)) return -ENOENT; - ret = allocate_cache_info(cpu); + /* + * Now that we have properly initialized the cache level info, make + * sure we don't try to do that again the next time we are called + * (e.g. as CPU hotplug callbacks). + */ + ci_cacheinfo(cpu)->early_ci_levels = false; + + if (cache_leaves(cpu) <= early_leaves) + return 0; + + kfree(per_cpu_cacheinfo(cpu)); + return allocate_cache_info(cpu); +} + +int detect_cache_attributes(unsigned int cpu) +{ + int ret; + + ret = init_level_allocate_ci(cpu); if (ret) return ret; -populate_leaves: /* * If LLC is valid the cache leaves were already populated so just go to * update the cpu map. diff --git a/drivers/base/class.c b/drivers/base/class.c index 2373b3e210d8..ac1808d1a2e8 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -20,8 +20,52 @@ #include <linux/mutex.h> #include "base.h" +/* /sys/class */ +static struct kset *class_kset; + #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) +/** + * class_to_subsys - Turn a struct class into a struct subsys_private + * + * @class: pointer to the struct bus_type to look up + * + * The driver core internals need to work on the subsys_private structure, not + * the external struct class pointer. This function walks the list of + * registered classes in the system and finds the matching one and returns the + * internal struct subsys_private that relates to that class. + * + * Note, the reference count of the return value is INCREMENTED if it is not + * NULL. A call to subsys_put() must be done when finished with the pointer in + * order for it to be properly freed. + */ +struct subsys_private *class_to_subsys(const struct class *class) +{ + struct subsys_private *sp = NULL; + struct kobject *kobj; + + if (!class || !class_kset) + return NULL; + + spin_lock(&class_kset->list_lock); + + if (list_empty(&class_kset->list)) + goto done; + + list_for_each_entry(kobj, &class_kset->list, entry) { + struct kset *kset = container_of(kobj, struct kset, kobj); + + sp = container_of_const(kset, struct subsys_private, subsys); + if (sp->class == class) + goto done; + } + sp = NULL; +done: + sp = subsys_get(sp); + spin_unlock(&class_kset->list_lock); + return sp; +} + static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { @@ -49,25 +93,24 @@ static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr, static void class_release(struct kobject *kobj) { struct subsys_private *cp = to_subsys_private(kobj); - struct class *class = cp->class; + const struct class *class = cp->class; pr_debug("class '%s': release.\n", class->name); - class->p = NULL; - if (class->class_release) class->class_release(class); else pr_debug("class '%s' does not have a release() function, " "be careful\n", class->name); + lockdep_unregister_key(&cp->lock_key); kfree(cp); } static const struct kobj_ns_type_operations *class_child_ns_type(const struct kobject *kobj) { const struct subsys_private *cp = to_subsys_private(kobj); - struct class *class = cp->class; + const struct class *class = cp->class; return class->ns_type; } @@ -83,44 +126,34 @@ static const struct kobj_type class_ktype = { .child_ns_type = class_child_ns_type, }; -/* Hotplug events for classes go to the class subsys */ -static struct kset *class_kset; - - -int class_create_file_ns(struct class *cls, const struct class_attribute *attr, +int class_create_file_ns(const struct class *cls, const struct class_attribute *attr, const void *ns) { + struct subsys_private *sp = class_to_subsys(cls); int error; - if (cls) - error = sysfs_create_file_ns(&cls->p->subsys.kobj, - &attr->attr, ns); - else - error = -EINVAL; + if (!sp) + return -EINVAL; + + error = sysfs_create_file_ns(&sp->subsys.kobj, &attr->attr, ns); + subsys_put(sp); + return error; } EXPORT_SYMBOL_GPL(class_create_file_ns); -void class_remove_file_ns(struct class *cls, const struct class_attribute *attr, +void class_remove_file_ns(const struct class *cls, const struct class_attribute *attr, const void *ns) { - if (cls) - sysfs_remove_file_ns(&cls->p->subsys.kobj, &attr->attr, ns); -} -EXPORT_SYMBOL_GPL(class_remove_file_ns); + struct subsys_private *sp = class_to_subsys(cls); -static struct class *class_get(struct class *cls) -{ - if (cls) - kset_get(&cls->p->subsys); - return cls; -} + if (!sp) + return; -static void class_put(struct class *cls) -{ - if (cls) - kset_put(&cls->p->subsys); + sysfs_remove_file_ns(&sp->subsys.kobj, &attr->attr, ns); + subsys_put(sp); } +EXPORT_SYMBOL_GPL(class_remove_file_ns); static struct device *klist_class_to_dev(struct klist_node *n) { @@ -142,21 +175,10 @@ static void klist_class_dev_put(struct klist_node *n) put_device(dev); } -static int class_add_groups(struct class *cls, - const struct attribute_group **groups) -{ - return sysfs_create_groups(&cls->p->subsys.kobj, groups); -} - -static void class_remove_groups(struct class *cls, - const struct attribute_group **groups) -{ - return sysfs_remove_groups(&cls->p->subsys.kobj, groups); -} - -int __class_register(struct class *cls, struct lock_class_key *key) +int class_register(const struct class *cls) { struct subsys_private *cp; + struct lock_class_key *key; int error; pr_debug("device class '%s': registering\n", cls->name); @@ -167,6 +189,8 @@ int __class_register(struct class *cls, struct lock_class_key *key) klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put); INIT_LIST_HEAD(&cp->interfaces); kset_init(&cp->glue_dirs); + key = &cp->lock_key; + lockdep_register_key(key); __mutex_init(&cp->mutex, "subsys mutex", key); error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name); if (error) { @@ -174,27 +198,15 @@ int __class_register(struct class *cls, struct lock_class_key *key) return error; } - /* set the default /sys/dev directory for devices of this class */ - if (!cls->dev_kobj) - cls->dev_kobj = sysfs_dev_char_kobj; - -#if defined(CONFIG_BLOCK) - /* let the block class directory show up in the root of sysfs */ - if (!sysfs_deprecated || cls != &block_class) - cp->subsys.kobj.kset = class_kset; -#else cp->subsys.kobj.kset = class_kset; -#endif cp->subsys.kobj.ktype = &class_ktype; cp->class = cls; - cls->p = cp; error = kset_register(&cp->subsys); if (error) goto err_out; - error = class_add_groups(class_get(cls), cls->class_groups); - class_put(cls); + error = sysfs_create_groups(&cp->subsys.kobj, cls->class_groups); if (error) { kobject_del(&cp->subsys.kobj); kfree_const(cp->subsys.kobj.name); @@ -204,30 +216,34 @@ int __class_register(struct class *cls, struct lock_class_key *key) err_out: kfree(cp); - cls->p = NULL; return error; } -EXPORT_SYMBOL_GPL(__class_register); +EXPORT_SYMBOL_GPL(class_register); -void class_unregister(struct class *cls) +void class_unregister(const struct class *cls) { + struct subsys_private *sp = class_to_subsys(cls); + + if (!sp) + return; + pr_debug("device class '%s': unregistering\n", cls->name); - class_remove_groups(cls, cls->class_groups); - kset_unregister(&cls->p->subsys); + + sysfs_remove_groups(&sp->subsys.kobj, cls->class_groups); + kset_unregister(&sp->subsys); + subsys_put(sp); } EXPORT_SYMBOL_GPL(class_unregister); -static void class_create_release(struct class *cls) +static void class_create_release(const struct class *cls) { pr_debug("%s called for %s\n", __func__, cls->name); kfree(cls); } /** - * __class_create - create a struct class structure - * @owner: pointer to the module that is to "own" this struct class + * class_create - create a struct class structure * @name: pointer to a string for the name of this class. - * @key: the lock_class_key for this class; used by mutex lock debugging * * This is used to create a struct class pointer that can then be used * in calls to device_create(). @@ -237,8 +253,7 @@ static void class_create_release(struct class *cls) * Note, the pointer created here is to be destroyed when finished by * making a call to class_destroy(). */ -struct class *__class_create(struct module *owner, const char *name, - struct lock_class_key *key) +struct class *class_create(const char *name) { struct class *cls; int retval; @@ -250,10 +265,9 @@ struct class *__class_create(struct module *owner, const char *name, } cls->name = name; - cls->owner = owner; cls->class_release = class_create_release; - retval = __class_register(cls, key); + retval = class_register(cls); if (retval) goto error; @@ -263,7 +277,7 @@ error: kfree(cls); return ERR_PTR(retval); } -EXPORT_SYMBOL_GPL(__class_create); +EXPORT_SYMBOL_GPL(class_create); /** * class_destroy - destroys a struct class structure @@ -272,7 +286,7 @@ EXPORT_SYMBOL_GPL(__class_create); * Note, the pointer to be destroyed must have been created with a call * to class_create(). */ -void class_destroy(struct class *cls) +void class_destroy(const struct class *cls) { if (IS_ERR_OR_NULL(cls)) return; @@ -293,14 +307,18 @@ EXPORT_SYMBOL_GPL(class_destroy); * otherwise if it is NULL, the iteration starts at the beginning of * the list. */ -void class_dev_iter_init(struct class_dev_iter *iter, struct class *class, - struct device *start, const struct device_type *type) +void class_dev_iter_init(struct class_dev_iter *iter, const struct class *class, + const struct device *start, const struct device_type *type) { + struct subsys_private *sp = class_to_subsys(class); struct klist_node *start_knode = NULL; + if (!sp) + return; + if (start) start_knode = &start->p->knode_class; - klist_iter_init_node(&class->p->klist_devices, &iter->ki, start_knode); + klist_iter_init_node(&sp->klist_devices, &iter->ki, start_knode); iter->type = type; } EXPORT_SYMBOL_GPL(class_dev_iter_init); @@ -364,16 +382,17 @@ EXPORT_SYMBOL_GPL(class_dev_iter_exit); * @fn is allowed to do anything including calling back into class * code. There's no locking restriction. */ -int class_for_each_device(struct class *class, struct device *start, +int class_for_each_device(const struct class *class, const struct device *start, void *data, int (*fn)(struct device *, void *)) { + struct subsys_private *sp = class_to_subsys(class); struct class_dev_iter iter; struct device *dev; int error = 0; if (!class) return -EINVAL; - if (!class->p) { + if (!sp) { WARN(1, "%s called for class '%s' before it was initialized", __func__, class->name); return -EINVAL; @@ -386,6 +405,7 @@ int class_for_each_device(struct class *class, struct device *start, break; } class_dev_iter_exit(&iter); + subsys_put(sp); return error; } @@ -411,16 +431,17 @@ EXPORT_SYMBOL_GPL(class_for_each_device); * @match is allowed to do anything including calling back into class * code. There's no locking restriction. */ -struct device *class_find_device(struct class *class, struct device *start, +struct device *class_find_device(const struct class *class, const struct device *start, const void *data, int (*match)(struct device *, const void *)) { + struct subsys_private *sp = class_to_subsys(class); struct class_dev_iter iter; struct device *dev; if (!class) return NULL; - if (!class->p) { + if (!sp) { WARN(1, "%s called for class '%s' before it was initialized", __func__, class->name); return NULL; @@ -434,6 +455,7 @@ struct device *class_find_device(struct class *class, struct device *start, } } class_dev_iter_exit(&iter); + subsys_put(sp); return dev; } @@ -441,26 +463,33 @@ EXPORT_SYMBOL_GPL(class_find_device); int class_interface_register(struct class_interface *class_intf) { - struct class *parent; + struct subsys_private *sp; + const struct class *parent; struct class_dev_iter iter; struct device *dev; if (!class_intf || !class_intf->class) return -ENODEV; - parent = class_get(class_intf->class); - if (!parent) + parent = class_intf->class; + sp = class_to_subsys(parent); + if (!sp) return -EINVAL; - mutex_lock(&parent->p->mutex); - list_add_tail(&class_intf->node, &parent->p->interfaces); + /* + * Reference in sp is now incremented and will be dropped when + * the interface is removed in the call to class_interface_unregister() + */ + + mutex_lock(&sp->mutex); + list_add_tail(&class_intf->node, &sp->interfaces); if (class_intf->add_dev) { class_dev_iter_init(&iter, parent, NULL, NULL); while ((dev = class_dev_iter_next(&iter))) - class_intf->add_dev(dev, class_intf); + class_intf->add_dev(dev); class_dev_iter_exit(&iter); } - mutex_unlock(&parent->p->mutex); + mutex_unlock(&sp->mutex); return 0; } @@ -468,29 +497,40 @@ EXPORT_SYMBOL_GPL(class_interface_register); void class_interface_unregister(struct class_interface *class_intf) { - struct class *parent = class_intf->class; + struct subsys_private *sp; + const struct class *parent = class_intf->class; struct class_dev_iter iter; struct device *dev; if (!parent) return; - mutex_lock(&parent->p->mutex); + sp = class_to_subsys(parent); + if (!sp) + return; + + mutex_lock(&sp->mutex); list_del_init(&class_intf->node); if (class_intf->remove_dev) { class_dev_iter_init(&iter, parent, NULL, NULL); while ((dev = class_dev_iter_next(&iter))) - class_intf->remove_dev(dev, class_intf); + class_intf->remove_dev(dev); class_dev_iter_exit(&iter); } - mutex_unlock(&parent->p->mutex); + mutex_unlock(&sp->mutex); - class_put(parent); + /* + * Decrement the reference count twice, once for the class_to_subsys() + * call in the start of this function, and the second one from the + * reference increment in class_interface_register() + */ + subsys_put(sp); + subsys_put(sp); } EXPORT_SYMBOL_GPL(class_interface_unregister); -ssize_t show_class_attr_string(struct class *class, - struct class_attribute *attr, char *buf) +ssize_t show_class_attr_string(const struct class *class, + const struct class_attribute *attr, char *buf) { struct class_attribute_string *cs; @@ -587,6 +627,31 @@ void class_compat_remove_link(struct class_compat *cls, struct device *dev, } EXPORT_SYMBOL_GPL(class_compat_remove_link); +/** + * class_is_registered - determine if at this moment in time, a class is + * registered in the driver core or not. + * @class: the class to check + * + * Returns a boolean to state if the class is registered in the driver core + * or not. Note that the value could switch right after this call is made, + * so only use this in places where you "know" it is safe to do so (usually + * to determine if the specific class has been registered yet or not). + * + * Be careful in using this. + */ +bool class_is_registered(const struct class *class) +{ + struct subsys_private *sp = class_to_subsys(class); + bool is_initialized = false; + + if (sp) { + is_initialized = true; + subsys_put(sp); + } + return is_initialized; +} +EXPORT_SYMBOL_GPL(class_is_registered); + int __init classes_init(void) { class_kset = kset_create_and_add("class", NULL, NULL); diff --git a/drivers/base/core.c b/drivers/base/core.c index 6878dfcbf0d6..3dff5037943e 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -36,19 +36,6 @@ #include "physical_location.h" #include "power/power.h" -#ifdef CONFIG_SYSFS_DEPRECATED -#ifdef CONFIG_SYSFS_DEPRECATED_V2 -long sysfs_deprecated = 1; -#else -long sysfs_deprecated = 0; -#endif -static int __init sysfs_deprecated_setup(char *arg) -{ - return kstrtol(arg, 10, &sysfs_deprecated); -} -early_param("sysfs.deprecated", sysfs_deprecated_setup); -#endif - /* Device links support. */ static LIST_HEAD(deferred_sync); static unsigned int defer_sync_state_count = 1; @@ -550,13 +537,11 @@ static void devlink_dev_release(struct device *dev) static struct class devlink_class = { .name = "devlink", - .owner = THIS_MODULE, .dev_groups = devlink_groups, .dev_release = devlink_dev_release, }; -static int devlink_add_symlinks(struct device *dev, - struct class_interface *class_intf) +static int devlink_add_symlinks(struct device *dev) { int ret; size_t len; @@ -605,8 +590,7 @@ out: return ret; } -static void devlink_remove_symlinks(struct device *dev, - struct class_interface *class_intf) +static void devlink_remove_symlinks(struct device *dev) { struct device_link *link = to_devlink(dev); size_t len; @@ -1173,10 +1157,7 @@ static void device_links_flush_sync_list(struct list_head *list, if (dev != dont_lock_dev) device_lock(dev); - if (dev->bus->sync_state) - dev->bus->sync_state(dev); - else if (dev->driver && dev->driver->sync_state) - dev->driver->sync_state(dev); + dev_sync_state(dev); if (dev != dont_lock_dev) device_unlock(dev); @@ -1685,6 +1666,31 @@ static int __init fw_devlink_strict_setup(char *arg) } early_param("fw_devlink.strict", fw_devlink_strict_setup); +#define FW_DEVLINK_SYNC_STATE_STRICT 0 +#define FW_DEVLINK_SYNC_STATE_TIMEOUT 1 + +#ifndef CONFIG_FW_DEVLINK_SYNC_STATE_TIMEOUT +static int fw_devlink_sync_state; +#else +static int fw_devlink_sync_state = FW_DEVLINK_SYNC_STATE_TIMEOUT; +#endif + +static int __init fw_devlink_sync_state_setup(char *arg) +{ + if (!arg) + return -EINVAL; + + if (strcmp(arg, "strict") == 0) { + fw_devlink_sync_state = FW_DEVLINK_SYNC_STATE_STRICT; + return 0; + } else if (strcmp(arg, "timeout") == 0) { + fw_devlink_sync_state = FW_DEVLINK_SYNC_STATE_TIMEOUT; + return 0; + } + return -EINVAL; +} +early_param("fw_devlink.sync_state", fw_devlink_sync_state_setup); + static inline u32 fw_devlink_get_flags(u8 fwlink_flags) { if (fwlink_flags & FWLINK_FLAG_CYCLE) @@ -1755,6 +1761,44 @@ void fw_devlink_drivers_done(void) device_links_write_unlock(); } +static int fw_devlink_dev_sync_state(struct device *dev, void *data) +{ + struct device_link *link = to_devlink(dev); + struct device *sup = link->supplier; + + if (!(link->flags & DL_FLAG_MANAGED) || + link->status == DL_STATE_ACTIVE || sup->state_synced || + !dev_has_sync_state(sup)) + return 0; + + if (fw_devlink_sync_state == FW_DEVLINK_SYNC_STATE_STRICT) { + dev_warn(sup, "sync_state() pending due to %s\n", + dev_name(link->consumer)); + return 0; + } + + if (!list_empty(&sup->links.defer_sync)) + return 0; + + dev_warn(sup, "Timed out. Forcing sync_state()\n"); + sup->state_synced = true; + get_device(sup); + list_add_tail(&sup->links.defer_sync, data); + + return 0; +} + +void fw_devlink_probing_done(void) +{ + LIST_HEAD(sync_list); + + device_links_write_lock(); + class_for_each_device(&devlink_class, NULL, &sync_list, + fw_devlink_dev_sync_state); + device_links_write_unlock(); + device_links_flush_sync_list(&sync_list, NULL); +} + /** * wait_for_init_devices_probe - Try to probe any device needed for init * @@ -2209,8 +2253,12 @@ static void fw_devlink_link_device(struct device *dev) int (*platform_notify)(struct device *dev) = NULL; int (*platform_notify_remove)(struct device *dev) = NULL; static struct kobject *dev_kobj; -struct kobject *sysfs_dev_char_kobj; -struct kobject *sysfs_dev_block_kobj; + +/* /sys/dev/char */ +static struct kobject *sysfs_dev_char_kobj; + +/* /sys/dev/block */ +static struct kobject *sysfs_dev_block_kobj; static DEFINE_MUTEX(device_hotplug_lock); @@ -2779,7 +2827,7 @@ EXPORT_SYMBOL_GPL(devm_device_add_groups); static int device_add_attrs(struct device *dev) { - struct class *class = dev->class; + const struct class *class = dev->class; const struct device_type *type = dev->type; int error; @@ -2846,7 +2894,7 @@ static int device_add_attrs(struct device *dev) static void device_remove_attrs(struct device *dev) { - struct class *class = dev->class; + const struct class *class = dev->class; const struct device_type *type = dev->type; if (dev->physical_location) { @@ -3079,7 +3127,7 @@ struct kobject *virtual_device_parent(struct device *dev) struct class_dir { struct kobject kobj; - struct class *class; + const struct class *class; }; #define to_class_dir(obj) container_of(obj, struct class_dir, kobj) @@ -3103,8 +3151,8 @@ static const struct kobj_type class_dir_ktype = { .child_ns_type = class_dir_child_ns_type }; -static struct kobject * -class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) +static struct kobject *class_dir_create_and_add(struct subsys_private *sp, + struct kobject *parent_kobj) { struct class_dir *dir; int retval; @@ -3113,12 +3161,12 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) if (!dir) return ERR_PTR(-ENOMEM); - dir->class = class; + dir->class = sp->class; kobject_init(&dir->kobj, &class_dir_ktype); - dir->kobj.kset = &class->p->glue_dirs; + dir->kobj.kset = &sp->glue_dirs; - retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name); + retval = kobject_add(&dir->kobj, parent_kobj, "%s", sp->class->name); if (retval < 0) { kobject_put(&dir->kobj); return ERR_PTR(retval); @@ -3131,21 +3179,13 @@ static DEFINE_MUTEX(gdp_mutex); static struct kobject *get_device_parent(struct device *dev, struct device *parent) { + struct subsys_private *sp = class_to_subsys(dev->class); struct kobject *kobj = NULL; - if (dev->class) { + if (sp) { struct kobject *parent_kobj; struct kobject *k; -#ifdef CONFIG_BLOCK - /* block disks show up in /sys/block */ - if (sysfs_deprecated && dev->class == &block_class) { - if (parent && parent->class == &block_class) - return &parent->kobj; - return &block_class.p->subsys.kobj; - } -#endif - /* * If we have no parent, we live in "virtual". * Class-devices with a non class-device as parent, live @@ -3153,30 +3193,34 @@ static struct kobject *get_device_parent(struct device *dev, */ if (parent == NULL) parent_kobj = virtual_device_parent(dev); - else if (parent->class && !dev->class->ns_type) + else if (parent->class && !dev->class->ns_type) { + subsys_put(sp); return &parent->kobj; - else + } else { parent_kobj = &parent->kobj; + } mutex_lock(&gdp_mutex); /* find our class-directory at the parent and reference it */ - spin_lock(&dev->class->p->glue_dirs.list_lock); - list_for_each_entry(k, &dev->class->p->glue_dirs.list, entry) + spin_lock(&sp->glue_dirs.list_lock); + list_for_each_entry(k, &sp->glue_dirs.list, entry) if (k->parent == parent_kobj) { kobj = kobject_get(k); break; } - spin_unlock(&dev->class->p->glue_dirs.list_lock); + spin_unlock(&sp->glue_dirs.list_lock); if (kobj) { mutex_unlock(&gdp_mutex); + subsys_put(sp); return kobj; } /* or create a new class-directory at the parent device */ - k = class_dir_create_and_add(dev->class, parent_kobj); + k = class_dir_create_and_add(sp, parent_kobj); /* do not emit an uevent for this simple "glue" directory */ mutex_unlock(&gdp_mutex); + subsys_put(sp); return k; } @@ -3199,10 +3243,23 @@ static struct kobject *get_device_parent(struct device *dev, static inline bool live_in_glue_dir(struct kobject *kobj, struct device *dev) { - if (!kobj || !dev->class || - kobj->kset != &dev->class->p->glue_dirs) + struct subsys_private *sp; + bool retval; + + if (!kobj || !dev->class) return false; - return true; + + sp = class_to_subsys(dev->class); + if (!sp) + return false; + + if (kobj->kset == &sp->glue_dirs) + retval = true; + else + retval = false; + + subsys_put(sp); + return retval; } static inline struct kobject *get_glue_dir(struct device *dev) @@ -3299,6 +3356,7 @@ static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) static int device_add_class_symlinks(struct device *dev) { struct device_node *of_node = dev_of_node(dev); + struct subsys_private *sp; int error; if (of_node) { @@ -3308,12 +3366,11 @@ static int device_add_class_symlinks(struct device *dev) /* An error here doesn't warrant bringing down the device */ } - if (!dev->class) + sp = class_to_subsys(dev->class); + if (!sp) return 0; - error = sysfs_create_link(&dev->kobj, - &dev->class->p->subsys.kobj, - "subsystem"); + error = sysfs_create_link(&dev->kobj, &sp->subsys.kobj, "subsystem"); if (error) goto out_devnode; @@ -3324,46 +3381,38 @@ static int device_add_class_symlinks(struct device *dev) goto out_subsys; } -#ifdef CONFIG_BLOCK - /* /sys/block has directories and does not need symlinks */ - if (sysfs_deprecated && dev->class == &block_class) - return 0; -#endif - /* link in the class directory pointing to the device */ - error = sysfs_create_link(&dev->class->p->subsys.kobj, - &dev->kobj, dev_name(dev)); + error = sysfs_create_link(&sp->subsys.kobj, &dev->kobj, dev_name(dev)); if (error) goto out_device; - - return 0; + goto exit; out_device: sysfs_remove_link(&dev->kobj, "device"); - out_subsys: sysfs_remove_link(&dev->kobj, "subsystem"); out_devnode: sysfs_remove_link(&dev->kobj, "of_node"); +exit: + subsys_put(sp); return error; } static void device_remove_class_symlinks(struct device *dev) { + struct subsys_private *sp = class_to_subsys(dev->class); + if (dev_of_node(dev)) sysfs_remove_link(&dev->kobj, "of_node"); - if (!dev->class) + if (!sp) return; if (dev->parent && device_is_not_partition(dev)) sysfs_remove_link(&dev->kobj, "device"); sysfs_remove_link(&dev->kobj, "subsystem"); -#ifdef CONFIG_BLOCK - if (sysfs_deprecated && dev->class == &block_class) - return; -#endif - sysfs_delete_link(&dev->class->p->subsys.kobj, &dev->kobj, dev_name(dev)); + sysfs_delete_link(&sp->subsys.kobj, &dev->kobj, dev_name(dev)); + subsys_put(sp); } /** @@ -3383,27 +3432,13 @@ int dev_set_name(struct device *dev, const char *fmt, ...) } EXPORT_SYMBOL_GPL(dev_set_name); -/** - * device_to_dev_kobj - select a /sys/dev/ directory for the device - * @dev: device - * - * By default we select char/ for new entries. Setting class->dev_obj - * to NULL prevents an entry from being created. class->dev_kobj must - * be set (or cleared) before any devices are registered to the class - * otherwise device_create_sys_dev_entry() and - * device_remove_sys_dev_entry() will disagree about the presence of - * the link. - */ +/* select a /sys/dev/ directory for the device */ static struct kobject *device_to_dev_kobj(struct device *dev) { - struct kobject *kobj; - - if (dev->class) - kobj = dev->class->dev_kobj; + if (is_blockdev(dev)) + return sysfs_dev_block_kobj; else - kobj = sysfs_dev_char_kobj; - - return kobj; + return sysfs_dev_char_kobj; } static int device_create_sys_dev_entry(struct device *dev) @@ -3472,6 +3507,7 @@ static int device_private_init(struct device *dev) */ int device_add(struct device *dev) { + struct subsys_private *sp; struct device *parent; struct kobject *kobj; struct class_interface *class_intf; @@ -3600,18 +3636,18 @@ int device_add(struct device *dev) klist_add_tail(&dev->p->knode_parent, &parent->p->klist_children); - if (dev->class) { - mutex_lock(&dev->class->p->mutex); + sp = class_to_subsys(dev->class); + if (sp) { + mutex_lock(&sp->mutex); /* tie the class to the device */ - klist_add_tail(&dev->p->knode_class, - &dev->class->p->klist_devices); + klist_add_tail(&dev->p->knode_class, &sp->klist_devices); /* notify any interfaces that the device is here */ - list_for_each_entry(class_intf, - &dev->class->p->interfaces, node) + list_for_each_entry(class_intf, &sp->interfaces, node) if (class_intf->add_dev) - class_intf->add_dev(dev, class_intf); - mutex_unlock(&dev->class->p->mutex); + class_intf->add_dev(dev); + mutex_unlock(&sp->mutex); + subsys_put(sp); } done: put_device(dev); @@ -3731,6 +3767,7 @@ EXPORT_SYMBOL_GPL(kill_device); */ void device_del(struct device *dev) { + struct subsys_private *sp; struct device *parent = dev->parent; struct kobject *glue_dir = NULL; struct class_interface *class_intf; @@ -3757,18 +3794,20 @@ void device_del(struct device *dev) device_remove_sys_dev_entry(dev); device_remove_file(dev, &dev_attr_dev); } - if (dev->class) { + + sp = class_to_subsys(dev->class); + if (sp) { device_remove_class_symlinks(dev); - mutex_lock(&dev->class->p->mutex); + mutex_lock(&sp->mutex); /* notify any interfaces that the device is now gone */ - list_for_each_entry(class_intf, - &dev->class->p->interfaces, node) + list_for_each_entry(class_intf, &sp->interfaces, node) if (class_intf->remove_dev) - class_intf->remove_dev(dev, class_intf); + class_intf->remove_dev(dev); /* remove the device from the class list */ klist_del(&dev->p->knode_class); - mutex_unlock(&dev->class->p->mutex); + mutex_unlock(&sp->mutex); + subsys_put(sp); } device_remove_file(dev, &dev_attr_uevent); device_remove_attrs(dev); @@ -4231,7 +4270,7 @@ static void device_create_release(struct device *dev) } static __printf(6, 0) struct device * -device_create_groups_vargs(struct class *class, struct device *parent, +device_create_groups_vargs(const struct class *class, struct device *parent, dev_t devt, void *drvdata, const struct attribute_group **groups, const char *fmt, va_list args) @@ -4291,11 +4330,8 @@ error: * pointer. * * Returns &struct device pointer on success, or ERR_PTR() on error. - * - * Note: the struct class passed to this function must have previously - * been created with a call to class_create(). */ -struct device *device_create(struct class *class, struct device *parent, +struct device *device_create(const struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...) { va_list vargs; @@ -4332,11 +4368,8 @@ EXPORT_SYMBOL_GPL(device_create); * pointer. * * Returns &struct device pointer on success, or ERR_PTR() on error. - * - * Note: the struct class passed to this function must have previously - * been created with a call to class_create(). */ -struct device *device_create_with_groups(struct class *class, +struct device *device_create_with_groups(const struct class *class, struct device *parent, dev_t devt, void *drvdata, const struct attribute_group **groups, @@ -4361,7 +4394,7 @@ EXPORT_SYMBOL_GPL(device_create_with_groups); * This call unregisters and cleans up a device that was created with a * call to device_create(). */ -void device_destroy(struct class *class, dev_t devt) +void device_destroy(const struct class *class, dev_t devt) { struct device *dev; @@ -4383,9 +4416,12 @@ EXPORT_SYMBOL_GPL(device_destroy); * on the same device to ensure that new_name is valid and * won't conflict with other devices. * - * Note: Don't call this function. Currently, the networking layer calls this - * function, but that will change. The following text from Kay Sievers offers - * some insight: + * Note: given that some subsystems (networking and infiniband) use this + * function, with no immediate plans for this to change, we cannot assume or + * require that this function not be called at all. + * + * However, if you're writing new code, do not call this function. The following + * text from Kay Sievers offers some insight: * * Renaming devices is racy at many levels, symlinks and other stuff are not * replaced atomically, and you get a "move" uevent, but it's not easy to @@ -4399,13 +4435,6 @@ EXPORT_SYMBOL_GPL(device_destroy); * kernel device renaming. Besides that, it's not even implemented now for * other things than (driver-core wise very simple) network devices. * - * We are currently about to change network renaming in udev to completely - * disallow renaming of devices in the same namespace as the kernel uses, - * because we can't solve the problems properly, that arise with swapping names - * of multiple interfaces without races. Means, renaming of eth[0-9]* will only - * be allowed to some other name than eth[0-9]*, for the aforementioned - * reasons. - * * Make up a "real" name in the driver before you register anything, or add * some other attributes for userspace to find the device, or use udev to add * symlinks -- but never rename kernel devices later, it's a complete mess. We @@ -4431,9 +4460,16 @@ int device_rename(struct device *dev, const char *new_name) } if (dev->class) { - error = sysfs_rename_link_ns(&dev->class->p->subsys.kobj, - kobj, old_device_name, + struct subsys_private *sp = class_to_subsys(dev->class); + + if (!sp) { + error = -EINVAL; + goto out; + } + + error = sysfs_rename_link_ns(&sp->subsys.kobj, kobj, old_device_name, new_name, kobject_namespace(kobj)); + subsys_put(sp); if (error) goto out; } @@ -4558,7 +4594,7 @@ static int device_attrs_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid) { struct kobject *kobj = &dev->kobj; - struct class *class = dev->class; + const struct class *class = dev->class; const struct device_type *type = dev->type; int error; @@ -4616,6 +4652,7 @@ int device_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid) { int error; struct kobject *kobj = &dev->kobj; + struct subsys_private *sp; dev = get_device(dev); if (!dev) @@ -4652,21 +4689,19 @@ int device_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid) if (error) goto out; -#ifdef CONFIG_BLOCK - if (sysfs_deprecated && dev->class == &block_class) - goto out; -#endif - /* * Change the owner of the symlink located in the class directory of * the device class associated with @dev which points to the actual * directory entry for @dev to @kuid/@kgid. This ensures that the * symlink shows the same permissions as its target. */ - error = sysfs_link_change_owner(&dev->class->p->subsys.kobj, &dev->kobj, - dev_name(dev), kuid, kgid); - if (error) + sp = class_to_subsys(dev->class); + if (!sp) { + error = -EINVAL; goto out; + } + error = sysfs_link_change_owner(&sp->subsys.kobj, &dev->kobj, dev_name(dev), kuid, kgid); + subsys_put(sp); out: put_device(dev); @@ -4965,9 +5000,13 @@ void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode) } else { if (fwnode_is_primary(fn)) { dev->fwnode = fn->secondary; + + /* Skip nullifying fn->secondary if the primary is shared */ + if (parent && fn == parent->fwnode) + return; + /* Set fn->secondary = NULL, so fn remains the primary fwnode */ - if (!(parent && fn == parent->fwnode)) - fn->secondary = NULL; + fn->secondary = NULL; } else { dev->fwnode = NULL; } diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 8def2ba08a82..9c09ca5c4ab6 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -315,6 +315,8 @@ static void deferred_probe_timeout_work_func(struct work_struct *work) list_for_each_entry(p, &deferred_probe_pending_list, deferred_probe) dev_info(p->device, "deferred probe pending\n"); mutex_unlock(&deferred_probe_mutex); + + fw_devlink_probing_done(); } static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func); @@ -364,6 +366,10 @@ static int deferred_probe_initcall(void) schedule_delayed_work(&deferred_probe_timeout_work, driver_deferred_probe_timeout * HZ); } + + if (!IS_ENABLED(CONFIG_MODULES)) + fw_devlink_probing_done(); + return 0; } late_initcall(deferred_probe_initcall); @@ -504,6 +510,27 @@ EXPORT_SYMBOL_GPL(device_bind_driver); static atomic_t probe_count = ATOMIC_INIT(0); static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); +static ssize_t state_synced_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret = 0; + + if (strcmp("1", buf)) + return -EINVAL; + + device_lock(dev); + if (!dev->state_synced) { + dev->state_synced = true; + dev_sync_state(dev); + } else { + ret = -EINVAL; + } + device_unlock(dev); + + return ret ? ret : count; +} + static ssize_t state_synced_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -515,7 +542,7 @@ static ssize_t state_synced_show(struct device *dev, return sysfs_emit(buf, "%u\n", val); } -static DEVICE_ATTR_RO(state_synced); +static DEVICE_ATTR_RW(state_synced); static void device_unbind_cleanup(struct device *dev) { @@ -708,7 +735,12 @@ static int really_probe_debug(struct device *dev, struct device_driver *drv) calltime = ktime_get(); ret = really_probe(dev, drv); rettime = ktime_get(); - pr_debug("probe of %s returned %d after %lld usecs\n", + /* + * Don't change this to pr_debug() because that requires + * CONFIG_DYNAMIC_DEBUG and we want a simple 'initcall_debug' on the + * kernel commandline to print this all the time at the debug level. + */ + printk(KERN_DEBUG "probe of %s returned %d after %lld usecs\n", dev_name(dev), ret, ktime_us_delta(rettime, calltime)); return ret; } diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index 1c06781f7114..91536ee05f14 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -167,7 +167,7 @@ static int devcd_free(struct device *dev, void *data) return 0; } -static ssize_t disabled_show(struct class *class, struct class_attribute *attr, +static ssize_t disabled_show(const struct class *class, const struct class_attribute *attr, char *buf) { return sysfs_emit(buf, "%d\n", devcd_disabled); @@ -197,7 +197,7 @@ static ssize_t disabled_show(struct class *class, struct class_attribute *attr, * so, above situation would not occur. */ -static ssize_t disabled_store(struct class *class, struct class_attribute *attr, +static ssize_t disabled_store(const struct class *class, const struct class_attribute *attr, const char *buf, size_t count) { long tmp = simple_strtol(buf, NULL, 10); @@ -226,7 +226,6 @@ ATTRIBUTE_GROUPS(devcd_class); static struct class devcd_class = { .name = "devcoredump", - .owner = THIS_MODULE, .dev_release = devcd_dev_release, .dev_groups = devcd_dev_groups, .class_groups = devcd_class_groups, diff --git a/drivers/base/devres.c b/drivers/base/devres.c index c0e100074aa3..5c998cfac335 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -722,20 +722,21 @@ static void devm_action_release(struct device *dev, void *res) } /** - * devm_add_action() - add a custom action to list of managed resources + * __devm_add_action() - add a custom action to list of managed resources * @dev: Device that owns the action * @action: Function that should be called * @data: Pointer to data passed to @action implementation + * @name: Name of the resource (for debugging purposes) * * This adds a custom action to the list of managed resources so that * it gets executed as part of standard resource unwinding. */ -int devm_add_action(struct device *dev, void (*action)(void *), void *data) +int __devm_add_action(struct device *dev, void (*action)(void *), void *data, const char *name) { struct action_devres *devres; - devres = devres_alloc(devm_action_release, - sizeof(struct action_devres), GFP_KERNEL); + devres = __devres_alloc_node(devm_action_release, sizeof(struct action_devres), + GFP_KERNEL, NUMA_NO_NODE, name); if (!devres) return -ENOMEM; @@ -745,7 +746,7 @@ int devm_add_action(struct device *dev, void (*action)(void *), void *data) devres_add(dev, devres); return 0; } -EXPORT_SYMBOL_GPL(devm_add_action); +EXPORT_SYMBOL_GPL(__devm_add_action); /** * devm_remove_action() - removes previously added custom action diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index ae72d4ba8547..b848764ef018 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -94,15 +94,6 @@ static struct file_system_type dev_fs_type = { .mount = public_dev_mount, }; -#ifdef CONFIG_BLOCK -static inline int is_blockdev(struct device *dev) -{ - return dev->class == &block_class; -} -#else -static inline int is_blockdev(struct device *dev) { return 0; } -#endif - static int devtmpfs_submit_req(struct req *req, const char *tmp) { init_completion(&req->done); diff --git a/drivers/base/firmware_loader/Kconfig b/drivers/base/firmware_loader/Kconfig index 5166b323a0f8..5ca00e02fe82 100644 --- a/drivers/base/firmware_loader/Kconfig +++ b/drivers/base/firmware_loader/Kconfig @@ -3,6 +3,8 @@ menu "Firmware loader" config FW_LOADER tristate "Firmware loading facility" if EXPERT + select CRYPTO_HASH if FW_LOADER_DEBUG + select CRYPTO_SHA256 if FW_LOADER_DEBUG default y help This enables the firmware loading facility in the kernel. The kernel @@ -24,6 +26,17 @@ config FW_LOADER You also want to be sure to enable this built-in if you are going to enable built-in firmware (CONFIG_EXTRA_FIRMWARE). +config FW_LOADER_DEBUG + bool "Log filenames and checksums for loaded firmware" + depends on CRYPTO = FW_LOADER || CRYPTO=y + depends on DYNAMIC_DEBUG + depends on FW_LOADER + default FW_LOADER + help + Select this option to use dynamic debug to log firmware filenames and + SHA256 checksums to the kernel log for each firmware file that is + loaded. + if FW_LOADER config FW_LOADER_PAGED_BUF diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 017c4cdb219e..9d79d5ad9102 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -493,9 +493,9 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, const void *in_buffer)) { size_t size; - int i, len; + int i, len, maxlen = 0; int rc = -ENOENT; - char *path; + char *path, *nt = NULL; size_t msize = INT_MAX; void *buffer = NULL; @@ -518,8 +518,17 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, if (!fw_path[i][0]) continue; - len = snprintf(path, PATH_MAX, "%s/%s%s", - fw_path[i], fw_priv->fw_name, suffix); + /* strip off \n from customized path */ + maxlen = strlen(fw_path[i]); + if (i == 0) { + nt = strchr(fw_path[i], '\n'); + if (nt) + maxlen = nt - fw_path[i]; + } + + len = snprintf(path, PATH_MAX, "%.*s/%s%s", + maxlen, fw_path[i], + fw_priv->fw_name, suffix); if (len >= PATH_MAX) { rc = -ENAMETOOLONG; break; @@ -791,6 +800,50 @@ static void fw_abort_batch_reqs(struct firmware *fw) mutex_unlock(&fw_lock); } +#if defined(CONFIG_FW_LOADER_DEBUG) +#include <crypto/hash.h> +#include <crypto/sha2.h> + +static void fw_log_firmware_info(const struct firmware *fw, const char *name, struct device *device) +{ + struct shash_desc *shash; + struct crypto_shash *alg; + u8 *sha256buf; + char *outbuf; + + alg = crypto_alloc_shash("sha256", 0, 0); + if (!alg) + return; + + sha256buf = kmalloc(SHA256_DIGEST_SIZE, GFP_KERNEL); + outbuf = kmalloc(SHA256_BLOCK_SIZE + 1, GFP_KERNEL); + shash = kmalloc(sizeof(*shash) + crypto_shash_descsize(alg), GFP_KERNEL); + if (!sha256buf || !outbuf || !shash) + goto out_free; + + shash->tfm = alg; + + if (crypto_shash_digest(shash, fw->data, fw->size, sha256buf) < 0) + goto out_shash; + + for (int i = 0; i < SHA256_DIGEST_SIZE; i++) + sprintf(&outbuf[i * 2], "%02x", sha256buf[i]); + outbuf[SHA256_BLOCK_SIZE] = 0; + dev_dbg(device, "Loaded FW: %s, sha256: %s\n", name, outbuf); + +out_shash: + crypto_free_shash(alg); +out_free: + kfree(shash); + kfree(outbuf); + kfree(sha256buf); +} +#else +static void fw_log_firmware_info(const struct firmware *fw, const char *name, + struct device *device) +{} +#endif + /* called from request_firmware() and request_firmware_work_func() */ static int _request_firmware(const struct firmware **firmware_p, const char *name, @@ -861,11 +914,13 @@ _request_firmware(const struct firmware **firmware_p, const char *name, revert_creds(old_cred); put_cred(kern_cred); - out: +out: if (ret < 0) { fw_abort_batch_reqs(fw); release_firmware(fw); fw = NULL; + } else { + fw_log_firmware_info(fw, name, device); } *firmware_p = fw; diff --git a/drivers/base/firmware_loader/sysfs.c b/drivers/base/firmware_loader/sysfs.c index 56911d75b90a..c9c93b47d9a5 100644 --- a/drivers/base/firmware_loader/sysfs.c +++ b/drivers/base/firmware_loader/sysfs.c @@ -25,7 +25,7 @@ void __fw_load_abort(struct fw_priv *fw_priv) } #ifdef CONFIG_FW_LOADER_USER_HELPER -static ssize_t timeout_show(struct class *class, struct class_attribute *attr, +static ssize_t timeout_show(const struct class *class, const struct class_attribute *attr, char *buf) { return sysfs_emit(buf, "%d\n", __firmware_loading_timeout()); @@ -44,7 +44,7 @@ static ssize_t timeout_show(struct class *class, struct class_attribute *attr, * * Note: zero means 'wait forever'. **/ -static ssize_t timeout_store(struct class *class, struct class_attribute *attr, +static ssize_t timeout_store(const struct class *class, const struct class_attribute *attr, const char *buf, size_t count) { int tmp_loading_timeout = simple_strtol(buf, NULL, 10); diff --git a/drivers/base/physical_location.h b/drivers/base/physical_location.h index 82cde9f1b161..3f3f61307998 100644 --- a/drivers/base/physical_location.h +++ b/drivers/base/physical_location.h @@ -8,7 +8,7 @@ #include <linux/device.h> #ifdef CONFIG_ACPI -extern bool dev_add_physical_location(struct device *dev); +bool dev_add_physical_location(struct device *dev); extern const struct attribute_group dev_attr_physical_location_group; #else static inline bool dev_add_physical_location(struct device *dev) { return false; }; diff --git a/drivers/base/power/wakeup_stats.c b/drivers/base/power/wakeup_stats.c index 924fac493c4f..6732ed2869f9 100644 --- a/drivers/base/power/wakeup_stats.c +++ b/drivers/base/power/wakeup_stats.c @@ -210,7 +210,7 @@ void wakeup_source_sysfs_remove(struct wakeup_source *ws) static int __init wakeup_sources_sysfs_init(void) { - wakeup_class = class_create(THIS_MODULE, "wakeup"); + wakeup_class = class_create("wakeup"); return PTR_ERR_OR_ZERO(wakeup_class); } diff --git a/drivers/base/property.c b/drivers/base/property.c index 083a95791d3b..f6117ec9805c 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -37,8 +37,10 @@ EXPORT_SYMBOL_GPL(__dev_fwnode_const); * @propname: Name of the property * * Check if property @propname is present in the device firmware description. + * + * Return: true if property @propname is present. Otherwise, returns false. */ -bool device_property_present(struct device *dev, const char *propname) +bool device_property_present(const struct device *dev, const char *propname) { return fwnode_property_present(dev_fwnode(dev), propname); } @@ -48,6 +50,8 @@ EXPORT_SYMBOL_GPL(device_property_present); * fwnode_property_present - check if a property of a firmware node is present * @fwnode: Firmware node whose property to check * @propname: Name of the property + * + * Return: true if property @propname is present. Otherwise, returns false. */ bool fwnode_property_present(const struct fwnode_handle *fwnode, const char *propname) @@ -86,7 +90,7 @@ EXPORT_SYMBOL_GPL(fwnode_property_present); * %-EOVERFLOW if the size of the property is not as expected. * %-ENXIO if no suitable firmware interface is present. */ -int device_property_read_u8_array(struct device *dev, const char *propname, +int device_property_read_u8_array(const struct device *dev, const char *propname, u8 *val, size_t nval) { return fwnode_property_read_u8_array(dev_fwnode(dev), propname, val, nval); @@ -114,7 +118,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u8_array); * %-EOVERFLOW if the size of the property is not as expected. * %-ENXIO if no suitable firmware interface is present. */ -int device_property_read_u16_array(struct device *dev, const char *propname, +int device_property_read_u16_array(const struct device *dev, const char *propname, u16 *val, size_t nval) { return fwnode_property_read_u16_array(dev_fwnode(dev), propname, val, nval); @@ -142,7 +146,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u16_array); * %-EOVERFLOW if the size of the property is not as expected. * %-ENXIO if no suitable firmware interface is present. */ -int device_property_read_u32_array(struct device *dev, const char *propname, +int device_property_read_u32_array(const struct device *dev, const char *propname, u32 *val, size_t nval) { return fwnode_property_read_u32_array(dev_fwnode(dev), propname, val, nval); @@ -170,7 +174,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u32_array); * %-EOVERFLOW if the size of the property is not as expected. * %-ENXIO if no suitable firmware interface is present. */ -int device_property_read_u64_array(struct device *dev, const char *propname, +int device_property_read_u64_array(const struct device *dev, const char *propname, u64 *val, size_t nval) { return fwnode_property_read_u64_array(dev_fwnode(dev), propname, val, nval); @@ -198,7 +202,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u64_array); * %-EOVERFLOW if the size of the property is not as expected. * %-ENXIO if no suitable firmware interface is present. */ -int device_property_read_string_array(struct device *dev, const char *propname, +int device_property_read_string_array(const struct device *dev, const char *propname, const char **val, size_t nval) { return fwnode_property_read_string_array(dev_fwnode(dev), propname, val, nval); @@ -220,7 +224,7 @@ EXPORT_SYMBOL_GPL(device_property_read_string_array); * %-EPROTO or %-EILSEQ if the property type is not a string. * %-ENXIO if no suitable firmware interface is present. */ -int device_property_read_string(struct device *dev, const char *propname, +int device_property_read_string(const struct device *dev, const char *propname, const char **val) { return fwnode_property_read_string(dev_fwnode(dev), propname, val); @@ -242,7 +246,7 @@ EXPORT_SYMBOL_GPL(device_property_read_string); * %-EPROTO if the property is not an array of strings, * %-ENXIO if no suitable firmware interface is present. */ -int device_property_match_string(struct device *dev, const char *propname, +int device_property_match_string(const struct device *dev, const char *propname, const char *string) { return fwnode_property_match_string(dev_fwnode(dev), propname, string); @@ -508,10 +512,10 @@ EXPORT_SYMBOL_GPL(fwnode_property_match_string); * Obtain a reference based on a named property in an fwnode, with * integer arguments. * - * Caller is responsible to call fwnode_handle_put() on the returned - * args->fwnode pointer. + * The caller is responsible for calling fwnode_handle_put() on the returned + * @args->fwnode pointer. * - * Returns: %0 on success + * Return: %0 on success * %-ENOENT when the index is out of bounds, the index has an empty * reference or the property was not found * %-EINVAL on parse error @@ -547,8 +551,11 @@ EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args); * * @index can be used when the named reference holds a table of references. * - * Returns pointer to the reference fwnode, or ERR_PTR. Caller is responsible to - * call fwnode_handle_put() on the returned fwnode pointer. + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. + * + * Return: a pointer to the reference fwnode, when found. Otherwise, + * returns an error pointer. */ struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode, const char *name, @@ -567,7 +574,7 @@ EXPORT_SYMBOL_GPL(fwnode_find_reference); * fwnode_get_name - Return the name of a node * @fwnode: The firmware node * - * Returns a pointer to the node name. + * Return: a pointer to the node name, or %NULL. */ const char *fwnode_get_name(const struct fwnode_handle *fwnode) { @@ -579,7 +586,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_name); * fwnode_get_name_prefix - Return the prefix of node for printing purposes * @fwnode: The firmware node * - * Returns the prefix of a node, intended to be printed right before the node. + * Return: the prefix of a node, intended to be printed right before the node. * The prefix works also as a separator between the nodes. */ const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode) @@ -591,7 +598,10 @@ const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode) * fwnode_get_parent - Return parent firwmare node * @fwnode: Firmware whose parent is retrieved * - * Return parent firmware node of the given node if possible or %NULL if no + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. + * + * Return: parent firmware node of the given node if possible or %NULL if no * parent was available. */ struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode) @@ -608,8 +618,12 @@ EXPORT_SYMBOL_GPL(fwnode_get_parent); * on the passed node, making it suitable for iterating through a * node's parents. * - * Returns a node pointer with refcount incremented, use - * fwnode_handle_put() on it when done. + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. Note that this function also puts a reference to @fwnode + * unconditionally. + * + * Return: parent firmware node of the given node if possible or %NULL if no + * parent was available. */ struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode) { @@ -629,10 +643,12 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_parent); * firmware node that has a corresponding struct device and returns that struct * device. * - * The caller of this function is expected to call put_device() on the returned - * device when they are done. + * The caller is responsible for calling put_device() on the returned device + * pointer. + * + * Return: a pointer to the device of the @fwnode's closest ancestor. */ -struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode) +struct device *fwnode_get_next_parent_dev(const struct fwnode_handle *fwnode) { struct fwnode_handle *parent; struct device *dev; @@ -651,7 +667,7 @@ struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode) * fwnode_count_parents - Return the number of parents a node has * @fwnode: The node the parents of which are to be counted * - * Returns the number of parents a node has. + * Return: the number of parents a node has. */ unsigned int fwnode_count_parents(const struct fwnode_handle *fwnode) { @@ -670,12 +686,12 @@ EXPORT_SYMBOL_GPL(fwnode_count_parents); * @fwnode: The node the parent of which is requested * @depth: Distance of the parent from the node * - * Returns the nth parent of a node. If there is no parent at the requested + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. + * + * Return: the nth parent of a node. If there is no parent at the requested * @depth, %NULL is returned. If @depth is 0, the functionality is equivalent to * fwnode_handle_get(). For @depth == 1, it is fwnode_get_parent() and so on. - * - * The caller is responsible for calling fwnode_handle_put() for the returned - * node. */ struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwnode, unsigned int depth) @@ -700,9 +716,9 @@ EXPORT_SYMBOL_GPL(fwnode_get_nth_parent); * * A node is considered an ancestor of itself too. * - * Returns true if @ancestor is an ancestor of @child. Otherwise, returns false. + * Return: true if @ancestor is an ancestor of @child. Otherwise, returns false. */ -bool fwnode_is_ancestor_of(struct fwnode_handle *ancestor, struct fwnode_handle *child) +bool fwnode_is_ancestor_of(const struct fwnode_handle *ancestor, const struct fwnode_handle *child) { struct fwnode_handle *parent; @@ -725,6 +741,10 @@ bool fwnode_is_ancestor_of(struct fwnode_handle *ancestor, struct fwnode_handle * fwnode_get_next_child_node - Return the next child node handle for a node * @fwnode: Firmware node to find the next child node for. * @child: Handle to one of the node's child nodes or a %NULL handle. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. Note that this function also puts a reference to @child + * unconditionally. */ struct fwnode_handle * fwnode_get_next_child_node(const struct fwnode_handle *fwnode, @@ -735,10 +755,13 @@ fwnode_get_next_child_node(const struct fwnode_handle *fwnode, EXPORT_SYMBOL_GPL(fwnode_get_next_child_node); /** - * fwnode_get_next_available_child_node - Return the next - * available child node handle for a node + * fwnode_get_next_available_child_node - Return the next available child node handle for a node * @fwnode: Firmware node to find the next child node for. * @child: Handle to one of the node's child nodes or a %NULL handle. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. Note that this function also puts a reference to @child + * unconditionally. */ struct fwnode_handle * fwnode_get_next_available_child_node(const struct fwnode_handle *fwnode, @@ -762,7 +785,11 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_available_child_node); /** * device_get_next_child_node - Return the next child node handle for a device * @dev: Device to find the next child node for. - * @child: Handle to one of the device's child nodes or a null handle. + * @child: Handle to one of the device's child nodes or a %NULL handle. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. Note that this function also puts a reference to @child + * unconditionally. */ struct fwnode_handle *device_get_next_child_node(const struct device *dev, struct fwnode_handle *child) @@ -787,6 +814,9 @@ EXPORT_SYMBOL_GPL(device_get_next_child_node); * fwnode_get_named_child_node - Return first matching named child node handle * @fwnode: Firmware node to find the named child node for. * @childname: String to match child node name against. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. */ struct fwnode_handle * fwnode_get_named_child_node(const struct fwnode_handle *fwnode, @@ -800,6 +830,9 @@ EXPORT_SYMBOL_GPL(fwnode_get_named_child_node); * device_get_named_child_node - Return first matching named child node handle * @dev: Device to find the named child node for. * @childname: String to match child node name against. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. */ struct fwnode_handle *device_get_named_child_node(const struct device *dev, const char *childname) @@ -812,7 +845,10 @@ EXPORT_SYMBOL_GPL(device_get_named_child_node); * fwnode_handle_get - Obtain a reference to a device node * @fwnode: Pointer to the device node to obtain the reference to. * - * Returns the fwnode handle. + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. + * + * Return: the fwnode handle. */ struct fwnode_handle *fwnode_handle_get(struct fwnode_handle *fwnode) { @@ -841,6 +877,8 @@ EXPORT_SYMBOL_GPL(fwnode_handle_put); * fwnode_device_is_available - check if a device is available for use * @fwnode: Pointer to the fwnode of the device. * + * Return: true if device is available for use. Otherwise, returns false. + * * For fwnode node types that don't implement the .device_is_available() * operation, this function returns true. */ @@ -859,6 +897,8 @@ EXPORT_SYMBOL_GPL(fwnode_device_is_available); /** * device_get_child_node_count - return the number of child nodes for device * @dev: Device to cound the child nodes for + * + * Return: the number of child nodes for a given device. */ unsigned int device_get_child_node_count(const struct device *dev) { @@ -895,7 +935,7 @@ EXPORT_SYMBOL_GPL(device_get_dma_attr); * 'phy-connection-type', and return its index in phy_modes table, or errno in * error case. */ -int fwnode_get_phy_mode(struct fwnode_handle *fwnode) +int fwnode_get_phy_mode(const struct fwnode_handle *fwnode) { const char *pm; int err, i; @@ -934,7 +974,7 @@ EXPORT_SYMBOL_GPL(device_get_phy_mode); * @fwnode: Pointer to the firmware node * @index: Index of the IO range * - * Returns a pointer to the mapped memory. + * Return: a pointer to the mapped memory. */ void __iomem *fwnode_iomap(struct fwnode_handle *fwnode, int index) { @@ -947,8 +987,8 @@ EXPORT_SYMBOL(fwnode_iomap); * @fwnode: Pointer to the firmware node * @index: Zero-based index of the IRQ * - * Returns Linux IRQ number on success. Other values are determined - * accordingly to acpi_/of_ irq_get() operation. + * Return: Linux IRQ number on success. Other values are determined + * according to acpi_irq_get() or of_irq_get() operation. */ int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index) { @@ -967,8 +1007,7 @@ EXPORT_SYMBOL(fwnode_irq_get); * number of the IRQ resource corresponding to the index of the matched * string. * - * Return: - * Linux IRQ number on success, or negative errno otherwise. + * Return: Linux IRQ number on success, or negative errno otherwise. */ int fwnode_irq_get_byname(const struct fwnode_handle *fwnode, const char *name) { @@ -990,7 +1029,11 @@ EXPORT_SYMBOL(fwnode_irq_get_byname); * @fwnode: Pointer to the parent firmware node * @prev: Previous endpoint node or %NULL to get the first * - * Returns an endpoint firmware node pointer or %NULL if no more endpoints + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. Note that this function also puts a reference to @prev + * unconditionally. + * + * Return: an endpoint firmware node pointer or %NULL if no more endpoints * are available. */ struct fwnode_handle * @@ -1030,6 +1073,9 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint); * fwnode_graph_get_port_parent - Return the device fwnode of a port endpoint * @endpoint: Endpoint firmware node of the port * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. + * * Return: the firmware node of the device the @endpoint belongs to. */ struct fwnode_handle * @@ -1051,6 +1097,9 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_port_parent); * @fwnode: Endpoint firmware node pointing to the remote endpoint * * Extracts firmware node of a remote device the @fwnode points to. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. */ struct fwnode_handle * fwnode_graph_get_remote_port_parent(const struct fwnode_handle *fwnode) @@ -1071,6 +1120,9 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port_parent); * @fwnode: Endpoint firmware node pointing to the remote endpoint * * Extracts firmware node of a remote port the @fwnode points to. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. */ struct fwnode_handle * fwnode_graph_get_remote_port(const struct fwnode_handle *fwnode) @@ -1084,6 +1136,9 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_remote_port); * @fwnode: Endpoint firmware node pointing to the remote endpoint * * Extracts firmware node of a remote endpoint the @fwnode points to. + * + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. */ struct fwnode_handle * fwnode_graph_get_remote_endpoint(const struct fwnode_handle *fwnode) @@ -1111,8 +1166,11 @@ static bool fwnode_graph_remote_available(struct fwnode_handle *ep) * @endpoint: identifier of the endpoint node under the port node * @flags: fwnode lookup flags * - * Return the fwnode handle of the local endpoint corresponding the port and - * endpoint IDs or NULL if not found. + * The caller is responsible for calling fwnode_handle_put() on the returned + * fwnode pointer. + * + * Return: the fwnode handle of the local endpoint corresponding the port and + * endpoint IDs or %NULL if not found. * * If FWNODE_GRAPH_ENDPOINT_NEXT is passed in @flags and the specified endpoint * has not been found, look for the closest endpoint ID greater than the @@ -1120,9 +1178,6 @@ static bool fwnode_graph_remote_available(struct fwnode_handle *ep) * * Does not return endpoints that belong to disabled devices or endpoints that * are unconnected, unless FWNODE_GRAPH_DEVICE_DISABLED is passed in @flags. - * - * The returned endpoint needs to be released by calling fwnode_handle_put() on - * it when it is not needed any more. */ struct fwnode_handle * fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode, @@ -1180,7 +1235,7 @@ EXPORT_SYMBOL_GPL(fwnode_graph_get_endpoint_by_id); * If FWNODE_GRAPH_DEVICE_DISABLED flag is specified, also unconnected endpoints * and endpoints connected to disabled devices are counted. */ -unsigned int fwnode_graph_get_endpoint_count(struct fwnode_handle *fwnode, +unsigned int fwnode_graph_get_endpoint_count(const struct fwnode_handle *fwnode, unsigned long flags) { struct fwnode_handle *ep; @@ -1328,7 +1383,8 @@ EXPORT_SYMBOL_GPL(fwnode_connection_find_match); * @fwnode and other device nodes. @match will be used to convert the * connection description to data the caller is expecting to be returned * through the @matches array. - * If @matches is NULL @matches_len is ignored and the total number of resolved + * + * If @matches is %NULL @matches_len is ignored and the total number of resolved * matches is returned. * * Return: Number of matches resolved, or negative errno. diff --git a/drivers/base/soc.c b/drivers/base/soc.c index 0fb1d4ab9d8a..8dec5228fde3 100644 --- a/drivers/base/soc.c +++ b/drivers/base/soc.c @@ -7,6 +7,7 @@ #include <linux/sysfs.h> #include <linux/init.h> +#include <linux/of.h> #include <linux/stat.h> #include <linux/slab.h> #include <linux/idr.h> @@ -110,6 +111,18 @@ static void soc_release(struct device *dev) kfree(soc_dev); } +static void soc_device_get_machine(struct soc_device_attribute *soc_dev_attr) +{ + struct device_node *np; + + if (soc_dev_attr->machine) + return; + + np = of_find_node_by_path("/"); + of_property_read_string(np, "model", &soc_dev_attr->machine); + of_node_put(np); +} + static struct soc_device_attribute *early_soc_dev_attr; struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr) @@ -118,6 +131,8 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr const struct attribute_group **soc_attr_groups; int ret; + soc_device_get_machine(soc_dev_attr); + if (!soc_bus_registered) { if (early_soc_dev_attr) return ERR_PTR(-EBUSY); |