From d82ba4c0b457f0cb30da7bbee935aad7793e5fac Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 Jul 2015 18:15:38 -0600 Subject: dm: core: Support finding a device by phandle It is common for one node to reference another via a phandle. Add support for obtaining an attached device by this method. As an example, a node may have a 'power-supply' property which references a regulator, allowing the driver to turn on its power. Signed-off-by: Simon Glass --- drivers/core/uclass.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'drivers/core') diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index ffe69956d5..5c4a66dd8c 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -273,6 +273,37 @@ static int uclass_find_device_by_of_offset(enum uclass_id id, int node, return -ENODEV; } +static int uclass_find_device_by_phandle(enum uclass_id id, + struct udevice *parent, + const char *name, + struct udevice **devp) +{ + struct udevice *dev; + struct uclass *uc; + int find_phandle; + int ret; + + *devp = NULL; + find_phandle = fdtdec_get_int(gd->fdt_blob, parent->of_offset, name, + -1); + if (find_phandle <= 0) + return -ENOENT; + ret = uclass_get(id, &uc); + if (ret) + return ret; + + list_for_each_entry(dev, &uc->dev_head, uclass_node) { + uint phandle = fdt_get_phandle(gd->fdt_blob, dev->of_offset); + + if (phandle == find_phandle) { + *devp = dev; + return 0; + } + } + + return -ENODEV; +} + int uclass_get_device_tail(struct udevice *dev, int ret, struct udevice **devp) { @@ -338,6 +369,17 @@ int uclass_get_device_by_of_offset(enum uclass_id id, int node, return uclass_get_device_tail(dev, ret, devp); } +int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent, + const char *name, struct udevice **devp) +{ + struct udevice *dev; + int ret; + + *devp = NULL; + ret = uclass_find_device_by_phandle(id, parent, name, &dev); + return uclass_get_device_tail(dev, ret, devp); +} + int uclass_first_device(enum uclass_id id, struct udevice **devp) { struct udevice *dev; -- cgit From 12dc8e7522230b269b4ca8fecc64bc8e59070a53 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 17 Jul 2015 09:22:07 -0600 Subject: dm: Make regmap and syscon optional Not all boards use garbage collection in their link step, so we should avoid adding options that rely on this for prevention of code bloat. Add separate Kconfig options for syscon and regmap uclasses. Signed-off-by: Simon Glass --- drivers/core/Kconfig | 19 +++++++++++++++++++ drivers/core/Makefile | 4 ++-- 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers/core') diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index e40372dd75..5d0e949f05 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -59,3 +59,22 @@ config DM_SEQ_ALIAS Most boards will have a '/aliases' node containing the path to numbered devices (e.g. serial0 = &serial0). This feature can be disabled if it is not required, to save code space in SPL. + +config REGMAP + bool "Support register maps" + depends on DM + help + Hardware peripherals tend to have one or more sets of registers + which can be accessed to control the hardware. A register map + models this with a simple read/write interface. It can in principle + support any bus type (I2C, SPI) but so far this only supports + direct memory access. + +config SYSCON + bool "Support system controllers" + depends on REGMAP + help + Many SoCs have a number of system controllers which are dealt with + as a group by a single driver. Some common functionality is provided + by this uclass, including accessing registers via regmap and + assigning a unique number to each. diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 5c2ead870b..ce3027a851 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -10,5 +10,5 @@ obj-$(CONFIG_OF_CONTROL) += simple-bus.o endif obj-$(CONFIG_DM_DEVICE_REMOVE) += device-remove.o obj-$(CONFIG_DM) += dump.o -obj-$(CONFIG_OF_CONTROL) += regmap.o -obj-$(CONFIG_OF_CONTROL) += syscon-uclass.o +obj-$(CONFIG_REGMAP) += regmap.o +obj-$(CONFIG_SYSCON) += syscon-uclass.o -- cgit From f33017716e5c430d84366ecc4476ba2b655f3fef Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 Jul 2015 20:53:44 -0600 Subject: dm: Support address translation for simple-bus The 'ranges' property can be used to specify a translation from the system address to the bus address. Add support for this using the dev_get_addr() function, which devices should use to find their address. Signed-off-by: Simon Glass --- drivers/core/device.c | 17 +++++++++++------ drivers/core/simple-bus.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 6 deletions(-) (limited to 'drivers/core') diff --git a/drivers/core/device.c b/drivers/core/device.c index 51b1b44e5b..d65717ddc7 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -552,17 +552,22 @@ const char *dev_get_uclass_name(struct udevice *dev) return dev->uclass->uc_drv->name; } -#ifdef CONFIG_OF_CONTROL fdt_addr_t dev_get_addr(struct udevice *dev) { - return fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); -} +#ifdef CONFIG_OF_CONTROL + fdt_addr_t addr; + + addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); + if (addr != FDT_ADDR_T_NONE) { + if (device_get_uclass_id(dev->parent) == UCLASS_SIMPLE_BUS) + addr = simple_bus_translate(dev->parent, addr); + } + + return addr; #else -fdt_addr_t dev_get_addr(struct udevice *dev) -{ return FDT_ADDR_T_NONE; -} #endif +} bool device_has_children(struct udevice *dev) { diff --git a/drivers/core/simple-bus.c b/drivers/core/simple-bus.c index 3ea4d8230b..913c3ccc70 100644 --- a/drivers/core/simple-bus.c +++ b/drivers/core/simple-bus.c @@ -10,8 +10,37 @@ DECLARE_GLOBAL_DATA_PTR; +struct simple_bus_plat { + u32 base; + u32 size; + u32 target; +}; + +fdt_addr_t simple_bus_translate(struct udevice *dev, fdt_addr_t addr) +{ + struct simple_bus_plat *plat = dev_get_uclass_platdata(dev); + + if (addr >= plat->base && addr < plat->base + plat->size) + addr = (addr - plat->base) + plat->target; + + return addr; +} + static int simple_bus_post_bind(struct udevice *dev) { + u32 cell[3]; + int ret; + + ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "ranges", + cell, ARRAY_SIZE(cell)); + if (!ret) { + struct simple_bus_plat *plat = dev_get_uclass_platdata(dev); + + plat->base = cell[0]; + plat->target = cell[1]; + plat->size = cell[2]; + } + return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); } @@ -19,6 +48,7 @@ UCLASS_DRIVER(simple_bus) = { .id = UCLASS_SIMPLE_BUS, .name = "simple_bus", .post_bind = simple_bus_post_bind, + .per_device_platdata_auto_alloc_size = sizeof(struct simple_bus_plat), }; static const struct udevice_id generic_simple_bus_ids[] = { -- cgit From aed1a4dd88e94001b811b297c1ff734c3f8d22d9 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 25 Jul 2015 21:52:34 +0900 Subject: dm: add DM_FLAG_BOUND flag Currently, we only have DM_FLAG_ACTIVATED to indicate the device status, but we still cannot know in which stage is in progress, binding or probing. This commit introduces a new flag, DM_FLAG_BOUND, which is set when the device is really bound, and cleared when it is unbound. Signed-off-by: Masahiro Yamada Acked-by: Simon Glass --- drivers/core/device-remove.c | 3 +++ drivers/core/device.c | 2 ++ 2 files changed, 5 insertions(+) (limited to 'drivers/core') diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c index 6b87f865e4..45d6543067 100644 --- a/drivers/core/device-remove.c +++ b/drivers/core/device-remove.c @@ -61,6 +61,9 @@ int device_unbind(struct udevice *dev) if (dev->flags & DM_FLAG_ACTIVATED) return -EINVAL; + if (!(dev->flags & DM_FLAG_BOUND)) + return -EINVAL; + drv = dev->driver; assert(drv); diff --git a/drivers/core/device.c b/drivers/core/device.c index d65717ddc7..bf6f2716da 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -132,6 +132,8 @@ int device_bind(struct udevice *parent, const struct driver *drv, dm_dbg("Bound device %s to %s\n", dev->name, parent->name); *devp = dev; + dev->flags |= DM_FLAG_BOUND; + return 0; fail_child_post_bind: -- cgit From 608f26c51bebc68db7f2edc7590ee513d2bc5465 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 25 Jul 2015 21:52:35 +0900 Subject: devres: introduce Devres (Managed Device Resource) framework In U-Boot's driver model, memory is basically allocated and freed in the core framework. So, low level drivers generally only have to specify the size of needed memory with .priv_auto_alloc_size, .platdata_auto_alloc_size, etc. Nevertheless, some drivers still need to allocate/free memory on their own in case they cannot statically know the necessary memory size. So, I believe it is reasonable enough to port Devres into U-boot. Devres, which originates in Linux, manages device resources for each device and automatically releases them on driver detach. With devres, device resources are guaranteed to be freed whether initialization fails half-way or the device gets detached. The basic idea is totally the same to that of Linux, but I tweaked it a bit so that it fits in U-Boot's driver model. In U-Boot, drivers are activated in two steps: binding and probing. Binding puts a driver and a device together. It is just data manipulation on the system memory, so nothing has happened on the hardware device at this moment. When the device is really used, it is probed. Probing initializes the real hardware device to make it really ready for use. So, the resources acquired during the probing process must be freed when the device is removed. Likewise, what has been allocated in binding should be released when the device is unbound. The struct devres has a member "probe" to remember when the resource was allocated. CONFIG_DEBUG_DEVRES is also supported for easier debugging. If enabled, debug messages are printed each time a resource is allocated/freed. Signed-off-by: Masahiro Yamada Acked-by: Simon Glass --- drivers/core/Kconfig | 10 +++ drivers/core/Makefile | 2 +- drivers/core/device-remove.c | 5 ++ drivers/core/device.c | 3 + drivers/core/devres.c | 196 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 drivers/core/devres.c (limited to 'drivers/core') diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 5d0e949f05..a002d69d79 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -78,3 +78,13 @@ config SYSCON as a group by a single driver. Some common functionality is provided by this uclass, including accessing registers via regmap and assigning a unique number to each. + +config DEBUG_DEVRES + bool "Managed device resources verbose debug messages" + depends on DM + help + If this option is enabled, devres debug messages are printed. + Select this if you are having a problem with devres or want to + debug resource management for a managed device. + + If you are unsure about this, Say N here. diff --git a/drivers/core/Makefile b/drivers/core/Makefile index ce3027a851..260833e8ee 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -4,7 +4,7 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y += device.o lists.o root.o uclass.o util.o +obj-y += device.o lists.o root.o uclass.o util.o devres.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_OF_CONTROL) += simple-bus.o endif diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c index 45d6543067..bd6d4062c9 100644 --- a/drivers/core/device-remove.c +++ b/drivers/core/device-remove.c @@ -95,6 +95,9 @@ int device_unbind(struct udevice *dev) if (dev->parent) list_del(&dev->sibling_node); + + devres_release_all(dev); + free(dev); return 0; @@ -128,6 +131,8 @@ void device_free(struct udevice *dev) dev->parent_priv = NULL; } } + + devres_release_probe(dev); } int device_remove(struct udevice *dev) diff --git a/drivers/core/device.c b/drivers/core/device.c index bf6f2716da..e3a42dc928 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -47,6 +47,7 @@ int device_bind(struct udevice *parent, const struct driver *drv, INIT_LIST_HEAD(&dev->sibling_node); INIT_LIST_HEAD(&dev->child_head); INIT_LIST_HEAD(&dev->uclass_node); + INIT_LIST_HEAD(&dev->devres_head); dev->platdata = platdata; dev->name = name; dev->of_offset = of_offset; @@ -170,6 +171,8 @@ fail_alloc2: dev->platdata = NULL; } fail_alloc1: + devres_release_all(dev); + free(dev); return ret; diff --git a/drivers/core/devres.c b/drivers/core/devres.c new file mode 100644 index 0000000000..49c270c57c --- /dev/null +++ b/drivers/core/devres.c @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * Based on the original work in Linux by + * Copyright (c) 2006 SUSE Linux Products GmbH + * Copyright (c) 2006 Tejun Heo + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +/** + * struct devres - Bookkeeping info for managed device resource + * @entry: List to associate this structure with a device + * @release: Callback invoked when this resource is released + * @probe: Flag to show when this resource was allocated + (true = probe, false = bind) + * @name: Name of release function + * @size: Size of resource data + * @data: Resource data + */ +struct devres { + struct list_head entry; + dr_release_t release; + bool probe; +#ifdef CONFIG_DEBUG_DEVRES + const char *name; + size_t size; +#endif + unsigned long long data[]; +}; + +#ifdef CONFIG_DEBUG_DEVRES +static void set_node_dbginfo(struct devres *dr, const char *name, size_t size) +{ + dr->name = name; + dr->size = size; +} + +static void devres_log(struct udevice *dev, struct devres *dr, + const char *op) +{ + printf("%s: DEVRES %3s %p %s (%lu bytes)\n", + dev->name, op, dr, dr->name, (unsigned long)dr->size); +} +#else /* CONFIG_DEBUG_DEVRES */ +#define set_node_dbginfo(dr, n, s) do {} while (0) +#define devres_log(dev, dr, op) do {} while (0) +#endif + +#if CONFIG_DEBUG_DEVRES +void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp, + const char *name) +#else +void *_devres_alloc(dr_release_t release, size_t size, gfp_t gfp) +#endif +{ + size_t tot_size = sizeof(struct devres) + size; + struct devres *dr; + + dr = kmalloc(tot_size, gfp); + if (unlikely(!dr)) + return NULL; + + INIT_LIST_HEAD(&dr->entry); + dr->release = release; + set_node_dbginfo(dr, name, size); + + return dr->data; +} + +void devres_free(void *res) +{ + if (res) { + struct devres *dr = container_of(res, struct devres, data); + + BUG_ON(!list_empty(&dr->entry)); + kfree(dr); + } +} + +void devres_add(struct udevice *dev, void *res) +{ + struct devres *dr = container_of(res, struct devres, data); + + devres_log(dev, dr, "ADD"); + BUG_ON(!list_empty(&dr->entry)); + dr->probe = dev->flags & DM_FLAG_BOUND ? true : false; + list_add_tail(&dr->entry, &dev->devres_head); +} + +void *devres_find(struct udevice *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + struct devres *dr; + + list_for_each_entry_reverse(dr, &dev->devres_head, entry) { + if (dr->release != release) + continue; + if (match && !match(dev, dr->data, match_data)) + continue; + return dr->data; + } + + return NULL; +} + +void *devres_get(struct udevice *dev, void *new_res, + dr_match_t match, void *match_data) +{ + struct devres *new_dr = container_of(new_res, struct devres, data); + void *res; + + res = devres_find(dev, new_dr->release, match, match_data); + if (!res) { + devres_add(dev, new_res); + res = new_res; + new_res = NULL; + } + devres_free(new_res); + + return res; +} + +void *devres_remove(struct udevice *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + void *res; + + res = devres_find(dev, release, match, match_data); + if (res) { + struct devres *dr = container_of(res, struct devres, data); + + list_del_init(&dr->entry); + devres_log(dev, dr, "REM"); + } + + return res; +} + +int devres_destroy(struct udevice *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + void *res; + + res = devres_remove(dev, release, match, match_data); + if (unlikely(!res)) + return -ENOENT; + + devres_free(res); + return 0; +} + +int devres_release(struct udevice *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + void *res; + + res = devres_remove(dev, release, match, match_data); + if (unlikely(!res)) + return -ENOENT; + + (*release)(dev, res); + devres_free(res); + return 0; +} + +static void release_nodes(struct udevice *dev, struct list_head *head, + bool probe_only) +{ + struct devres *dr, *tmp; + + list_for_each_entry_safe_reverse(dr, tmp, head, entry) { + if (probe_only && !dr->probe) + break; + devres_log(dev, dr, "REL"); + dr->release(dev, dr->data); + list_del(&dr->entry); + kfree(dr); + } +} + +void devres_release_probe(struct udevice *dev) +{ + release_nodes(dev, &dev->devres_head, true); +} + +void devres_release_all(struct udevice *dev) +{ + release_nodes(dev, &dev->devres_head, false); +} -- cgit From 2b07f6859ad17b74ce490f371f4878add6ae5a11 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 25 Jul 2015 21:52:36 +0900 Subject: devres: add devm_kmalloc() and friends (managed memory allocators) devm_kmalloc() is identical to kmalloc() except that the memory allocated with it is managed and will be automatically released when the device is removed/unbound. Likewise for the other variants. Signed-off-by: Masahiro Yamada Acked-by: Simon Glass --- drivers/core/devres.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'drivers/core') diff --git a/drivers/core/devres.c b/drivers/core/devres.c index 49c270c57c..f235c1bcfd 100644 --- a/drivers/core/devres.c +++ b/drivers/core/devres.c @@ -194,3 +194,37 @@ void devres_release_all(struct udevice *dev) { release_nodes(dev, &dev->devres_head, false); } + +/* + * Managed kmalloc/kfree + */ +static void devm_kmalloc_release(struct udevice *dev, void *res) +{ + /* noop */ +} + +static int devm_kmalloc_match(struct udevice *dev, void *res, void *data) +{ + return res == data; +} + +void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp) +{ + void *data; + + data = _devres_alloc(devm_kmalloc_release, size, gfp); + if (unlikely(!data)) + return NULL; + + devres_add(dev, data); + + return data; +} + +void devm_kfree(struct udevice *dev, void *p) +{ + int rc; + + rc = devres_destroy(dev, devm_kmalloc_release, devm_kmalloc_match, p); + WARN_ON(rc); +} -- cgit From e2282d70763ddf06f9b02007445729c841ef4083 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 25 Jul 2015 21:52:37 +0900 Subject: devres: make Devres optional with CONFIG_DEVRES Currently, Devres requires additional 16 byte for each allocation, which is not so insignificant in some cases. Add CONFIG_DEVRES to make this framework optional. If the option is disabled, devres functions fall back to non-managed variants. For example, devres_alloc() to kzalloc(), devm_kmalloc() to kmalloc(), etc. Because devres_head is also surrounded by an ifdef conditional, there is no memory overhead when CONFIG_DEVRES is disabled. Signed-off-by: Masahiro Yamada Suggested-by: Simon Glass Acked-by: Simon Glass --- drivers/core/Kconfig | 15 ++++++++++++++- drivers/core/Makefile | 3 ++- drivers/core/device.c | 2 ++ 3 files changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers/core') diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index a002d69d79..8ae0072aa9 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -79,9 +79,22 @@ config SYSCON by this uclass, including accessing registers via regmap and assigning a unique number to each. +config DEVRES + bool "Managed device resources" + depends on DM + help + This option enables the Managed device resources core support. + Device resources managed by the devres framework are automatically + released whether initialization fails half-way or the device gets + detached. + + If this option is disabled, devres functions fall back to + non-managed variants. For example, devres_alloc() to kzalloc(), + devm_kmalloc() to kmalloc(), etc. + config DEBUG_DEVRES bool "Managed device resources verbose debug messages" - depends on DM + depends on DEVRES help If this option is enabled, devres debug messages are printed. Select this if you are having a problem with devres or want to diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 260833e8ee..ccc2fd4e21 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -4,7 +4,8 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y += device.o lists.o root.o uclass.o util.o devres.o +obj-y += device.o lists.o root.o uclass.o util.o +obj-$(CONFIG_DEVRES) += devres.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_OF_CONTROL) += simple-bus.o endif diff --git a/drivers/core/device.c b/drivers/core/device.c index e3a42dc928..caaf231921 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -47,7 +47,9 @@ int device_bind(struct udevice *parent, const struct driver *drv, INIT_LIST_HEAD(&dev->sibling_node); INIT_LIST_HEAD(&dev->child_head); INIT_LIST_HEAD(&dev->uclass_node); +#ifdef CONFIG_DEVRES INIT_LIST_HEAD(&dev->devres_head); +#endif dev->platdata = platdata; dev->name = name; dev->of_offset = of_offset; -- cgit From 40b6f2d020ca8074ed38a1b6bfa170aead1a170e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 25 Jul 2015 21:52:38 +0900 Subject: devres: add debug command to dump device resources This new command can dump all device resources associated to each device. The fields in every line shows: - The address of the resource - The size of the resource - The name of the release function - The stage in which the resource has been acquired (BIND/PROBE) Currently, there is no driver using devres, but if such drivers are implemented, the output of this command should look like this: => dm devres - root_driver - soc - extbus - serial@54006800 bfb541e8 (8 byte) devm_kmalloc_release BIND bfb54440 (4 byte) devm_kmalloc_release PROBE bfb54460 (4 byte) devm_kmalloc_release PROBE - serial@54006900 bfb54270 (8 byte) devm_kmalloc_release BIND - gpio@55000000 - i2c@58780000 bfb5bce8 (12 byte) devm_kmalloc_release PROBE bfb5bd10 (4 byte) devm_kmalloc_release PROBE - eeprom bfb54418 (12 byte) devm_kmalloc_release BIND Signed-off-by: Masahiro Yamada Acked-by: Simon Glass --- drivers/core/Kconfig | 3 ++- drivers/core/devres.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'drivers/core') diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 8ae0072aa9..c82b5645cd 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -93,10 +93,11 @@ config DEVRES devm_kmalloc() to kmalloc(), etc. config DEBUG_DEVRES - bool "Managed device resources verbose debug messages" + bool "Managed device resources debugging functions" depends on DEVRES help If this option is enabled, devres debug messages are printed. + Also, a function is available to dump a list of device resources. Select this if you are having a problem with devres or want to debug resource management for a managed device. diff --git a/drivers/core/devres.c b/drivers/core/devres.c index f235c1bcfd..605295bd14 100644 --- a/drivers/core/devres.c +++ b/drivers/core/devres.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include /** * struct devres - Bookkeeping info for managed device resource @@ -195,6 +197,33 @@ void devres_release_all(struct udevice *dev) release_nodes(dev, &dev->devres_head, false); } +#ifdef CONFIG_DEBUG_DEVRES +static void dump_resources(struct udevice *dev, int depth) +{ + struct devres *dr; + struct udevice *child; + + printf("- %s\n", dev->name); + + list_for_each_entry(dr, &dev->devres_head, entry) + printf(" %p (%lu byte) %s %s\n", dr, + (unsigned long)dr->size, dr->name, + dr->probe ? "PROBE" : "BIND"); + + list_for_each_entry(child, &dev->child_head, sibling_node) + dump_resources(child, depth + 1); +} + +void dm_dump_devres(void) +{ + struct udevice *root; + + root = dm_root(); + if (root) + dump_resources(root, 0); +} +#endif + /* * Managed kmalloc/kfree */ -- cgit From f5c67ea036be174f75cb48b8f91894bc710811dd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 30 Jul 2015 13:40:39 -0600 Subject: dm: core: Add a way to set a device name Some devices are bound entirely by probing and do not have the benefit of a device tree to give them a name. This is very common with PCI and USB. In most cases this is fine, but we should add an official way to set a device name. This should be called in the device's bind() method. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/core/device.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/core') diff --git a/drivers/core/device.c b/drivers/core/device.c index caaf231921..bbe7a94f2a 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -603,3 +603,13 @@ bool device_is_last_sibling(struct udevice *dev) return false; return list_is_last(&dev->sibling_node, &parent->child_head); } + +int device_set_name(struct udevice *dev, const char *name) +{ + name = strdup(name); + if (!name) + return -ENOMEM; + dev->name = name; + + return 0; +} -- cgit