diff options
Diffstat (limited to 'drivers/base')
| -rw-r--r-- | drivers/base/base.h | 36 | ||||
| -rw-r--r-- | drivers/base/bus.c | 11 | ||||
| -rw-r--r-- | drivers/base/cacheinfo.c | 23 | ||||
| -rw-r--r-- | drivers/base/core.c | 184 | ||||
| -rw-r--r-- | drivers/base/cpu.c | 4 | ||||
| -rw-r--r-- | drivers/base/dd.c | 27 | ||||
| -rw-r--r-- | drivers/base/devcoredump.c | 7 | ||||
| -rw-r--r-- | drivers/base/driver.c | 79 | ||||
| -rw-r--r-- | drivers/base/faux.c | 32 | ||||
| -rw-r--r-- | drivers/base/firmware_loader/main.c | 71 | ||||
| -rw-r--r-- | drivers/base/firmware_loader/sysfs_upload.c | 8 | ||||
| -rw-r--r-- | drivers/base/isa.c | 12 | ||||
| -rw-r--r-- | drivers/base/memory.c | 47 | ||||
| -rw-r--r-- | drivers/base/node.c | 6 | ||||
| -rw-r--r-- | drivers/base/pinctrl.c | 2 | ||||
| -rw-r--r-- | drivers/base/platform-msi.c | 4 | ||||
| -rw-r--r-- | drivers/base/platform.c | 39 | ||||
| -rw-r--r-- | drivers/base/power/main.c | 67 | ||||
| -rw-r--r-- | drivers/base/power/power.h | 7 | ||||
| -rw-r--r-- | drivers/base/power/wakeup.c | 71 | ||||
| -rw-r--r-- | drivers/base/property.c | 4 | ||||
| -rw-r--r-- | drivers/base/regmap/regcache.c | 2 | ||||
| -rw-r--r-- | drivers/base/regmap/regmap-i2c.c | 2 | ||||
| -rw-r--r-- | drivers/base/regmap/regmap-sdw-mbq.c | 2 | ||||
| -rw-r--r-- | drivers/base/regmap/regmap.c | 3 | ||||
| -rw-r--r-- | drivers/base/swnode.c | 40 |
26 files changed, 508 insertions, 282 deletions
diff --git a/drivers/base/base.h b/drivers/base/base.h index 30b416588617..a5b7abc10ff0 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -86,18 +86,6 @@ struct driver_private { }; #define to_driver(obj) container_of(obj, struct driver_private, kobj) -#ifdef CONFIG_RUST -/** - * struct driver_type - Representation of a Rust driver type. - */ -struct driver_type { - /** - * @id: Representation of core::any::TypeId. - */ - u8 id[16]; -} __packed; -#endif - /** * struct device_private - structure to hold the private to the driver core * portions of the device structure. @@ -115,7 +103,6 @@ struct driver_type { * dev_err_probe() for later retrieval via debugfs * @device: pointer back to the struct device that this structure is * associated with. - * @driver_type: The type of the bound Rust driver. * @dead: This device is currently either in the process of or has been * removed from the system. Any asynchronous events scheduled for this * device should exit without taking any action. @@ -132,9 +119,6 @@ struct device_private { const struct device_driver *async_driver; char *deferred_probe_reason; struct device *device; -#ifdef CONFIG_RUST - struct driver_type driver_type; -#endif u8 dead:1; }; #define to_device_private_parent(obj) \ @@ -188,6 +172,20 @@ static inline int driver_match_device(const struct device_driver *drv, return drv->bus->match ? drv->bus->match(dev, drv) : 1; } +static inline bool dev_has_sync_state(struct device *dev) +{ + struct device_driver *drv; + + if (!dev) + return false; + drv = READ_ONCE(dev->driver); + if (drv && drv->sync_state) + return true; + if (dev->bus && dev->bus->sync_state) + return true; + return false; +} + static inline void dev_sync_state(struct device *dev) { if (dev->bus->sync_state) @@ -196,8 +194,10 @@ static inline void dev_sync_state(struct device *dev) dev->driver->sync_state(dev); } -int driver_add_groups(const struct device_driver *drv, const struct attribute_group **groups); -void driver_remove_groups(const struct device_driver *drv, const struct attribute_group **groups); +int driver_add_groups(const struct device_driver *drv, + const struct attribute_group *const *groups); +void driver_remove_groups(const struct device_driver *drv, + const struct attribute_group *const *groups); void device_driver_detach(struct device *dev); static inline void device_set_driver(struct device *dev, const struct device_driver *drv) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 8b6722ff8590..d17bd91490ee 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -544,10 +544,10 @@ static const struct attribute_group driver_override_dev_group = { */ int bus_add_device(struct device *dev) { - struct subsys_private *sp = bus_to_subsys(dev->bus); + struct subsys_private *sp; int error; - if (!sp) { + if (!dev->bus) { /* * This is a normal operation for many devices that do not * have a bus assigned to them, just say that all went @@ -556,6 +556,13 @@ int bus_add_device(struct device *dev) return 0; } + sp = bus_to_subsys(dev->bus); + if (!sp) { + pr_err("%s: cannot add device '%s' to unregistered bus '%s'\n", + __func__, dev_name(dev), dev->bus->name); + return -EINVAL; + } + /* * Reference in sp is now incremented and will be dropped when * the device is removed from the bus diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index 391ac5e3d2f5..70701d3bc81c 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -17,6 +17,7 @@ #include <linux/init.h> #include <linux/of.h> #include <linux/sched.h> +#include <linux/sched/topology.h> #include <linux/slab.h> #include <linux/smp.h> #include <linux/sysfs.h> @@ -68,6 +69,24 @@ bool last_level_cache_is_valid(unsigned int cpu) } +/* + * Get the cacheinfo of the LLC associated with @cpu. + * Derived from update_per_cpu_data_slice_size_cpu(). + */ +struct cacheinfo *get_cpu_cacheinfo_llc(unsigned int cpu) +{ + struct cacheinfo *llc; + + if (!last_level_cache_is_valid(cpu)) + return NULL; + + llc = per_cpu_cacheinfo_idx(cpu, cache_leaves(cpu) - 1); + if (llc->type != CACHE_TYPE_DATA && llc->type != CACHE_TYPE_UNIFIED) + return NULL; + + return llc; +} + bool last_level_cache_is_shared(unsigned int cpu_x, unsigned int cpu_y) { struct cacheinfo *llc_x, *llc_y; @@ -1018,6 +1037,7 @@ static int cacheinfo_cpu_online(unsigned int cpu) goto err; if (cpu_map_shared_cache(true, cpu, &cpu_map)) update_per_cpu_data_slice_size(true, cpu, cpu_map); + sched_update_llc_bytes(cpu); return 0; err: free_cache_attributes(cpu); @@ -1036,6 +1056,9 @@ static int cacheinfo_cpu_pre_down(unsigned int cpu) free_cache_attributes(cpu); if (nr_shared > 1) update_per_cpu_data_slice_size(false, cpu, cpu_map); + + sched_update_llc_bytes(cpu); + return 0; } diff --git a/drivers/base/core.c b/drivers/base/core.c index bd2ddf2aab50..4d026682944f 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -235,6 +235,79 @@ static void __fw_devlink_pickup_dangling_consumers(struct fwnode_handle *fwnode, __fw_devlink_pickup_dangling_consumers(child, new_sup); } +static void fw_devlink_pickup_dangling_consumers(struct device *dev) +{ + struct fwnode_handle *child; + + guard(mutex)(&fwnode_link_lock); + + fwnode_for_each_available_child_node(dev->fwnode, child) + __fw_devlink_pickup_dangling_consumers(child, dev->fwnode); + __fw_devlink_link_to_consumers(dev); +} + +/** + * fw_devlink_refresh_fwnode - Recheck the tree under this firmware node + * @fwnode: The fwnode under which the fwnode tree has changed + * + * This function is mainly meant to adjust the supplier/consumer dependencies + * after a fwnode tree overlay has occurred. + */ +void fw_devlink_refresh_fwnode(struct fwnode_handle *fwnode) +{ + struct device *dev; + + /* + * Find the closest ancestor fwnode that has been converted to a device + * that can bind to a driver (bus device). + */ + fwnode_handle_get(fwnode); + do { + if (fwnode_test_flag(fwnode, FWNODE_FLAG_NOT_DEVICE)) + continue; + + dev = get_dev_from_fwnode(fwnode); + if (!dev) + continue; + + if (dev->bus) + break; + + put_device(dev); + } while ((fwnode = fwnode_get_next_parent(fwnode))); + + /* + * If none of the ancestor fwnodes have (yet) been converted to a device + * that can bind to a driver, there's nothing to fix up. + */ + if (!fwnode) + return; + + WARN(device_is_bound(dev) && dev->links.status != DL_DEV_DRIVER_BOUND, + "Don't multithread overlaying and probing the same device!\n"); + + /* + * If the device has already bound to a driver, then we need to redo + * some of the work that was done after the device was bound to a + * driver. If the device hasn't bound to a driver, running things too + * soon would incorrectly pick up consumers that it shouldn't. + */ + if (dev->links.status == DL_DEV_DRIVER_BOUND) { + fw_devlink_pickup_dangling_consumers(dev); + /* + * Some of dangling consumers could have been put previously in + * the deferred probe list due to the unavailability of their + * suppliers. Those consumers have been picked up and some of + * their suppliers links have been updated. Time to re-try their + * probe sequence. + */ + driver_deferred_probe_trigger(); + } + + put_device(dev); + fwnode_handle_put(fwnode); +} + static DEFINE_MUTEX(device_links_lock); DEFINE_STATIC_SRCU(device_links_srcu); @@ -422,7 +495,7 @@ void device_pm_move_to_tail(struct device *dev) #define to_devlink(dev) container_of((dev), struct device_link, link_dev) static ssize_t status_show(struct device *dev, - struct device_attribute *attr, char *buf) + const struct device_attribute *attr, char *buf) { const char *output; @@ -452,10 +525,10 @@ static ssize_t status_show(struct device *dev, return sysfs_emit(buf, "%s\n", output); } -static DEVICE_ATTR_RO(status); +static const DEVICE_ATTR_RO(status); static ssize_t auto_remove_on_show(struct device *dev, - struct device_attribute *attr, char *buf) + const struct device_attribute *attr, char *buf) { struct device_link *link = to_devlink(dev); const char *output; @@ -469,27 +542,27 @@ static ssize_t auto_remove_on_show(struct device *dev, return sysfs_emit(buf, "%s\n", output); } -static DEVICE_ATTR_RO(auto_remove_on); +static const DEVICE_ATTR_RO(auto_remove_on); static ssize_t runtime_pm_show(struct device *dev, - struct device_attribute *attr, char *buf) + const struct device_attribute *attr, char *buf) { struct device_link *link = to_devlink(dev); return sysfs_emit(buf, "%d\n", device_link_test(link, DL_FLAG_PM_RUNTIME)); } -static DEVICE_ATTR_RO(runtime_pm); +static const DEVICE_ATTR_RO(runtime_pm); static ssize_t sync_state_only_show(struct device *dev, - struct device_attribute *attr, char *buf) + const struct device_attribute *attr, char *buf) { struct device_link *link = to_devlink(dev); return sysfs_emit(buf, "%d\n", device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)); } -static DEVICE_ATTR_RO(sync_state_only); +static const DEVICE_ATTR_RO(sync_state_only); -static struct attribute *devlink_attrs[] = { +static const struct attribute *const devlink_attrs[] = { &dev_attr_status.attr, &dev_attr_auto_remove_on.attr, &dev_attr_runtime_pm.attr, @@ -1011,7 +1084,7 @@ static void device_links_missing_supplier(struct device *dev) static bool dev_is_best_effort(struct device *dev) { - return (fw_devlink_best_effort && dev->can_match) || + return (fw_devlink_best_effort && dev_can_match(dev)) || (dev->fwnode && fwnode_test_flag(dev->fwnode, FWNODE_FLAG_BEST_EFFORT)); } @@ -1079,7 +1152,7 @@ int device_links_check_suppliers(struct device *dev) if (dev_is_best_effort(dev) && device_link_test(link, DL_FLAG_INFERRED) && - !link->supplier->can_match) { + !dev_can_match(link->supplier)) { ret = -EAGAIN; continue; } @@ -1123,7 +1196,7 @@ static void __device_links_queue_sync_state(struct device *dev, if (!dev_has_sync_state(dev)) return; - if (dev->state_synced) + if (dev_state_synced(dev)) return; list_for_each_entry(link, &dev->links.consumers, s_node) { @@ -1138,7 +1211,7 @@ static void __device_links_queue_sync_state(struct device *dev, * than once. This can happen if new consumers get added to the device * and probed before the list is flushed. */ - dev->state_synced = true; + dev_set_state_synced(dev); if (WARN_ON(!list_empty(&dev->links.defer_sync))) return; @@ -1233,7 +1306,7 @@ static void device_link_drop_managed(struct device_link *link) } static ssize_t waiting_for_supplier_show(struct device *dev, - struct device_attribute *attr, + const struct device_attribute *attr, char *buf) { bool val; @@ -1244,7 +1317,7 @@ static ssize_t waiting_for_supplier_show(struct device *dev, device_unlock(dev); return sysfs_emit(buf, "%u\n", val); } -static DEVICE_ATTR_RO(waiting_for_supplier); +static const DEVICE_ATTR_RO(waiting_for_supplier); /** * device_links_force_bind - Prepares device to be force bound @@ -1312,16 +1385,8 @@ void device_links_driver_bound(struct device *dev) * child firmware node. */ if (dev->fwnode && dev->fwnode->dev == dev) { - struct fwnode_handle *child; - fwnode_links_purge_suppliers(dev->fwnode); - - guard(mutex)(&fwnode_link_lock); - - fwnode_for_each_available_child_node(dev->fwnode, child) - __fw_devlink_pickup_dangling_consumers(child, - dev->fwnode); - __fw_devlink_link_to_consumers(dev); + fw_devlink_pickup_dangling_consumers(dev); } device_remove_file(dev, &dev_attr_waiting_for_supplier); @@ -1370,7 +1435,7 @@ void device_links_driver_bound(struct device *dev) } else if (dev_is_best_effort(dev) && device_link_test(link, DL_FLAG_INFERRED) && link->status != DL_STATE_CONSUMER_PROBE && - !link->supplier->can_match) { + !dev_can_match(link->supplier)) { /* * When dev_is_best_effort() is true, we ignore device * links to suppliers that don't have a driver. If the @@ -1435,7 +1500,8 @@ static void __device_links_no_driver(struct device *dev) if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) { WRITE_ONCE(link->status, DL_STATE_AVAILABLE); } else { - WARN_ON(!device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)); + WARN_ON(link->supplier->links.status != DL_DEV_UNBINDING && + !device_link_test(link, DL_FLAG_SYNC_STATE_ONLY)); WRITE_ONCE(link->status, DL_STATE_DORMANT); } } @@ -1758,7 +1824,7 @@ static int fw_devlink_no_driver(struct device *dev, void *data) { struct device_link *link = to_devlink(dev); - if (!link->supplier->can_match) + if (!dev_can_match(link->supplier)) fw_devlink_relax_link(link); return 0; @@ -1779,7 +1845,7 @@ static int fw_devlink_dev_sync_state(struct device *dev, void *data) struct device *sup = link->supplier; if (!device_link_test(link, DL_FLAG_MANAGED) || - link->status == DL_STATE_ACTIVE || sup->state_synced || + link->status == DL_STATE_ACTIVE || dev_state_synced(sup) || !dev_has_sync_state(sup)) return 0; @@ -1793,7 +1859,7 @@ static int fw_devlink_dev_sync_state(struct device *dev, void *data) return 0; dev_warn(sup, "Timed out. Forcing sync_state()\n"); - sup->state_synced = true; + dev_set_state_synced(sup); get_device(sup); list_add_tail(&sup->links.defer_sync, data); @@ -2419,9 +2485,11 @@ static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, if (dev_attr->show) ret = dev_attr->show(dev, dev_attr, buf); + else if (dev_attr->show_const) + ret = dev_attr->show_const(dev, dev_attr, buf); if (ret >= (ssize_t)PAGE_SIZE) { - printk("dev_attr_show: %pS returned bad count\n", - dev_attr->show); + printk("dev_attr_show: %pS/%pS returned bad count\n", + dev_attr->show, dev_attr->show_const); } return ret; } @@ -2435,6 +2503,8 @@ static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr, if (dev_attr->store) ret = dev_attr->store(dev, dev_attr, buf, count); + else if (dev_attr->store_const) + ret = dev_attr->store_const(dev, dev_attr, buf, count); return ret; } @@ -2722,7 +2792,7 @@ static const struct kset_uevent_ops device_uevent_ops = { .uevent = dev_uevent, }; -static ssize_t uevent_show(struct device *dev, struct device_attribute *attr, +static ssize_t uevent_show(struct device *dev, const struct device_attribute *attr, char *buf) { struct kobject *top_kobj; @@ -2765,7 +2835,7 @@ out: return len; } -static ssize_t uevent_store(struct device *dev, struct device_attribute *attr, +static ssize_t uevent_store(struct device *dev, const struct device_attribute *attr, const char *buf, size_t count) { int rc; @@ -2779,20 +2849,20 @@ static ssize_t uevent_store(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR_RW(uevent); +static const DEVICE_ATTR_RW(uevent); -static ssize_t online_show(struct device *dev, struct device_attribute *attr, +static ssize_t online_show(struct device *dev, const struct device_attribute *attr, char *buf) { bool val; device_lock(dev); - val = !dev->offline; + val = !dev_offline(dev); device_unlock(dev); return sysfs_emit(buf, "%u\n", val); } -static ssize_t online_store(struct device *dev, struct device_attribute *attr, +static ssize_t online_store(struct device *dev, const struct device_attribute *attr, const char *buf, size_t count) { bool val; @@ -2810,9 +2880,9 @@ static ssize_t online_store(struct device *dev, struct device_attribute *attr, unlock_device_hotplug(); return ret < 0 ? ret : count; } -static DEVICE_ATTR_RW(online); +static const DEVICE_ATTR_RW(online); -static ssize_t removable_show(struct device *dev, struct device_attribute *attr, +static ssize_t removable_show(struct device *dev, const struct device_attribute *attr, char *buf) { const char *loc; @@ -2829,7 +2899,7 @@ static ssize_t removable_show(struct device *dev, struct device_attribute *attr, } return sysfs_emit(buf, "%s\n", loc); } -static DEVICE_ATTR_RO(removable); +static const DEVICE_ATTR_RO(removable); int device_add_groups(struct device *dev, const struct attribute_group *const *groups) @@ -2913,7 +2983,7 @@ static int device_add_attrs(struct device *dev) if (error) goto err_remove_type_groups; - if (device_supports_offline(dev) && !dev->offline_disabled) { + if (device_supports_offline(dev) && !dev_offline_disabled(dev)) { error = device_create_file(dev, &dev_attr_online); if (error) goto err_remove_dev_groups; @@ -2980,12 +3050,12 @@ static void device_remove_attrs(struct device *dev) device_remove_groups(dev, class->dev_groups); } -static ssize_t dev_show(struct device *dev, struct device_attribute *attr, +static ssize_t dev_show(struct device *dev, const struct device_attribute *attr, char *buf) { return print_dev_t(buf, dev->devt); } -static DEVICE_ATTR_RO(dev); +static const DEVICE_ATTR_RO(dev); /* /sys/devices/ */ struct kset *devices_kset; @@ -3047,10 +3117,10 @@ int device_create_file(struct device *dev, int error = 0; if (dev) { - WARN(((attr->attr.mode & S_IWUGO) && !attr->store), + WARN(((attr->attr.mode & S_IWUGO) && !(attr->store || attr->store_const)), "Attribute %s: write permission without 'store'\n", attr->attr.name); - WARN(((attr->attr.mode & S_IRUGO) && !attr->show), + WARN(((attr->attr.mode & S_IRUGO) && !(attr->show || attr->show_const)), "Attribute %s: read permission without 'show'\n", attr->attr.name); error = sysfs_create_file(&dev->kobj, &attr->attr); @@ -3170,11 +3240,7 @@ void device_initialize(struct device *dev) INIT_LIST_HEAD(&dev->links.suppliers); INIT_LIST_HEAD(&dev->links.defer_sync); dev->links.status = DL_DEV_NO_DRIVER; -#if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \ - defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU) || \ - defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL) - dev->dma_coherent = dma_default_coherent; -#endif + dev_assign_dma_coherent(dev, dma_default_coherent); swiotlb_dev_init(dev); } EXPORT_SYMBOL_GPL(device_initialize); @@ -3710,7 +3776,7 @@ int device_add(struct device *dev) * match with any driver, don't block its consumers from probing in * case the consumer device is able to operate without this supplier. */ - if (dev->fwnode && fw_devlink_drv_reg_done && !dev->can_match) + if (dev->fwnode && fw_devlink_drv_reg_done && !dev_can_match(dev)) fw_devlink_unblock_consumers(dev); if (parent) @@ -4180,7 +4246,7 @@ static int device_check_offline(struct device *dev, void *not_used) if (ret) return ret; - return device_supports_offline(dev) && !dev->offline ? -EBUSY : 0; + return device_supports_offline(dev) && !dev_offline(dev) ? -EBUSY : 0; } /** @@ -4198,7 +4264,7 @@ int device_offline(struct device *dev) { int ret; - if (dev->offline_disabled) + if (dev_offline_disabled(dev)) return -EPERM; ret = device_for_each_child(dev, NULL, device_check_offline); @@ -4207,13 +4273,13 @@ int device_offline(struct device *dev) device_lock(dev); if (device_supports_offline(dev)) { - if (dev->offline) { + if (dev_offline(dev)) { ret = 1; } else { ret = dev->bus->offline(dev); if (!ret) { kobject_uevent(&dev->kobj, KOBJ_OFFLINE); - dev->offline = true; + dev_set_offline(dev); } } } @@ -4238,11 +4304,11 @@ int device_online(struct device *dev) device_lock(dev); if (device_supports_offline(dev)) { - if (dev->offline) { + if (dev_offline(dev)) { ret = dev->bus->online(dev); if (!ret) { kobject_uevent(&dev->kobj, KOBJ_ONLINE); - dev->offline = false; + dev_clear_offline(dev); } } else { ret = 1; @@ -4716,7 +4782,7 @@ static int device_attrs_change_owner(struct device *dev, kuid_t kuid, if (error) return error; - if (device_supports_offline(dev) && !dev->offline_disabled) { + if (device_supports_offline(dev) && !dev_offline_disabled(dev)) { /* Change online device attributes of @dev to @kuid/@kgid. */ error = sysfs_file_change_owner(kobj, dev_attr_online.attr.name, kuid, kgid); @@ -5283,7 +5349,7 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2) { of_node_put(dev->of_node); dev->of_node = of_node_get(dev2->of_node); - dev->of_node_reused = true; + dev_set_of_node_reused(dev); } EXPORT_SYMBOL_GPL(device_set_of_node_from_dev); diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 875abdc9942e..19d288a3c80c 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -422,8 +422,8 @@ int register_cpu(struct cpu *cpu, int num) cpu->dev.id = num; cpu->dev.bus = &cpu_subsys; cpu->dev.release = cpu_device_release; - cpu->dev.offline_disabled = !cpu->hotpluggable; - cpu->dev.offline = !cpu_online(num); + dev_assign_offline_disabled(&cpu->dev, !cpu->hotpluggable); + dev_assign_offline(&cpu->dev, !cpu_online(num)); cpu->dev.of_node = of_get_cpu_node(num, NULL); cpu->dev.groups = common_cpu_attr_groups; if (cpu->hotpluggable) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 1dc1e3528043..60c005223844 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -132,7 +132,7 @@ static DECLARE_WORK(deferred_probe_work, deferred_probe_work_func); void driver_deferred_probe_add(struct device *dev) { - if (!dev->can_match) + if (!dev_can_match(dev)) return; mutex_lock(&deferred_probe_mutex); @@ -323,12 +323,11 @@ void deferred_probe_extend_timeout(void) * If the work hasn't been queued yet or if the work expired, don't * start a new one. */ - if (cancel_delayed_work(&deferred_probe_timeout_work)) { - schedule_delayed_work(&deferred_probe_timeout_work, - driver_deferred_probe_timeout * HZ); + if (delayed_work_pending(&deferred_probe_timeout_work) && + mod_delayed_work(system_percpu_wq, &deferred_probe_timeout_work, + secs_to_jiffies(driver_deferred_probe_timeout))) pr_debug("Extended deferred probe timeout by %d secs\n", driver_deferred_probe_timeout); - } } /** @@ -569,12 +568,10 @@ static ssize_t state_synced_store(struct device *dev, return -EINVAL; device_lock(dev); - if (!dev->state_synced) { - dev->state_synced = true; + if (!dev_test_and_set_state_synced(dev)) dev_sync_state(dev); - } else { + else ret = -EINVAL; - } device_unlock(dev); return ret ? ret : count; @@ -586,7 +583,7 @@ static ssize_t state_synced_show(struct device *dev, bool val; device_lock(dev); - val = dev->state_synced; + val = dev_state_synced(dev); device_unlock(dev); return sysfs_emit(buf, "%u\n", val); @@ -595,9 +592,9 @@ static DEVICE_ATTR_RW(state_synced); static void device_unbind_cleanup(struct device *dev) { - devres_release_all(dev); if (dev->driver->p_cb.post_unbind_rust) dev->driver->p_cb.post_unbind_rust(dev); + devres_release_all(dev); arch_teardown_dma_ops(dev); kfree(dev->dma_range_map); dev->dma_range_map = NULL; @@ -849,14 +846,14 @@ static int __driver_probe_device(const struct device_driver *drv, struct device return dev_err_probe(dev, -EPROBE_DEFER, "Device not ready to probe\n"); /* - * Set can_match = true after calling dev_ready_to_probe(), so + * Call dev_set_can_match() after calling dev_ready_to_probe(), so * driver_deferred_probe_add() won't actually add the device to the * deferred probe list when dev_ready_to_probe() returns false. * * When dev_ready_to_probe() returns false, it means that device_add() * will do another probe() attempt for us. */ - dev->can_match = true; + dev_set_can_match(dev); dev_dbg(dev, "bus: '%s': %s: matched device with driver %s\n", drv->bus->name, __func__, drv->name); @@ -1002,7 +999,7 @@ static int __device_attach_driver(struct device_driver *drv, void *_data) return 0; } else if (ret == -EPROBE_DEFER) { dev_dbg(dev, "Device match requests probe deferral\n"); - dev->can_match = true; + dev_set_can_match(dev); driver_deferred_probe_add(dev); /* * Device can't match with a driver right now, so don't attempt @@ -1254,7 +1251,7 @@ static int __driver_attach(struct device *dev, void *data) return 0; } else if (ret == -EPROBE_DEFER) { dev_dbg(dev, "Device match requests probe deferral\n"); - dev->can_match = true; + dev_set_can_match(dev); driver_deferred_probe_add(dev); /* * Driver could not match with device, but may match with diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index 7e4a491bf15e..8bb1763083dd 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -471,10 +471,3 @@ static int __init devcoredump_init(void) return class_register(&devcd_class); } __initcall(devcoredump_init); - -static void __exit devcoredump_exit(void) -{ - class_for_each_device(&devcd_class, NULL, NULL, devcd_free); - class_unregister(&devcd_class); -} -__exitcall(devcoredump_exit); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 8ab010ddf709..5d9c39081339 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -31,81 +31,6 @@ static struct device *next_device(struct klist_iter *i) } /** - * driver_set_override() - Helper to set or clear driver override. - * @dev: Device to change - * @override: Address of string to change (e.g. &device->driver_override); - * The contents will be freed and hold newly allocated override. - * @s: NUL-terminated string, new driver name to force a match, pass empty - * string to clear it ("" or "\n", where the latter is only for sysfs - * interface). - * @len: length of @s - * - * Helper to set or clear driver override in a device, intended for the cases - * when the driver_override field is allocated by driver/bus code. - * - * Returns: 0 on success or a negative error code on failure. - */ -int driver_set_override(struct device *dev, const char **override, - const char *s, size_t len) -{ - const char *new, *old; - char *cp; - - if (!override || !s) - return -EINVAL; - - /* - * The stored value will be used in sysfs show callback (sysfs_emit()), - * which has a length limit of PAGE_SIZE and adds a trailing newline. - * Thus we can store one character less to avoid truncation during sysfs - * show. - */ - if (len >= (PAGE_SIZE - 1)) - return -EINVAL; - - /* - * Compute the real length of the string in case userspace sends us a - * bunch of \0 characters like python likes to do. - */ - len = strlen(s); - - if (!len) { - /* Empty string passed - clear override */ - device_lock(dev); - old = *override; - *override = NULL; - device_unlock(dev); - kfree(old); - - return 0; - } - - cp = strnchr(s, len, '\n'); - if (cp) - len = cp - s; - - new = kstrndup(s, len, GFP_KERNEL); - if (!new) - return -ENOMEM; - - device_lock(dev); - old = *override; - if (cp != s) { - *override = new; - } else { - /* "\n" passed - clear override */ - kfree(new); - *override = NULL; - } - device_unlock(dev); - - kfree(old); - - return 0; -} -EXPORT_SYMBOL_GPL(driver_set_override); - -/** * driver_for_each_device - Iterator for devices bound to a driver. * @drv: Driver we're iterating. * @start: Device to begin with @@ -203,13 +128,13 @@ void driver_remove_file(const struct device_driver *drv, EXPORT_SYMBOL_GPL(driver_remove_file); int driver_add_groups(const struct device_driver *drv, - const struct attribute_group **groups) + const struct attribute_group *const *groups) { return sysfs_create_groups(&drv->p->kobj, groups); } void driver_remove_groups(const struct device_driver *drv, - const struct attribute_group **groups) + const struct attribute_group *const *groups) { sysfs_remove_groups(&drv->p->kobj, groups); } diff --git a/drivers/base/faux.c b/drivers/base/faux.c index fb3e42f21362..a8329f88222e 100644 --- a/drivers/base/faux.c +++ b/drivers/base/faux.c @@ -133,6 +133,9 @@ struct faux_device *faux_device_create_with_groups(const char *name, struct device *dev; int ret; + if (!faux_bus_root) + return NULL; + faux_obj = kzalloc_obj(*faux_obj); if (!faux_obj) return NULL; @@ -232,34 +235,29 @@ EXPORT_SYMBOL_GPL(faux_device_destroy); int __init faux_bus_init(void) { + struct device *root; int ret; - faux_bus_root = kzalloc_obj(*faux_bus_root); - if (!faux_bus_root) - return -ENOMEM; - - dev_set_name(faux_bus_root, "faux"); - - ret = device_register(faux_bus_root); - if (ret) { - put_device(faux_bus_root); - return ret; - } + root = root_device_register("faux"); + if (IS_ERR(root)) + return PTR_ERR(root); ret = bus_register(&faux_bus_type); if (ret) - goto error_bus; + goto err_deregister_root; ret = driver_register(&faux_driver); if (ret) - goto error_driver; + goto err_deregister_bus; - return ret; + faux_bus_root = root; + + return 0; -error_driver: +err_deregister_bus: bus_unregister(&faux_bus_type); +err_deregister_root: + root_device_unregister(root); -error_bus: - device_unregister(faux_bus_root); return ret; } diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index a11b30dda23b..24213a0ea831 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -1132,6 +1132,7 @@ EXPORT_SYMBOL(release_firmware); /* Async support */ struct firmware_work { struct work_struct work; + struct list_head list; struct module *module; const char *name; struct device *device; @@ -1140,6 +1141,17 @@ struct firmware_work { u32 opt_flags; }; +static LIST_HEAD(firmware_work_list); +static DEFINE_SPINLOCK(firmware_work_lock); + +static void firmware_work_free(struct firmware_work *fw_work) +{ + put_device(fw_work->device); /* taken in request_firmware_nowait() */ + module_put(fw_work->module); + kfree_const(fw_work->name); + kfree(fw_work); +} + static void request_firmware_work_func(struct work_struct *work) { struct firmware_work *fw_work; @@ -1150,11 +1162,15 @@ static void request_firmware_work_func(struct work_struct *work) _request_firmware(&fw, fw_work->name, fw_work->device, NULL, 0, 0, fw_work->opt_flags); fw_work->cont(fw, fw_work->context); - put_device(fw_work->device); /* taken in request_firmware_nowait() */ - module_put(fw_work->module); - kfree_const(fw_work->name); - kfree(fw_work); + spin_lock_irq(&firmware_work_lock); + if (!list_empty(&fw_work->list)) { + list_del_init(&fw_work->list); + spin_unlock_irq(&firmware_work_lock); + firmware_work_free(fw_work); + return; + } + spin_unlock_irq(&firmware_work_lock); } @@ -1164,6 +1180,7 @@ static int _request_firmware_nowait( void (*cont)(const struct firmware *fw, void *context), bool nowarn) { struct firmware_work *fw_work; + unsigned long flags; fw_work = kzalloc_obj(struct firmware_work, gfp); if (!fw_work) @@ -1196,7 +1213,12 @@ static int _request_firmware_nowait( get_device(fw_work->device); INIT_WORK(&fw_work->work, request_firmware_work_func); + + spin_lock_irqsave(&firmware_work_lock, flags); + list_add_tail(&fw_work->list, &firmware_work_list); schedule_work(&fw_work->work); + spin_unlock_irqrestore(&firmware_work_lock, flags); + return 0; } @@ -1259,6 +1281,44 @@ int firmware_request_nowait_nowarn( } EXPORT_SYMBOL_GPL(firmware_request_nowait_nowarn); +/** + * request_firmware_nowait_cancel() - cancel an async firmware request + * @device: device for which the firmware is being loaded + * @context: context passed to request_firmware_nowait() + * @cont: callback passed to request_firmware_nowait() + * + * Cancel a pending request_firmware_nowait() request for @device, @context + * and @cont. If the associated work has already started, this function waits + * until the callback has returned. If the callback has already completed, this + * function does nothing. + * + * This function may sleep. + */ +void request_firmware_nowait_cancel(struct device *device, void *context, + void (*cont)(const struct firmware *fw, + void *context)) +{ + struct firmware_work *fw_work = NULL; + struct firmware_work *tmp; + + spin_lock_irq(&firmware_work_lock); + list_for_each_entry_reverse(tmp, &firmware_work_list, list) { + if (tmp->device == device && tmp->context == context && + tmp->cont == cont) { + fw_work = tmp; + list_del_init(&fw_work->list); + break; + } + } + spin_unlock_irq(&firmware_work_lock); + + if (!fw_work) + return; + cancel_work_sync(&fw_work->work); + firmware_work_free(fw_work); +} +EXPORT_SYMBOL_GPL(request_firmware_nowait_cancel); + #ifdef CONFIG_FW_CACHE static ASYNC_DOMAIN_EXCLUSIVE(fw_cache_domain); @@ -1503,9 +1563,10 @@ static void device_cache_fw_images(void) mutex_lock(&fw_lock); fwc->state = FW_LOADER_START_CACHE; - dpm_for_each_dev(NULL, dev_cache_fw_image); mutex_unlock(&fw_lock); + dpm_for_each_dev(NULL, dev_cache_fw_image); + /* wait for completion of caching firmware for all devices */ async_synchronize_full_domain(&fw_cache_domain); diff --git a/drivers/base/firmware_loader/sysfs_upload.c b/drivers/base/firmware_loader/sysfs_upload.c index f59a7856934c..efc33294212f 100644 --- a/drivers/base/firmware_loader/sysfs_upload.c +++ b/drivers/base/firmware_loader/sysfs_upload.c @@ -343,7 +343,6 @@ firmware_upload_register(struct module *module, struct device *parent, goto free_fw_upload_priv; } fw_upload->priv = fw_sysfs; - fw_sysfs->fw_upload_priv = fw_upload_priv; fw_dev = &fw_sysfs->dev; ret = alloc_lookup_fw_priv(name, &fw_cache, &fw_priv, NULL, 0, 0, @@ -351,10 +350,12 @@ firmware_upload_register(struct module *module, struct device *parent, if (ret != 0) { if (ret > 0) ret = -EINVAL; - goto free_fw_sysfs; + put_device(fw_dev); + goto free_fw_upload_priv; } fw_priv->is_paged_buf = true; fw_sysfs->fw_priv = fw_priv; + fw_sysfs->fw_upload_priv = fw_upload_priv; ret = device_add(fw_dev); if (ret) { @@ -365,9 +366,6 @@ firmware_upload_register(struct module *module, struct device *parent, return fw_upload; -free_fw_sysfs: - kfree(fw_sysfs); - free_fw_upload_priv: kfree(fw_upload_priv); diff --git a/drivers/base/isa.c b/drivers/base/isa.c index fd076cc63cb6..5887e4211f80 100644 --- a/drivers/base/isa.c +++ b/drivers/base/isa.c @@ -11,9 +11,7 @@ #include <linux/dma-mapping.h> #include <linux/isa.h> -static struct device isa_bus = { - .init_name = "isa" -}; +static struct device *isa_bus; struct isa_dev { struct device dev; @@ -131,7 +129,7 @@ int isa_register_driver(struct isa_driver *isa_driver, unsigned int ndev) break; } - isa_dev->dev.parent = &isa_bus; + isa_dev->dev.parent = isa_bus; isa_dev->dev.bus = &isa_bus_type; dev_set_name(&isa_dev->dev, "%s.%u", @@ -169,9 +167,11 @@ static int __init isa_bus_init(void) error = bus_register(&isa_bus_type); if (!error) { - error = device_register(&isa_bus); - if (error) + isa_bus = root_device_register("isa"); + if (IS_ERR(isa_bus)) { + error = PTR_ERR(isa_bus); bus_unregister(&isa_bus_type); + } } return error; } diff --git a/drivers/base/memory.c b/drivers/base/memory.c index f806a683b767..bcfe2d9f4adb 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -649,7 +649,7 @@ int __weak arch_get_memory_phys_device(unsigned long start_pfn) * * Called under device_hotplug_lock. */ -struct memory_block *find_memory_block_by_id(unsigned long block_id) +struct memory_block *memory_block_get(unsigned long block_id) { struct memory_block *mem; @@ -659,16 +659,6 @@ struct memory_block *find_memory_block_by_id(unsigned long block_id) return mem; } -/* - * Called under device_hotplug_lock. - */ -struct memory_block *find_memory_block(unsigned long section_nr) -{ - unsigned long block_id = memory_block_id(section_nr); - - return find_memory_block_by_id(block_id); -} - static struct attribute *memory_memblk_attrs[] = { &dev_attr_phys_index.attr, &dev_attr_state.attr, @@ -697,11 +687,11 @@ static int __add_memory_block(struct memory_block *memory) memory->dev.id = memory->start_section_nr / sections_per_block; memory->dev.release = memory_block_release; memory->dev.groups = memory_memblk_attr_groups; - memory->dev.offline = memory->state == MEM_OFFLINE; + dev_assign_offline(&memory->dev, memory->state == MEM_OFFLINE); ret = device_register(&memory->dev); if (ret) { - put_device(&memory->dev); + memory_block_put(memory); return ret; } ret = xa_err(xa_store(&memory_blocks, memory->dev.id, memory, @@ -795,9 +785,9 @@ static int add_memory_block(unsigned long block_id, int nid, unsigned long state struct memory_block *mem; int ret = 0; - mem = find_memory_block_by_id(block_id); + mem = memory_block_get(block_id); if (mem) { - put_device(&mem->dev); + memory_block_put(mem); return -EEXIST; } mem = kzalloc_obj(*mem); @@ -807,7 +797,6 @@ static int add_memory_block(unsigned long block_id, int nid, unsigned long state mem->start_section_nr = block_id * sections_per_block; mem->state = state; mem->nid = nid; - mem->altmap = altmap; INIT_LIST_HEAD(&mem->group_next); #ifndef CONFIG_NUMA @@ -825,6 +814,8 @@ static int add_memory_block(unsigned long block_id, int nid, unsigned long state if (ret) return ret; + mem->altmap = altmap; + if (group) { mem->group = group; list_add(&mem->group_next, &group->memory_blocks); @@ -845,8 +836,8 @@ static void remove_memory_block(struct memory_block *memory) memory->group = NULL; } - /* drop the ref. we got via find_memory_block() */ - put_device(&memory->dev); + /* drop the ref. we got via memory_block_get() */ + memory_block_put(memory); device_unregister(&memory->dev); } @@ -880,7 +871,7 @@ int create_memory_block_devices(unsigned long start, unsigned long size, end_block_id = block_id; for (block_id = start_block_id; block_id != end_block_id; block_id++) { - mem = find_memory_block_by_id(block_id); + mem = memory_block_get(block_id); if (WARN_ON_ONCE(!mem)) continue; remove_memory_block(mem); @@ -908,7 +899,7 @@ void remove_memory_block_devices(unsigned long start, unsigned long size) return; for (block_id = start_block_id; block_id != end_block_id; block_id++) { - mem = find_memory_block_by_id(block_id); + mem = memory_block_get(block_id); if (WARN_ON_ONCE(!mem)) continue; num_poisoned_pages_sub(-1UL, memblk_nr_poison(mem)); @@ -1015,12 +1006,12 @@ int walk_memory_blocks(unsigned long start, unsigned long size, return 0; for (block_id = start_block_id; block_id <= end_block_id; block_id++) { - mem = find_memory_block_by_id(block_id); + mem = memory_block_get(block_id); if (!mem) continue; ret = func(mem, arg); - put_device(&mem->dev); + memory_block_put(mem); if (ret) break; } @@ -1228,19 +1219,23 @@ int walk_dynamic_memory_groups(int nid, walk_memory_groups_func_t func, void memblk_nr_poison_inc(unsigned long pfn) { const unsigned long block_id = pfn_to_block_id(pfn); - struct memory_block *mem = find_memory_block_by_id(block_id); + struct memory_block *mem = memory_block_get(block_id); - if (mem) + if (mem) { atomic_long_inc(&mem->nr_hwpoison); + memory_block_put(mem); + } } void memblk_nr_poison_sub(unsigned long pfn, long i) { const unsigned long block_id = pfn_to_block_id(pfn); - struct memory_block *mem = find_memory_block_by_id(block_id); + struct memory_block *mem = memory_block_get(block_id); - if (mem) + if (mem) { atomic_long_sub(i, &mem->nr_hwpoison); + memory_block_put(mem); + } } static unsigned long memblk_nr_poison(struct memory_block *mem) diff --git a/drivers/base/node.c b/drivers/base/node.c index 126f66aa2c3e..3da91929ad4e 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -523,6 +523,7 @@ static ssize_t node_read_meminfo(struct device *dev, #ifdef CONFIG_UNACCEPTED_MEMORY "Node %d Unaccepted: %8lu kB\n" #endif + "Node %d Balloon: %8lu kB\n" "Node %d GPUActive: %8lu kB\n" "Node %d GPUReclaim: %8lu kB\n" , @@ -559,6 +560,7 @@ static ssize_t node_read_meminfo(struct device *dev, nid, K(sum_zone_node_page_state(nid, NR_UNACCEPTED)) #endif , + nid, K(node_page_state(pgdat, NR_BALLOON_PAGES)), nid, K(node_page_state(pgdat, NR_GPU_ACTIVE)), nid, K(node_page_state(pgdat, NR_GPU_RECLAIM)) ); @@ -847,13 +849,13 @@ static void register_memory_blocks_under_nodes(void) for (block_id = start_block_id; block_id <= end_block_id; block_id++) { struct memory_block *mem; - mem = find_memory_block_by_id(block_id); + mem = memory_block_get(block_id); if (!mem) continue; memory_block_add_nid_early(mem, nid); do_register_memory_block_under_node(nid, mem); - put_device(&mem->dev); + memory_block_put(mem); } } diff --git a/drivers/base/pinctrl.c b/drivers/base/pinctrl.c index 6e250272c843..0bbc83231234 100644 --- a/drivers/base/pinctrl.c +++ b/drivers/base/pinctrl.c @@ -24,7 +24,7 @@ int pinctrl_bind_pins(struct device *dev) { int ret; - if (dev->of_node_reused) + if (dev_of_node_reused(dev)) return 0; dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL); diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c index 70db08f3ac6f..69eed058eb20 100644 --- a/drivers/base/platform-msi.c +++ b/drivers/base/platform-msi.c @@ -61,10 +61,6 @@ static const struct msi_domain_template platform_msi_template = { * parent. The parent domain sets up the new domain. The domain has * a fixed size of @nvec. The domain is managed by devres and will * be removed when the device is removed. - * - * Note: For migration purposes this falls back to the original platform_msi code - * up to the point where all platforms have been converted to the MSI - * parent model. */ int platform_device_msi_init_and_alloc_irqs(struct device *dev, unsigned int nvec, irq_write_msi_msg_t write_msi_msg) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 75b4698d0e58..fb9120b0bcfe 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -606,6 +606,12 @@ static void platform_device_release(struct device *dev) kfree(pa); } +static void platform_device_release_full(struct device *dev) +{ + device_remove_software_node(dev); + platform_device_release(dev); +} + /** * platform_device_alloc - create a platform device * @name: base name of the device we're adding @@ -848,7 +854,13 @@ struct platform_device *platform_device_register_full(const struct platform_devi int ret; struct platform_device *pdev; - if (pdevinfo->swnode && pdevinfo->properties) + /* + * Only one software node per device is allowed. Make sure we don't + * accept or create two. + */ + if ((pdevinfo->swnode && pdevinfo->properties) || + (pdevinfo->swnode && is_software_node(pdevinfo->fwnode)) || + (pdevinfo->properties && is_software_node(pdevinfo->fwnode))) return ERR_PTR(-EINVAL); pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id); @@ -858,7 +870,7 @@ struct platform_device *platform_device_register_full(const struct platform_devi pdev->dev.parent = pdevinfo->parent; pdev->dev.fwnode = pdevinfo->fwnode; pdev->dev.of_node = of_node_get(to_of_node(pdev->dev.fwnode)); - pdev->dev.of_node_reused = pdevinfo->of_node_reused; + dev_assign_of_node_reused(&pdev->dev, pdevinfo->of_node_reused); if (pdevinfo->dma_mask) { pdev->platform_dma_mask = pdevinfo->dma_mask; @@ -878,6 +890,8 @@ struct platform_device *platform_device_register_full(const struct platform_devi ret = device_add_software_node(&pdev->dev, pdevinfo->swnode); if (ret) goto err; + + pdev->dev.release = platform_device_release_full; } else if (pdevinfo->properties) { ret = device_create_managed_software_node(&pdev->dev, pdevinfo->properties, NULL); @@ -901,11 +915,14 @@ EXPORT_SYMBOL_GPL(platform_device_register_full); * __platform_driver_register - register a driver for platform-level devices * @drv: platform driver structure * @owner: owning module/driver + * @mod_name: module name string */ -int __platform_driver_register(struct platform_driver *drv, struct module *owner) +int __platform_driver_register(struct platform_driver *drv, struct module *owner, + const char *mod_name) { drv->driver.owner = owner; drv->driver.bus = &platform_bus_type; + drv->driver.mod_name = mod_name; return driver_register(&drv->driver); } @@ -938,6 +955,7 @@ static int is_bound_to_driver(struct device *dev, void *driver) * @drv: platform driver structure * @probe: the driver probe routine, probably from an __init section * @module: module which will be the owner of the driver + * @mod_name: module name string * * Use this instead of platform_driver_register() when you know the device * is not hotpluggable and has already been registered, and you want to @@ -955,7 +973,8 @@ static int is_bound_to_driver(struct device *dev, void *driver) */ int __init_or_module __platform_driver_probe(struct platform_driver *drv, int (*probe)(struct platform_device *), - struct module *module) + struct module *module, + const char *mod_name) { int retval; @@ -983,7 +1002,7 @@ int __init_or_module __platform_driver_probe(struct platform_driver *drv, /* temporary section violation during probe() */ drv->probe = probe; - retval = __platform_driver_register(drv, module); + retval = __platform_driver_register(drv, module, mod_name); if (retval) return retval; @@ -1011,6 +1030,7 @@ EXPORT_SYMBOL_GPL(__platform_driver_probe); * @data: platform specific data for this platform device * @size: size of platform specific data * @module: module which will be the owner of the driver + * @mod_name: module name string * * Use this in legacy-style modules that probe hardware directly and * register a single platform device and corresponding platform driver. @@ -1021,7 +1041,7 @@ struct platform_device * __init_or_module __platform_create_bundle(struct platform_driver *driver, int (*probe)(struct platform_device *), struct resource *res, unsigned int n_res, - const void *data, size_t size, struct module *module) + const void *data, size_t size, struct module *module, const char *mod_name) { struct platform_device *pdev; int error; @@ -1044,7 +1064,7 @@ __platform_create_bundle(struct platform_driver *driver, if (error) goto err_pdev_put; - error = __platform_driver_probe(driver, probe, module); + error = __platform_driver_probe(driver, probe, module, mod_name); if (error) goto err_pdev_del; @@ -1064,6 +1084,7 @@ EXPORT_SYMBOL_GPL(__platform_create_bundle); * @drivers: an array of drivers to register * @count: the number of drivers to register * @owner: module owning the drivers + * @mod_name: module name string * * Registers platform drivers specified by an array. On failure to register a * driver, all previously registered drivers will be unregistered. Callers of @@ -1073,7 +1094,7 @@ EXPORT_SYMBOL_GPL(__platform_create_bundle); * Returns: 0 on success or a negative error code on failure. */ int __platform_register_drivers(struct platform_driver * const *drivers, - unsigned int count, struct module *owner) + unsigned int count, struct module *owner, const char *mod_name) { unsigned int i; int err; @@ -1081,7 +1102,7 @@ int __platform_register_drivers(struct platform_driver * const *drivers, for (i = 0; i < count; i++) { pr_debug("registering platform driver %ps\n", drivers[i]); - err = __platform_driver_register(drivers[i], owner); + err = __platform_driver_register(drivers[i], owner, mod_name); if (err < 0) { pr_err("failed to register platform driver %ps: %d\n", drivers[i], err); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index e1b550664bab..f71467f6ada4 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -28,6 +28,7 @@ #include <linux/interrupt.h> #include <linux/sched.h> #include <linux/sched/debug.h> +#include <linux/sysctl.h> #include <linux/async.h> #include <linux/suspend.h> #include <trace/events/power.h> @@ -115,7 +116,7 @@ void device_pm_sleep_init(struct device *dev) dev->power.is_noirq_suspended = false; dev->power.is_late_suspended = false; init_completion(&dev->power.completion); - complete_all(&dev->power.completion); + complete(&dev->power.completion); dev->power.wakeup = NULL; INIT_LIST_HEAD(&dev->power.entry); } @@ -252,6 +253,10 @@ static void dpm_wait(struct device *dev, bool async) if (!dev) return; + /* Devices with no PM support don't use the completion. */ + if (dev->power.no_pm) + return; + if (async || (pm_async_enabled && dev->power.async_suspend)) wait_for_completion(&dev->power.completion); } @@ -527,6 +532,58 @@ module_param(dpm_watchdog_all_cpu_backtrace, bool, 0644); MODULE_PARM_DESC(dpm_watchdog_all_cpu_backtrace, "Backtrace all CPUs on DPM watchdog timeout"); +static unsigned int __read_mostly dpm_watchdog_timeout = CONFIG_DPM_WATCHDOG_TIMEOUT; +static unsigned int __read_mostly dpm_watchdog_warning_timeout = + CONFIG_DPM_WATCHDOG_WARNING_TIMEOUT; +static const unsigned int dpm_watchdog_timeout_max = CONFIG_DPM_WATCHDOG_TIMEOUT; + +static int proc_dodpm_watchdog_timeout_secs(const struct ctl_table *table, + int write, void *buffer, + size_t *lenp, loff_t *ppos) +{ + struct ctl_table ctl = *table; + unsigned int val = dpm_watchdog_timeout; + int ret; + + ctl.data = &val; + ret = proc_douintvec_minmax(&ctl, write, buffer, lenp, ppos); + if (ret || !write) + return ret; + + if (val < dpm_watchdog_warning_timeout) + dpm_watchdog_warning_timeout = val; + dpm_watchdog_timeout = val; + + return 0; +} + +static const struct ctl_table dpm_watchdog_sysctls[] = { + { + .procname = "dpm_watchdog_timeout_secs", + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dodpm_watchdog_timeout_secs, + .extra1 = SYSCTL_ONE, + .extra2 = (void *)&dpm_watchdog_timeout_max, + }, + { + .procname = "dpm_watchdog_warning_timeout_secs", + .data = &dpm_watchdog_warning_timeout, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_douintvec_minmax, + .extra1 = SYSCTL_ONE, + .extra2 = (void *)&dpm_watchdog_timeout, + }, +}; + +static int __init dpm_watchdog_sysctl_init(void) +{ + register_sysctl_init("kernel", dpm_watchdog_sysctls); + return 0; +} +subsys_initcall(dpm_watchdog_sysctl_init); + /** * dpm_watchdog_handler - Driver suspend / resume watchdog handler. * @t: The timer that PM watchdog depends on. @@ -552,9 +609,9 @@ static void dpm_watchdog_handler(struct timer_list *t) dev_driver_string(wd->dev), dev_name(wd->dev)); } - time_left = CONFIG_DPM_WATCHDOG_TIMEOUT - CONFIG_DPM_WATCHDOG_WARNING_TIMEOUT; + time_left = dpm_watchdog_timeout - dpm_watchdog_warning_timeout; dev_warn(wd->dev, "**** DPM device timeout after %u seconds; %u seconds until panic ****\n", - CONFIG_DPM_WATCHDOG_WARNING_TIMEOUT, time_left); + dpm_watchdog_warning_timeout, time_left); show_stack(wd->tsk, NULL, KERN_WARNING); wd->fatal = true; @@ -572,11 +629,11 @@ static void dpm_watchdog_set(struct dpm_watchdog *wd, struct device *dev) wd->dev = dev; wd->tsk = current; - wd->fatal = CONFIG_DPM_WATCHDOG_TIMEOUT == CONFIG_DPM_WATCHDOG_WARNING_TIMEOUT; + wd->fatal = dpm_watchdog_timeout == dpm_watchdog_warning_timeout; timer_setup_on_stack(timer, dpm_watchdog_handler, 0); /* use same timeout value for both suspend and resume */ - timer->expires = jiffies + HZ * CONFIG_DPM_WATCHDOG_WARNING_TIMEOUT; + timer->expires = jiffies + HZ * dpm_watchdog_warning_timeout; add_timer(timer); } diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 922ed457db19..8823aceeac8b 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -168,3 +168,10 @@ static inline void device_pm_init(struct device *dev) device_pm_sleep_init(dev); pm_runtime_init(dev); } + +#ifdef CONFIG_BPF_SYSCALL +struct bpf_ws_lock { }; +struct bpf_ws_lock *bpf_wakeup_sources_read_lock(void); +void bpf_wakeup_sources_read_unlock(struct bpf_ws_lock *lock); +void *bpf_wakeup_sources_get_head(void); +#endif diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index b8e48a023bf0..80b497de2deb 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -1168,11 +1168,78 @@ static const struct file_operations wakeup_sources_stats_fops = { .release = seq_release_private, }; -static int __init wakeup_sources_debugfs_init(void) +#ifdef CONFIG_BPF_SYSCALL +#include <linux/btf.h> + +__bpf_kfunc_start_defs(); + +/** + * bpf_wakeup_sources_read_lock - Acquire the SRCU lock for wakeup sources + * + * The underlying SRCU lock returns an integer index. However, the BPF verifier + * requires a pointer (PTR_TO_BTF_ID) to strictly track the state of acquired + * resources using KF_ACQUIRE and KF_RELEASE semantics. We use an opaque + * structure pointer (struct bpf_ws_lock *) to satisfy the verifier while + * safely encoding the integer index within the pointer address itself. + * + * Return: An opaque pointer encoding the SRCU lock index + 1 (to avoid NULL). + */ +__bpf_kfunc struct bpf_ws_lock *bpf_wakeup_sources_read_lock(void) +{ + return (struct bpf_ws_lock *)(long)(wakeup_sources_read_lock() + 1); +} + +/** + * bpf_wakeup_sources_read_unlock - Release the SRCU lock for wakeup sources + * @lock: The opaque pointer returned by bpf_wakeup_sources_read_lock() + * + * The BPF verifier guarantees that @lock is a valid, unreleased pointer from + * the acquire function. We decode the pointer back into the integer SRCU index + * by subtracting 1 and release the lock. + */ +__bpf_kfunc void bpf_wakeup_sources_read_unlock(struct bpf_ws_lock *lock) +{ + wakeup_sources_read_unlock((int)(long)lock - 1); +} + +/** + * bpf_wakeup_sources_get_head - Get the head of the wakeup sources list + * + * Return: The head of the wakeup sources list. + */ +__bpf_kfunc void *bpf_wakeup_sources_get_head(void) +{ + return &wakeup_sources; +} + +__bpf_kfunc_end_defs(); + +BTF_KFUNCS_START(wakeup_source_kfunc_ids) +BTF_ID_FLAGS(func, bpf_wakeup_sources_read_lock, KF_ACQUIRE) +BTF_ID_FLAGS(func, bpf_wakeup_sources_read_unlock, KF_RELEASE) +BTF_ID_FLAGS(func, bpf_wakeup_sources_get_head) +BTF_KFUNCS_END(wakeup_source_kfunc_ids) + +static const struct btf_kfunc_id_set wakeup_source_kfunc_set = { + .set = &wakeup_source_kfunc_ids, +}; + +static void __init wakeup_sources_bpf_init(void) +{ + if (register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &wakeup_source_kfunc_set)) + pm_pr_dbg("Wakeup: failed to register BTF kfuncs\n"); +} +#else +static inline void wakeup_sources_bpf_init(void) {} +#endif /* CONFIG_BPF_SYSCALL */ + +static int __init wakeup_sources_init(void) { debugfs_create_file("wakeup_sources", 0444, NULL, NULL, &wakeup_sources_stats_fops); + wakeup_sources_bpf_init(); + return 0; } -postcore_initcall(wakeup_sources_debugfs_init); +postcore_initcall(wakeup_sources_init); diff --git a/drivers/base/property.c b/drivers/base/property.c index 8e0148a37fff..e08eadd66f4f 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -1277,8 +1277,10 @@ fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode, if (fwnode_ep.port != port) continue; - if (fwnode_ep.id == endpoint) + if (fwnode_ep.id == endpoint) { + fwnode_handle_put(best_ep); return ep; + } if (!endpoint_next) continue; diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 27616b05111c..aa8f2efed779 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -245,7 +245,7 @@ err_exit: if (map->cache_ops->exit) { dev_dbg(map->dev, "Destroying %s cache\n", map->cache_ops->name); map->lock(map->lock_arg); - ret = map->cache_ops->exit(map); + map->cache_ops->exit(map); map->unlock(map->lock_arg); } err_free_reg_defaults: diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index 31e30dfced19..51a04961faf7 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -337,7 +337,7 @@ static int regmap_smbus_word_write_reg16(void *context, const void *data, val = ((u8 *)data)[2]; return i2c_smbus_write_word_data(i2c, addr_hi, - cpu_to_le16(((u16)val << 8) | addr_lo)); + ((u16)val << 8) | addr_lo); } static const struct regmap_bus regmap_smbus_byte_word_reg16 = { diff --git a/drivers/base/regmap/regmap-sdw-mbq.c b/drivers/base/regmap/regmap-sdw-mbq.c index 4533fe793c5f..2585933d4946 100644 --- a/drivers/base/regmap/regmap-sdw-mbq.c +++ b/drivers/base/regmap/regmap-sdw-mbq.c @@ -172,7 +172,7 @@ static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *va ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size); if (ret == -ENODATA) { if (!deferrable) - dev_warn(dev, "Defer on undeferable control: %x\n", reg); + dev_warn(dev, "Defer on undeferrable control: %x\n", reg); ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx); if (ret) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index b2b26f07f4e3..e6e022b02637 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -3257,6 +3257,9 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, *change = false; if (regmap_volatile(map, reg) && map->reg_update_bits) { + if (map->cache_only) + return -EBUSY; + reg = regmap_reg_addr(map, reg); ret = map->reg_update_bits(map->bus_context, reg, mask, val); if (ret == 0 && change) diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index a19f8f722bc8..869228a65cb3 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -374,20 +374,28 @@ EXPORT_SYMBOL_GPL(property_entries_free); /* -------------------------------------------------------------------------- */ /* fwnode operations */ -static struct fwnode_handle *software_node_get(struct fwnode_handle *fwnode) +static struct swnode *swnode_get(struct swnode *swnode) { - struct swnode *swnode = to_swnode(fwnode); - kobject_get(&swnode->kobj); + return swnode; +} + +static void swnode_put(struct swnode *swnode) +{ + kobject_put(&swnode->kobj); +} + +static struct fwnode_handle *software_node_get(struct fwnode_handle *fwnode) +{ + struct swnode *swnode = swnode_get(to_swnode(fwnode)); + return &swnode->fwnode; } static void software_node_put(struct fwnode_handle *fwnode) { - struct swnode *swnode = to_swnode(fwnode); - - kobject_put(&swnode->kobj); + swnode_put(to_swnode(fwnode)); } static bool software_node_property_present(const struct fwnode_handle *fwnode, @@ -493,7 +501,7 @@ software_node_get_named_child_node(const struct fwnode_handle *fwnode, list_for_each_entry(child, &swnode->children, entry) { if (!strcmp(childname, kobject_name(&child->kobj))) { - kobject_get(&child->kobj); + swnode_get(child); return &child->fwnode; } } @@ -737,7 +745,7 @@ software_node_find_by_name(const struct software_node *parent, const char *name) swnode = kobj_to_swnode(k); if (parent == swnode->node->parent && swnode->node->name && !strcmp(name, swnode->node->name)) { - kobject_get(&swnode->kobj); + swnode_get(swnode); break; } swnode = NULL; @@ -835,13 +843,13 @@ swnode_register(const struct software_node *node, struct swnode *parent, parent ? &parent->kobj : NULL, "node%d", swnode->id); if (ret) { - kobject_put(&swnode->kobj); + swnode_put(swnode); return ERR_PTR(ret); } /* * Assign the flag only in the successful case, so - * the above kobject_put() won't mess up with properties. + * the above swnode_put() won't mess up with properties. */ swnode->allocated = allocated; @@ -978,7 +986,7 @@ void fwnode_remove_software_node(struct fwnode_handle *fwnode) if (!swnode) return; - kobject_put(&swnode->kobj); + swnode_put(swnode); } EXPORT_SYMBOL_GPL(fwnode_remove_software_node); @@ -1002,7 +1010,7 @@ int device_add_software_node(struct device *dev, const struct software_node *nod swnode = software_node_to_swnode(node); if (swnode) { - kobject_get(&swnode->kobj); + swnode_get(swnode); } else { ret = software_node_register(node); if (ret) @@ -1044,7 +1052,7 @@ void device_remove_software_node(struct device *dev) software_node_notify_remove(dev); set_secondary_fwnode(dev, NULL); - kobject_put(&swnode->kobj); + swnode_put(swnode); } EXPORT_SYMBOL_GPL(device_remove_software_node); @@ -1097,7 +1105,7 @@ void software_node_notify(struct device *dev) if (!swnode) return; - kobject_get(&swnode->kobj); + swnode_get(swnode); ret = sysfs_create_link(&dev->kobj, &swnode->kobj, "software_node"); if (ret) return; @@ -1119,11 +1127,11 @@ void software_node_notify_remove(struct device *dev) sysfs_remove_link(&swnode->kobj, dev_name(dev)); sysfs_remove_link(&dev->kobj, "software_node"); - kobject_put(&swnode->kobj); + swnode_put(swnode); if (swnode->managed) { set_secondary_fwnode(dev, NULL); - kobject_put(&swnode->kobj); + swnode_put(swnode); } } |
