diff options
Diffstat (limited to 'drivers/base')
42 files changed, 2943 insertions, 1260 deletions
diff --git a/drivers/base/base.h b/drivers/base/base.h index 1782f3aa386e..e05db388bd1c 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -131,6 +131,8 @@ extern void device_remove_groups(struct device *dev, extern char *make_class_name(const char *name, struct kobject *kobj); extern int devres_release_all(struct device *dev); +extern void device_block_probing(void); +extern void device_unblock_probing(void); /* /sys/devices directory */ extern struct kset *devices_kset; diff --git a/drivers/base/class.c b/drivers/base/class.c index 6e810881e48b..71059e32bebc 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -406,7 +406,7 @@ EXPORT_SYMBOL_GPL(class_for_each_device); * * Note, you will need to drop the reference with put_device() after use. * - * @fn is allowed to do anything including calling back into class + * @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, diff --git a/drivers/base/component.c b/drivers/base/component.c index f748430bb654..04a1582e80bb 100644 --- a/drivers/base/component.c +++ b/drivers/base/component.c @@ -18,18 +18,24 @@ #include <linux/mutex.h> #include <linux/slab.h> +struct component; + +struct component_match_array { + void *data; + int (*compare)(struct device *, void *); + void (*release)(struct device *, void *); + struct component *component; + bool duplicate; +}; + struct component_match { size_t alloc; size_t num; - struct { - void *data; - int (*fn)(struct device *, void *); - } compare[0]; + struct component_match_array *compare; }; struct master { struct list_head node; - struct list_head components; bool bound; const struct component_master_ops *ops; @@ -39,7 +45,6 @@ struct master { struct component { struct list_head node; - struct list_head master_node; struct master *master; bool bound; @@ -63,48 +68,21 @@ static struct master *__master_find(struct device *dev, return NULL; } -/* Attach an unattached component to a master. */ -static void component_attach_master(struct master *master, struct component *c) -{ - c->master = master; - - list_add_tail(&c->master_node, &master->components); -} - -/* Detach a component from a master. */ -static void component_detach_master(struct master *master, struct component *c) -{ - list_del(&c->master_node); - - c->master = NULL; -} - -/* - * Add a component to a master, finding the component via the compare - * function and compare data. This is safe to call for duplicate matches - * and will not result in the same component being added multiple times. - */ -int component_master_add_child(struct master *master, +static struct component *find_component(struct master *master, int (*compare)(struct device *, void *), void *compare_data) { struct component *c; - int ret = -ENXIO; list_for_each_entry(c, &component_list, node) { if (c->master && c->master != master) continue; - if (compare(c->dev, compare_data)) { - if (!c->master) - component_attach_master(master, c); - ret = 0; - break; - } + if (compare(c->dev, compare_data)) + return c; } - return ret; + return NULL; } -EXPORT_SYMBOL_GPL(component_master_add_child); static int find_components(struct master *master) { @@ -112,39 +90,44 @@ static int find_components(struct master *master) size_t i; int ret = 0; - if (!match) { - /* - * Search the list of components, looking for components that - * belong to this master, and attach them to the master. - */ - return master->ops->add_components(master->dev, master); - } - /* * Scan the array of match functions and attach * any components which are found to this master. */ for (i = 0; i < match->num; i++) { - ret = component_master_add_child(master, - match->compare[i].fn, - match->compare[i].data); - if (ret) + struct component_match_array *mc = &match->compare[i]; + struct component *c; + + dev_dbg(master->dev, "Looking for component %zu\n", i); + + if (match->compare[i].component) + continue; + + c = find_component(master, mc->compare, mc->data); + if (!c) { + ret = -ENXIO; break; + } + + dev_dbg(master->dev, "found component %s, duplicate %u\n", dev_name(c->dev), !!c->master); + + /* Attach this component to the master */ + match->compare[i].duplicate = !!c->master; + match->compare[i].component = c; + c->master = master; } return ret; } -/* Detach all attached components from this master */ -static void master_remove_components(struct master *master) +/* Detach component from associated master */ +static void remove_component(struct master *master, struct component *c) { - while (!list_empty(&master->components)) { - struct component *c = list_first_entry(&master->components, - struct component, master_node); - - WARN_ON(c->master != master); + size_t i; - component_detach_master(master, c); - } + /* Detach the component from this master. */ + for (i = 0; i < master->match->num; i++) + if (master->match->compare[i].component == c) + master->match->compare[i].component = NULL; } /* @@ -159,44 +142,32 @@ static int try_to_bring_up_master(struct master *master, { int ret; - if (master->bound) - return 0; + dev_dbg(master->dev, "trying to bring up master\n"); - /* - * Search the list of components, looking for components that - * belong to this master, and attach them to the master. - */ if (find_components(master)) { - /* Failed to find all components */ - ret = 0; - goto out; + dev_dbg(master->dev, "master has incomplete components\n"); + return 0; } if (component && component->master != master) { - ret = 0; - goto out; + dev_dbg(master->dev, "master is not for this component (%s)\n", + dev_name(component->dev)); + return 0; } - if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) { - ret = -ENOMEM; - goto out; - } + if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) + return -ENOMEM; /* Found all components */ ret = master->ops->bind(master->dev); if (ret < 0) { devres_release_group(master->dev, NULL); dev_info(master->dev, "master bind failed: %d\n", ret); - goto out; + return ret; } master->bound = true; return 1; - -out: - master_remove_components(master); - - return ret; } static int try_to_bring_up_masters(struct component *component) @@ -205,9 +176,11 @@ static int try_to_bring_up_masters(struct component *component) int ret = 0; list_for_each_entry(m, &masters, node) { - ret = try_to_bring_up_master(m, component); - if (ret != 0) - break; + if (!m->bound) { + ret = try_to_bring_up_master(m, component); + if (ret != 0) + break; + } } return ret; @@ -220,45 +193,59 @@ static void take_down_master(struct master *master) devres_release_group(master->dev, NULL); master->bound = false; } +} + +static void component_match_release(struct device *master, + struct component_match *match) +{ + unsigned int i; + + for (i = 0; i < match->num; i++) { + struct component_match_array *mc = &match->compare[i]; + + if (mc->release) + mc->release(master, mc->data); + } - master_remove_components(master); + kfree(match->compare); } -static size_t component_match_size(size_t num) +static void devm_component_match_release(struct device *dev, void *res) { - return offsetof(struct component_match, compare[num]); + component_match_release(dev, res); } -static struct component_match *component_match_realloc(struct device *dev, +static int component_match_realloc(struct device *dev, struct component_match *match, size_t num) { - struct component_match *new; + struct component_match_array *new; - if (match && match->alloc == num) - return match; + if (match->alloc == num) + return 0; - new = devm_kmalloc(dev, component_match_size(num), GFP_KERNEL); + new = kmalloc_array(num, sizeof(*new), GFP_KERNEL); if (!new) - return ERR_PTR(-ENOMEM); + return -ENOMEM; - if (match) { - memcpy(new, match, component_match_size(min(match->num, num))); - devm_kfree(dev, match); - } else { - new->num = 0; + if (match->compare) { + memcpy(new, match->compare, sizeof(*new) * + min(match->num, num)); + kfree(match->compare); } + match->compare = new; + match->alloc = num; - new->alloc = num; - - return new; + return 0; } /* - * Add a component to be matched. + * Add a component to be matched, with a release function. * * The match array is first created or extended if necessary. */ -void component_match_add(struct device *dev, struct component_match **matchptr, +void component_match_add_release(struct device *master, + struct component_match **matchptr, + void (*release)(struct device *, void *), int (*compare)(struct device *, void *), void *compare_data) { struct component_match *match = *matchptr; @@ -266,22 +253,55 @@ void component_match_add(struct device *dev, struct component_match **matchptr, if (IS_ERR(match)) return; - if (!match || match->num == match->alloc) { - size_t new_size = match ? match->alloc + 16 : 15; + if (!match) { + match = devres_alloc(devm_component_match_release, + sizeof(*match), GFP_KERNEL); + if (!match) { + *matchptr = ERR_PTR(-ENOMEM); + return; + } - match = component_match_realloc(dev, match, new_size); + devres_add(master, match); *matchptr = match; + } + + if (match->num == match->alloc) { + size_t new_size = match ? match->alloc + 16 : 15; + int ret; - if (IS_ERR(match)) + ret = component_match_realloc(master, match, new_size); + if (ret) { + *matchptr = ERR_PTR(ret); return; + } } - match->compare[match->num].fn = compare; + match->compare[match->num].compare = compare; + match->compare[match->num].release = release; match->compare[match->num].data = compare_data; + match->compare[match->num].component = NULL; match->num++; } -EXPORT_SYMBOL(component_match_add); +EXPORT_SYMBOL(component_match_add_release); + +static void free_master(struct master *master) +{ + struct component_match *match = master->match; + int i; + + list_del(&master->node); + + if (match) { + for (i = 0; i < match->num; i++) { + struct component *c = match->compare[i].component; + if (c) + c->master = NULL; + } + } + + kfree(master); +} int component_master_add_with_match(struct device *dev, const struct component_master_ops *ops, @@ -290,15 +310,10 @@ int component_master_add_with_match(struct device *dev, struct master *master; int ret; - if (ops->add_components && match) - return -EINVAL; - - if (match) { - /* Reallocate the match array for its true size */ - match = component_match_realloc(dev, match, match->num); - if (IS_ERR(match)) - return PTR_ERR(match); - } + /* Reallocate the match array for its true size */ + ret = component_match_realloc(dev, match, match->num); + if (ret) + return ret; master = kzalloc(sizeof(*master), GFP_KERNEL); if (!master) @@ -307,7 +322,6 @@ int component_master_add_with_match(struct device *dev, master->dev = dev; master->ops = ops; master->match = match; - INIT_LIST_HEAD(&master->components); /* Add to the list of available masters. */ mutex_lock(&component_mutex); @@ -315,24 +329,15 @@ int component_master_add_with_match(struct device *dev, ret = try_to_bring_up_master(master, NULL); - if (ret < 0) { - /* Delete off the list if we weren't successful */ - list_del(&master->node); - kfree(master); - } + if (ret < 0) + free_master(master); + mutex_unlock(&component_mutex); return ret < 0 ? ret : 0; } EXPORT_SYMBOL_GPL(component_master_add_with_match); -int component_master_add(struct device *dev, - const struct component_master_ops *ops) -{ - return component_master_add_with_match(dev, ops, NULL); -} -EXPORT_SYMBOL_GPL(component_master_add); - void component_master_del(struct device *dev, const struct component_master_ops *ops) { @@ -342,9 +347,7 @@ void component_master_del(struct device *dev, master = __master_find(dev, ops); if (master) { take_down_master(master); - - list_del(&master->node); - kfree(master); + free_master(master); } mutex_unlock(&component_mutex); } @@ -366,6 +369,7 @@ void component_unbind_all(struct device *master_dev, void *data) { struct master *master; struct component *c; + size_t i; WARN_ON(!mutex_is_locked(&component_mutex)); @@ -373,8 +377,12 @@ void component_unbind_all(struct device *master_dev, void *data) if (!master) return; - list_for_each_entry_reverse(c, &master->components, master_node) - component_unbind(c, master, data); + /* Unbind components in reverse order */ + for (i = master->match->num; i--; ) + if (!master->match->compare[i].duplicate) { + c = master->match->compare[i].component; + component_unbind(c, master, data); + } } EXPORT_SYMBOL_GPL(component_unbind_all); @@ -434,6 +442,7 @@ int component_bind_all(struct device *master_dev, void *data) { struct master *master; struct component *c; + size_t i; int ret = 0; WARN_ON(!mutex_is_locked(&component_mutex)); @@ -442,16 +451,21 @@ int component_bind_all(struct device *master_dev, void *data) if (!master) return -EINVAL; - list_for_each_entry(c, &master->components, master_node) { - ret = component_bind(c, master, data); - if (ret) - break; - } + /* Bind components in match order */ + for (i = 0; i < master->match->num; i++) + if (!master->match->compare[i].duplicate) { + c = master->match->compare[i].component; + ret = component_bind(c, master, data); + if (ret) + break; + } if (ret != 0) { - list_for_each_entry_continue_reverse(c, &master->components, - master_node) - component_unbind(c, master, data); + for (; i--; ) + if (!master->match->compare[i].duplicate) { + c = master->match->compare[i].component; + component_unbind(c, master, data); + } } return ret; @@ -477,6 +491,8 @@ int component_add(struct device *dev, const struct component_ops *ops) ret = try_to_bring_up_masters(component); if (ret < 0) { + if (component->master) + remove_component(component->master, component); list_del(&component->node); kfree(component); @@ -499,8 +515,10 @@ void component_del(struct device *dev, const struct component_ops *ops) break; } - if (component && component->master) + if (component && component->master) { take_down_master(component->master); + remove_component(component->master, component); + } mutex_unlock(&component_mutex); diff --git a/drivers/base/core.c b/drivers/base/core.c index 334ec7ef1960..0a8bdade53f2 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1066,7 +1066,7 @@ int device_add(struct device *dev) dev->kobj.parent = kobj; /* use parent numa_node */ - if (parent) + if (parent && (dev_to_node(dev) == NUMA_NO_NODE)) set_dev_node(dev, dev_to_node(parent)); /* first, register with generic layer. */ @@ -2261,7 +2261,10 @@ void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode) if (fwnode_is_primary(fn)) fn = fn->secondary; - fwnode->secondary = fn; + if (fn) { + WARN_ON(fwnode->secondary); + fwnode->secondary = fn; + } dev->fwnode = fwnode; } else { dev->fwnode = fwnode_is_primary(dev->fwnode) ? diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 91bbb1959d8d..691eeea2f19a 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -200,7 +200,7 @@ static const struct attribute_group *hotplugable_cpu_attr_groups[] = { struct cpu_attr { struct device_attribute attr; - const struct cpumask *const * const map; + const struct cpumask *const map; }; static ssize_t show_cpus_attr(struct device *dev, @@ -209,7 +209,7 @@ static ssize_t show_cpus_attr(struct device *dev, { struct cpu_attr *ca = container_of(attr, struct cpu_attr, attr); - return cpumap_print_to_pagebuf(true, buf, *ca->map); + return cpumap_print_to_pagebuf(true, buf, ca->map); } #define _CPU_ATTR(name, map) \ @@ -217,9 +217,9 @@ static ssize_t show_cpus_attr(struct device *dev, /* Keep in sync with cpu_subsys_attrs */ static struct cpu_attr cpu_attrs[] = { - _CPU_ATTR(online, &cpu_online_mask), - _CPU_ATTR(possible, &cpu_possible_mask), - _CPU_ATTR(present, &cpu_present_mask), + _CPU_ATTR(online, &__cpu_online_mask), + _CPU_ATTR(possible, &__cpu_possible_mask), + _CPU_ATTR(present, &__cpu_present_mask), }; /* diff --git a/drivers/base/dd.c b/drivers/base/dd.c index be0eb4639128..16688f50729c 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -55,6 +55,13 @@ static struct workqueue_struct *deferred_wq; static atomic_t deferred_trigger_count = ATOMIC_INIT(0); /* + * In some cases, like suspend to RAM or hibernation, It might be reasonable + * to prohibit probing of devices as it could be unsafe. + * Once defer_all_probes is true all drivers probes will be forcibly deferred. + */ +static bool defer_all_probes; + +/* * deferred_probe_work_func() - Retry probing devices in the active list. */ static void deferred_probe_work_func(struct work_struct *work) @@ -172,6 +179,30 @@ static void driver_deferred_probe_trigger(void) } /** + * device_block_probing() - Block/defere device's probes + * + * It will disable probing of devices and defer their probes instead. + */ +void device_block_probing(void) +{ + defer_all_probes = true; + /* sync with probes to avoid races. */ + wait_for_device_probe(); +} + +/** + * device_unblock_probing() - Unblock/enable device's probes + * + * It will restore normal behavior and trigger re-probing of deferred + * devices. + */ +void device_unblock_probing(void) +{ + defer_all_probes = false; + driver_deferred_probe_trigger(); +} + +/** * deferred_probe_initcall() - Enable probing of deferred devices * * We don't want to get in the way when the bulk of drivers are getting probed. @@ -192,9 +223,23 @@ static int deferred_probe_initcall(void) } late_initcall(deferred_probe_initcall); +/** + * device_is_bound() - Check if device is bound to a driver + * @dev: device to check + * + * Returns true if passed device has already finished probing successfully + * against a driver. + * + * This function must be called with the device lock held. + */ +bool device_is_bound(struct device *dev) +{ + return dev->p && klist_node_attached(&dev->p->knode_driver); +} + static void driver_bound(struct device *dev) { - if (klist_node_attached(&dev->p->knode_driver)) { + if (device_is_bound(dev)) { printk(KERN_WARNING "%s: device %s already bound\n", __func__, kobject_name(&dev->kobj)); return; @@ -205,6 +250,8 @@ static void driver_bound(struct device *dev) klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); + device_pm_check_callbacks(dev); + /* * Make sure the device is no longer in one of the deferred lists and * kick off retrying all pending devices @@ -268,6 +315,9 @@ int device_bind_driver(struct device *dev) ret = driver_sysfs_add(dev); if (!ret) driver_bound(dev); + else if (dev->bus) + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, + BUS_NOTIFY_DRIVER_NOT_BOUND, dev); return ret; } EXPORT_SYMBOL_GPL(device_bind_driver); @@ -277,9 +327,20 @@ static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); static int really_probe(struct device *dev, struct device_driver *drv) { - int ret = 0; + int ret = -EPROBE_DEFER; int local_trigger_count = atomic_read(&deferred_trigger_count); + if (defer_all_probes) { + /* + * Value of defer_all_probes can be set only by + * device_defer_all_probes_enable() which, in turn, will call + * wait_for_device_probe() right after that to avoid any races. + */ + dev_dbg(dev, "Driver %s force probe deferral\n", drv->name); + driver_deferred_probe_add(dev); + return ret; + } + atomic_inc(&probe_count); pr_debug("bus: '%s': %s: probing driver %s with device %s\n", drv->bus->name, __func__, drv->name, dev_name(dev)); @@ -290,7 +351,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) /* If using pinctrl, bind pins now before probing */ ret = pinctrl_bind_pins(dev); if (ret) - goto probe_failed; + goto pinctrl_bind_failed; if (driver_sysfs_add(dev)) { printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", @@ -322,6 +383,8 @@ static int really_probe(struct device *dev, struct device_driver *drv) goto probe_failed; } + pinctrl_init_done(dev); + if (dev->pm_domain && dev->pm_domain->sync) dev->pm_domain->sync(dev); @@ -332,12 +395,17 @@ static int really_probe(struct device *dev, struct device_driver *drv) goto done; probe_failed: + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, + BUS_NOTIFY_DRIVER_NOT_BOUND, dev); +pinctrl_bind_failed: devres_release_all(dev); driver_sysfs_remove(dev); dev->driver = NULL; dev_set_drvdata(dev, NULL); if (dev->pm_domain && dev->pm_domain->dismiss) dev->pm_domain->dismiss(dev); + pm_runtime_reinit(dev); switch (ret) { case -EPROBE_DEFER: @@ -391,6 +459,10 @@ int driver_probe_done(void) */ void wait_for_device_probe(void) { + /* wait for the deferred probe workqueue to finish */ + if (driver_deferred_probe_enable) + flush_workqueue(deferred_wq); + /* wait for the known devices to complete their probing */ wait_event(probe_waitqueue, atomic_read(&probe_count) == 0); async_synchronize_full(); @@ -488,6 +560,7 @@ static int __device_attach_driver(struct device_driver *drv, void *_data) struct device_attach_data *data = _data; struct device *dev = data->dev; bool async_allowed; + int ret; /* * Check if device has already been claimed. This may @@ -498,8 +571,17 @@ static int __device_attach_driver(struct device_driver *drv, void *_data) if (dev->driver) return -EBUSY; - if (!driver_match_device(drv, dev)) + ret = driver_match_device(drv, dev); + if (ret == 0) { + /* no match */ return 0; + } else if (ret == -EPROBE_DEFER) { + dev_dbg(dev, "Device match requests probe deferral\n"); |