diff options
Diffstat (limited to 'include')
-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 |
8 files changed, 354 insertions, 254 deletions
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 |