diff options
author | Tom Rini <trini@konsulko.com> | 2020-01-09 08:52:21 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-01-09 08:52:21 -0500 |
commit | d6b92b9742f125542dd0985976c3a6c560ed40fd (patch) | |
tree | df47458afa5280a80aa6ea789ac4d935aabe64ed | |
parent | a74a2134b245d19a999c796d29285597a22954ed (diff) | |
parent | aaa05deb1283b6beb7334adfa4094fb6bd4ab750 (diff) | |
download | u-boot-d6b92b9742f125542dd0985976c3a6c560ed40fd.tar.gz |
Merge tag 'dm-pull-8jan20' of git://git.denx.de/u-boot-dmWIP/09Jan2020
dm: Increased separation of ofdata_to_platdata() and probe methods
-rw-r--r-- | arch/sandbox/dts/test.dts | 4 | ||||
-rw-r--r-- | arch/x86/cpu/apollolake/p2sb.c | 20 | ||||
-rw-r--r-- | arch/x86/cpu/apollolake/pmc.c | 20 | ||||
-rw-r--r-- | drivers/clk/aspeed/clk_ast2500.c | 4 | ||||
-rw-r--r-- | drivers/core/device-remove.c | 1 | ||||
-rw-r--r-- | drivers/core/device.c | 56 | ||||
-rw-r--r-- | drivers/core/devres.c | 57 | ||||
-rw-r--r-- | drivers/core/lists.c | 4 | ||||
-rw-r--r-- | drivers/pci/pci-uclass.c | 13 | ||||
-rw-r--r-- | drivers/usb/gadget/composite.c | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/f_mass_storage.c | 4 | ||||
-rw-r--r-- | drivers/usb/musb-new/musb_core.c | 4 | ||||
-rw-r--r-- | drivers/usb/musb-new/musb_gadget_ep0.c | 2 | ||||
-rw-r--r-- | include/dm/device-internal.h | 16 | ||||
-rw-r--r-- | include/dm/device.h | 259 | ||||
-rw-r--r-- | include/dm/devres.h | 289 | ||||
-rw-r--r-- | include/dm/uclass-id.h | 1 | ||||
-rw-r--r-- | include/fdt_support.h | 1 | ||||
-rw-r--r-- | include/log.h | 16 | ||||
-rw-r--r-- | include/test/test.h | 10 | ||||
-rw-r--r-- | include/test/ut.h | 16 | ||||
-rw-r--r-- | test/dm/Makefile | 1 | ||||
-rw-r--r-- | test/dm/devres.c | 186 | ||||
-rw-r--r-- | test/dm/test-fdt.c | 58 | ||||
-rw-r--r-- | test/ut.c | 14 | ||||
-rw-r--r-- | tools/binman/README.entries | 2 | ||||
-rw-r--r-- | tools/binman/etype/u_boot_with_ucode_ptr.py | 2 |
27 files changed, 767 insertions, 297 deletions
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 4ea8fea674..e529c54d8d 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -201,6 +201,10 @@ compatible = "denx,u-boot-fdt-test1"; }; + devres-test { + compatible = "denx,u-boot-devres-test"; + }; + clocks { clk_fixed: clk-fixed { compatible = "fixed-clock"; diff --git a/arch/x86/cpu/apollolake/p2sb.c b/arch/x86/cpu/apollolake/p2sb.c index eb27861b7a..b72f50a627 100644 --- a/arch/x86/cpu/apollolake/p2sb.c +++ b/arch/x86/cpu/apollolake/p2sb.c @@ -106,11 +106,6 @@ int apl_p2sb_ofdata_to_platdata(struct udevice *dev) if (plat->bdf < 0) return log_msg_ret("Cannot get p2sb PCI address", plat->bdf); - } else { - plat->mmio_base = dev_read_addr_pci(dev); - /* Don't set BDF since it should not be used */ - if (!plat->mmio_base || plat->mmio_base == FDT_ADDR_T_NONE) - return -EINVAL; } #else plat->mmio_base = plat->dtplat.early_regs[0]; @@ -124,10 +119,19 @@ int apl_p2sb_ofdata_to_platdata(struct udevice *dev) static int apl_p2sb_probe(struct udevice *dev) { - if (spl_phase() == PHASE_TPL) + if (spl_phase() == PHASE_TPL) { return apl_p2sb_early_init(dev); - else if (spl_phase() == PHASE_SPL) - return apl_p2sb_spl_init(dev); + } else { + struct p2sb_platdata *plat = dev_get_platdata(dev); + + plat->mmio_base = dev_read_addr_pci(dev); + /* Don't set BDF since it should not be used */ + if (!plat->mmio_base || plat->mmio_base == FDT_ADDR_T_NONE) + return -EINVAL; + + if (spl_phase() == PHASE_SPL) + return apl_p2sb_spl_init(dev); + } return 0; } diff --git a/arch/x86/cpu/apollolake/pmc.c b/arch/x86/cpu/apollolake/pmc.c index 683c6082f2..aec0c8394c 100644 --- a/arch/x86/cpu/apollolake/pmc.c +++ b/arch/x86/cpu/apollolake/pmc.c @@ -119,8 +119,16 @@ int apl_pmc_ofdata_to_uc_platdata(struct udevice *dev) ret = dev_read_u32_array(dev, "early-regs", base, ARRAY_SIZE(base)); if (ret) return log_msg_ret("Missing/short early-regs", ret); - upriv->pmc_bar0 = (void *)base[0]; - upriv->pmc_bar2 = (void *)base[2]; + if (spl_phase() == PHASE_TPL) { + upriv->pmc_bar0 = (void *)base[0]; + upriv->pmc_bar2 = (void *)base[2]; + + /* Since PCI is not enabled, we must get the BDF manually */ + plat->bdf = pci_get_devfn(dev); + if (plat->bdf < 0) + return log_msg_ret("Cannot get PMC PCI address", + plat->bdf); + } upriv->acpi_base = base[4]; /* Since PCI is not enabled, we must get the BDF manually */ @@ -187,8 +195,14 @@ static int enable_pmcbar(struct udevice *dev) static int apl_pmc_probe(struct udevice *dev) { - if (spl_phase() == PHASE_TPL) + if (spl_phase() == PHASE_TPL) { return enable_pmcbar(dev); + } else { + struct acpi_pmc_upriv *upriv = dev_get_uclass_priv(dev); + + upriv->pmc_bar0 = (void *)dm_pci_read_bar32(dev, 0); + upriv->pmc_bar2 = (void *)dm_pci_read_bar32(dev, 2); + } return 0; } diff --git a/drivers/clk/aspeed/clk_ast2500.c b/drivers/clk/aspeed/clk_ast2500.c index 9249cf9cdf..b3a3f3d4dd 100644 --- a/drivers/clk/aspeed/clk_ast2500.c +++ b/drivers/clk/aspeed/clk_ast2500.c @@ -490,7 +490,7 @@ struct clk_ops ast2500_clk_ops = { .enable = ast2500_clk_enable, }; -static int ast2500_clk_probe(struct udevice *dev) +static int ast2500_clk_ofdata_to_platdata(struct udevice *dev) { struct ast2500_clk_priv *priv = dev_get_priv(dev); @@ -525,5 +525,5 @@ U_BOOT_DRIVER(aspeed_ast2500_scu) = { .priv_auto_alloc_size = sizeof(struct ast2500_clk_priv), .ops = &ast2500_clk_ops, .bind = ast2500_clk_bind, - .probe = ast2500_clk_probe, + .ofdata_to_platdata = ast2500_clk_ofdata_to_platdata, }; diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c index 5c8dc4ad70..444e34b492 100644 --- a/drivers/core/device-remove.c +++ b/drivers/core/device-remove.c @@ -140,6 +140,7 @@ void device_free(struct udevice *dev) dev->parent_priv = NULL; } } + dev->flags &= ~DM_FLAG_PLATDATA_VALID; devres_release_probe(dev); } diff --git a/drivers/core/device.c b/drivers/core/device.c index 4e037083a6..9f39218423 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -311,17 +311,16 @@ static void *alloc_priv(int size, uint flags) return priv; } -int device_probe(struct udevice *dev) +int device_ofdata_to_platdata(struct udevice *dev) { const struct driver *drv; int size = 0; int ret; - int seq; if (!dev) return -EINVAL; - if (dev->flags & DM_FLAG_ACTIVATED) + if (dev->flags & DM_FLAG_PLATDATA_VALID) return 0; drv = dev->driver; @@ -346,7 +345,7 @@ int device_probe(struct udevice *dev) } } - /* Ensure all parents are probed */ + /* Allocate parent data for this child */ if (dev->parent) { size = dev->parent->driver->per_child_auto_alloc_size; if (!size) { @@ -360,7 +359,45 @@ int device_probe(struct udevice *dev) goto fail; } } + } + + if (drv->ofdata_to_platdata && + (CONFIG_IS_ENABLED(OF_PLATDATA) || dev_has_of_node(dev))) { + ret = drv->ofdata_to_platdata(dev); + if (ret) + goto fail; + } + + dev->flags |= DM_FLAG_PLATDATA_VALID; + return 0; +fail: + device_free(dev); + + return ret; +} + +int device_probe(struct udevice *dev) +{ + const struct driver *drv; + int ret; + int seq; + + if (!dev) + return -EINVAL; + + if (dev->flags & DM_FLAG_ACTIVATED) + return 0; + + drv = dev->driver; + assert(drv); + + ret = device_ofdata_to_platdata(dev); + if (ret) + goto fail; + + /* Ensure all parents are probed */ + if (dev->parent) { ret = device_probe(dev->parent); if (ret) goto fail; @@ -411,13 +448,6 @@ int device_probe(struct udevice *dev) goto fail; } - if (drv->ofdata_to_platdata && - (CONFIG_IS_ENABLED(OF_PLATDATA) || dev_has_of_node(dev))) { - ret = drv->ofdata_to_platdata(dev); - if (ret) - goto fail; - } - /* Only handle devices that have a valid ofnode */ if (dev_of_valid(dev)) { /* @@ -431,10 +461,8 @@ int device_probe(struct udevice *dev) if (drv->probe) { ret = drv->probe(dev); - if (ret) { - dev->flags &= ~DM_FLAG_ACTIVATED; + if (ret) goto fail; - } } ret = uclass_post_probe_device(dev); diff --git a/drivers/core/devres.c b/drivers/core/devres.c index f2a19ec61b..237b42653c 100644 --- a/drivers/core/devres.c +++ b/drivers/core/devres.c @@ -7,6 +7,8 @@ * Copyright (c) 2006 Tejun Heo <teheo@suse.de> */ +#define LOG_CATEGORY LOGC_DEVRES + #include <common.h> #include <linux/compat.h> #include <linux/kernel.h> @@ -15,12 +17,23 @@ #include <dm/root.h> #include <dm/util.h> +/** enum devres_phase - Shows where resource was allocated + * + * DEVRES_PHASE_BIND: In the bind() method + * DEVRES_PHASE_OFDATA: In the ofdata_to_platdata() method + * DEVRES_PHASE_PROBE: In the probe() method + */ +enum devres_phase { + DEVRES_PHASE_BIND, + DEVRES_PHASE_OFDATA, + DEVRES_PHASE_PROBE, +}; + /** * 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) + * @probe: Show where this resource was allocated * @name: Name of release function * @size: Size of resource data * @data: Resource data @@ -28,7 +41,7 @@ struct devres { struct list_head entry; dr_release_t release; - bool probe; + enum devres_phase phase; #ifdef CONFIG_DEBUG_DEVRES const char *name; size_t size; @@ -46,8 +59,8 @@ static void set_node_dbginfo(struct devres *dr, const char *name, size_t 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); + log_debug("%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) @@ -80,7 +93,7 @@ void devres_free(void *res) if (res) { struct devres *dr = container_of(res, struct devres, data); - BUG_ON(!list_empty(&dr->entry)); + assert_noisy(list_empty(&dr->entry)); kfree(dr); } } @@ -90,8 +103,13 @@ 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; + assert_noisy(list_empty(&dr->entry)); + if (dev->flags & DM_FLAG_PLATDATA_VALID) + dr->phase = DEVRES_PHASE_PROBE; + else if (dev->flags & DM_FLAG_BOUND) + dr->phase = DEVRES_PHASE_OFDATA; + else + dr->phase = DEVRES_PHASE_BIND; list_add_tail(&dr->entry, &dev->devres_head); } @@ -172,12 +190,12 @@ int devres_release(struct udevice *dev, dr_release_t release, } static void release_nodes(struct udevice *dev, struct list_head *head, - bool probe_only) + bool probe_and_ofdata_only) { struct devres *dr, *tmp; list_for_each_entry_safe_reverse(dr, tmp, head, entry) { - if (probe_only && !dr->probe) + if (probe_and_ofdata_only && dr->phase == DEVRES_PHASE_BIND) break; devres_log(dev, dr, "REL"); dr->release(dev, dr->data); @@ -197,6 +215,8 @@ void devres_release_all(struct udevice *dev) } #ifdef CONFIG_DEBUG_DEVRES +static char *const devres_phase_name[] = {"BIND", "OFDATA", "PROBE"}; + static void dump_resources(struct udevice *dev, int depth) { struct devres *dr; @@ -207,7 +227,7 @@ static void dump_resources(struct udevice *dev, int depth) 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"); + devres_phase_name[dr->phase]); list_for_each_entry(child, &dev->child_head, sibling_node) dump_resources(child, depth + 1); @@ -221,6 +241,19 @@ void dm_dump_devres(void) if (root) dump_resources(root, 0); } + +void devres_get_stats(const struct udevice *dev, struct devres_stats *stats) +{ + struct devres *dr; + + stats->allocs = 0; + stats->total_size = 0; + list_for_each_entry(dr, &dev->devres_head, entry) { + stats->allocs++; + stats->total_size += dr->size; + } +} + #endif /* @@ -254,5 +287,5 @@ void devm_kfree(struct udevice *dev, void *p) int rc; rc = devres_destroy(dev, devm_kmalloc_release, devm_kmalloc_match, p); - WARN_ON(rc); + assert_noisy(!rc); } diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 4681b3e5dd..68204c303f 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -176,8 +176,10 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, if (pre_reloc_only) { if (!dm_ofnode_pre_reloc(node) && - !(entry->flags & DM_FLAG_PRE_RELOC)) + !(entry->flags & DM_FLAG_PRE_RELOC)) { + log_debug("Skipping device pre-relocation\n"); return 0; + } } log_debug(" - found match at '%s': '%s' matches '%s'\n", diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 7308f612b6..5be2dfd0bf 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -48,6 +48,19 @@ pci_dev_t dm_pci_get_bdf(struct udevice *dev) struct pci_child_platdata *pplat = dev_get_parent_platdata(dev); struct udevice *bus = dev->parent; + /* + * This error indicates that @dev is a device on an unprobed PCI bus. + * The bus likely has bus=seq == -1, so the PCI_ADD_BUS() macro below + * will produce a bad BDF> + * + * A common cause of this problem is that this function is called in the + * ofdata_to_platdata() method of @dev. Accessing the PCI bus in that + * method is not allowed, since it has not yet been probed. To fix this, + * move that access to the probe() method of @dev instead. + */ + if (!device_active(bus)) + log_err("PCI: Device '%s' on unprobed bus '%s'\n", dev->name, + bus->name); return PCI_ADD_BUS(bus->seq, pplat->devfn); } diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index c98a444245..4a6f4271d5 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1003,7 +1003,11 @@ static void composite_unbind(struct usb_gadget *gadget) * so there's no i/o concurrency that could affect the * state protected by cdev->lock. */ +#ifdef __UBOOT__ + assert_noisy(!cdev->config); +#else BUG_ON(cdev->config); +#endif while (!list_empty(&cdev->configs)) { c = list_first_entry(&cdev->configs, diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 45c7b58eed..c1e6506659 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -390,7 +390,11 @@ static inline int __fsg_is_set(struct fsg_common *common, if (common->fsg) return 1; ERROR(common, "common->fsg is NULL in %s at %u\n", func, line); +#ifdef __UBOOT__ + assert_noisy(false); +#else WARN_ON(1); +#endif return 0; } diff --git a/drivers/usb/musb-new/musb_core.c b/drivers/usb/musb-new/musb_core.c index afea9fbcef..ab5e3aa9d1 100644 --- a/drivers/usb/musb-new/musb_core.c +++ b/drivers/usb/musb-new/musb_core.c @@ -1859,7 +1859,11 @@ allocate_instance(struct device *dev, musb->ctrl_base = mbase; musb->nIrq = -ENODEV; musb->config = config; +#ifdef __UBOOT__ + assert_noisy(musb->config->num_eps <= MUSB_C_NUM_EPS); +#else BUG_ON(musb->config->num_eps > MUSB_C_NUM_EPS); +#endif for (epnum = 0, ep = musb->endpoints; epnum < musb->config->num_eps; epnum++, ep++) { diff --git a/drivers/usb/musb-new/musb_gadget_ep0.c b/drivers/usb/musb-new/musb_gadget_ep0.c index 9835a2e2bf..3ef8fe1373 100644 --- a/drivers/usb/musb-new/musb_gadget_ep0.c +++ b/drivers/usb/musb-new/musb_gadget_ep0.c @@ -882,7 +882,7 @@ finish: default: /* "can't happen" */ - WARN_ON(1); + assert_noisy(false); musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SENDSTALL); musb->ep0_state = MUSB_EP0_STAGE_IDLE; break; diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index ee2b24a62a..294d6c1810 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -84,6 +84,22 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, const struct driver_info *info, struct udevice **devp); /** + * device_ofdata_to_platdata() - Read platform data for a device + * + * Read platform data for a device (typically from the device tree) so that + * the information needed to probe the device is present. + * + * This may cause some others devices to be probed if this one depends on them, + * e.g. a GPIO line will cause a GPIO device to be probed. + * + * All private data associated with the device is allocated. + * + * @dev: Pointer to device to process + * @return 0 if OK, -ve on error + */ +int device_ofdata_to_platdata(struct udevice *dev); + +/** * device_probe() - Probe a device, activating it * * Activate a device so that it is ready for use. All its parents are probed diff --git a/include/dm/device.h b/include/dm/device.h index d7ad9d6728..1138a09149 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -45,6 +45,7 @@ struct driver_info; /* Device name is allocated and should be freed on unbind() */ #define DM_FLAG_NAME_ALLOCED (1 << 7) +/* Device has platform data provided by of-platdata */ #define DM_FLAG_OF_PLATDATA (1 << 8) /* @@ -64,6 +65,9 @@ struct driver_info; /* DM does not enable/disable the power domains corresponding to this device */ #define DM_FLAG_DEFAULT_PD_CTRL_OFF (1 << 11) +/* Driver platdata has been read. Cleared when the device is removed */ +#define DM_FLAG_PLATDATA_VALID (1 << 12) + /* * One or multiple of these flags are passed to device_remove() so that * a selective device removal as specified by the remove-stage and the @@ -716,260 +720,7 @@ static inline bool device_is_on_pci_bus(struct udevice *dev) */ int dm_scan_fdt_dev(struct udevice *dev); -/* device resource management */ -typedef void (*dr_release_t)(struct udevice *dev, void *res); -typedef int (*dr_match_t)(struct udevice *dev, void *res, void *match_data); - -#ifdef CONFIG_DEVRES - -#ifdef CONFIG_DEBUG_DEVRES -void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp, - const char *name); -#define _devres_alloc(release, size, gfp) \ - __devres_alloc(release, size, gfp, #release) -#else -void *_devres_alloc(dr_release_t release, size_t size, gfp_t gfp); -#endif - -/** - * devres_alloc() - Allocate device resource data - * @release: Release function devres will be associated with - * @size: Allocation size - * @gfp: Allocation flags - * - * Allocate devres of @size bytes. The allocated area is associated - * with @release. The returned pointer can be passed to - * other devres_*() functions. - * - * RETURNS: - * Pointer to allocated devres on success, NULL on failure. - */ -#define devres_alloc(release, size, gfp) \ - _devres_alloc(release, size, gfp | __GFP_ZERO) - -/** - * devres_free() - Free device resource data - * @res: Pointer to devres data to free - * - * Free devres created with devres_alloc(). - */ -void devres_free(void *res); - -/** - * devres_add() - Register device resource - * @dev: Device to add resource to - * @res: Resource to register - * - * Register devres @res to @dev. @res should have been allocated - * using devres_alloc(). On driver detach, the associated release - * function will be invoked and devres will be freed automatically. - */ -void devres_add(struct udevice *dev, void *res); - -/** - * devres_find() - Find device resource - * @dev: Device to lookup resource from - * @release: Look for resources associated with this release function - * @match: Match function (optional) - * @match_data: Data for the match function - * - * Find the latest devres of @dev which is associated with @release - * and for which @match returns 1. If @match is NULL, it's considered - * to match all. - * - * @return pointer to found devres, NULL if not found. - */ -void *devres_find(struct udevice *dev, dr_release_t release, - dr_match_t match, void *match_data); - -/** - * devres_get() - Find devres, if non-existent, add one atomically - * @dev: Device to lookup or add devres for - * @new_res: Pointer to new initialized devres to add if not found - * @match: Match function (optional) - * @match_data: Data for the match function - * - * Find the latest devres of @dev which has the same release function - * as @new_res and for which @match return 1. If found, @new_res is - * freed; otherwise, @new_res is added atomically. - * - * @return ointer to found or added devres. - */ -void *devres_get(struct udevice *dev, void *new_res, - dr_match_t match, void *match_data); - -/** - * devres_remove() - Find a device resource and remove it - * @dev: Device to find resource from - * @release: Look for resources associated with this release function - * @match: Match function (optional) - * @match_data: Data for the match function - * - * Find the latest devres of @dev associated with @release and for - * which @match returns 1. If @match is NULL, it's considered to - * match all. If found, the resource is removed atomically and - * returned. - * - * @return ointer to removed devres on success, NULL if not found. - */ -void *devres_remove(struct udevice *dev, dr_release_t release, - dr_match_t match, void *match_data); - -/** - * devres_destroy() - Find a device resource and destroy it - * @dev: Device to find resource from - * @release: Look for resources associated with this release function - * @match: Match function (optional) - * @match_data: Data for the match function - * - * Find the latest devres of @dev associated with @release and for - * which @match returns 1. If @match is NULL, it's considered to - * match all. If found, the resource is removed atomically and freed. - * - * Note that the release function for the resource will not be called, - * only the devres-allocated data will be freed. The caller becomes - * responsible for freeing any other data. - * - * @return 0 if devres is found and freed, -ENOENT if not found. - */ -int devres_destroy(struct udevice *dev, dr_release_t release, - dr_match_t match, void *match_data); - -/** - * devres_release() - Find a device resource and destroy it, calling release - * @dev: Device to find resource from - * @release: Look for resources associated with this release function - * @match: Match function (optional) - * @match_data: Data for the match function - * - * Find the latest devres of @dev associated with @release and for - * which @match returns 1. If @match is NULL, it's considered to - * match all. If found, the resource is removed atomically, the - * release function called and the resource freed. - * - * @return 0 if devres is found and freed, -ENOENT if not found. - */ -int devres_release(struct udevice *dev, dr_release_t release, - dr_match_t match, void *match_data); - -/* managed devm_k.alloc/kfree for device drivers */ -/** - * devm_kmalloc() - Resource-managed kmalloc - * @dev: Device to allocate memory for - * @size: Allocation size - * @gfp: Allocation gfp flags - * - * Managed kmalloc. Memory allocated with this function is - * automatically freed on driver detach. Like all other devres - * resources, guaranteed alignment is unsigned long long. - * - * @return pointer to allocated memory on success, NULL on failure. - */ -void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp); -static inline void *devm_kzalloc(struct udevice *dev, size_t size, gfp_t gfp) -{ - return devm_kmalloc(dev, size, gfp | __GFP_ZERO); -} -static inline void *devm_kmalloc_array(struct udevice *dev, - size_t n, size_t size, gfp_t flags) -{ - if (size != 0 && n > SIZE_MAX / size) - return NULL; - return devm_kmalloc(dev, n * size, flags); -} -static inline void *devm_kcalloc(struct udevice *dev, - size_t n, size_t size, gfp_t flags) -{ - return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO); -} - -/** - * devm_kfree() - Resource-managed kfree - * @dev: Device this memory belongs to - * @ptr: Memory to free - * - * Free memory allocated with devm_kmalloc(). - */ -void devm_kfree(struct udevice *dev, void *ptr); - -#else /* ! CONFIG_DEVRES */ - -static inline void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp) -{ - return kzalloc(size, gfp); -} - -static inline void devres_free(void *res) -{ - kfree(res); -} - -static inline void devres_add(struct udevice *dev, void *res) -{ -} - -static inline void *devres_find(struct udevice *dev, dr_release_t release, - dr_match_t match, void *match_data) -{ - return NULL; -} - -static inline void *devres_get(struct udevice *dev, void *new_res, - dr_match_t match, void *match_data) -{ - return NULL; -} - -static inline void *devres_remove(struct udevice *dev, dr_release_t release, - dr_match_t match, void *match_data) -{ - return NULL; -} - -static inline int devres_destroy(struct udevice *dev, dr_release_t release, - dr_match_t match, void *match_data) -{ - return 0; -} - -static inline int devres_release(struct udevice *dev, dr_release_t release, - dr_match_t match, void *match_data) -{ - return 0; -} - -static inline void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp) -{ - return kmalloc(size, gfp); -} - -static inline void *devm_kzalloc(struct udevice *dev, size_t size, gfp_t gfp) -{ - return kzalloc(size, gfp); -} - -static inline void *devm_kmalloc_array(struct udevice *dev, - size_t n, size_t size, gfp_t flags) -{ - /* TODO: add kmalloc_array() to linux/compat.h */ - if (size != 0 && n > SIZE_MAX / size) - return NULL; - return kmalloc(n * size, flags); -} - -static inline void *devm_kcalloc(struct udevice *dev, - size_t n, size_t size, gfp_t flags) -{ - /* TODO: add kcalloc() to linux/compat.h */ - return kmalloc(n * size, flags | __GFP_ZERO); -} - -static inline void devm_kfree(struct udevice *dev, void *ptr) -{ - kfree(ptr); -} - -#endif /* ! CONFIG_DEVRES */ +#include <dm/devres.h> /* * REVISIT: diff --git a/include/dm/devres.h b/include/dm/devres.h new file mode 100644 index 0000000000..9c69196054 --- /dev/null +++ b/include/dm/devres.h @@ -0,0 +1,289 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * Based on the original work in Linux by + * Copyright (c) 2006 SUSE Linux Products GmbH + * Copyright (c) 2006 Tejun Heo <teheo@suse.de> + * Copyright 2019 Google LLC + */ + +#ifndef _DM_DEVRES_H +#define _DM_DEVRES_H + +/* device resource management */ +typedef void (*dr_release_t)(struct udevice *dev, void *res); +typedef int (*dr_match_t)(struct udevice *dev, void *res, void *match_data); + +/** + * struct devres_stats - Information about devres allocations for a device + * + * @allocs: Number of allocations + * @total_size: Total size of allocations in bytes + */ +struct devres_stats { + int allocs; + int total_size; +}; + +#ifdef CONFIG_DEVRES + +#ifdef CONFIG_DEBUG_DEVRES +void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp, + const char *name); +#define _devres_alloc(release, size, gfp) \ + __devres_alloc(release, size, gfp, #release) +#else +void *_devres_alloc(dr_release_t release, size_t size, gfp_t gfp); +#endif + +/** + * devres_alloc() - Allocate device resource data + * @release: Release function devres will be associated with + * @size: Allocation size + * @gfp: Allocation flags + * + * Allocate devres of @size bytes. The allocated area is associated + * with @release. The returned pointer can be passed to + * other devres_*() functions. + * + * RETURNS: + * Pointer to allocated devres on success, NULL on failure. + */ +#define devres_alloc(release, size, gfp) \ + _devres_alloc(release, size, (gfp) | __GFP_ZERO) + +/** + * devres_free() - Free device resource data + * @res: Pointer to devres data to free + * + * Free devres created with devres_alloc(). + */ +void devres_free(void *res); + +/** + * devres_add() - Register device resource + * @dev: Device to add resource to + * @res: Resource to register + * + * Register devres @res to @dev. @res should have been allocated + * using devres_alloc(). On driver detach, the associated release + * function will be invoked and devres will be freed automatically. + */ +void devres_add(struct udevice *dev, void *res); + +/** + * devres_find() - Find device resource + * @dev: Device to lookup resource from + * @release: Look for resources associated with this release function + * @match: Match function (optional) + * @match_data: Data for the match function + * + * Find the latest devres of @dev which is associated with @release + * and for which @match returns 1. If @match is NULL, it's considered + * to match all. + * + * @return pointer to found devres, NULL if not found. + */ +void *devres_find(struct udevice *dev, dr_release_t release, + dr_match_t match, void *match_data); + +/** + * devres_get() - Find devres, if non-existent, add one atomically + * @dev: Device to lookup or add devres for + * @new_res: Pointer to new initialized devres to add if not found + * @match: Match function (optional) + * @match_data: Data for the match function + * + * Find the latest devres of @dev which has the same release function + * as @new_res and for which @match return 1. If found, @new_res is + * freed; otherwise, @new_res is added atomically. + * + * @return ointer to found or added devres. + */ +void *devres_get(struct udevice *dev, void *new_res, + dr_match_t match, void *match_data); + +/** + * devres_remove() - Find a device resource and remove it + * @dev: Device to find resource from + * @release: Look for resources associated with this release function + * @match: Match function (optional) + * @match_data: Data for the match function + * + * Find the latest devres of @dev associated with @release and for + * which @match returns 1. If @match is NULL, it's considered to + * match all. If found, the resource is removed atomically and + * returned. + * + * @return ointer to removed devres on success, NULL if not found. + */ +void *devres_remove(struct udevice *dev, dr_release_t release, + dr_match_t match, void *match_data); + +/** + * devres_destroy() - Find a device resource and destroy it + * @dev: Device to find resource from + * @release: Look for resources associated with this release function + * @match: Match function (optional) + * @match_data: Data for the match function + * + * Find the latest devres of @dev associated with @release and for + * which @match returns 1. If @match is NULL, it's considered to + * match all. If found, the resource is removed atomically and freed. + * + * Note that the release function for the resource will not be called, + * only the devres-allocated data will be freed. The caller becomes + * responsible for freeing any other data. + * + * @return 0 if devres is found and freed, -ENOENT if not found. + */ +int devres_destroy(struct udevice *dev, dr_release_t release, + dr_match_t match, void *match_data); + +/** + * devres_release() - Find a device resource and destroy it, calling release + * @dev: Device to find resource from + * @release: Look for resources associated with this release function + * @match: Match function (optional) + * @match_data: Data for the match function + * + * Find the latest devres of @dev associated with @release and for + * which @match returns 1. If @match is NULL, it's considered to + * match all. If found, the resource is removed atomically, the + * release function called and the resource freed. + * + * @return 0 if devres is found and freed, -ENOENT if not found. + */ +int devres_release(struct udevice *dev, dr_release_t release, + dr_match_t match, void *match_data); + +/* managed devm_k.alloc/kfree for device drivers */ +/** + * devm_kmalloc() - Resource-managed kmalloc + * @dev: Device to allocate memory for + * @size: Allocation size + * @gfp: Allocation gfp flags + * + * Managed kmalloc. Memory allocated with this function is + * automatically freed on driver detach. Like all other devres + * resources, guaranteed alignment is unsigned long long. + * + * @return pointer to allocated memory on success, NULL on failure. + */ +void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp); +static inline void *devm_kzalloc(struct udevice *dev, size_t size, gfp_t gfp) +{ + return devm_kmalloc(dev, size, gfp | __GFP_ZERO); +} + +static inline void *devm_kmalloc_array(struct udevice *dev, + size_t n, size_t size, gfp_t flags) +{ + if (size != 0 && n > SIZE_MAX / size) + return NULL; + return devm_kmalloc(dev, n * size, flags); +} + +static inline void *devm_kcalloc(struct udevice *dev, + size_t n, size_t size, gfp_t flags) +{ + return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO); +} + +/** + * devm_kfree() - Resource-managed kfree + * @dev: Device this memory belongs to + * @ptr: Memory to free + * + * Free memory allocated with devm_kmalloc(). + */ +void devm_kfree(struct udevice *dev, void *ptr); + +/* Get basic stats on allocations */ +void devres_get_stats(const struct udevice *dev, struct devres_stats *stats); + +#else /* ! CONFIG_DEVRES */ + +static inline void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp) +{ + return kzalloc(size, gfp); +} + +static inline void devres_free(void *res) +{ + kfree(res); +} + +static inline void devres_add(struct udevice *dev, void *res) +{ +} + +static inline void *devres_find(struct udevice *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + return NULL; +} + +static inline void *devres_get(struct udevice *dev, void *new_res, + dr_match_t match, void *match_data) +{ + return NULL; +} + +static inline void *devres_remove(struct udevice *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + return NULL; +} + +static inline int devres_destroy(struct udevice *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + return 0; +} + +static inline int devres_release(struct udevice *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + return 0; +} + +static inline void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp) +{ + return kmalloc(size, gfp); +} + +static inline void *devm_kzalloc(struct udevice *dev, size_t size, gfp_t gfp) +{ + return kzalloc(size, gfp); +} + +static inline void *devm_kmalloc_array(struct udevice *dev, + size_t n, size_t size, gfp_t flags) +{ + /* TODO: add kmalloc_array() to linux/compat.h */ + if (size != 0 && n > SIZE_MAX / size) + return NULL; + return kmalloc(n * size, flags); +} + +static inline void *devm_kcalloc(struct udevice *dev, + size_t n, size_t size, gfp_t flags) +{ + /* TODO: add kcalloc() to linux/compat.h */ + return kmalloc(n * size, flags | __GFP_ZERO); +} + +static inline void devm_kfree(struct udevice *dev, void *ptr) +{ + kfree(ptr); +} + +static inline void devres_get_stats(const struct udevice *dev, + struct devres_stats *stats) +{ +} + +#endif /* DEVRES */ +#endif /* _DM_DEVRES_H */ diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 67f5d673cb..598f65ea7a 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -19,6 +19,7 @@ enum uclass_id { UCLASS_TEST_BUS, UCLASS_TEST_PROBE, UCLASS_TEST_DUMMY, + UCLASS_TEST_DEVRES, UCLASS_SPI_EMUL, /* sandbox SPI device emulator */ UCLASS_I2C_EMUL, /* sandbox I2C device emulator */ UCLASS_I2C_EMUL_PARENT, /* parent for I2C device emulators */ diff --git a/include/fdt_support.h b/include/fdt_support.h index 2286ea7793..3f4bc643d4 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -9,6 +9,7 @@ #ifdef CONFIG_OF_LIBFDT +#include <asm/u-boot.h> #include <linux/libfdt.h> u32 fdt_getprop_u32_default_node(const void *fdt, int off, int cell, diff --git a/include/log.h b/include/log.h index d8f18a6afd..62fb8afbd0 100644 --- a/include/log.h +++ b/include/log.h @@ -9,6 +9,7 @@ #ifndef __LOG_H #define __LOG_H +#include <command.h> #include <dm/uclass-id.h> #include <linux/list.h> @@ -49,6 +50,7 @@ enum log_category_t { LOGC_ALLOC, /* Memory allocation */ LOGC_SANDBOX, /* Related to the sandbox board */ LOGC_BLOBLIST, /* Bloblist */ + LOGC_DEVRES, /* Device resources (devres_... functions) */ LOGC_COUNT, /* Number of log categories */ LOGC_END, /* Sentinel value for a list of log categories */ @@ -218,6 +220,20 @@ void __assert_fail(const char *assertion, const char *file, unsigned int line, ({ if (!(x) && _DEBUG) \ __assert_fail(#x, __FILE__, __LINE__, __func__); }) +/* + * This one actually gets compiled in even without DEBUG. It doesn't include the + * full pathname as it may be huge. Only use this when the user should be + * warning, similar to BUG_ON() in linux. + * + * @return true if assertion succeeded (condition is true), else false + */ +#define assert_noisy(x) \ + ({ bool _val = (x); \ + if (!_val) \ + __assert_fail(#x, "?", __LINE__, __func__); \ + _val; \ + }) + #if CONFIG_IS_ENABLED(LOG) && defined(CONFIG_LOG_ERROR_RETURN) /* * Log an error return value, possibly with a message. Usage: diff --git a/include/test/test.h b/include/test/test.h index 98fbcd11f6..e5bef4759a 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -46,5 +46,15 @@ struct unit_test { .func = _name, \ } +/* Sizes for devres tests */ +enum { + TEST_DEVRES_SIZE = 100, + TEST_DEVRES_COUNT = 10, + TEST_DEVRES_TOTAL = TEST_DEVRES_SIZE * TEST_DEVRES_COUNT, + + /* A few different sizes */ + TEST_DEVRES_SIZE2 = 15, + TEST_DEVRES_SIZE3 = 37, +}; #endif /* __TEST_TEST_H */ diff --git a/include/test/ut.h b/include/test/ut.h index fbfde10719..f616c202f3 100644 --- a/include/test/ut.h +++ b/include/test/ut.h @@ -149,4 +149,20 @@ void ut_failf(struct unit_test_state *uts, const char *fname, int line, /* Assert that an operation succeeds (returns 0) */ #define ut_assertok(cond) ut_asserteq(0, cond) +/** + * ut_check_free() - Return the number of bytes free in the malloc() pool + * + * @return bytes free + */ +ulong ut_check_free(void); + +/** + * ut_check_delta() - Return the number of bytes allocated/freed + * + * @last: Last value from ut_check_free + * @return free memory delta from @last; positive means more memory has been + * allocated, negative means less has been allocated (i.e. some is freed) + */ +long ut_check_delta(ulong last); + #endif diff --git a/test/dm/Makefile b/test/dm/Makefile index 201e2b093c..dd1ceff86c 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_BLK) += blk.o obj-$(CONFIG_BOARD) += board.o obj-$(CONFIG_DM_BOOTCOUNT) += bootcount.o obj-$(CONFIG_CLK) += clk.o clk_ccf.o +obj-$(CONFIG_DEVRES) += devres.o obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi_host.o obj-$(CONFIG_DM_ETH) += eth.o obj-$(CONFIG_FIRMWARE) += firmware.o diff --git a/test/dm/devres.c b/test/dm/devres.c new file mode 100644 index 0000000000..e7331897de --- /dev/null +++ b/test/dm/devres.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Tests for the devres ( + * + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <errno.h> +#include <dm.h> +#include <malloc.h> +#include <dm/device-internal.h> +#include <dm/test.h> +#include <dm/uclass-internal.h> +#include <test/ut.h> + +/* Test that devm_kmalloc() allocates memory, free when device is removed */ +static int dm_test_devres_alloc(struct unit_test_state *uts) +{ + ulong mem_start, mem_dev, mem_kmalloc; + struct udevice *dev; + void *ptr; + + mem_start = ut_check_delta(0); + ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev)); + mem_dev = ut_check_delta(mem_start); + ut_assert(mem_dev > 0); + + /* This should increase allocated memory */ + ptr = devm_kmalloc(dev, TEST_DEVRES_SIZE, 0); + ut_assert(ptr != NULL); + mem_kmalloc = ut_check_delta(mem_dev); + ut_assert(mem_kmalloc > 0); + + /* Check that ptr is freed */ + device_remove(dev, DM_REMOVE_NORMAL); + ut_asserteq(0, ut_check_delta(mem_start)); + + return 0; +} +DM_TEST(dm_test_devres_alloc, DM_TESTF_SCAN_PDATA); + +/* Test devm_kfree() can be used to free memory too */ +static int dm_test_devres_free(struct unit_test_state *uts) +{ + ulong mem_start, mem_dev, mem_kmalloc; + struct udevice *dev; + void *ptr; + + mem_start = ut_check_delta(0); + ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev)); + mem_dev = ut_check_delta(mem_start); + ut_assert(mem_dev > 0); + + ptr = devm_kmalloc(dev, TEST_DEVRES_SIZE, 0); + ut_assert(ptr != NULL); + mem_kmalloc = ut_check_delta(mem_dev); + ut_assert(mem_kmalloc > 0); + + /* Free the ptr and check that memory usage goes down */ + devm_kfree(dev, ptr); + ut_assert(ut_check_delta(mem_kmalloc) < 0); + + device_remove(dev, DM_REMOVE_NORMAL); + ut_asserteq(0, ut_check_delta(mem_start)); + + return 0; +} +DM_TEST(dm_test_devres_free, DM_TESTF_SCAN_PDATA); + + +/* Test that kzalloc() returns memory that is zeroed */ +static int dm_test_devres_kzalloc(struct unit_test_state *uts) +{ + struct udevice *dev; + u8 *ptr, val; + int i; + + ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev)); + + ptr = devm_kzalloc(dev, TEST_DEVRES_SIZE, 0); + ut_assert(ptr != NULL); + for (val = 0, i = 0; i < TEST_DEVRES_SIZE; i++) + val |= *ptr; + ut_asserteq(0, val); + + return 0; +} +DM_TEST(dm_test_devres_kzalloc, DM_TESTF_SCAN_PDATA); + +/* Test that devm_kmalloc_array() allocates an array that can be set */ +static int dm_test_devres_kmalloc_array(struct unit_test_state *uts) +{ + ulong mem_start, mem_dev; + struct udevice *dev; + u8 *ptr; + + mem_start = ut_check_delta(0); + ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev)); + mem_dev = ut_check_delta(mem_start); + + ptr = devm_kmalloc_array(dev, TEST_DEVRES_COUNT, TEST_DEVRES_SIZE, 0); + ut_assert(ptr != NULL); + memset(ptr, '\xff', TEST_DEVRES_TOTAL); + ut_assert(ut_check_delta(mem_dev) > 0); + + device_remove(dev, DM_REMOVE_NORMAL); + ut_asserteq(0, ut_check_delta(mem_start)); + + return 0; +} +DM_TEST(dm_test_devres_kmalloc_array, DM_TESTF_SCAN_PDATA); + +/* Test that devm_kcalloc() allocates a zeroed array */ +static int dm_test_devres_kcalloc(struct unit_test_state *uts) +{ + ulong mem_start, mem_dev; + struct udevice *dev; + u8 *ptr, val; + int i; + + mem_start = ut_check_delta(0); + ut_assertok(uclass_first_device_err(UCLASS_TEST, &dev)); + mem_dev = ut_check_delta(mem_start); + ut_assert(mem_dev > 0); + + /* This should increase allocated memory */ + ptr = devm_kcalloc(dev, TEST_DEVRES_SIZE, TEST_DEVRES_COUNT, 0); + ut_assert(ptr != NULL); + ut_assert(ut_check_delta(mem_dev) > 0); + for (val = 0, i = 0; i < TEST_DEVRES_TOTAL; i++) + val |= *ptr; + ut_asserteq(0, val); + + /* Check that ptr is freed */ + device_remove(dev, DM_REMOVE_NORMAL); + ut_asserteq(0, ut_check_delta(mem_start)); + + return 0; +} +DM_TEST(dm_test_devres_kcalloc, DM_TESTF_SCAN_PDATA); + +/* Test devres releases resources automatically as expected */ +static int dm_test_devres_phase(struct unit_test_state *uts) +{ + struct devres_stats stats; + struct udevice *dev; + + /* + * The device is bound already, so find it and check that it has the + * allocation created in the bind() method. + */ + ut_assertok(uclass_find_first_device(UCLASS_TEST_DEVRES, &dev)); + devres_get_stats(dev, &stats); + ut_asserteq(1, stats.allocs); + ut_asserteq(TEST_DEVRES_SIZE, stats.total_size); + + /* Getting platdata should add one allocation */ + ut_assertok(device_ofdata_to_platdata(dev)); + devres_get_stats(dev, &stats); + ut_asserteq(2, stats.allocs); + ut_asserteq(TEST_DEVRES_SIZE + TEST_DEVRES_SIZE3, stats.total_size); + + /* Probing the device should add one allocation */ + ut_assertok(uclass_first_device(UCLASS_TEST_DEVRES, &dev)); + ut_assert(dev != NULL); + devres_get_stats(dev, &stats); + ut_asserteq(3, stats.allocs); + ut_asserteq(TEST_DEVRES_SIZE + TEST_DEVRES_SIZE2 + TEST_DEVRES_SIZE3, + stats.total_size); + + /* Removing the device should drop both those allocations */ + device_remove(dev, DM_REMOVE_NORMAL); + devres_get_stats(dev, &stats); + ut_asserteq(1, stats.allocs); + ut_asserteq(TEST_DEVRES_SIZE, stats.total_size); + + /* Unbinding removes the other. Note this access a freed pointer */ + device_unbind(dev); + devres_get_stats(dev, &stats); + ut_asserteq(0, stats.allocs); + ut_asserteq(0, stats.total_size); + + return 0; +} +DM_TEST(dm_test_devres_phase, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c index 1fb8b5c248..d59c449ce0 100644 --- a/test/dm/test-fdt.c +++ b/test/dm/test-fdt.c @@ -153,6 +153,64 @@ UCLASS_DRIVER(testprobe) = { .flags = DM_UC_FLAG_SEQ_ALIAS, }; +struct dm_testdevres_pdata { + void *ptr; +}; + +struct dm_testdevres_priv { + void *ptr; + void *ptr_ofdata; +}; + +static int testdevres_drv_bind(struct udevice *dev) +{ + struct dm_testdevres_pdata *pdata = dev_get_platdata(dev); + + pdata->ptr = devm_kmalloc(dev, TEST_DEVRES_SIZE, 0); + + return 0; +} + +static int testdevres_drv_ofdata_to_platdata(struct udevice *dev) +{ + struct dm_testdevres_priv *priv = dev_get_priv(dev); + + priv->ptr_ofdata = devm_kmalloc(dev, TEST_DEVRES_SIZE3, 0); + + return 0; +} + +static int testdevres_drv_probe(struct udevice *dev) +{ + struct dm_testdevres_priv *priv = dev_get_priv(dev); + + priv->ptr = devm_kmalloc(dev, TEST_DEVRES_SIZE2, 0); + + return 0; +} + +static const struct udevice_id testdevres_ids[] = { + { .compatible = "denx,u-boot-devres-test" }, + { } +}; + +U_BOOT_DRIVER(testdevres_drv) = { + .name = "testdevres_drv", + .of_match = testdevres_ids, + .id = UCLASS_TEST_DEVRES, + .bind = testdevres_drv_bind, + .ofdata_to_platdata = testdevres_drv_ofdata_to_platdata, + .probe = testdevres_drv_probe, + .platdata_auto_alloc_size = sizeof(struct dm_testdevres_pdata), + .priv_auto_alloc_size = sizeof(struct dm_testdevres_priv), +}; + +UCLASS_DRIVER(testdevres) = { + .name = "testdevres", + .id = UCLASS_TEST_DEVRES, + .flags = DM_UC_FLAG_SEQ_ALIAS, +}; + int dm_check_devices(struct unit_test_state *uts, int num_devices) { struct udevice *dev; @@ -6,6 +6,7 @@ */ #include <common.h> +#include <malloc.h> #include <test/test.h> #include <test/ut.h> @@ -32,3 +33,16 @@ void ut_failf(struct unit_test_state *uts, const char *fname, int line, putc('\n'); uts->fail_count++; } + +ulong ut_check_free(void) +{ + struct mallinfo info = mallinfo(); + + return info.uordblks; +} + +long ut_check_delta(ulong last) +{ + return ut_check_free() - last; +} + diff --git a/tools/binman/README.entries b/tools/binman/README.entries index 0576e63a86..6a816bba6b 100644 --- a/tools/binman/README.entries +++ b/tools/binman/README.entries @@ -971,7 +971,7 @@ Entry: u-boot-with-ucode-ptr: U-Boot with embedded microcode pointer -------------------------------------------------------------------- Properties / Entry arguments: - - filename: Filename of u-boot-nodtb.dtb (default 'u-boot-nodtb.dtb') + - filename: Filename of u-boot-nodtb.bin (default 'u-boot-nodtb.bin') - optional-ucode: boolean property to make microcode optional. If the u-boot.bin image does not include microcode, no error will be generated. diff --git a/tools/binman/etype/u_boot_with_ucode_ptr.py b/tools/binman/etype/u_boot_with_ucode_ptr.py index cb7dbc68db..960a5efeb4 100644 --- a/tools/binman/etype/u_boot_with_ucode_ptr.py +++ b/tools/binman/etype/u_boot_with_ucode_ptr.py @@ -18,7 +18,7 @@ class Entry_u_boot_with_ucode_ptr(Entry_blob): """U-Boot with embedded microcode pointer Properties / Entry arguments: - - filename: Filename of u-boot-nodtb.dtb (default 'u-boot-nodtb.dtb') + - filename: Filename of u-boot-nodtb.bin (default 'u-boot-nodtb.bin') - optional-ucode: boolean property to make microcode optional. If the u-boot.bin image does not include microcode, no error will be generated. |