summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2023-01-17 20:47:12 +0300
committerTom Rini <trini@konsulko.com>2023-01-24 02:11:39 +0300
commit3d01254140fc9e5e900d739cb97bd9fba6aa2b68 (patch)
treef0ab5ee057999c7b07d19beefd3761ddeb6696a8
parentc0f19fedaa742adbe0f4e29e9a956ea05fe22057 (diff)
downloadu-boot-3d01254140fc9e5e900d739cb97bd9fba6aa2b68.tar.xz
dm: core: Support sorting devices with dm tree
Add a -s flag to sort the top-level devices in order of uclass ID. Signed-off-by: Simon Glass <sjg@chromium.org>
-rw-r--r--cmd/dm.c10
-rw-r--r--doc/usage/cmd/dm.rst5
-rw-r--r--drivers/core/dump.c65
-rw-r--r--include/dm/util.h8
-rw-r--r--test/py/tests/test_dm.py38
5 files changed, 114 insertions, 12 deletions
diff --git a/cmd/dm.c b/cmd/dm.c
index 218be85795..979cd36061 100644
--- a/cmd/dm.c
+++ b/cmd/dm.c
@@ -59,7 +59,11 @@ static int do_dm_dump_static_driver_info(struct cmd_tbl *cmdtp, int flag,
static int do_dm_dump_tree(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
- dm_dump_tree();
+ bool sort;
+
+ sort = argc > 1 && !strcmp(argv[1], "-s");
+
+ dm_dump_tree(sort);
return 0;
}
@@ -87,7 +91,7 @@ static char dm_help_text[] =
"dm drivers Dump list of drivers with uclass and instances\n"
DM_MEM_HELP
"dm static Dump list of drivers with static platform data\n"
- "dm tree Dump tree of driver model devices ('*' = activated)\n"
+ "dm tree [-s] Dump tree of driver model devices (-s=sort)\n"
"dm uclass Dump list of instances for each uclass"
;
#endif
@@ -98,5 +102,5 @@ U_BOOT_CMD_WITH_SUBCMDS(dm, "Driver model low level access", dm_help_text,
U_BOOT_SUBCMD_MKENT(drivers, 1, 1, do_dm_dump_drivers),
DM_MEM
U_BOOT_SUBCMD_MKENT(static, 1, 1, do_dm_dump_static_driver_info),
- U_BOOT_SUBCMD_MKENT(tree, 1, 1, do_dm_dump_tree),
+ U_BOOT_SUBCMD_MKENT(tree, 2, 1, do_dm_dump_tree),
U_BOOT_SUBCMD_MKENT(uclass, 1, 1, do_dm_dump_uclass));
diff --git a/doc/usage/cmd/dm.rst b/doc/usage/cmd/dm.rst
index 7bc1962a75..236cd02bd6 100644
--- a/doc/usage/cmd/dm.rst
+++ b/doc/usage/cmd/dm.rst
@@ -12,7 +12,7 @@ Synopis
dm devres
dm drivers
dm static
- dm tree
+ dm tree [-s]
dm uclass
Description
@@ -123,6 +123,9 @@ Name
Shows the device name as well as the tree structure, since child devices are
shown attached to their parent.
+If -s is given, the top-level devices (those which are children of the root
+device) are shown sorted in order of uclass ID, so it is easier to find a
+particular device type.
dm uclass
~~~~~~~~~
diff --git a/drivers/core/dump.c b/drivers/core/dump.c
index 1c1f7e4d30..0c7d2ec4d0 100644
--- a/drivers/core/dump.c
+++ b/drivers/core/dump.c
@@ -5,12 +5,34 @@
#include <common.h>
#include <dm.h>
+#include <malloc.h>
#include <mapmem.h>
+#include <sort.h>
#include <dm/root.h>
#include <dm/util.h>
#include <dm/uclass-internal.h>
-static void show_devices(struct udevice *dev, int depth, int last_flag)
+/**
+ * struct sort_info - information used for sorting
+ *
+ * @dev: List of devices
+ * @alloced: Maximum number of devices in @dev
+ */
+struct sort_info {
+ struct udevice **dev;
+ int size;
+};
+
+static int h_cmp_uclass_id(const void *d1, const void *d2)
+{
+ const struct udevice *const *dev1 = d1;
+ const struct udevice *const *dev2 = d2;
+
+ return device_get_uclass_id(*dev1) - device_get_uclass_id(*dev2);
+}
+
+static void show_devices(struct udevice *dev, int depth, int last_flag,
+ struct udevice **devs)
{
int i, is_last;
struct udevice *child;
@@ -39,21 +61,52 @@ static void show_devices(struct udevice *dev, int depth, int last_flag)
printf("%s\n", dev->name);
- device_foreach_child(child, dev) {
- is_last = list_is_last(&child->sibling_node, &dev->child_head);
- show_devices(child, depth + 1, (last_flag << 1) | is_last);
+ if (devs) {
+ int count;
+ int i;
+
+ count = 0;
+ device_foreach_child(child, dev)
+ devs[count++] = child;
+ qsort(devs, count, sizeof(struct udevice *), h_cmp_uclass_id);
+
+ for (i = 0; i < count; i++) {
+ show_devices(devs[i], depth + 1,
+ (last_flag << 1) | (i == count - 1),
+ devs + count);
+ }
+ } else {
+ device_foreach_child(child, dev) {
+ is_last = list_is_last(&child->sibling_node,
+ &dev->child_head);
+ show_devices(child, depth + 1,
+ (last_flag << 1) | is_last, NULL);
+ }
}
}
-void dm_dump_tree(void)
+void dm_dump_tree(bool sort)
{
struct udevice *root;
root = dm_root();
if (root) {
+ int dev_count, uclasses;
+ struct udevice **devs = NULL;
+
+ dm_get_stats(&dev_count, &uclasses);
+
printf(" Class Index Probed Driver Name\n");
printf("-----------------------------------------------------------\n");
- show_devices(root, -1, 0);
+ if (sort) {
+ devs = calloc(dev_count, sizeof(struct udevice *));
+ if (!devs) {
+ printf("(out of memory)\n");
+ return;
+ }
+ }
+ show_devices(root, -1, 0, devs);
+ free(devs);
}
}
diff --git a/include/dm/util.h b/include/dm/util.h
index e10c6060ce..4bb49e9e8c 100644
--- a/include/dm/util.h
+++ b/include/dm/util.h
@@ -26,8 +26,12 @@ struct list_head;
*/
int list_count_items(struct list_head *head);
-/* Dump out a tree of all devices */
-void dm_dump_tree(void);
+/**
+ * Dump out a tree of all devices
+ *
+ * @sort: Sort by uclass name
+ */
+void dm_dump_tree(bool sort);
/* Dump out a list of uclasses and their devices */
void dm_dump_uclass(void);
diff --git a/test/py/tests/test_dm.py b/test/py/tests/test_dm.py
index ea93061fdf..68d4ea1223 100644
--- a/test/py/tests/test_dm.py
+++ b/test/py/tests/test_dm.py
@@ -16,6 +16,44 @@ def test_dm_compat(u_boot_console):
for driver in drivers:
assert driver in response
+ # check sorting - output looks something like this:
+ # testacpi 0 [ ] testacpi_drv |-- acpi-test
+ # testacpi 1 [ ] testacpi_drv | `-- child
+ # pci_emul_p 1 [ ] pci_emul_parent_drv |-- pci-emul2
+ # pci_emul 5 [ ] sandbox_swap_case_em | `-- emul2@1f,0
+
+ # The number of '| ' and '--' matches indicate the indent level. We start
+ # checking sorting only after UCLASS_AXI_EMUL after which the names should
+ # be sorted.
+
+ response = u_boot_console.run_command('dm tree -s')
+ lines = response.split('\n')[2:]
+ stack = [] # holds where we were up to at the previous indent level
+ prev = '' # uclass name of previous line
+ start = False
+ for line in lines:
+ indent = line.count('| ') + ('--' in line)
+ cur = line.split()[0]
+ if not start:
+ if cur != 'axi_emul':
+ continue
+ start = True
+
+ # Handle going up or down an indent level
+ if indent > len(stack):
+ stack.append(prev)
+ prev = ''
+ elif indent < len(stack):
+ prev = stack.pop()
+
+ # Check that the current uclass name is not alphabetically before the
+ # previous one
+ if 'emul' not in cur and cur < prev:
+ print('indent', cur >= prev, indent, prev, cur, stack)
+ assert cur >= prev
+ prev = cur
+
+
@pytest.mark.buildconfigspec('cmd_dm')
def test_dm_drivers(u_boot_console):
"""Test that each driver in `dm compat` is also listed in `dm drivers`."""