mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-09-28 23:50:26 +09:00
dm: Increased separation of ofdata_to_platdata() and probe methods
-----BEGIN PGP SIGNATURE----- iQFFBAABCgAvFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAl4WGTURHHNqZ0BjaHJv bWl1bS5vcmcACgkQfxc6PpAIreaB9wf+P/DA1udn1JKSL7sGkqzXlWGtC6qTU5eY em6GpotS3BiJx40vvKCYc1LbVbVEwXNKvs0AcxvqTxA+9ZiNAFERjbtmxPaqFUHe +vBcqTkYOSOIoSkWTAK+leqVirfGQULdLhITI7sHoF+37UbsDKlSlHjHQZ4XL9Xn fey1eGNaT+QThJ23GTZtZJAHUzoK870+qUhkqifUdHpvnxOJ/j75/AU7zNYlJJHW 12H3DqeoBRnQU0sPsyY/4Bm0e5+GalYMS9XCcWKxxFqPh7/NQoV7Z7yqvKsm7KXc 2VsZk8D+3lU4486JKpfOeCcdUCfgNPSR35AQwQttzNNc9nfYJRpfxA== =56sP -----END PGP SIGNATURE----- Merge tag 'dm-pull-8jan20' of git://git.denx.de/u-boot-dm dm: Increased separation of ofdata_to_platdata() and probe methods
This commit is contained in:
commit
d6b92b9742
@ -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";
|
||||
|
@ -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)
|
||||
} 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;
|
||||
}
|
||||
|
@ -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);
|
||||
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;
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -140,6 +140,7 @@ void device_free(struct udevice *dev)
|
||||
dev->parent_priv = NULL;
|
||||
}
|
||||
}
|
||||
dev->flags &= ~DM_FLAG_PLATDATA_VALID;
|
||||
|
||||
devres_release_probe(dev);
|
||||
}
|
||||
|
@ -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,11 +461,9 @@ 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);
|
||||
if (ret)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -176,9 +176,11 @@ 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",
|
||||
entry->name, entry->of_match->compatible,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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++) {
|
||||
|
@ -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;
|
||||
|
@ -83,6 +83,22 @@ int device_bind_with_driver_data(struct udevice *parent,
|
||||
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
|
||||
*
|
||||
|
@ -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:
|
||||
|
289
include/dm/devres.h
Normal file
289
include/dm/devres.h
Normal file
@ -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 */
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
186
test/dm/devres.c
Normal file
186
test/dm/devres.c
Normal file
@ -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);
|
@ -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;
|
||||
|
14
test/ut.c
14
test/ut.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user