From 2dd6acb795962638cf57dd5e1248dd30588ae7a7 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 29 Sep 2021 18:04:39 +0300 Subject: net: introduce a helper to determine whether to use in-band autoneg Certain serial SERDES protocols like 1000base-x, 2500base-x, SGMII, USXGMII can operate either in a mode where the PHY (be it on-board or inside an SFP module) passes the link parameters (speed, duplex, pause) to the MAC through in-band through control words standardized by IEEE 802.3 clause 37, or in a mode where the MAC must configure (force) its link parameters based on information obtained out-of-band (MDIO reads, guesswork etc). In Linux, the OF node property named "managed" is parsed by the phylink framework, and the convention is that if a driver uses phylink, then the presence of this property means that in-band autoneg should be enabled, otherwise it shouldn't. To be compatible with the OF node bindings of drivers that use phylink in Linux, introduce parsing support for this property in U-Boot too. Signed-off-by: Vladimir Oltean Reviewed-by: Ramon Fried Reviewed-by: Bin Meng Reviewed-by: Ramon Fried --- drivers/core/of_extra.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/core') diff --git a/drivers/core/of_extra.c b/drivers/core/of_extra.c index 632a1c2210e..59ce9174ad0 100644 --- a/drivers/core/of_extra.c +++ b/drivers/core/of_extra.c @@ -155,3 +155,15 @@ bool ofnode_phy_is_fixed_link(ofnode eth_node, ofnode *phy_node) return true; } + +bool ofnode_eth_uses_inband_aneg(ofnode eth_node) +{ + bool inband_aneg = false; + const char *managed; + + managed = ofnode_read_string(eth_node, "managed"); + if (managed && !strcmp(managed, "in-band-status")) + inband_aneg = true; + + return inband_aneg; +} -- cgit v1.3.1 From 804431830593820575158aa5c4b098aab59efc88 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 23 Oct 2021 17:26:05 -0600 Subject: dm: core: Fix handling of uclass pre_unbind method This method is currently called after the platform data has been freed. But the pre_unbind() method may wish to access this, e.g. to free some data structures stored there. Split the unbinding of devices into two pieces, as is done with removal. This corrects the problem. Also tidy a code-style issue in device_remove() while we are here. Signed-off-by: Simon Glass --- drivers/core/device-remove.c | 9 +++++---- drivers/core/uclass.c | 8 +++++++- include/dm/uclass-internal.h | 14 +++++++++++++- 3 files changed, 25 insertions(+), 6 deletions(-) (limited to 'drivers/core') diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c index 11d3959d20f..69c50da44a9 100644 --- a/drivers/core/device-remove.c +++ b/drivers/core/device-remove.c @@ -95,6 +95,9 @@ int device_unbind(struct udevice *dev) if (ret) return log_msg_ret("child unbind", ret); + ret = uclass_pre_unbind_device(dev); + if (ret) + return log_msg_ret("uc", ret); if (dev_get_flags(dev) & DM_FLAG_ALLOC_PDATA) { free(dev_get_plat(dev)); dev_set_plat(dev, NULL); @@ -142,10 +145,8 @@ void device_free(struct udevice *dev) } if (dev->parent) { size = dev->parent->driver->per_child_auto; - if (!size) { - size = dev->parent->uclass->uc_drv-> - per_child_auto; - } + if (!size) + size = dev->parent->uclass->uc_drv->per_child_auto; if (size) { free(dev_get_parent_priv(dev)); dev_set_parent_priv(dev, NULL); diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index c5a50952fd0..2fede896bfb 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -682,7 +682,7 @@ err: } #if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE) -int uclass_unbind_device(struct udevice *dev) +int uclass_pre_unbind_device(struct udevice *dev) { struct uclass *uc; int ret; @@ -694,7 +694,13 @@ int uclass_unbind_device(struct udevice *dev) return ret; } + return 0; +} + +int uclass_unbind_device(struct udevice *dev) +{ list_del(&dev->uclass_node); + return 0; } #endif diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h index 57c664c6daa..49808c5c856 100644 --- a/include/dm/uclass-internal.h +++ b/include/dm/uclass-internal.h @@ -243,6 +243,17 @@ int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent, */ int uclass_bind_device(struct udevice *dev); +#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE) +/** + * uclass_pre_unbind_device() - Prepare to deassociate device with a uclass + * + * Call any handled needed before uclass_unbind_device() is called + * + * @dev: Pointer to the device + * #return 0 on success, -ve on error + */ +int uclass_pre_unbind_device(struct udevice *dev); + /** * uclass_unbind_device() - Deassociate device with a uclass * @@ -251,9 +262,10 @@ int uclass_bind_device(struct udevice *dev); * @dev: Pointer to the device * #return 0 on success, -ve on error */ -#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE) int uclass_unbind_device(struct udevice *dev); + #else +static inline int uclass_pre_unbind_device(struct udevice *dev) { return 0; } static inline int uclass_unbind_device(struct udevice *dev) { return 0; } #endif -- cgit v1.3.1 From 32c6a8e1f803e2a42fa7bf76f23231736841bfc0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 23 Oct 2021 17:26:06 -0600 Subject: dm: core: Fix up string-function documentation The details for of_property_read_string_helper() and ofnode_read_string_index() are a little inaccurate. Fix up the comments to avoid confusion. Signed-off-by: Simon Glass --- drivers/core/of_access.c | 3 ++- include/dm/ofnode.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/core') diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c index 9960e6b310b..3707143ae66 100644 --- a/drivers/core/of_access.c +++ b/drivers/core/of_access.c @@ -581,7 +581,8 @@ int of_property_match_string(const struct device_node *np, const char *propname, * @propname: name of the property to be searched. * @out_strs: output array of string pointers. * @sz: number of array elements to read. - * @skip: Number of strings to skip over at beginning of list. + * @skip: Number of strings to skip over at beginning of list (cannot be + * negative) * * Don't call this function directly. It is a utility helper for the * of_property_read_string*() family of functions. diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 0f680e5aa62..0eae8f9a813 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -590,11 +590,11 @@ int ofnode_stringlist_search(ofnode node, const char *propname, * * @node: node to check * @propname: name of the property containing the string list - * @index: index of the string to return + * @index: index of the string to return (cannot be negative) * @lenp: return location for the string length or an error code on failure * * @return: - * length of string, if found or -ve error value if not found + * 0 if found or -ve error value if not found */ int ofnode_read_string_index(ofnode node, const char *propname, int index, const char **outp); -- cgit v1.3.1 From 075bfc9575aedca15e61f5f1cfa300409e2979fe Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 23 Oct 2021 17:26:07 -0600 Subject: dm: core: Add a way to obtain a string list At present we support reading a string list a string at a time. Apart from being inefficient, this makes it impossible to separate reading of the devicetree into the of_to_plat() method where it belongs, since any code which needs access to the string must read it from the devicetree. Add a function which returns the string property as an array of pointers to the strings, which is easily used by clients. Signed-off-by: Simon Glass --- drivers/core/ofnode.c | 26 ++++++++++++++++++++++++++ drivers/core/read.c | 6 ++++++ include/dm/ofnode.h | 20 ++++++++++++++++++++ include/dm/read.h | 28 ++++++++++++++++++++++++++++ test/dm/ofnode.c | 20 ++++++++++++++++++++ 5 files changed, 100 insertions(+) (limited to 'drivers/core') diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 08705ef8d99..709bea272a6 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -456,6 +456,32 @@ int ofnode_read_string_count(ofnode node, const char *property) } } +int ofnode_read_string_list(ofnode node, const char *property, + const char ***listp) +{ + const char **prop; + int count; + int i; + + *listp = NULL; + count = ofnode_read_string_count(node, property); + if (count < 0) + return count; + if (!count) + return 0; + + prop = calloc(count + 1, sizeof(char *)); + if (!prop) + return -ENOMEM; + + for (i = 0; i < count; i++) + ofnode_read_string_index(node, property, i, &prop[i]); + prop[count] = NULL; + *listp = prop; + + return count; +} + static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in, struct ofnode_phandle_args *out) { diff --git a/drivers/core/read.c b/drivers/core/read.c index 4307ca45799..31f9e78a062 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -205,6 +205,12 @@ int dev_read_string_count(const struct udevice *dev, const char *propname) return ofnode_read_string_count(dev_ofnode(dev), propname); } +int dev_read_string_list(const struct udevice *dev, const char *propname, + const char ***listp) +{ + return ofnode_read_string_list(dev_ofnode(dev), propname, listp); +} + int dev_read_phandle_with_args(const struct udevice *dev, const char *list_name, const char *cells_name, int cell_count, int index, struct ofnode_phandle_args *out_args) diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 0eae8f9a813..6601bd83189 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -609,6 +609,26 @@ int ofnode_read_string_index(ofnode node, const char *propname, int index, */ int ofnode_read_string_count(ofnode node, const char *property); +/** + * ofnode_read_string_list() - read a list of strings + * + * This produces a list of string pointers with each one pointing to a string + * in the string list. If the property does not exist, it returns {NULL}. + * + * The data is allocated and the caller is reponsible for freeing the return + * value (the list of string pointers). The strings themselves may not be + * changed as they point directly into the devicetree property. + * + * @node: node to check + * @listp: returns an allocated, NULL-terminated list of strings if the return + * value is > 0, else is set to NULL + * @return number of strings in list, 0 if none, -ENOMEM if out of memory, + * -EINVAL if no such property, -EENODATA if property is empty + * @return: NULL-terminated list of strings (NULL if no property or empty) + */ +int ofnode_read_string_list(ofnode node, const char *property, + const char ***listp); + /** * ofnode_parse_phandle_with_args() - Find a node pointed by phandle in a list * diff --git a/include/dm/read.h b/include/dm/read.h index 890bf3d8472..75c6ad6ee49 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -371,6 +371,27 @@ int dev_read_string_index(const struct udevice *dev, const char *propname, * number of strings in the list, or -ve error value if not found */ int dev_read_string_count(const struct udevice *dev, const char *propname); + +/** + * dev_read_string_list() - read a list of strings + * + * This produces a list of string pointers with each one pointing to a string + * in the string list. If the property does not exist, it returns {NULL}. + * + * The data is allocated and the caller is reponsible for freeing the return + * value (the list of string pointers). The strings themselves may not be + * changed as they point directly into the devicetree property. + * + * @dev: device to examine + * @propname: name of the property containing the string list + * @listp: returns an allocated, NULL-terminated list of strings if the return + * value is > 0, else is set to NULL + * @return number of strings in list, 0 if none, -ENOMEM if out of memory, + * -ENOENT if no such property + */ +int dev_read_string_list(const struct udevice *dev, const char *propname, + const char ***listp); + /** * dev_read_phandle_with_args() - Find a node pointed by phandle in a list * @@ -906,6 +927,13 @@ static inline int dev_read_string_count(const struct udevice *dev, return ofnode_read_string_count(dev_ofnode(dev), propname); } +static inline int dev_read_string_list(const struct udevice *dev, + const char *propname, + const char ***listp) +{ + return ofnode_read_string_list(dev_ofnode(dev), propname, listp); +} + static inline int dev_read_phandle_with_args(const struct udevice *dev, const char *list_name, const char *cells_name, int cell_count, int index, struct ofnode_phandle_args *out_args) diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index c72e082983c..5e7c9681c79 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -354,6 +354,7 @@ DM_TEST(dm_test_ofnode_for_each_compatible_node, UT_TESTF_SCAN_FDT); static int dm_test_ofnode_string(struct unit_test_state *uts) { + const char **val; const char *out; ofnode node; @@ -366,6 +367,10 @@ static int dm_test_ofnode_string(struct unit_test_state *uts) ut_asserteq_str("test string", out); ut_asserteq(0, ofnode_stringlist_search(node, "str-value", "test string")); + ut_asserteq(1, ofnode_read_string_list(node, "str-value", &val)); + ut_asserteq_str("test string", val[0]); + ut_assertnull(val[1]); + free(val); /* list of strings */ ut_asserteq(5, ofnode_read_string_count(node, "mux-control-names")); @@ -374,6 +379,15 @@ static int dm_test_ofnode_string(struct unit_test_state *uts) ut_asserteq_str("mux0", out); ut_asserteq(0, ofnode_stringlist_search(node, "mux-control-names", "mux0")); + ut_asserteq(5, ofnode_read_string_list(node, "mux-control-names", + &val)); + ut_asserteq_str("mux0", val[0]); + ut_asserteq_str("mux1", val[1]); + ut_asserteq_str("mux2", val[2]); + ut_asserteq_str("mux3", val[3]); + ut_asserteq_str("mux4", val[4]); + ut_assertnull(val[5]); + free(val); ut_assertok(ofnode_read_string_index(node, "mux-control-names", 4, &out)); @@ -387,6 +401,7 @@ DM_TEST(dm_test_ofnode_string, 0); static int dm_test_ofnode_string_err(struct unit_test_state *uts) { + const char **val; const char *out; ofnode node; @@ -401,16 +416,21 @@ static int dm_test_ofnode_string_err(struct unit_test_state *uts) ut_asserteq(-EINVAL, ofnode_read_string_count(node, "missing")); ut_asserteq(-EINVAL, ofnode_read_string_index(node, "missing", 0, &out)); + ut_asserteq(-EINVAL, ofnode_read_string_list(node, "missing", &val)); /* empty property */ ut_asserteq(-ENODATA, ofnode_read_string_count(node, "bool-value")); ut_asserteq(-ENODATA, ofnode_read_string_index(node, "bool-value", 0, &out)); + ut_asserteq(-ENODATA, ofnode_read_string_list(node, "bool-value", + &val)); /* badly formatted string list */ ut_asserteq(-EILSEQ, ofnode_read_string_count(node, "int64-value")); ut_asserteq(-EILSEQ, ofnode_read_string_index(node, "int64-value", 0, &out)); + ut_asserteq(-EILSEQ, ofnode_read_string_list(node, "int64-value", + &val)); /* out of range / not found */ ut_asserteq(-ENODATA, ofnode_read_string_index(node, "str-value", 1, -- cgit v1.3.1 From 4b030177b6608bc6f2508e023089112e8adb2f4b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 23 Oct 2021 17:26:08 -0600 Subject: dm: core: Allow finding children / uclasses by partial name In some cases it is useful to search just by a partial name, such as when looking for a sibling device that has a common name substring. Add helper functions to handle these requirements. Signed-off-by: Simon Glass --- drivers/core/device.c | 13 ++++++++++--- drivers/core/uclass.c | 9 +++++++-- include/dm/device.h | 12 ++++++++++++ include/dm/uclass.h | 9 +++++++++ 4 files changed, 38 insertions(+), 5 deletions(-) (limited to 'drivers/core') diff --git a/drivers/core/device.c b/drivers/core/device.c index efd07176e37..aed093c2af1 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -902,15 +902,16 @@ int device_find_first_child_by_uclass(const struct udevice *parent, return -ENODEV; } -int device_find_child_by_name(const struct udevice *parent, const char *name, - struct udevice **devp) +int device_find_child_by_namelen(const struct udevice *parent, const char *name, + int len, struct udevice **devp) { struct udevice *dev; *devp = NULL; list_for_each_entry(dev, &parent->child_head, sibling_node) { - if (!strcmp(dev->name, name)) { + if (!strncmp(dev->name, name, len) && + strlen(dev->name) == len) { *devp = dev; return 0; } @@ -919,6 +920,12 @@ int device_find_child_by_name(const struct udevice *parent, const char *name, return -ENODEV; } +int device_find_child_by_name(const struct udevice *parent, const char *name, + struct udevice **devp) +{ + return device_find_child_by_namelen(parent, name, strlen(name), devp); +} + int device_first_child_err(struct udevice *parent, struct udevice **devp) { struct udevice *dev; diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 2fede896bfb..3de5f27fe4a 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -180,20 +180,25 @@ void uclass_set_priv(struct uclass *uc, void *priv) uc->priv_ = priv; } -enum uclass_id uclass_get_by_name(const char *name) +enum uclass_id uclass_get_by_name_len(const char *name, int len) { int i; for (i = 0; i < UCLASS_COUNT; i++) { struct uclass_driver *uc_drv = lists_uclass_lookup(i); - if (uc_drv && !strcmp(uc_drv->name, name)) + if (uc_drv && !strncmp(uc_drv->name, name, len)) return i; } return UCLASS_INVALID; } +enum uclass_id uclass_get_by_name(const char *name) +{ + return uclass_get_by_name_len(name, strlen(name)); +} + int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp) { struct udevice *iter; diff --git a/include/dm/device.h b/include/dm/device.h index 3028d002ab0..daf28a0a457 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -758,6 +758,18 @@ int device_find_first_child_by_uclass(const struct udevice *parent, enum uclass_id uclass_id, struct udevice **devp); +/** + * device_find_child_by_name() - Find a child by device name + * + * @parent: Parent device to search + * @name: Name to look for + * @len: Length of the name + * @devp: Returns device found, if any + * @return 0 if found, else -ENODEV + */ +int device_find_child_by_namelen(const struct udevice *parent, const char *name, + int len, struct udevice **devp); + /** * device_find_child_by_name() - Find a child by device name * diff --git a/include/dm/uclass.h b/include/dm/uclass.h index 15e5f9ef5bc..aea2f34fce1 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -172,6 +172,15 @@ int uclass_get(enum uclass_id key, struct uclass **ucp); */ const char *uclass_get_name(enum uclass_id id); +/** + * uclass_get_by_name() - Look up a uclass by its driver name + * + * @name: Name to look up + * @len: Length of name + * @returns the associated uclass ID, or UCLASS_INVALID if not found + */ +enum uclass_id uclass_get_by_name_len(const char *name, int len); + /** * uclass_get_by_name() - Look up a uclass by its driver name * -- cgit v1.3.1 From 29fe555dec4c18096ab1ddd51398317160359ba1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 23 Oct 2021 17:26:09 -0600 Subject: dm: core: Add a way to count the devices in a uclass Add a function that returns the number of devices in a uclass. This can be helpful in sizing an array that needs to hold a list of them. Signed-off-by: Simon Glass --- drivers/core/uclass.c | 12 ++++++++++++ include/dm/uclass.h | 8 ++++++++ 2 files changed, 20 insertions(+) (limited to 'drivers/core') diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 3de5f27fe4a..2aa21430775 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -794,6 +794,18 @@ int uclass_probe_all(enum uclass_id id) return 0; } +int uclass_id_count(enum uclass_id id) +{ + struct udevice *dev; + struct uclass *uc; + int count = 0; + + uclass_id_foreach_dev(id, dev, uc) + count++; + + return count; +} + UCLASS_DRIVER(nop) = { .id = UCLASS_NOP, .name = "nop", diff --git a/include/dm/uclass.h b/include/dm/uclass.h index aea2f34fce1..f1fd2ba2463 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -425,6 +425,14 @@ int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data, */ int uclass_probe_all(enum uclass_id id); +/** + * uclass_id_count() - Count the number of devices in a uclass + * + * @id: uclass ID to look up + * @return number of devices in that uclass (0 if none) + */ +int uclass_id_count(enum uclass_id id); + /** * uclass_id_foreach_dev() - Helper function to iteration through devices * -- cgit v1.3.1 From af13df7014d7dc78b5461b65de78ca5096e5701c Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 19 Nov 2021 10:02:27 +0100 Subject: dm: add debug message when failed to select the default pinctrl Add a message on probe in driver model core when the default pinctrl selection failed. This message is displayed only when the pinctrl API is implemented, i.e. when result is not ENOSYS. Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass --- drivers/core/device.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/core') diff --git a/drivers/core/device.c b/drivers/core/device.c index aed093c2af1..74374ff881c 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -533,8 +533,12 @@ int device_probe(struct udevice *dev) * is set just above. However, the PCI bus' probe() method and * associated uclass methods have not yet been called. */ - if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL) - pinctrl_select_state(dev, "default"); + if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL) { + ret = pinctrl_select_state(dev, "default"); + if (ret && ret != -ENOSYS) + log_debug("Device '%s' failed to configure default pinctrl: %d (%s)\n", + dev->name, ret, errno_str(ret)); + } if (CONFIG_IS_ENABLED(POWER_DOMAIN) && dev->parent && (device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) && @@ -586,8 +590,12 @@ int device_probe(struct udevice *dev) if (ret) goto fail_uclass; - if (dev->parent && device_get_uclass_id(dev) == UCLASS_PINCTRL) - pinctrl_select_state(dev, "default"); + if (dev->parent && device_get_uclass_id(dev) == UCLASS_PINCTRL) { + ret = pinctrl_select_state(dev, "default"); + if (ret && ret != -ENOSYS) + log_debug("Device '%s' failed to configure default pinctrl: %d (%s)\n", + dev->name, ret, errno_str(ret)); + } return 0; fail_uclass: -- cgit v1.3.1 From fe67ba7418a1d31341a766b3f01833803dcba4f5 Mon Sep 17 00:00:00 2001 From: Alexander Preißner Date: Sat, 6 Nov 2021 02:08:59 +0100 Subject: drivers: core: lists: fix for loop index type * fixes the bug in function bind_drivers_pass that for CONFIG_CC_OPTIMIZE_FOR_SIZE=n and no entries in the driver_info list, i.e. n_ents == 0, the processor steps into the first loop iteration despite the loop condition being false. * the Xilinx Zynq-7000 device would eventually hang due to an attempted access to an invalid memory address * the bug is fixed by changing the type of idx from uint to int Board: zynq-zybo Target: ARM Compiler: arm-none-eabi-gcc 9.2.1 Signed-off-by: Alexander Preissner Acked-by: Simon Glass Tested-by: Simon Glass --- drivers/core/lists.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/core') diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 5d4f2ea0e3a..d2e9dc5719b 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -58,7 +58,7 @@ static int bind_drivers_pass(struct udevice *parent, bool pre_reloc_only) const int n_ents = ll_entry_count(struct driver_info, driver_info); bool missing_parent = false; int result = 0; - uint idx; + int idx; /* * Do one iteration through the driver_info records. For of-platdata, -- cgit v1.3.1 From 6476c4d9818beac88610f18ff3c3cb05c7a1f33b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 16 Dec 2021 20:59:32 -0700 Subject: dm: core: Allow getting some basic stats Add a function that returns some basic stats about driver model. For now we only have two. Signed-off-by: Simon Glass --- drivers/core/device.c | 11 +++++++++++ drivers/core/root.c | 7 +++++++ drivers/core/uclass.c | 13 +++++++++++++ include/dm/device.h | 11 ++++++++++- include/dm/root.h | 8 ++++++++ include/dm/uclass-internal.h | 7 +++++++ test/dm/core.c | 41 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 97 insertions(+), 1 deletion(-) (limited to 'drivers/core') diff --git a/drivers/core/device.c b/drivers/core/device.c index 74374ff881c..4873c47d10b 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -739,6 +739,17 @@ int device_get_child_count(const struct udevice *parent) return count; } +int device_get_decendent_count(const struct udevice *parent) +{ + const struct udevice *dev; + int count = 1; + + list_for_each_entry(dev, &parent->child_head, sibling_node) + count += device_get_decendent_count(dev); + + return count; +} + int device_find_child_by_seq(const struct udevice *parent, int seq, struct udevice **devp) { diff --git a/drivers/core/root.c b/drivers/core/root.c index 26b8195faa3..815173f86eb 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -407,6 +408,12 @@ int dm_init_and_scan(bool pre_reloc_only) return 0; } +void dm_get_stats(int *device_countp, int *uclass_countp) +{ + *device_countp = device_get_decendent_count(gd->dm_root); + *uclass_countp = uclass_get_count(); +} + #ifdef CONFIG_ACPIGEN static int root_acpi_get_name(const struct udevice *dev, char *out_name) { diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 2aa21430775..336ea8d243d 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -643,6 +643,19 @@ int uclass_next_device_check(struct udevice **devp) return device_probe(*devp); } +int uclass_get_count(void) +{ + const struct uclass *uc; + int count = 0; + + if (gd->dm_root) { + list_for_each_entry(uc, gd->uclass_root, sibling_node) + count++; + } + + return count; +} + int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data, struct udevice **devp) { diff --git a/include/dm/device.h b/include/dm/device.h index 544734ecb31..cf785f7ae21 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -593,7 +593,7 @@ int device_get_child(const struct udevice *parent, int index, struct udevice **devp); /** - * device_get_child_count() - Get the available child count of a device + * device_get_child_count() - Get the child count of a device * * Returns the number of children to a device. * @@ -601,6 +601,15 @@ int device_get_child(const struct udevice *parent, int index, */ int device_get_child_count(const struct udevice *parent); +/** + * device_get_decendent_count() - Get the total number of decendents of a device + * + * Returns the total number of decendents, including all children + * + * @parent: Parent device to check + */ +int device_get_decendent_count(const struct udevice *parent); + /** * device_find_child_by_seq() - Find a child device based on a sequence * diff --git a/include/dm/root.h b/include/dm/root.h index 42510b106ab..780f269db65 100644 --- a/include/dm/root.h +++ b/include/dm/root.h @@ -131,4 +131,12 @@ int dm_remove_devices_flags(uint flags); static inline int dm_remove_devices_flags(uint flags) { return 0; } #endif +/** + * dm_get_stats() - Get some stats for driver mode + * + * @device_countp: Returns total number of devices that are bound + * @uclass_countp: Returns total number of uclasses in use + */ +void dm_get_stats(int *device_countp, int *uclass_countp); + #endif diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h index 49808c5c856..fb0edcc2969 100644 --- a/include/dm/uclass-internal.h +++ b/include/dm/uclass-internal.h @@ -306,6 +306,13 @@ int uclass_pre_remove_device(struct udevice *dev); static inline int uclass_pre_remove_device(struct udevice *dev) { return 0; } #endif +/** + * uclass_get_count() - Get the number of uclasses + * + * Returns the number of uclasses instantiated in driver model + */ +int uclass_get_count(void); + /** * uclass_find() - Find uclass by its id * diff --git a/test/dm/core.c b/test/dm/core.c index c9a7606666c..c76dfdb1651 100644 --- a/test/dm/core.c +++ b/test/dm/core.c @@ -307,11 +307,15 @@ static int dm_test_lifecycle(struct unit_test_state *uts) { int op_count[DM_TEST_OP_COUNT]; struct udevice *dev, *test_dev; + int start_dev_count, start_uc_count; + int dev_count, uc_count; int pingret; int ret; memcpy(op_count, dm_testdrv_op_count, sizeof(op_count)); + dm_get_stats(&start_dev_count, &start_uc_count); + ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual, &dev)); ut_assert(dev); @@ -319,6 +323,11 @@ static int dm_test_lifecycle(struct unit_test_state *uts) == op_count[DM_TEST_OP_BIND] + 1); ut_assert(!dev_get_priv(dev)); + /* We should have one more device */ + dm_get_stats(&dev_count, &uc_count); + ut_asserteq(start_dev_count + 1, dev_count); + ut_asserteq(start_uc_count, uc_count); + /* Probe the device - it should fail allocating private data */ uts->force_fail_alloc = 1; ret = device_probe(dev); @@ -353,6 +362,11 @@ static int dm_test_lifecycle(struct unit_test_state *uts) ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_UNBIND]); ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_PRE_UNBIND]); + /* We should have one less device */ + dm_get_stats(&dev_count, &uc_count); + ut_asserteq(start_dev_count, dev_count); + ut_asserteq(start_uc_count, uc_count); + return 0; } DM_TEST(dm_test_lifecycle, UT_TESTF_SCAN_PDATA | UT_TESTF_PROBE_TEST); @@ -526,17 +540,31 @@ DM_TEST(dm_test_leak, 0); /* Test uclass init/destroy methods */ static int dm_test_uclass(struct unit_test_state *uts) { + int dev_count, uc_count; struct uclass *uc; + /* We should have just the root device and uclass */ + dm_get_stats(&dev_count, &uc_count); + ut_asserteq(1, dev_count); + ut_asserteq(1, uc_count); + ut_assertok(uclass_get(UCLASS_TEST, &uc)); ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_INIT]); ut_asserteq(0, dm_testdrv_op_count[DM_TEST_OP_DESTROY]); ut_assert(uclass_get_priv(uc)); + dm_get_stats(&dev_count, &uc_count); + ut_asserteq(1, dev_count); + ut_asserteq(2, uc_count); + ut_assertok(uclass_destroy(uc)); ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_INIT]); ut_asserteq(1, dm_testdrv_op_count[DM_TEST_OP_DESTROY]); + dm_get_stats(&dev_count, &uc_count); + ut_asserteq(1, dev_count); + ut_asserteq(1, uc_count); + return 0; } DM_TEST(dm_test_uclass, 0); @@ -1217,3 +1245,16 @@ static int dm_test_dma_offset(struct unit_test_state *uts) } DM_TEST(dm_test_dma_offset, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); #endif + +/* Test dm_get_stats() */ +static int dm_test_get_stats(struct unit_test_state *uts) +{ + int dev_count, uc_count; + + dm_get_stats(&dev_count, &uc_count); + ut_assert(dev_count > 50); + ut_assert(uc_count > 30); + + return 0; +} +DM_TEST(dm_test_get_stats, UT_TESTF_SCAN_FDT); -- cgit v1.3.1