diff options
Diffstat (limited to 'drivers/base')
29 files changed, 601 insertions, 338 deletions
diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 8b93a7f291ec..ef8e44a7d288 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -30,3 +30,6 @@ obj-y += test/ ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG +# define_trace.h needs to know how to find our header +CFLAGS_trace.o := -I$(src) +obj-$(CONFIG_TRACING) += trace.o diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 9c00d203d61e..01ef796c2055 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -284,8 +284,8 @@ fail: * matching classdev or fail all of them. * * @dev: The generic device to run the trigger for - * @fn the function to execute for each classdev. - * @undo A function to undo the work previously done in case of error + * @fn: the function to execute for each classdev. + * @undo: A function to undo the work previously done in case of error * * This function is a safe version of * attribute_container_device_trigger. It stops on the first error and @@ -343,7 +343,7 @@ attribute_container_device_trigger_safe(struct device *dev, * attribute_container_device_trigger - execute a trigger for each matching classdev * * @dev: The generic device to run the trigger for - * @fn the function to execute for each classdev. + * @fn: the function to execute for each classdev. * * This function is for executing a trigger when you need to know both * the container and the classdev. If you only care about the diff --git a/drivers/base/base.h b/drivers/base/base.h index e5f9b7e656c3..404db83ee5ec 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -152,7 +152,6 @@ extern int driver_add_groups(struct device_driver *drv, const struct attribute_group **groups); extern void driver_remove_groups(struct device_driver *drv, const struct attribute_group **groups); -int device_driver_attach(struct device_driver *drv, struct device *dev); void device_driver_detach(struct device *dev); extern char *make_class_name(const char *name, struct kobject *kobj); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 36d0c654ea61..1f6b4bd61056 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -210,15 +210,11 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf, int err = -ENODEV; dev = bus_find_device_by_name(bus, NULL, buf); - if (dev && dev->driver == NULL && driver_match_device(drv, dev)) { + if (dev && driver_match_device(drv, dev)) { err = device_driver_attach(drv, dev); - - if (err > 0) { + if (!err) { /* success */ err = count; - } else if (err == 0) { - /* driver didn't accept device */ - err = -ENODEV; } } put_device(dev); diff --git a/drivers/base/component.c b/drivers/base/component.c index 272ba42392f0..5e79299f6c3f 100644 --- a/drivers/base/component.c +++ b/drivers/base/component.c @@ -63,7 +63,7 @@ struct master { bool bound; const struct component_master_ops *ops; - struct device *dev; + struct device *parent; struct component_match *match; }; @@ -95,7 +95,7 @@ static int component_devices_show(struct seq_file *s, void *data) seq_printf(s, "%-40s %20s\n", "master name", "status"); seq_puts(s, "-------------------------------------------------------------\n"); seq_printf(s, "%-40s %20s\n\n", - dev_name(m->dev), m->bound ? "bound" : "not bound"); + dev_name(m->parent), m->bound ? "bound" : "not bound"); seq_printf(s, "%-40s %20s\n", "device name", "status"); seq_puts(s, "-------------------------------------------------------------\n"); @@ -124,13 +124,13 @@ core_initcall(component_debug_init); static void component_master_debugfs_add(struct master *m) { - debugfs_create_file(dev_name(m->dev), 0444, component_debugfs_dir, m, + debugfs_create_file(dev_name(m->parent), 0444, component_debugfs_dir, m, &component_devices_fops); } static void component_master_debugfs_del(struct master *m) { - debugfs_remove(debugfs_lookup(dev_name(m->dev), component_debugfs_dir)); + debugfs_remove(debugfs_lookup(dev_name(m->parent), component_debugfs_dir)); } #else @@ -143,13 +143,13 @@ static void component_master_debugfs_del(struct master *m) #endif -static struct master *__master_find(struct device *dev, +static struct master *__master_find(struct device *parent, const struct component_master_ops *ops) { struct master *m; list_for_each_entry(m, &masters, node) - if (m->dev == dev && (!ops || m->ops == ops)) + if (m->parent == parent && (!ops || m->ops == ops)) return m; return NULL; @@ -189,7 +189,7 @@ static int find_components(struct master *master) struct component_match_array *mc = &match->compare[i]; struct component *c; - dev_dbg(master->dev, "Looking for component %zu\n", i); + dev_dbg(master->parent, "Looking for component %zu\n", i); if (match->compare[i].component) continue; @@ -200,7 +200,7 @@ static int find_components(struct master *master) break; } - dev_dbg(master->dev, "found component %s, duplicate %u\n", dev_name(c->dev), !!c->master); + dev_dbg(master->parent, "found component %s, duplicate %u\n", dev_name(c->dev), !!c->master); /* Attach this component to the master */ match->compare[i].duplicate = !!c->master; @@ -233,28 +233,28 @@ static int try_to_bring_up_master(struct master *master, { int ret; - dev_dbg(master->dev, "trying to bring up master\n"); + dev_dbg(master->parent, "trying to bring up master\n"); if (find_components(master)) { - dev_dbg(master->dev, "master has incomplete components\n"); + dev_dbg(master->parent, "master has incomplete components\n"); return 0; } if (component && component->master != master) { - dev_dbg(master->dev, "master is not for this component (%s)\n", + dev_dbg(master->parent, "master is not for this component (%s)\n", dev_name(component->dev)); return 0; } - if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) + if (!devres_open_group(master->parent, NULL, GFP_KERNEL)) return -ENOMEM; /* Found all components */ - ret = master->ops->bind(master->dev); + ret = master->ops->bind(master->parent); if (ret < 0) { - devres_release_group(master->dev, NULL); + devres_release_group(master->parent, NULL); if (ret != -EPROBE_DEFER) - dev_info(master->dev, "master bind failed: %d\n", ret); + dev_info(master->parent, "master bind failed: %d\n", ret); return ret; } @@ -281,34 +281,28 @@ static int try_to_bring_up_masters(struct component *component) static void take_down_master(struct master *master) { if (master->bound) { - master->ops->unbind(master->dev); - devres_release_group(master->dev, NULL); + master->ops->unbind(master->parent); + devres_release_group(master->parent, NULL); master->bound = false; } } -static void component_match_release(struct device *master, - struct component_match *match) +static void devm_component_match_release(struct device *parent, void *res) { + struct component_match *match = res; 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); + mc->release(parent, mc->data); } kfree(match->compare); } -static void devm_component_match_release(struct device *dev, void *res) -{ - component_match_release(dev, res); -} - -static int component_match_realloc(struct device *dev, - struct component_match *match, size_t num) +static int component_match_realloc(struct component_match *match, size_t num) { struct component_match_array *new; @@ -359,7 +353,7 @@ static void __component_match_add(struct device *master, size_t new_size = match->alloc + 16; int ret; - ret = component_match_realloc(master, match, new_size); + ret = component_match_realloc(match, new_size); if (ret) { *matchptr = ERR_PTR(ret); return; @@ -451,7 +445,7 @@ static void free_master(struct master *master) /** * component_master_add_with_match - register an aggregate driver - * @dev: device with the aggregate driver + * @parent: parent device of the aggregate driver * @ops: callbacks for the aggregate driver * @match: component match list for the aggregate driver * @@ -461,7 +455,7 @@ static void free_master(struct master *master) * &component_master_ops.bind from @ops. Must be unregistered by calling * component_master_del(). */ -int component_master_add_with_match(struct device *dev, +int component_master_add_with_match(struct device *parent, const struct component_master_ops *ops, struct component_match *match) { @@ -469,7 +463,7 @@ int component_master_add_with_match(struct device *dev, int ret; /* Reallocate the match array for its true size */ - ret = component_match_realloc(dev, match, match->num); + ret = component_match_realloc(match, match->num); if (ret) return ret; @@ -477,7 +471,7 @@ int component_master_add_with_match(struct device *dev, if (!master) return -ENOMEM; - master->dev = dev; + master->parent = parent; master->ops = ops; master->match = match; @@ -499,20 +493,20 @@ EXPORT_SYMBOL_GPL(component_master_add_with_match); /** * component_master_del - unregister an aggregate driver - * @dev: device with the aggregate driver + * @parent: parent device of the aggregate driver * @ops: callbacks for the aggregate driver * * Unregisters an aggregate driver registered with * component_master_add_with_match(). If necessary the aggregate driver is first * disassembled by calling &component_master_ops.unbind from @ops. */ -void component_master_del(struct device *dev, +void component_master_del(struct device *parent, const struct component_master_ops *ops) { struct master *master; mutex_lock(&component_mutex); - master = __master_find(dev, ops); + master = __master_find(parent, ops); if (master) { take_down_master(master); free_master(master); @@ -527,7 +521,7 @@ static void component_unbind(struct component *component, WARN_ON(!component->bound); if (component->ops && component->ops->unbind) - component->ops->unbind(component->dev, master->dev, data); + component->ops->unbind(component->dev, master->parent, data); component->bound = false; /* Release all resources claimed in the binding of this component */ @@ -536,14 +530,14 @@ static void component_unbind(struct component *component, /** * component_unbind_all - unbind all components of an aggregate driver - * @master_dev: device with the aggregate driver + * @parent: parent device of the aggregate driver * @data: opaque pointer, passed to all components * - * Unbinds all components of the aggregate @dev by passing @data to their + * Unbinds all components of the aggregate device by passing @data to their * &component_ops.unbind functions. Should be called from * &component_master_ops.unbind. */ -void component_unbind_all(struct device *master_dev, void *data) +void component_unbind_all(struct device *parent, void *data) { struct master *master; struct component *c; @@ -551,7 +545,7 @@ void component_unbind_all(struct device *master_dev, void *data) WARN_ON(!mutex_is_locked(&component_mutex)); - master = __master_find(master_dev, NULL); + master = __master_find(parent, NULL); if (!master) return; @@ -574,7 +568,7 @@ static int component_bind(struct component *component, struct master *master, * This allows us to roll-back a failed component without * affecting anything else. */ - if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) + if (!devres_open_group(master->parent, NULL, GFP_KERNEL)) return -ENOMEM; /* @@ -583,14 +577,14 @@ static int component_bind(struct component *component, struct master *master, * at the appropriate moment. */ if (!devres_open_group(component->dev, component, GFP_KERNEL)) { - devres_release_group(master->dev, NULL); + devres_release_group(master->parent, NULL); return -ENOMEM; } - dev_dbg(master->dev, "binding %s (ops %ps)\n", + dev_dbg(master->parent, "binding %s (ops %ps)\n", dev_name(component->dev), component->ops); - ret = component->ops->bind(component->dev, master->dev, data); + ret = component->ops->bind(component->dev, master->parent, data); if (!ret) { component->bound = true; @@ -601,16 +595,16 @@ static int component_bind(struct component *component, struct master *master, * can clean those resources up independently. */ devres_close_group(component->dev, NULL); - devres_remove_group(master->dev, NULL); + devres_remove_group(master->parent, NULL); - dev_info(master->dev, "bound %s (ops %ps)\n", + dev_info(master->parent, "bound %s (ops %ps)\n", dev_name(component->dev), component->ops); } else { devres_release_group(component->dev, NULL); - devres_release_group(master->dev, NULL); + devres_release_group(master->parent, NULL); if (ret != -EPROBE_DEFER) - dev_err(master->dev, "failed to bind %s (ops %ps): %d\n", + dev_err(master->parent, "failed to bind %s (ops %ps): %d\n", dev_name(component->dev), component->ops, ret); } @@ -619,14 +613,14 @@ static int component_bind(struct component *component, struct master *master, /** * component_bind_all - bind all components of an aggregate driver - * @master_dev: device with the aggregate driver + * @parent: parent device of the aggregate driver * @data: opaque pointer, passed to all components * * Binds all components of the aggregate @dev by passing @data to their * &component_ops.bind functions. Should be called from * &component_master_ops.bind. */ -int component_bind_all(struct device *master_dev, void *data) +int component_bind_all(struct device *parent, void *data) { struct master *master; struct component *c; @@ -635,7 +629,7 @@ int component_bind_all(struct device *master_dev, void *data) WARN_ON(!mutex_is_locked(&component_mutex)); - master = __master_find(master_dev, NULL); + master = __master_find(parent, NULL); if (!master) return -EINVAL; diff --git a/drivers/base/core.c b/drivers/base/core.c index 54ba506e5a89..0027a2d1de99 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -3442,7 +3442,7 @@ bool kill_device(struct device *dev) * to run while we are tearing out the bus/class/sysfs from * underneath the device. */ - lockdep_assert_held(&dev->mutex); + device_lock_assert(dev); if (dev->p->dead) return false; @@ -4727,6 +4727,13 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2) } EXPORT_SYMBOL_GPL(device_set_of_node_from_dev); +void device_set_node(struct device *dev, struct fwnode_handle *fwnode) +{ + dev->fwnode = fwnode; + dev->of_node = to_of_node(fwnode); +} +EXPORT_SYMBOL_GPL(device_set_node); + int device_match_name(struct device *dev, const void *name) { return sysfs_streq(dev_name(dev), name); diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 2b9e41377a07..5ef14db97904 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -175,7 +175,7 @@ static struct attribute *crash_note_cpu_attrs[] = { NULL }; -static struct attribute_group crash_note_cpu_attr_group = { +static const struct attribute_group crash_note_cpu_attr_group = { .attrs = crash_note_cpu_attrs, }; #endif @@ -475,7 +475,7 @@ static struct attribute *cpu_root_attrs[] = { NULL }; -static struct attribute_group cpu_root_attr_group = { +static const struct attribute_group cpu_root_attr_group = { .attrs = cpu_root_attrs, }; diff --git a/drivers/base/dd.c b/drivers/base/dd.c index ecd7cf848daf..daeb9b5763ae 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -471,6 +471,8 @@ static void driver_sysfs_remove(struct device *dev) * (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. + * + * Callers should prefer to use device_driver_attach() instead. */ int device_bind_driver(struct device *dev) { @@ -491,15 +493,6 @@ EXPORT_SYMBOL_GPL(device_bind_driver); static atomic_t probe_count = ATOMIC_INIT(0); static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); -static void driver_deferred_probe_add_trigger(struct device *dev, - int local_trigger_count) -{ - driver_deferred_probe_add(dev); - /* Did a trigger occur while probing? Need to re-trigger if yes */ - if (local_trigger_count != atomic_read(&deferred_trigger_count)) - driver_deferred_probe_trigger(); -} - static ssize_t state_synced_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -513,12 +506,43 @@ static ssize_t state_synced_show(struct device *dev, } static DEVICE_ATTR_RO(state_synced); + +static int call_driver_probe(struct device *dev, struct device_driver *drv) +{ + int ret = 0; + + if (dev->bus->probe) + ret = dev->bus->probe(dev); + else if (drv->probe) + ret = drv->probe(dev); + + switch (ret) { + case 0: + break; + case -EPROBE_DEFER: + /* Driver requested deferred probing */ + dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name); + break; + case -ENODEV: + case -ENXIO: + pr_debug("%s: probe of %s rejects match %d\n", + drv->name, dev_name(dev), ret); + break; + default: + /* driver matched but the probe failed */ + pr_warn("%s: probe of %s failed with error %d\n", + drv->name, dev_name(dev), ret); + break; + } + + return ret; +} + static int really_probe(struct device *dev, struct device_driver *drv) { - int ret = -EPROBE_DEFER; - int local_trigger_count = atomic_read(&deferred_trigger_count); bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) && !drv->suppress_bind_attrs; + int ret; if (defer_all_probes) { /* @@ -527,17 +551,13 @@ static int really_probe(struct device *dev, struct device_driver *drv) * 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; + return -EPROBE_DEFER; } ret = device_links_check_suppliers(dev); - if (ret == -EPROBE_DEFER) - driver_deferred_probe_add_trigger(dev, local_trigger_count); if (ret) 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)); if (!list_empty(&dev->devres_head)) { @@ -572,14 +592,14 @@ re_probe: goto probe_failed; } - if (dev->bus->probe) { - ret = dev->bus->probe(dev); - if (ret) - goto probe_failed; - } else if (drv->probe) { - ret = drv->probe(dev); - if (ret) - goto probe_failed; + ret = call_driver_probe(dev, drv); + if (ret) { + /* + * Return probe errors as positive values so that the callers + * can distinguish them from other errors. + */ + ret = -ret; + goto probe_failed; } if (device_add_groups(dev, drv->dev_groups)) { @@ -621,7 +641,6 @@ re_probe: dev->pm_domain->sync(dev); driver_bound(dev); - ret = 1; pr_debug("bus: '%s': %s: bound device %s to driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); goto done; @@ -650,31 +669,7 @@ pinctrl_bind_failed: dev->pm_domain->dismiss(dev); pm_runtime_reinit(dev); dev_pm_set_driver_flags(dev, 0); - - switch (ret) { - case -EPROBE_DEFER: - /* Driver requested deferred probing */ - dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name); - driver_deferred_probe_add_trigger(dev, local_trigger_count); - break; - case -ENODEV: - case -ENXIO: - pr_debug("%s: probe of %s rejects match %d\n", - drv->name, dev_name(dev), ret); - break; - default: - /* driver matched but the probe failed */ - pr_warn("%s: probe of %s failed with error %d\n", - drv->name, dev_name(dev), ret); - } - /* - * Ignore errors returned by ->probe so that the next driver can try - * its luck. - */ - ret = 0; done: - atomic_dec(&probe_count); - wake_up_all(&probe_waitqueue); return ret; } @@ -728,25 +723,14 @@ void wait_for_device_probe(void) } EXPORT_SYMBOL_GPL(wait_for_device_probe); -/** - * driver_probe_device - attempt to bind device & driver together - * @drv: driver to bind a device to - * @dev: device to try to bind to the driver - * - * This function returns -ENODEV if the device is not registered, - * 1 if the device is bound successfully and 0 otherwise. - * - * This function must be called with @dev lock held. When called for a - * USB interface, @dev->parent lock must be held as well. - * - * If the device has a parent, runtime-resume the parent before driver probing. - */ -static int driver_probe_device(struct device_driver *drv, struct device *dev) +static int __driver_probe_device(struct device_driver *drv, struct device *dev) { int ret = 0; - if (!device_is_registered(dev)) + if (dev->p->dead || !device_is_registered(dev)) return -ENODEV; + if (dev->driver) + return -EBUSY; dev->can_match = true; pr_debug("bus: '%s': %s: matched device %s with driver %s\n", @@ -770,6 +754,42 @@ static int driver_probe_device(struct device_driver *drv, struct device *dev) return ret; } +/** + * driver_probe_device - attempt to bind device & driver together + * @drv: driver to bind a device to + * @dev: device to try to bind to the driver + * + * This function returns -ENODEV if the device is not registered, -EBUSY if it + * already has a driver, 0 if the device is bound successfully and a positive + * (inverted) error code for failures from the ->probe method. + * + * This function must be called with @dev lock held. When called for a + * USB interface, @dev->parent lock must be held as well. + * + * If the device has a parent, runtime-resume the parent before driver probing. + */ +static int driver_probe_device(struct device_driver *drv, struct device *dev) +{ + int trigger_count = atomic_read(&deferred_trigger_count); + int ret; + + atomic_inc(&probe_count); + ret = __driver_probe_device(drv, dev); + if (ret == -EPROBE_DEFER || ret == EPROBE_DEFER) { + driver_deferred_probe_add(dev); + + /* + * Did a trigger occur while probing? Need to re-trigger if yes + */ + if (trigger_count != atomic_read(&deferred_trigger_count) && + !defer_all_probes) + driver_deferred_probe_trigger(); + } + atomic_dec(&probe_count); + wake_up_all(&probe_waitqueue); + return ret; +} + static inline bool cmdline_requested_async_probing(const char *drv_name) { return parse_option_str(async_probe_drv_names, drv_name); @@ -867,7 +887,14 @@ static int __device_attach_driver(struct device_driver *drv, void *_data) if (data->check_async && async_allowed != data->want_async) return 0; - return driver_probe_device(drv, dev); + /* + * Ignore errors returned by ->probe so that the next driver can try + * its luck. + */ + ret = driver_probe_device(drv, dev); + if (ret < 0) + return ret; + return ret == 0; } static void __device_attach_async_helper(void *_dev, async_cookie_t cookie) @@ -1023,43 +1050,34 @@ static void __device_driver_unlock(struct device *dev, struct device *parent) * @dev: Device to attach it to * * Manually attach driver to a device. Will acquire both @dev lock and - * @dev->parent lock if needed. + * @dev->parent lock if needed. Returns 0 on success, -ERR on failure. */ int device_driver_attach(struct device_driver *drv, struct device *dev) { - int ret = 0; + int ret; __device_driver_lock(dev, dev->parent); - - /* - * If device has been removed or someone has already successfully - * bound a driver before us just skip the driver probe call. - */ - if (!dev->p->dead && !dev->driver) - ret = driver_probe_device(drv, dev); - + ret = __driver_probe_device(drv, dev); __device_driver_unlock(dev, dev->parent); + /* also return probe errors as normal negative errnos */ + if (ret > 0) + ret = -ret; + if (ret == -EPROBE_DEFER) + return -EAGAIN; return ret; } +EXPORT_SYMBOL_GPL(device_driver_attach); static void __driver_attach_async_helper(void *_dev, async_cookie_t cookie) { struct device *dev = _dev; struct device_driver *drv; - int ret = 0; + int ret; __device_driver_lock(dev, dev->parent); - drv = dev->p->async_driver; - - /* - * If device has been removed or someone has already successfully - * bound a driver before us just skip the driver probe call. - */ - if (!dev->p->dead && !dev->driver) - ret = driver_probe_device(drv, dev); - + ret = driver_probe_device(drv, dev); __device_driver_unlock(dev, dev->parent); dev_dbg(dev, "driver %s async attach completed: %d\n", drv->name, ret); @@ -1114,7 +1132,9 @@ static int __driver_attach(struct device *dev, void *data) return 0; } - device_driver_attach(drv, dev); + __device_driver_lock(dev, dev->parent); + driver_probe_device(drv, dev); + __device_driver_unlock(dev, dev->parent); return 0; } diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index 8eec0e0ddff7..f4d794d6bb85 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -3,10 +3,6 @@ * Copyright(c) 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 Intel Deutschland GmbH * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * * Author: Johannes Berg <johannes@sipsolutions.net> */ #include <linux/module.h> diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 8746f2212781..eaa9a5cd1db9 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -14,14 +14,13 @@ #include <asm/sections.h> #include "base.h" +#include "trace.h" struct devres_node { struct list_head entry; dr_release_t release; -#ifdef CONFIG_DEBUG_DEVRES const char *name; size_t size; -#endif }; struct devres { @@ -43,10 +42,6 @@ struct devres_group { /* -- 8 pointers */ }; -#ifdef CONFIG_DEBUG_DEVRES -static int log_devres = 0; -module_param_named(log, log_devres, int, S_IRUGO | S_IWUSR); - static void set_node_dbginfo(struct devres_node *node, const char *name, size_t size) { @@ -54,7 +49,11 @@ static void set_node_dbginfo(struct devres_node *node, const char *name, node->size = size; } -static void devres_log(struct device *dev, struct devres_node *node, +#ifdef CONFIG_DEBUG_DEVRES +static int log_devres = 0; +module_param_named(log, log_devres, int, S_IRUGO | S_IWUSR); + +static void devres_dbg(struct device *dev, struct devres_node *node, const char *op) { if (unlikely(log_devres)) @@ -62,10 +61,16 @@ static void devres_log(struct device *dev, struct devres_node *node, op, node, node->name, node->size); } #else /* CONFIG_DEBUG_DEVRES */ -#define set_node_dbginfo(node, n, s) do {} while (0) -#define devres_log(dev, node, op) do {} while (0) +#define devres_dbg(dev, node, op) do {} while (0) #endif /* CONFIG_DEBUG_DEVRES */ +static void devres_log(struct device *dev, struct devres_node *node, + const char *op) +{ + trace_devres_log(dev, op, node, node->name, node->size); + devres_dbg(dev, node, op); +} + /* * Release functions for devres group. These callbacks are used only * for identification. @@ -134,26 +139,13 @@ static void replace_dr(struct device *dev, list_replace(&old->entry, &new->entry); } -#ifdef CONFIG_DEBUG_DEVRES -void * __devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid, - const char *name) -{ - struct devres *dr; - - dr = alloc_dr(release, size, gfp | __GFP_ZERO, nid); - if (unlikely(!dr)) - return NULL; - set_node_dbginfo(&dr->node, name, size); - return dr->data; -} -EXPORT_SYMBOL_GPL(__devres_alloc_node); -#else /** - * devres_alloc_node - Allocate device resource data + * __devres_alloc_node - Allocate device resource data * @release: Release function devres will be associated with * @size: Allocation size * @gfp: Allocation flags * @nid: NUMA node + * @name: Name of the resource * * Allocate devres of @size bytes. The allocated area is zeroed, then * associated with @release. The returned pointer can be passed to @@ -162,17 +154,18 @@ EXPORT_SYMBOL_GPL(__devres_alloc_node); * RETURNS: * Pointer to allocated devres on success, NULL on failure. */ -void * devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid) +void *__devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid, + const char *name) { struct devres *dr; dr = alloc_dr(release, size, gfp | __GFP_ZERO, nid); if (unlikely(!dr)) return NULL; + set_node_dbginfo(&dr->node, name, size); return dr->data; } -EXPORT_SYMBOL_GPL(devres_alloc_node); -#endif +EXPORT_SYMBOL_GPL(__devres_alloc_node); /** * devres_for_each_res - Resource iterator @@ -438,20 +431,16 @@ static int remove_nodes(struct device *dev, struct list_head *first, struct list_head *end, struct list_head *todo) { + struct devres_node *node, *n; int cnt = 0, nr_groups = 0; - struct list_head *cur; /* First pass - move normal devres entries to @todo and clear * devres_group colors. */ - cur = first; - while (cur != end) { - struct devres_node *node; + node = list_entry(first, struct devres_node, entry); + list_for_each_entry_safe_from(node, n, end, entry) { struct devres_group *grp; - node = list_entry(cur, struct devres_node, entry); - cur = cur->next; - grp = node_to_group(node); if (grp) { /* clear color of group markers in the first pass */ @@ -471,18 +460,14 @@ static int remove_nodes(struct device *dev, /* Second pass - Scan groups and color them. A group gets * color value of two iff the group is wholly contained in - * [cur, end). That is, for a closed group, both opening and - * closing markers should be in the range, while just the + * [current node, end). That is, for a closed group, both opening + * and closing markers should be in the range, while just the * opening marker is enough for an open group. */ - cur = first; - while (cur != end) { - struct devres_node *node; + node = list_entry(first, struct devres_node, entry); + list_for_each_entry_safe_from(node, n, end, entry) { struct devres_group *grp; - node = list_entry(cur, struct devres_node, entry); - cur = cur->next; - grp = node_to_group(node); BUG_ON(!grp || list_empty(&grp->node[0].entry)); @@ -492,7 +477,7 @@ static int remove_nodes(struct device *dev, BUG_ON(grp->color <= 0 || grp->color > 2); if (grp->color == 2) { - /* No need to update cur or end. The removed + /* No need to update current node or end. The removed * nodes are always before both. */ list_move_tail(&grp->node[0].entry, todo); @@ -503,28 +488,18 @@ static int remove_nodes(struct device *dev, return cnt; } -static int release_nodes(struct device *dev, struct list_head *first, - struct list_head *end, unsigned long flags) - __releases(&dev->devres_lock) +static void release_nodes(struct device *dev, struct list_head *todo) { - LIST_HEAD(todo); - int cnt; struct devres *dr, *tmp; - cnt = remove_nodes(dev, first, end, &todo); - - spin_unlock_irqrestore(&dev->devres_lock, flags); - /* Release. Note that both devres and devres_group are * handled as devres in the following loop. This is safe. */ - list_for_each_entry_safe_reverse(dr, tmp, &todo, node.entry) { + list_for_each_entry_safe_reverse(dr, tmp, todo, node.entry) { devres_log(dev, &dr->node, "REL"); dr->node.release(dev, dr->data); kfree(dr); } - - return cnt; } /** @@ -537,13 +512,23 @@ static int release_nodes(struct device *dev, struct list_head *first, int devres_release_all(struct device *dev) { unsigned long flags; + LIST_HEAD(todo); + int cnt; /* Looks like an uninitialized device structure */ if (WARN_ON(dev->devres_head.next == NULL)) return -ENODEV; + + /* Nothing to release if list is empty */ + if (list_empty(&dev->devres_head)) + return 0; + spin_lock_irqsave(&dev->devres_lock, flags); - return release_nodes(dev, dev->devres_head.next, &dev->devres_head, - flags); + cnt = remove_nodes(dev, dev->devres_head.next, &dev->devres_head, &todo); + spin_unlock_irqrestore(&dev->devres_lock, flags); + + release_nodes(dev, &todo); + return cnt; } /** @@ -679,6 +664,7 @@ int devres_release_group(struct device *dev, void *id) { struct devres_group *grp; unsigned long flags; + LIST_HEAD(todo); int cnt = 0; spin_lock_irqsave(&dev->devres_lock, flags); @@ -691,7 +677,10 @@ int devres_release_group(struct device *dev, void *id) if (!list_empty(&grp->node[1].entry)) end = grp->node[1].entry.next; - cnt = release_nodes(dev, first, end, flags); + cnt = remove_nodes(dev, first, end, &todo); + spin_unlock_irqrestore(&dev->devres_lock, flags); + + release_nodes(dev, &todo); } else { WARN_ON(1); spin_unlock_irqrestore(&dev->devres_lock, flags); diff --git a/drivers/base/firmware_loader/builtin/Makefile b/drivers/base/firmware_loader/builtin/Makefile index 5fa7ce3745a0..101754ad48d9 100644 --- a/drivers/base/firmware_loader/builtin/Makefile +++ b/drivers/base/firmware_loader/builtin/Makefile @@ -8,7 +8,6 @@ fwdir := $(addprefix $(srctree)/,$(filter-out /%,$(fwdir)))$(filter /%,$(fwdir)) obj-y := $(addsuffix .gen.o, $(subst $(quote),,$(CONFIG_EXTRA_FIRMWARE))) FWNAME = $(patsubst $(obj)/%.gen.S,%,$@) -comma := , FWSTR = $(subst $(comma),_,$(subst /,_,$(subst .,_,$(subst -,_,$(FWNAME))))) ASM_WORD = $(if $(CONFIG_64BIT),.quad,.long) ASM_ALIGN = $(if $(CONFIG_64BIT),3,2) diff --git a/drivers/base/memory.c b/drivers/base/memory.c index d5ffaab3cb61..aa31a21f33d7 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -596,7 +596,7 @@ static struct attribute *memory_memblk_attrs[] = { NULL }; -static struct attribute_group memory_memblk_attr_group = { +static const struct attribute_group memory_memblk_attr_group = { .attrs = memory_memblk_attrs, }; @@ -772,7 +772,7 @@ static struct attribute *memory_root_attrs[] = { NULL }; -static struct attribute_group memory_root_attr_group = { +static const struct attribute_group memory_root_attr_group = { .attrs = memory_root_attrs, }; diff --git a/drivers/base/node.c b/drivers/base/node.c index 2c36f61d30bc..4a4ae868ad9f 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -233,7 +233,7 @@ static ssize_t name##_show(struct device *dev, \ return sysfs_emit(buf, fmt "\n", \ to_cache_info(dev)->cache_attrs.name); \ } \ -DEVICE_ATTR_RO(name); +static DEVICE_ATTR_RO(name); CACHE_ATTR(size, "%llu") CACHE_ATTR(line_size, "%u") @@ -482,6 +482,7 @@ static DEVICE_ATTR(meminfo, 0444, node_read_meminfo, NULL); static ssize_t node_read_numastat(struct device *dev, struct device_attribute *attr, char *buf) { + fold_vm_numa_events(); return sysfs_emit(buf, "numa_hit %lu\n" "numa_miss %lu\n" @@ -489,12 +490,12 @@ static ssize_t node_read_numastat(struct device *dev, "interleave_hit %lu\n" "local_node %lu\n" "other_node %lu\n", - sum_zone_numa_state(dev->id, NUMA_HIT), - sum_zone_numa_state(dev->id, NUMA_MISS), - sum_zone_numa_state(dev->id, NUMA_FOREIGN), - sum_zone_numa_state(dev->id, NUMA_INTERLEAVE_HIT), - sum_zone_numa_state(dev->id, NUMA_LOCAL), - sum_zone_numa_state(dev->id, NUMA_OTHER)); + sum_zone_numa_event_state(dev->id, NUMA_HIT), + sum_zone_numa_event_state(dev->id, NUMA_MISS), + sum_zone_numa_event_state(dev->id, NUMA_FOREIGN), + sum_zone_numa_event_state(dev->id, NUMA_INTERLEAVE_HIT), + sum_zone_numa_event_state(dev->id, NUMA_LOCAL), + sum_zone_numa_event_state(dev->id, NUMA_OTHER)); } static DEVICE_ATTR(numastat, 0444, node_read_numastat, NULL); @@ -512,10 +513,11 @@ static ssize_t node_read_vmstat(struct device *dev, sum_zone_node_page_state(nid, i)); #ifdef CONFIG_NUMA - for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++) + fold_vm_numa_events(); + for (i = 0; i < NR_VM_NUMA_EVENT_ITEMS; i++) len += sysfs_emit_at(buf, len, "%s %lu\n", numa_stat_name(i), - sum_zone_numa_state(nid, i)); + sum_zone_numa_event_state(nid, i)); #endif for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) { @@ -1036,7 +1038,7 @@ static struct attribute *node_state_attrs[] = { NULL }; -static struct attribute_group memory_root_attr_group = { +static const struct attribute_group memory_root_attr_group = { .attrs = node_state_attrs, }; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 9cd34def2237..8640578f45e9 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -125,26 +125,6 @@ void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev, EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource); /** - * devm_platform_ioremap_resource_wc - write-combined variant of - * devm_platform_ioremap_resource() - * - * @pdev: platform device to use both for memory resource lookup as well as - * resource management - * @index: resource index - * - * Return: a pointer to the remapped memory or an ERR_PTR() encoded error code - * on failure. - */ -void __iomem *devm_platform_ioremap_resource_wc(struct platform_device *pdev, - unsigned int index) -{ - struct resource *res; - - res = platform_get_resource(pdev, IORESOURCE_MEM, index); - return devm_ioremap_resource_wc(&pdev->dev, res); -} - -/** * devm_platform_ioremap_resource_byname - call devm_ioremap_resource for * a platform device, retrieve the * resource by name @@ -1355,7 +1335,7 @@ static umode_t platform_dev_attrs_visible(struct kobject *kobj, struct attribute return a->mode; } -static struct attribute_group platform_dev_group = { +static const struct attribute_group platform_dev_group = { .attrs = platform_dev_attrs, .is_visible = platform_dev_attrs_visible, }; diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index b6a782c31613..ab0b740cc0f1 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -379,6 +379,44 @@ err: return ret; } +static int genpd_set_performance_state(struct device *dev, unsigned int state) +{ + struct generic_pm_domain *genpd = dev_to_genpd(dev); + struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev); + unsigned int prev_state; + int ret; + + prev_state = gpd_data->performance_state; + if (prev_state == state) + return 0; + + gpd_data->performance_state = state; + state = _genpd_reeval_performance_state(genpd, state); + + ret = _genpd_set_performance_state(genpd, state, 0); + if (ret) + gpd_data->performance_state = prev_state; + + return ret; +} + +static int genpd_drop_performance_state(struct device *dev) +{ + unsigned int prev_state = dev_gpd_data(dev)->performance_state; + + if (!genpd_set_performance_state(dev, 0)) + return prev_state; + + return 0; +} + +static void genpd_restore_performance_state(struct device *dev, + unsigned int state) +{ + if (state) + genpd_set_performance_state(dev, state); +} + /** * dev_pm_genpd_set_performance_state- Set performance state of device's power * domain. @@ -397,8 +435,6 @@ err: int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state) { struct generic_pm_domain *genpd; - struct generic_pm_domain_data *gpd_data; - unsigned int prev; int ret; genpd = dev_to_genpd_safe(dev); @@ -410,16 +446,7 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state) return -EINVAL; genpd_lock(genpd); - - gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); - prev = gpd_data->performance_state; - gpd_data->performance_state = state; - - state = _genpd_reeval_performance_state(genpd, state); - ret = _genpd_set_performance_state(genpd, state, 0); - if (ret) - gpd_data->performance_state = prev; - + ret = genpd_set_performance_state(dev, state); genpd_unlock(genpd); return ret; @@ -572,6 +599,7 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd) * RPM status of the releated device is in an intermediate state, not yet turned * into RPM_SUSPENDED. This means genpd_power_off() must allow one device to not * be RPM_SUSPENDED, while it tries to power off the PM domain. + * @depth: nesting count for lockdep. * * If all of the @genpd's devices have been suspended and all of its subdomains * have been powered down, remove power from @genpd. @@ -832,7 +860,8 @@ static int genpd_runtime_suspend(struct device *dev) { struct generic_pm_domain *genpd; bool (*suspend_ok)(struct device *__dev); - struct gpd_timing_data *td = &dev_gpd_data(dev)->td; + struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev); + struct gpd_timing_data *td = &gpd_data->td; bool runtime_pm = pm_runtime_enabled(dev); ktime_t time_start; s64 elapsed_ns; @@ -889,6 +918,7 @@ static int genpd_runtime_suspend(struct device *dev) return 0; genpd_lock(genpd); + gpd_data->rpm_pstate = genpd_drop_performance_state(dev); genpd_power_off(genpd, true, 0); genpd_unlock(genpd); @@ -906,7 +936,8 @@ static int genpd_runtime_suspend(struct device *dev) static int genpd_runtime_resume(struct device *dev) { struct generic_pm_domain *genpd; - struct gpd_timing_data *td = &dev_gpd_data(dev)->td; + struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev); + struct gpd_timing_data *td = &gpd_data->td; bool runtime_pm = pm_runtime_enabled(dev); ktime_t time_start; s64 elapsed_ns; @@ -930,6 +961,8 @@ static int genpd_runtime_resume(struct device *dev) genpd_lock(genpd); ret = genpd_power_on(genpd, 0); + if (!ret) + genpd_restore_performance_state(dev, gpd_data->rpm_pstate); genpd_unlock(genpd); if (ret) @@ -968,6 +1001,7 @@ err_stop: err_poweroff: if (!pm_runtime_is_irq_safe(dev) || genpd_is_irq_safe(genpd)) { genpd_lock(genpd); + gpd_data->rpm_pstate = genpd_drop_performance_state(dev); genpd_power_off(genpd, true, 0); genpd_unlock(genpd); } @@ -2505,7 +2539,7 @@ EXPORT_SYMBOL_GPL(of_genpd_remove_subdomain); /** * of_genpd_remove_last - Remove the last PM domain registered for a provider - * @provider: Pointer to device structure associated with provider + * @np: Pointer to device node associated with provider * * Find the last PM domain that was added by a particular provider and * remove this PM domain from the list of PM domains. The provider is diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c index c6c218758f0b..cd08c5885190 100644 --- a/drivers/base/power/domain_governor.c +++ b/drivers/base/power/domain_governor.c @@ -252,6 +252,7 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd, /** * _default_power_down_ok - Default generic PM domain power off governor routine. * @pd: PM domain to check. + * @now: current ktime. * * This routine must be executed under the PM domain's lock. */ diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index b570848d23e0..8a66eaf731e4 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -345,7 +345,7 @@ static void rpm_suspend_suppliers(struct device *dev) static int __rpm_callback(int (*cb)(struct device *), struct device *dev) __releases(&dev->power.lock) __acquires(&dev->power.lock) { - int retval, idx; + int retval = 0, idx; bool use_links = dev->power.links_count > 0; if (dev->power.irq_safe) { @@ -373,7 +373,8 @@ static int __rpm_callback(int (*cb)(struct device *), struct device *dev) } } - retval = cb(dev); + if (cb) + retval = cb(dev); if (dev->power.irq_safe) { spin_lock(&dev->power.lock); @@ -446,7 +447,10 @@ static int rpm_idle(struct device *dev, int rpmflags) /* Pending requests need to be canceled. */ dev->power.request = RPM_REQ_NONE; - if (dev->power.no_callbacks) + callback = RPM_GET_CALLBACK(dev, runtime_idle); + + /* If no callback assume success. */ + if (!callback || dev->power.no_callbacks) goto out; /* Carry out an asynchronous or a synchronous idle notification. */ @@ -462,10 +466,7 @@ static int rpm_idle(struct device *dev, int rpmflags) dev->power.idle_notification = true; - callback = RPM_GET_CALLBACK(dev, runtime_idle); - - if (callback) - retval = __rpm_callback(callback, dev); + retval = __rpm_callback(callback, dev); dev->power.idle_notification = false; wake_up_all(&dev->power.wait_queue); @@ -484,9 +485,6 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev) { int retval; - if (!cb) - return -ENOSYS; - if (dev->power.memalloc_noio) { unsigned int noio_flag; diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c index 8e021082dba8..3bad3266a2ad 100644 --- a/drivers/base/power/wakeirq.c +++ b/drivers/base/power/wakeirq.c @@ -182,7 +182,6 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq) wirq->dev = dev; wirq->irq = irq; - irq_set_status_flags(irq, IRQ_NOAUTOEN); /* Prevent deferred spurious wakeirqs with disable_irq_nosync() */ irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); @@ -192,7 +191,8 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq) * so we use a threaded irq. */ err = request_threaded_irq(irq, NULL, handle_threaded_wake_irq, - IRQF_ONESHOT, wirq->name, wirq); + IRQF_ONESHOT | IRQF_NO_AUTOEN, + wirq->name, wirq); if (err) goto err_free_name; diff --git a/drivers/base/property.c b/drivers/base/property.c index 1421e9548857..d0874f6c29bb 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -21,7 +21,7 @@ struct fwnode_handle *dev_fwnode(struct device *dev) { return IS_ENABLED(CONFIG_OF) && dev->of_node ? - &dev->of_node->fwnode : dev->fwnode; + of_fwnode_handle(dev->of_node) : dev->fwnode; } EXPORT_SYMBOL_GPL(dev_fwnode); @@ -627,14 +627,15 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_parent); */ struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode) { - struct device *dev = NULL; + struct device *dev; fwnode_handle_get(fwnode); do { fwnode = fwnode_get_next_parent(fwnode); - if (fwnode) - dev = get_dev_from_fwnode(fwnode); - } while (fwnode && !dev); + if (!fwnode) + return NULL; + dev = get_dev_from_fwnode(fwnode); + } while (!dev); fwnode_handle_put(fwnode); return dev; } @@ -742,10 +743,9 @@ fwnode_get_next_available_child_node(const struct fwnode_handle *fwnode, do { next_child = fwnode_get_next_child_node(fwnode, next_child); - - if (!next_child || fwnode_device_is_available(next_child)) - break; - } while (next_child); + if (!next_child) + return NULL; + } while (!fwnode_device_is_available(next_child)); return next_child; } @@ -759,13 +759,8 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_available_child_node); struct fwnode_handle *device_get_next_child_node(struct device *dev, struct fwnode_handle *child) { - struct acpi_device *adev = ACPI_COMPANION(dev); - struct fwnode_handle *fwnode = NULL, *next; - - if (dev->of_node) - fwnode = &dev->of_node->fwnode; - else if (adev) - fwnode = acpi_fwnode_handle(adev); + const struct fwnode_handle *fwnode = dev_fwnode(dev); + struct fwnode_handle *next; /* Try to find a child in primary fwnode */ next = fwnode_get_next_child_node(fwnode, child); @@ -868,28 +863,31 @@ EXPORT_SYMBOL_GPL(device_get_child_node_count); bool device_dma_supported(struct device *dev) { + const struct fwnode_handle *fwnode = dev_fwnode(dev); + /* For DT, this is always supported. * For ACPI, this depends on CCA, which * is determined by the acpi_dma_supported(). */ - if (IS_ENABLED(CONFIG_OF) && dev->of_node) + if (is_of_node(fwnode)) return true; - return acpi_dma_supported(ACPI_COMPANION(dev)); + return acpi_dma_supported(to_acpi_device_node(fwnode)); } EXPORT_SYMBOL_GPL(device_dma_supported); enum dev_dma_attr device_get_dma_attr(struct device *dev) { + const struct fwnode_handle *fwnode = dev_fwnode(dev); enum dev_dma_attr attr = DEV_DMA_NOT_SUPPORTED; - if (IS_ENABLED(CONFIG_OF) && dev->of_node) { - if (of_dma_is_coherent(dev->of_node)) + if (is_of_node(fwnode)) { + if (of_dma_is_coherent(to_of_node(fwnode))) attr = DEV_DMA_COHERENT; else attr = DEV_DMA_NON_COHERENT; } else - attr = acpi_get_dma_attr(ACPI_COMPANION(dev)); + attr = acpi_get_dma_attr(to_acpi_device_node(fwnode)); return attr; } @@ -1007,14 +1005,13 @@ EXPORT_SYMBOL(device_get_mac_address); * Returns Linux IRQ number on success. Other values are determined * accordingly to acpi_/of_ irq_get() operation. */ -int fwnode_irq_get(struct fwnode_handle *fwnode, unsigned int index) +int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index) { - struct device_node *of_node = to_of_node(fwnode); struct resource res; int ret; - if (IS_ENABLED(CONFIG_OF) && of_node) - return of_irq_get(of_node, index); + if (is_of_node(fwnode)) + return of_irq_get(to_of_node(fwnode), index); ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), index, &res); if (ret) diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 50b1e2d06a25..159bac6c5046 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig @@ -4,8 +4,9 @@ # subsystems should select the appropriate symbols. config REGMAP - default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM) + default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO) select IRQ_DOMAIN if REGMAP_IRQ + select MDIO_BUS if REGMAP_MDIO bool config REGCACHE_COMPRESSED @@ -36,6 +37,9 @@ config REGMAP_W1 tristate depends on W1 +config REGMAP_MDIO + tristate + config REGMAP_MMIO tristate diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index 33f63adb5b3d..11facb32a027 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_REGMAP_SOUNDWIRE_MBQ) += regmap-sdw-mbq.o obj-$(CONFIG_REGMAP_SCCB) += regmap-sccb.o obj-$(CONFIG_REGMAP_I3C) += regmap-i3c.o obj-$(CONFIG_REGMAP_SPI_AVMM) += regmap-spi-avmm.o +obj-$(CONFIG_REGMAP_MDIO) += regmap-mdio.o diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index 62b95a9212ae..980e5ce6a3a3 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -306,33 +306,64 @@ static const struct regmap_bus regmap_i2c_smbus_i2c_block_reg16 = { static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, const struct regmap_config *config) { + const struct i2c_adapter_quirks *quirks; + const struct regmap_bus *bus = NULL; + struct regmap_bus *ret_bus; + u16 max_read = 0, max_write = 0; + if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) - return ®map_i2c; + bus = ®map_i2c; else if (config->val_bits == 8 && config->reg_bits == 8 && i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) - return ®map_i2c_smbus_i2c_block; + bus = ®map_i2c_smbus_i2c_block; else if (config->val_bits == 8 && config->reg_bits == 16 && i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) - return ®map_i2c_smbus_i2c_block_reg16; + bus = ®map_i2c_smbus_i2c_block_reg16; else if (config->val_bits == 16 && config->reg_bits == 8 && i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_WORD_DATA)) switch (regmap_get_val_endian(&i2c->dev, NULL, config)) { case REGMAP_ENDIAN_LITTLE: - return ®map_smbus_word; + bus = ®map_smbus_word; + break; case REGMAP_ENDIAN_BIG: - return ®map_smbus_word_swapped; + bus = ®map_smbus_word_swapped; + break; default: /* everything else is not supported */ break; } else if (config->val_bits == 8 && config->reg_bits == 8 && i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return ®map_smbus_byte; + bus = ®map_smbus_byte; + + if (!bus) + return ERR_PTR(-ENOTSUPP); + + quirks = i2c->adapter->quirks; + if (quirks) { + if (quirks->max_read_len && + (bus->max_raw_read == 0 || bus->max_raw_read > quirks->max_read_len)) + max_read = quirks->max_read_len; + + if (quirks->max_write_len && + (bus->max_raw_write == 0 || bus->max_raw_write > quirks->max_write_len)) + max_write = quirks->max_write_len; + + if (max_read || max_write) { + ret_bus = kmemdup(bus, sizeof(*bus), GFP_KERNEL); + if (!ret_bus) + return ERR_PTR(-ENOMEM); + ret_bus->free_on_exit = true; + ret_bus->max_raw_read = max_read; + ret_bus->max_raw_write = max_write; + bus = ret_bus; + } + } - return ERR_PTR(-ENOTSUPP); + return bus; } struct regmap *__regmap_init_i2c(struct i2c_client *i2c, diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 760296a4b606..d2656581a608 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -531,6 +531,10 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) } } + if (chip->status_invert) + for (i = 0; i < data->chip->num_regs; i++) + data->status_buf[i] = ~data->status_buf[i]; + /* * Ignore masked IRQs and ack if we need to; we ack early so * there is no race between handling and acknowleding the @@ -800,6 +804,9 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode, goto err_alloc; } + if (chip->status_invert) + d->status_buf[i] = ~d->status_buf[i]; + if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) { reg = sub_irq_reg(d, d->chip->ack_base, i); if (chip->ack_invert) diff --git a/drivers/base/regmap/regmap-mdio.c b/drivers/base/regmap/regmap-mdio.c new file mode 100644 index 000000000000..6a20201299f5 --- /dev/null +++ b/drivers/base/regmap/regmap-mdio.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/errno.h> +#include <linux/mdio.h> +#include <linux/module.h> +#include <linux/regmap.h> + +#define REGVAL_MASK GENMASK(15, 0) +#define REGNUM_C22_MASK GENMASK(4, 0) +/* Clause-45 mask includes the device type (5 bit) and actual register number (16 bit) */ +#define REGNUM_C45_MASK GENMASK(20, 0) + +static int regmap_mdio_read(struct mdio_device *mdio_dev, u32 reg, unsigned int *val) +{ + int ret; + + ret = mdiobus_read(mdio_dev->bus, mdio_dev->addr, reg); + if (ret < 0) + return ret; + + *val = ret & REGVAL_MASK; + return 0; +} + +static int regmap_mdio_write(struct mdio_device *mdio_dev, u32 reg, unsigned int val) +{ + return mdiobus_write(mdio_dev->bus, mdio_dev->addr, reg, val); +} + +static int regmap_mdio_c22_read(void *context, unsigned int reg, unsigned int *val) +{ + struct mdio_device *mdio_dev = context; + + if (unlikely(reg & ~REGNUM_C22_MASK)) + return -ENXIO; + + return regmap_mdio_read(mdio_dev, reg, val); +} + +static int regmap_mdio_c22_write(void *context, unsigned int reg, unsigned int val) +{ + struct mdio_device *mdio_dev = context; + + if (unlikely(reg & ~REGNUM_C22_MASK)) + return -ENXIO; + + return mdiobus_write(mdio_dev->bus, mdio_dev->addr, reg, val); +} + +static const struct regmap_bus regmap_mdio_c22_bus = { + .reg_write = regmap_mdio_c22_write, + .reg_read = regmap_mdio_c22_read, +}; + +static int regmap_mdio_c45_read(void *context, unsigned int reg, unsigned int *val) +{ + struct mdio_device *mdio_dev = context; + + if (unlikely(reg & ~REGNUM_C45_MASK)) + return -ENXIO; + + return regmap_mdio_read(mdio_dev, MII_ADDR_C45 | reg, val); +} + +static int regmap_mdio_c45_write(void *context, unsigned int reg, unsigned int val) +{ + struct mdio_device *mdio_dev = context; + + if (unlikely(reg & ~REGNUM_C45_MASK)) + return -ENXIO; + + return regmap_mdio_write(mdio_dev, MII_ADDR_C45 | reg, val); +} + +static const struct regmap_bus regmap_mdio_c45_bus = { + .reg_write = regmap_mdio_c45_write, + .reg_read = regmap_mdio_c45_read, +}; + +struct regmap *__regmap_init_mdio(struct mdio_device *mdio_dev, + const struct regmap_config *config, struct lock_class_key *lock_key, + const char *lock_name) +{ + const struct regmap_bus *bus; + + if (config->reg_bits == 5 && config->val_bits == 16) + bus = ®map_mdio_c22_bus; + else if (config->reg_bits == 21 && config->val_bits == 16) + bus = ®map_mdio_c45_bus; + else + return ERR_PTR(-EOPNOTSUPP); + + return __regmap_init(&mdio_dev->dev, bus, mdio_dev, config, lock_key, lock_name); +} +EXPORT_SYMBOL_GPL(__regmap_init_mdio); + +struct regmap *__devm_regmap_init_mdio(struct mdio_device *mdio_dev, + const struct regmap_config *config, struct lock_class_key *lock_key, + const char *lock_name) +{ + const struct regmap_bus *bus; + + if (config->reg_bits == 5 && config->val_bits == 16) + bus = ®map_mdio_c22_bus; + else if (config->reg_bits == 21 && config->val_bits == 16) + bus = ®map_mdio_c45_bus; + else + return ERR_PTR(-EOPNOTSUPP); + + return __devm_regmap_init(&mdio_dev->dev, bus, mdio_dev, config, lock_key, lock_name); +} +EXPORT_SYMBOL_GPL(__devm_regmap_init_mdio); + +MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>"); +MODULE_DESCRIPTION("Regmap MDIO Module"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 297e95be25b3..fe3e38dd5324 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -243,6 +243,16 @@ static void regmap_format_7_9_write(struct regmap *map, *out = cpu_to_be16((reg << 9) | val); } +static void regmap_format_7_17_write(struct regmap *map, + unsigned int reg, unsigned int val) +{ + u8 *out = map->work_buf; + + out[2] = val; + out[1] = val >> 8; + out[0] = (val >> 16) | (reg << 1); +} + static void regmap_format_10_14_write(struct regmap *map, unsigned int reg, unsigned int val) { @@ -885,6 +895,9 @@ struct regmap *__regmap_init(struct device *dev, case 9: map->format.format_write = regmap_format_7_9_write; break; + case 17: + map->format.format_write = regmap_format_7_17_write; + break; default: goto err_hwlock; } @@ -1496,6 +1509,8 @@ void regmap_exit(struct regmap *map) mutex_destroy(&map->mutex); kfree_const(map->name); kfree(map->patch); + if (map->bus && map->bus->free_on_exit) + kfree(map->bus); kfree(map); } EXPORT_SYMBOL_GPL(regmap_exit); diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index 3cc11b813f28..d1f1a8240120 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -1045,7 +1045,15 @@ int device_add_software_node(struct device *dev, const struct software_node *nod } set_secondary_fwnode(dev, &swnode->fwnode); - software_node_notify(dev, KOBJ_ADD); + + /* + * If the device has been fully registered by the time this function is + * called, software_node_notify() must be called separately so that the + * symlinks get created and the reference count of the node is kept in + * balance. + */ + if (device_is_registered(dev)) + software_node_notify(dev, KOBJ_ADD); return 0; } @@ -1065,7 +1073,8 @@ void device_remove_software_node(struct device *dev) if (!swnode) return; - software_node_notify(dev, KOBJ_REMOVE); + if (device_is_registered(dev)) + software_node_notify(dev, KOBJ_REMOVE); set_secondary_fwnode(dev, NULL); kobject_put(&swnode->kobj); } @@ -1119,8 +1128,7 @@ int software_node_notify(struct device *dev, unsigned long action) switch (action) { case KOBJ_ADD: - ret = sysfs_create_link_nowarn(&dev->kobj, &swnode->kobj, - "software_node"); + ret = sysfs_create_link(&dev->kobj, &swnode->kobj, "software_node"); if (ret) break; diff --git a/drivers/base/test/property-entry-test.c b/drivers/base/test/property-entry-test.c index 1106fedcceed..6071d5bc128c 100644 --- a/drivers/base/test/property-entry-test.c +++ b/drivers/base/test/property-entry-test.c @@ -32,11 +32,11 @@ static void pe_test_uints(struct kunit *test) error = fwnode_property_read_u8(node, "prop-u8", &val_u8); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)val_u8, 8); + KUNIT_EXPECT_EQ(test, val_u8, 8); error = fwnode_property_read_u8_array(node, "prop-u8", array_u8, 1); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)array_u8[0], 8); + KUNIT_EXPECT_EQ(test, array_u8[0], 8); error = fwnode_property_read_u8_array(node, "prop-u8", array_u8, 2); KUNIT_EXPECT_NE(test, error, 0); @@ -49,14 +49,14 @@ static void pe_test_uints(struct kunit *test) error = fwnode_property_read_u16(node, "prop-u16", &val_u16); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)val_u16, 16); + KUNIT_EXPECT_EQ(test, val_u16, 16); error = fwnode_property_count_u16(node, "prop-u16"); KUNIT_EXPECT_EQ(test, error, 1); error = fwnode_property_read_u16_array(node, "prop-u16", array_u16, 1); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)array_u16[0], 16); + KUNIT_EXPECT_EQ(test, array_u16[0], 16); error = fwnode_property_read_u16_array(node, "prop-u16", array_u16, 2); KUNIT_EXPECT_NE(test, error, 0); @@ -69,14 +69,14 @@ static void pe_test_uints(struct kunit *test) error = fwnode_property_read_u32(node, "prop-u32", &val_u32); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)val_u32, 32); + KUNIT_EXPECT_EQ(test, val_u32, 32); error = fwnode_property_count_u32(node, "prop-u32"); KUNIT_EXPECT_EQ(test, error, 1); error = fwnode_property_read_u32_array(node, "prop-u32", array_u32, 1); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)array_u32[0], 32); + KUNIT_EXPECT_EQ(test, array_u32[0], 32); error = fwnode_property_read_u32_array(node, "prop-u32", array_u32, 2); KUNIT_EXPECT_NE(test, error, 0); @@ -89,14 +89,14 @@ static void pe_test_uints(struct kunit *test) error = fwnode_property_read_u64(node, "prop-u64", &val_u64); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)val_u64, 64); + KUNIT_EXPECT_EQ(test, val_u64, 64); error = fwnode_property_count_u64(node, "prop-u64"); KUNIT_EXPECT_EQ(test, error, 1); error = fwnode_property_read_u64_array(node, "prop-u64", array_u64, 1); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)array_u64[0], 64); + KUNIT_EXPECT_EQ(test, array_u64[0], 64); error = fwnode_property_read_u64_array(node, "prop-u64", array_u64, 2); KUNIT_EXPECT_NE(test, error, 0); @@ -140,19 +140,19 @@ static void pe_test_uint_arrays(struct kunit *test) error = fwnode_property_read_u8(node, "prop-u8", &val_u8); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)val_u8, 8); + KUNIT_EXPECT_EQ(test, val_u8, 8); error = fwnode_property_count_u8(node, "prop-u8"); KUNIT_EXPECT_EQ(test, error, 10); error = fwnode_property_read_u8_array(node, "prop-u8", array_u8, 1); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)array_u8[0], 8); + KUNIT_EXPECT_EQ(test, array_u8[0], 8); error = fwnode_property_read_u8_array(node, "prop-u8", array_u8, 2); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)array_u8[0], 8); - KUNIT_EXPECT_EQ(test, (int)array_u8[1], 9); + KUNIT_EXPECT_EQ(test, array_u8[0], 8); + KUNIT_EXPECT_EQ(test, array_u8[1], 9); error = fwnode_property_read_u8_array(node, "prop-u8", array_u8, 17); KUNIT_EXPECT_NE(test, error, 0); @@ -165,19 +165,19 @@ static void pe_test_uint_arrays(struct kunit *test) error = fwnode_property_read_u16(node, "prop-u16", &val_u16); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)val_u16, 16); + KUNIT_EXPECT_EQ(test, val_u16, 16); error = fwnode_property_count_u16(node, "prop-u16"); KUNIT_EXPECT_EQ(test, error, 10); error = fwnode_property_read_u16_array(node, "prop-u16", array_u16, 1); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)array_u16[0], 16); + KUNIT_EXPECT_EQ(test, array_u16[0], 16); error = fwnode_property_read_u16_array(node, "prop-u16", array_u16, 2); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)array_u16[0], 16); - KUNIT_EXPECT_EQ(test, (int)array_u16[1], 17); + KUNIT_EXPECT_EQ(test, array_u16[0], 16); + KUNIT_EXPECT_EQ(test, array_u16[1], 17); error = fwnode_property_read_u16_array(node, "prop-u16", array_u16, 17); KUNIT_EXPECT_NE(test, error, 0); @@ -190,19 +190,19 @@ static void pe_test_uint_arrays(struct kunit *test) error = fwnode_property_read_u32(node, "prop-u32", &val_u32); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)val_u32, 32); + KUNIT_EXPECT_EQ(test, val_u32, 32); error = fwnode_property_count_u32(node, "prop-u32"); KUNIT_EXPECT_EQ(test, error, 10); error = fwnode_property_read_u32_array(node, "prop-u32", array_u32, 1); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)array_u32[0], 32); + KUNIT_EXPECT_EQ(test, array_u32[0], 32); error = fwnode_property_read_u32_array(node, "prop-u32", array_u32, 2); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)array_u32[0], 32); - KUNIT_EXPECT_EQ(test, (int)array_u32[1], 33); + KUNIT_EXPECT_EQ(test, array_u32[0], 32); + KUNIT_EXPECT_EQ(test, array_u32[1], 33); error = fwnode_property_read_u32_array(node, "prop-u32", array_u32, 17); KUNIT_EXPECT_NE(test, error, 0); @@ -215,19 +215,19 @@ static void pe_test_uint_arrays(struct kunit *test) error = fwnode_property_read_u64(node, "prop-u64", &val_u64); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)val_u64, 64); + KUNIT_EXPECT_EQ(test, val_u64, 64); error = fwnode_property_count_u64(node, "prop-u64"); KUNIT_EXPECT_EQ(test, error, 10); error = fwnode_property_read_u64_array(node, "prop-u64", array_u64, 1); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)array_u64[0], 64); + KUNIT_EXPECT_EQ(test, array_u64[0], 64); error = fwnode_property_read_u64_array(node, "prop-u64", array_u64, 2); KUNIT_EXPECT_EQ(test, error, 0); - KUNIT_EXPECT_EQ(test, (int)array_u64[0], 64); - KUNIT_EXPECT_EQ(test, (int)array_u64[1], 65); + KUNIT_EXPECT_EQ(test, array_u64[0], 64); + KUNIT_EXPECT_EQ(test, array_u64[1], 65); error = fwnode_property_read_u64_array(node, "prop-u64", array_u64, 17); KUNIT_EXPECT_NE(test, error, 0); @@ -358,13 +358,13 @@ static void pe_test_move_inline_u8(struct kunit *test) KUNIT_EXPECT_TRUE(test, copy[0].is_inline); data_ptr = (u8 *)©[0].value; - KUNIT_EXPECT_EQ(test, (int)data_ptr[0], 1); - KUNIT_EXPECT_EQ(test, (int)data_ptr[1], 2); + KUNIT_EXPECT_EQ(test, data_ptr[0], 1); + KUNIT_EXPECT_EQ(test, data_ptr[1], 2); KUNIT_EXPECT_FALSE(test, copy[1].is_inline); data_ptr = copy[1].pointer; - KUNIT_EXPECT_EQ(test, (int)data_ptr[0], 5); - KUNIT_EXPECT_EQ(test, (int)data_ptr[1], 6); + KUNIT_EXPECT_EQ(test, data_ptr[0], 5); + KUNIT_EXPECT_EQ(test, data_ptr[1], 6); property_entries_free(copy); } diff --git a/drivers/base/trace.c b/drivers/base/trace.c new file mode 100644 index 000000000000..b24b0a309c4a --- /dev/null +++ b/drivers/base/trace.c @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Device core Trace Support + * Copyright (C) 2021, Intel Corporation + * + * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> + */ + +#define CREATE_TRACE_POINTS +#include "trace.h" diff --git a/drivers/base/trace.h b/drivers/base/trace.h new file mode 100644 index 000000000000..3192e18f877e --- /dev/null +++ b/drivers/base/trace.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Device core Trace Support + * Copyright (C) 2021, Intel Corporation + * + * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM dev + +#if !defined(__DEV_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define __DEV_TRACE_H + +#include <linux/device.h> +#include <linux/tracepoint.h> +#include <linux/types.h> + +DECLARE_EVENT_CLASS(devres, + TP_PROTO(struct device *dev, const char *op, void *node, const char *name, size_t size), + TP_ARGS(dev, op, node, name, size), + TP_STRUCT__entry( + __string(devname, dev_name(dev)) + __field(struct device *, dev) + __field(const char *, op) + __field(void *, node) + __field(const char *, name) + __field(size_t, size) + ), + TP_fast_assign( + __assign_str(devname, dev_name(dev)); + __entry->op = op; + __entry->node = node; + __entry->name = name; + __entry->size = size; + ), + TP_printk("%s %3s %p %s (%zu bytes)", __get_str(devname), + __entry->op, __entry->node, __entry->name, __entry->size) +); + +DEFINE_EVENT(devres, devres_log, + TP_PROTO(struct device *dev, const char *op, void *node, const char *name, size_t size), + TP_ARGS(dev, op, node, name, size) +); + +#endif /* __DEV_TRACE_H */ + +/* this part has to be here */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +#include <trace/define_trace.h> |