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>
This commit is contained in:
Simon Glass 2023-01-17 10:47:12 -07:00 committed by Tom Rini
parent c0f19fedaa
commit 3d01254140
5 changed files with 114 additions and 12 deletions

View file

@ -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, static int do_dm_dump_tree(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]) char *const argv[])
{ {
dm_dump_tree(); bool sort;
sort = argc > 1 && !strcmp(argv[1], "-s");
dm_dump_tree(sort);
return 0; return 0;
} }
@ -87,7 +91,7 @@ static char dm_help_text[] =
"dm drivers Dump list of drivers with uclass and instances\n" "dm drivers Dump list of drivers with uclass and instances\n"
DM_MEM_HELP DM_MEM_HELP
"dm static Dump list of drivers with static platform data\n" "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" "dm uclass Dump list of instances for each uclass"
; ;
#endif #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), U_BOOT_SUBCMD_MKENT(drivers, 1, 1, do_dm_dump_drivers),
DM_MEM DM_MEM
U_BOOT_SUBCMD_MKENT(static, 1, 1, do_dm_dump_static_driver_info), 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)); U_BOOT_SUBCMD_MKENT(uclass, 1, 1, do_dm_dump_uclass));

View file

@ -12,7 +12,7 @@ Synopis
dm devres dm devres
dm drivers dm drivers
dm static dm static
dm tree dm tree [-s]
dm uclass dm uclass
Description Description
@ -123,6 +123,9 @@ Name
Shows the device name as well as the tree structure, since child devices are Shows the device name as well as the tree structure, since child devices are
shown attached to their parent. 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 dm uclass
~~~~~~~~~ ~~~~~~~~~

View file

@ -5,12 +5,34 @@
#include <common.h> #include <common.h>
#include <dm.h> #include <dm.h>
#include <malloc.h>
#include <mapmem.h> #include <mapmem.h>
#include <sort.h>
#include <dm/root.h> #include <dm/root.h>
#include <dm/util.h> #include <dm/util.h>
#include <dm/uclass-internal.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; int i, is_last;
struct udevice *child; struct udevice *child;
@ -39,21 +61,52 @@ static void show_devices(struct udevice *dev, int depth, int last_flag)
printf("%s\n", dev->name); printf("%s\n", dev->name);
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) { device_foreach_child(child, dev) {
is_last = list_is_last(&child->sibling_node, &dev->child_head); is_last = list_is_last(&child->sibling_node,
show_devices(child, depth + 1, (last_flag << 1) | is_last); &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; struct udevice *root;
root = dm_root(); root = dm_root();
if (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(" Class Index Probed Driver Name\n");
printf("-----------------------------------------------------------\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);
} }
} }

View file

@ -26,8 +26,12 @@ struct list_head;
*/ */
int list_count_items(struct list_head *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 */ /* Dump out a list of uclasses and their devices */
void dm_dump_uclass(void); void dm_dump_uclass(void);

View file

@ -16,6 +16,44 @@ def test_dm_compat(u_boot_console):
for driver in drivers: for driver in drivers:
assert driver in response 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') @pytest.mark.buildconfigspec('cmd_dm')
def test_dm_drivers(u_boot_console): def test_dm_drivers(u_boot_console):
"""Test that each driver in `dm compat` is also listed in `dm drivers`.""" """Test that each driver in `dm compat` is also listed in `dm drivers`."""