diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/base.h | 3 | ||||
-rw-r--r-- | drivers/base/core.c | 324 | ||||
-rw-r--r-- | drivers/base/dd.c | 63 | ||||
-rw-r--r-- | drivers/base/devres.c | 25 | ||||
-rw-r--r-- | drivers/base/driver.c | 4 | ||||
-rw-r--r-- | drivers/base/firmware_loader/fallback_platform.c | 5 | ||||
-rw-r--r-- | drivers/base/firmware_loader/main.c | 12 | ||||
-rw-r--r-- | drivers/base/memory.c | 15 | ||||
-rw-r--r-- | drivers/base/platform.c | 28 | ||||
-rw-r--r-- | drivers/base/swnode.c | 8 | ||||
-rw-r--r-- | drivers/base/topology.c | 2 |
11 files changed, 422 insertions, 67 deletions
diff --git a/drivers/base/base.h b/drivers/base/base.h index 40fb069a8a7e..91cfb8405abd 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -93,6 +93,7 @@ struct device_private { struct klist_node knode_class; struct list_head deferred_probe; struct device_driver *async_driver; + char *deferred_probe_reason; struct device *device; u8 dead:1; }; @@ -134,6 +135,8 @@ extern void device_release_driver_internal(struct device *dev, extern void driver_detach(struct device_driver *drv); extern int driver_probe_device(struct device_driver *drv, struct device *dev); extern void driver_deferred_probe_del(struct device *dev); +extern 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) { diff --git a/drivers/base/core.c b/drivers/base/core.c index 05d414e9e8a4..778c7a435cbd 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -236,6 +236,210 @@ void device_pm_move_to_tail(struct device *dev) device_links_read_unlock(idx); } +#define to_devlink(dev) container_of((dev), struct device_link, link_dev) + +static ssize_t status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char *status; + + switch (to_devlink(dev)->status) { + case DL_STATE_NONE: + status = "not tracked"; break; + case DL_STATE_DORMANT: + status = "dormant"; break; + case DL_STATE_AVAILABLE: + status = "available"; break; + case DL_STATE_CONSUMER_PROBE: + status = "consumer probing"; break; + case DL_STATE_ACTIVE: + status = "active"; break; + case DL_STATE_SUPPLIER_UNBIND: + status = "supplier unbinding"; break; + default: + status = "unknown"; break; + } + return sprintf(buf, "%s\n", status); +} +static DEVICE_ATTR_RO(status); + +static ssize_t auto_remove_on_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct device_link *link = to_devlink(dev); + char *str; + + if (link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER) + str = "supplier unbind"; + else if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER) + str = "consumer unbind"; + else + str = "never"; + + return sprintf(buf, "%s\n", str); +} +static DEVICE_ATTR_RO(auto_remove_on); + +static ssize_t runtime_pm_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct device_link *link = to_devlink(dev); + + return sprintf(buf, "%d\n", !!(link->flags & DL_FLAG_PM_RUNTIME)); +} +static DEVICE_ATTR_RO(runtime_pm); + +static ssize_t sync_state_only_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct device_link *link = to_devlink(dev); + + return sprintf(buf, "%d\n", !!(link->flags & DL_FLAG_SYNC_STATE_ONLY)); +} +static DEVICE_ATTR_RO(sync_state_only); + +static struct attribute *devlink_attrs[] = { + &dev_attr_status.attr, + &dev_attr_auto_remove_on.attr, + &dev_attr_runtime_pm.attr, + &dev_attr_sync_state_only.attr, + NULL, +}; +ATTRIBUTE_GROUPS(devlink); + +static void device_link_free(struct device_link *link) +{ + while (refcount_dec_not_one(&link->rpm_active)) + pm_runtime_put(link->supplier); + + put_device(link->consumer); + put_device(link->supplier); + kfree(link); +} + +#ifdef CONFIG_SRCU +static void __device_link_free_srcu(struct rcu_head *rhead) +{ + device_link_free(container_of(rhead, struct device_link, rcu_head)); +} + +static void devlink_dev_release(struct device *dev) +{ + struct device_link *link = to_devlink(dev); + + call_srcu(&device_links_srcu, &link->rcu_head, __device_link_free_srcu); +} +#else +static void devlink_dev_release(struct device *dev) +{ + device_link_free(to_devlink(dev)); +} +#endif + +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) +{ + int ret; + size_t len; + struct device_link *link = to_devlink(dev); + struct device *sup = link->supplier; + struct device *con = link->consumer; + char *buf; + + len = max(strlen(dev_name(sup)), strlen(dev_name(con))); + len += strlen("supplier:") + 1; + buf = kzalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = sysfs_create_link(&link->link_dev.kobj, &sup->kobj, "supplier"); + if (ret) + goto out; + + ret = sysfs_create_link(&link->link_dev.kobj, &con->kobj, "consumer"); + if (ret) + goto err_con; + + snprintf(buf, len, "consumer:%s", dev_name(con)); + ret = sysfs_create_link(&sup->kobj, &link->link_dev.kobj, buf); + if (ret) + goto err_con_dev; + + snprintf(buf, len, "supplier:%s", dev_name(sup)); + ret = sysfs_create_link(&con->kobj, &link->link_dev.kobj, buf); + if (ret) + goto err_sup_dev; + + goto out; + +err_sup_dev: + snprintf(buf, len, "consumer:%s", dev_name(con)); + sysfs_remove_link(&sup->kobj, buf); +err_con_dev: + sysfs_remove_link(&link->link_dev.kobj, "consumer"); +err_con: + sysfs_remove_link(&link->link_dev.kobj, "supplier"); +out: + kfree(buf); + return ret; +} + +static void devlink_remove_symlinks(struct device *dev, + struct class_interface *class_intf) +{ + struct device_link *link = to_devlink(dev); + size_t len; + struct device *sup = link->supplier; + struct device *con = link->consumer; + char *buf; + + sysfs_remove_link(&link->link_dev.kobj, "consumer"); + sysfs_remove_link(&link->link_dev.kobj, "supplier"); + + len = max(strlen(dev_name(sup)), strlen(dev_name(con))); + len += strlen("supplier:") + 1; + buf = kzalloc(len, GFP_KERNEL); + if (!buf) { + WARN(1, "Unable to properly free device link symlinks!\n"); + return; + } + + snprintf(buf, len, "supplier:%s", dev_name(sup)); + sysfs_remove_link(&con->kobj, buf); + snprintf(buf, len, "consumer:%s", dev_name(con)); + sysfs_remove_link(&sup->kobj, buf); + kfree(buf); +} + +static struct class_interface devlink_class_intf = { + .class = &devlink_class, + .add_dev = devlink_add_symlinks, + .remove_dev = devlink_remove_symlinks, +}; + +static int __init devlink_class_init(void) +{ + int ret; + + ret = class_register(&devlink_class); + if (ret) + return ret; + + ret = class_interface_register(&devlink_class_intf); + if (ret) + class_unregister(&devlink_class); + + return ret; +} +postcore_initcall(devlink_class_init); + #define DL_MANAGED_LINK_FLAGS (DL_FLAG_AUTOREMOVE_CONSUMER | \ DL_FLAG_AUTOREMOVE_SUPPLIER | \ DL_FLAG_AUTOPROBE_CONSUMER | \ @@ -408,13 +612,6 @@ struct device_link *device_link_add(struct device *consumer, refcount_set(&link->rpm_active, 1); - if (flags & DL_FLAG_PM_RUNTIME) { - if (flags & DL_FLAG_RPM_ACTIVE) - refcount_inc(&link->rpm_active); - - pm_runtime_new_link(consumer); - } - get_device(supplier); link->supplier = supplier; INIT_LIST_HEAD(&link->s_node); @@ -424,6 +621,25 @@ struct device_link *device_link_add(struct device *consumer, link->flags = flags; kref_init(&link->kref); + link->link_dev.class = &devlink_class; + device_set_pm_not_required(&link->link_dev); + dev_set_name(&link->link_dev, "%s--%s", + dev_name(supplier), dev_name(consumer)); + if (device_register(&link->link_dev)) { + put_device(consumer); + put_device(supplier); + kfree(link); + link = NULL; + goto out; + } + + if (flags & DL_FLAG_PM_RUNTIME) { + if (flags & DL_FLAG_RPM_ACTIVE) + refcount_inc(&link->rpm_active); + + pm_runtime_new_link(consumer); + } + /* Determine the initial link state. */ if (flags & DL_FLAG_STATELESS) link->status = DL_STATE_NONE; @@ -539,22 +755,7 @@ static void device_link_add_missing_supplier_links(void) mutex_unlock(&wfs_lock); } -static void device_link_free(struct device_link *link) -{ - while (refcount_dec_not_one(&link->rpm_active)) - pm_runtime_put(link->supplier); - - put_device(link->consumer); - put_device(link->supplier); - kfree(link); -} - #ifdef CONFIG_SRCU -static void __device_link_free_srcu(struct rcu_head *rhead) -{ - device_link_free(container_of(rhead, struct device_link, rcu_head)); -} - static void __device_link_del(struct kref *kref) { struct device_link *link = container_of(kref, struct device_link, kref); @@ -567,7 +768,7 @@ static void __device_link_del(struct kref *kref) list_del_rcu(&link->s_node); list_del_rcu(&link->c_node); - call_srcu(&device_links_srcu, &link->rcu_head, __device_link_free_srcu); + device_unregister(&link->link_dev); } #else /* !CONFIG_SRCU */ static void __device_link_del(struct kref *kref) @@ -582,7 +783,7 @@ static void __device_link_del(struct kref *kref) list_del(&link->s_node); list_del(&link->c_node); - device_link_free(link); + device_unregister(&link->link_dev); } #endif /* !CONFIG_SRCU */ @@ -850,6 +1051,22 @@ static void device_link_drop_managed(struct device_link *link) kref_put(&link->kref, __device_link_del); } +static ssize_t waiting_for_supplier_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + bool val; + + device_lock(dev); + mutex_lock(&wfs_lock); + val = !list_empty(&dev->links.needs_suppliers) + && dev->links.need_for_probe; + mutex_unlock(&wfs_lock); + device_unlock(dev); + return sprintf(buf, "%u\n", val); +} +static DEVICE_ATTR_RO(waiting_for_supplier); + /** * device_links_driver_bound - Update device links after probing its driver. * @dev: Device to update the links for. @@ -874,6 +1091,7 @@ void device_links_driver_bound(struct device *dev) mutex_lock(&wfs_lock); list_del_init(&dev->links.needs_suppliers); mutex_unlock(&wfs_lock); + device_remove_file(dev, &dev_attr_waiting_for_supplier); device_links_write_lock(); @@ -1160,6 +1378,9 @@ static void device_links_purge(struct device *dev) { struct device_link *link, *ln; + if (dev->class == &devlink_class) + return; + mutex_lock(&wfs_lock); list_del(&dev->links.needs_suppliers); mutex_unlock(&wfs_lock); @@ -1969,8 +2190,16 @@ static int device_add_attrs(struct device *dev) goto err_remove_dev_groups; } + if (fw_devlink_flags && !fw_devlink_is_permissive()) { + error = device_create_file(dev, &dev_attr_waiting_for_supplier); + if (error) + goto err_remove_dev_online; + } + return 0; + err_remove_dev_online: + device_remove_file(dev, &dev_attr_online); err_remove_dev_groups: device_remove_groups(dev, dev->groups); err_remove_type_groups: @@ -1988,6 +2217,7 @@ static void device_remove_attrs(struct device *dev) struct class *class = dev->class; const struct device_type *type = dev->type; + device_remove_file(dev, &dev_attr_waiting_for_supplier); device_remove_file(dev, &dev_attr_online); device_remove_groups(dev, dev->groups); @@ -3973,6 +4203,52 @@ define_dev_printk_level(_dev_info, KERN_INFO); #endif +/** + * dev_err_probe - probe error check and log helper + * @dev: the pointer to the struct device + * @err: error value to test + * @fmt: printf-style format string + * @...: arguments as specified in the format string + * + * This helper implements common pattern present in probe functions for error + * checking: print debug or error message depending if the error value is + * -EPROBE_DEFER and propagate error upwards. + * In case of -EPROBE_DEFER it sets also defer probe reason, which can be + * checked later by reading devices_deferred debugfs attribute. + * It replaces code sequence: + * if (err != -EPROBE_DEFER) + * dev_err(dev, ...); + * else + * dev_dbg(dev, ...); + * return err; + * with + * return dev_err_probe(dev, err, ...); + * + * Returns @err. + * + */ +int dev_err_probe(const struct device *dev, int err, const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + + va_start(args, fmt); + vaf.fmt = fmt; + vaf.va = &args; + + if (err != -EPROBE_DEFER) { + dev_err(dev, "error %d: %pV", err, &vaf); + } else { + device_set_deferred_probe_reason(dev, &vaf); + dev_dbg(dev, "error %d: %pV", err, &vaf); + } + + va_end(args); + + return err; +} +EXPORT_SYMBOL_GPL(dev_err_probe); + static inline bool fwnode_is_primary(struct fwnode_handle *fwnode) { return fwnode && !IS_ERR(fwnode->secondary); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 48ca81cb8ebc..857b0a928e8d 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -27,6 +27,7 @@ #include <linux/async.h> #include <linux/pm_runtime.h> #include <linux/pinctrl/devinfo.h> +#include <linux/slab.h> #include "base.h" #include "power/power.h" @@ -136,6 +137,8 @@ void driver_deferred_probe_del(struct device *dev) if (!list_empty(&dev->p->deferred_probe)) { dev_dbg(dev, "Removed from deferred list\n"); list_del_init(&dev->p->deferred_probe); + kfree(dev->p->deferred_probe_reason); + dev->p->deferred_probe_reason = NULL; } mutex_unlock(&deferred_probe_mutex); } @@ -206,6 +209,23 @@ void device_unblock_probing(void) driver_deferred_probe_trigger(); } +/** + * device_set_deferred_probe_reason() - Set defer probe reason message for device + * @dev: the pointer to the struct device + * @vaf: the pointer to va_format structure with message + */ +void device_set_deferred_probe_reason(const struct device *dev, struct va_format *vaf) +{ + const char *drv = dev_driver_string(dev); + + mutex_lock(&deferred_probe_mutex); + + kfree(dev->p->deferred_probe_reason); + dev->p->deferred_probe_reason = kasprintf(GFP_KERNEL, "%s: %pV", drv, vaf); + + mutex_unlock(&deferred_probe_mutex); +} + /* * deferred_devs_show() - Show the devices in the deferred probe pending list. */ @@ -216,7 +236,8 @@ static int deferred_devs_show(struct seq_file *s, void *data) mutex_lock(&deferred_probe_mutex); list_for_each_entry(curr, &deferred_probe_pending_list, deferred_probe) - seq_printf(s, "%s\n", dev_name(curr->device)); + seq_printf(s, "%s\t%s", dev_name(curr->device), + curr->device->p->deferred_probe_reason ?: "\n"); mutex_unlock(&deferred_probe_mutex); @@ -276,7 +297,7 @@ static void deferred_probe_timeout_work_func(struct work_struct *work) list_for_each_entry_safe(private, p, &deferred_probe_pending_list, deferred_probe) dev_info(private->device, "deferred probe pending\n"); - wake_up(&probe_timeout_waitqueue); + wake_up_all(&probe_timeout_waitqueue); } static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func); @@ -425,10 +446,9 @@ static void driver_sysfs_remove(struct device *dev) * Allow manual attachment of a driver to a device. * Caller must have already set @dev->driver. * - * Note that this does not modify the bus reference count - * nor take the bus's rwsem. Please verify those are accounted - * for before calling this. (It is ok to call with no other effort - * from a driver's probe() method.) + * Note that this does not modify the bus reference count. + * Please verify that is accounted for before calling this. + * (It is ok to call with no other effort from a driver's probe() method.) * * This function must be called with the device lock held. */ @@ -458,6 +478,18 @@ static void driver_deferred_probe_add_trigger(struct device *dev, driver_deferred_probe_trigger(); } +static ssize_t state_synced_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool val; + + device_lock(dev); + val = dev->state_synced; + device_unlock(dev); + return sprintf(buf, "%u\n", val); +} +static DEVICE_ATTR_RO(state_synced); + static int really_probe(struct device *dev, struct device_driver *drv) { int ret = -EPROBE_DEFER; @@ -487,7 +519,8 @@ static int really_probe(struct device *dev, struct device_driver *drv) drv->bus->name, __func__, drv->name, dev_name(dev)); if (!list_empty(&dev->devres_head)) { dev_crit(dev, "Resources present before probing\n"); - return -EBUSY; + ret = -EBUSY; + goto done; } re_probe: @@ -531,9 +564,16 @@ re_probe: goto dev_groups_failed; } + if (dev_has_sync_state(dev) && + device_create_file(dev, &dev_attr_state_synced)) { + dev_err(dev, "state_synced sysfs add failed\n"); + goto dev_sysfs_state_synced_failed; + } + if (test_remove) { test_remove = false; + device_remove_file(dev, &dev_attr_state_synced); device_remove_groups(dev, drv->dev_groups); if (dev->bus->remove) @@ -563,6 +603,8 @@ re_probe: drv->bus->name, __func__, dev_name(dev), drv->name); goto done; +dev_sysfs_state_synced_failed: + device_remove_groups(dev, drv->dev_groups); dev_groups_failed: if (dev->bus->remove) dev->bus->remove(dev); @@ -607,7 +649,7 @@ pinctrl_bind_failed: ret = 0; done: atomic_dec(&probe_count); - wake_up(&probe_waitqueue); + wake_up_all(&probe_waitqueue); return ret; } @@ -843,7 +885,9 @@ static int __device_attach(struct device *dev, bool allow_async) int ret = 0; device_lock(dev); - if (dev->driver) { + if (dev->p->dead) { + goto out_unlock; + } else if (dev->driver) { if (device_is_bound(dev)) { ret = 1; goto out_unlock; @@ -1100,6 +1144,7 @@ static void __device_release_driver(struct device *dev, struct device *parent) pm_runtime_put_sync(dev); + device_remove_file(dev, &dev_attr_state_synced); device_remove_groups(dev, drv->dev_groups); if (dev->bus && dev->bus->remove) diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 0bbb328bd17f..ed615d3b9cf1 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -89,15 +89,23 @@ static struct devres_group * node_to_group(struct devres_node *node) return NULL; } +static bool check_dr_size(size_t size, size_t *tot_size) +{ + /* We must catch any near-SIZE_MAX cases that could overflow. */ + if (unlikely(check_add_overflow(sizeof(struct devres), + size, tot_size))) + return false; + + return true; +} + static __always_inline struct devres * alloc_dr(dr_release_t release, size_t size, gfp_t gfp, int nid) { size_t tot_size; struct devres *dr; - /* We must catch any near-SIZE_MAX cases that could overflow. */ - if (unlikely(check_add_overflow(sizeof(struct devres), size, - &tot_size))) + if (!check_dr_size(size, &tot_size)) return NULL; dr = kmalloc_node_track_caller(tot_size, gfp, nid); @@ -807,10 +815,13 @@ static int devm_kmalloc_match(struct device *dev, void *res, void *data) * RETURNS: * Pointer to allocated memory on success, NULL on failure. */ -void * devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) +void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) { struct devres *dr; + if (unlikely(!size)) + return ZERO_SIZE_PTR; + /* use raw alloc_dr for kmalloc caller tracing */ dr = alloc_dr(devm_kmalloc_release, size, gfp, dev_to_node(dev)); if (unlikely(!dr)) @@ -942,10 +953,10 @@ void devm_kfree(struct device *dev, const void *p) int rc; /* - * Special case: pointer to a string in .rodata returned by - * devm_kstrdup_const(). + * Special cases: pointer to a string in .rodata returned by + * devm_kstrdup_const() or NULL/ZERO ptr. */ - if (unlikely(is_kernel_rodata((unsigned long)p))) + if (unlikely(is_kernel_rodata((unsigned long)p) || ZERO_OR_NULL_PTR(p))) return; rc = devres_destroy(dev, devm_kmalloc_release, diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 57c68769e157..8c0d33e182fd 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -158,12 +158,12 @@ int driver_register(struct device_driver *drv) if ((drv->bus->probe && drv->probe) || (drv->bus->remove && drv->remove) || (drv->bus->shutdown && drv->shutdown)) - printk(KERN_WARNING "Driver '%s' needs updating - please use " + pr_warn("Driver '%s' needs updating - please use " "bus_type methods\n", drv->name); other = driver_find(drv->name, drv->bus); if (other) { - printk(KERN_ERR "Error: Driver '%s' is already registered, " + pr_err("Error: Driver '%s' is already registered, " "aborting...\n", drv->name); return -EBUSY; } diff --git a/drivers/base/firmware_loader/fallback_platform.c b/drivers/base/firmware_loader/fallback_platform.c index cdd2c9a9f38a..685edb7dd05a 100644 --- a/drivers/base/firmware_loader/fallback_platform.c +++ b/drivers/base/firmware_loader/fallback_platform.c @@ -25,7 +25,10 @@ int firmware_fallback_platform(struct fw_priv *fw_priv, u32 opt_flags) if (rc) return rc; /* rc == -ENOENT when the fw was not found */ - fw_priv->data = vmalloc(size); + if (fw_priv->data && size > fw_priv->allocated_size) + return -ENOMEM; + if (!fw_priv->data) + fw_priv->data = vmalloc(size); if (!fw_priv->data) return -ENOMEM; diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index ca871b13524e..9da0c9d5f538 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -838,12 +838,12 @@ EXPORT_SYMBOL(request_firmware); * @name: name of firmware file * @device: device for which firmware is being loaded * - * This function is similar in behaviour to request_firmware(), except - * it doesn't produce warning messages when the file is not found. - * The sysfs fallback mechanism is enabled if direct filesystem lookup fails, - * however, however failures to find the firmware file with it are still - * suppressed. It is therefore up to the driver to check for the return value - * of this call and to decide when to inform the users of errors. + * This function is similar in behaviour to request_firmware(), except it + * doesn't produce warning messages when the file is not found. The sysfs + * fallback mechanism is enabled if direct filesystem lookup fails. However, + * failures to find the firmware file with it are still suppressed. It is + * therefore up to the driver to check for the return value of this call and to + * decide when to inform the users of errors. **/ int firmware_request_nowarn(const struct firmware **firmware, const char *name, struct device *device) diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 2b09b68b9f78..4db3c660de83 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -50,14 +50,14 @@ int memhp_online_type_from_str(const char *str) static int sections_per_block; -static inline unsigned long base_memory_block_id(unsigned long section_nr) +static inline unsigned long memory_block_id(unsigned long section_nr) { return section_nr / sections_per_block; } static inline unsigned long pfn_to_block_id(unsigned long pfn) { - return base_memory_block_id(pfn_to_section_nr(pfn)); + return memory_block_id(pfn_to_section_nr(pfn)); } static inline unsigned long phys_to_block_id(unsigned long phys) @@ -517,7 +517,7 @@ static struct memory_block *find_memory_block_by_id(unsigned long block_id) */ struct memory_block *find_memory_block(struct mem_section *section) { - unsigned long block_id = base_memory_block_id(__section_nr(section)); + unsigned long block_id = memory_block_id(__section_nr(section)); return find_memory_block_by_id(block_id); } @@ -570,8 +570,7 @@ int register_memory(struct memory_block *memory) return ret; } -static int init_memory_block(struct memory_block **memory, - unsigned long block_id, unsigned long state) +static int init_memory_block(unsigned long block_id, unsigned long state) { struct memory_block *mem; unsigned long start_pfn; @@ -594,14 +593,12 @@ static int init_memory_block(struct memory_block **memory, ret = register_memory(mem); - *memory = mem; return ret; } static int add_memory_block(unsigned long base_section_nr) { int section_count = 0; - struct memory_block *mem; unsigned long nr; for (nr = base_section_nr; nr < base_section_nr + sections_per_block; @@ -611,7 +608,7 @@ static int add_memory_block(unsigned long base_section_nr) if (section_count == 0) return 0; - return init_memory_block(&mem, base_memory_block_id(base_section_nr), + return init_memory_block(memory_block_id(base_section_nr), MEM_ONLINE); } @@ -647,7 +644,7 @@ int create_memory_block_devices(unsigned long start, unsigned long size) return -EINVAL; for (block_id = start_block_id; block_id != end_block_id; block_id++) { - ret = init_memory_block(&mem, block_id, MEM_OFFLINE); + ret = init_memory_block(block_id, MEM_OFFLINE); if (ret) break; } diff --git a/drivers/base/platform.c b/drivers/base/platform.c index c0d0a5490ac6..e5d8a0503b4f 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -1019,7 +1019,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a, if (len != -ENODEV) return len; - len = acpi_device_modalias(dev, buf, PAGE_SIZE -1); + len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1); if (len != -ENODEV) return len; @@ -1076,13 +1076,37 @@ static ssize_t driver_override_show(struct device *dev, } static DEVICE_ATTR_RW(driver_override); +static ssize_t numa_node_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", dev_to_node(dev)); +} +static DEVICE_ATTR_RO(numa_node); + +static umode_t platform_dev_attrs_visible(struct kobject *kobj, struct attribute *a, + int n) +{ + struct device *dev = container_of(kobj, typeof(*dev), kobj); + + if (a == &dev_attr_numa_node.attr && + dev_to_node(dev) == NUMA_NO_NODE) + return 0; + + return a->mode; +} static struct attribute *platform_dev_attrs[] = { &dev_attr_modalias.attr, + &dev_attr_numa_node.attr, &dev_attr_driver_override.attr, NULL, }; -ATTRIBUTE_GROUPS(platform_dev); + +static struct attribute_group platform_dev_group = { + .attrs = platform_dev_attrs, + .is_visible = platform_dev_attrs_visible, +}; +__ATTRIBUTE_GROUPS(platform_dev); static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) { diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index e5eb27375416..010828fc785b 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -761,17 +761,13 @@ EXPORT_SYMBOL_GPL(software_node_register_node_group); */ void software_node_unregister_node_group(const struct software_node **node_group) { - struct swnode *swnode; unsigned int i; if (!node_group) return; - for (i = 0; node_group[i]; i++) { - swnode = software_node_to_swnode(node_group[i]); - if (swnode) - fwnode_remove_software_node(&swnode->fwnode); - } + for (i = 0; node_group[i]; i++) + software_node_unregister(node_group[i]); } EXPORT_SYMBOL_GPL(software_node_unregister_node_group); diff --git a/drivers/base/topology.c b/drivers/base/topology.c index 4e033d4cc0dc..ad8d33c6077b 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -133,7 +133,7 @@ static int topology_remove_dev(unsigned int cpu) return 0; } -static int topology_sysfs_init(void) +static int __init topology_sysfs_init(void) { return cpuhp_setup_state(CPUHP_TOPOLOGY_PREPARE, "base/topology:prepare", topology_add_dev, |