summaryrefslogtreecommitdiff
path: root/test/dm/core.c
diff options
context:
space:
mode:
authorJanne Grunau <j@jannau.net>2024-11-23 22:44:05 +0100
committerTom Rini <trini@konsulko.com>2024-11-24 15:41:28 -0600
commitdabaa4ae32062cb3f3d995e5c63e6cef54ad079b (patch)
treef6cbd5ae28f1e3d6db7e83ef3ff724d055ddf8f6 /test/dm/core.c
parent544a76bac3393045e86a56cc5dfe2477e437c59b (diff)
dm: Add dm_remove_devices_active() for ordered device removal
This replaces dm_remove_devices_flags() calls in all boot implementations to ensure non vital devices are consistently removed first. All boot implementation except arch/arm/lib/bootm.c currently just call dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL). This can result in crashes when dependencies between devices exists. The driver model's design document describes DM_FLAG_VITAL as "indicates that the device is 'vital' to the operation of other devices". Device removal at boot should follow this. Instead of adding dm_remove_devices_flags() with (DM_REMOVE_ACTIVE_ALL | DM_REMOVE_NON_VITAL) everywhere add dm_remove_devices_active() which does this. Fixes a NULL pointer deref in the apple dart IOMMU driver during EFI boot. The xhci-pci (driver which depends on the IOMMU to work) removes its mapping on removal. This explodes when the IOMMU device was removed first. dm_remove_devices_flags() is kept since it is used for testing of device_remove() calls in dm. Signed-off-by: Janne Grunau <j@jannau.net>
Diffstat (limited to 'test/dm/core.c')
-rw-r--r--test/dm/core.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/test/dm/core.c b/test/dm/core.c
index 7371d3ff426..c59ffc6f611 100644
--- a/test/dm/core.c
+++ b/test/dm/core.c
@@ -999,6 +999,56 @@ static int dm_test_remove_vital(struct unit_test_state *uts)
}
DM_TEST(dm_test_remove_vital, 0);
+/* Test removal of 'active' devices */
+static int dm_test_remove_active(struct unit_test_state *uts)
+{
+ struct udevice *normal, *dma, *vital, *dma_vital;
+
+ /* Skip the behaviour in test_post_probe() */
+ uts->skip_post_probe = 1;
+
+ ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual,
+ &normal));
+ ut_assertnonnull(normal);
+
+ ut_assertok(device_bind_by_name(uts->root, false, &driver_info_act_dma,
+ &dma));
+ ut_assertnonnull(dma);
+
+ ut_assertok(device_bind_by_name(uts->root, false,
+ &driver_info_vital_clk, &vital));
+ ut_assertnonnull(vital);
+
+ ut_assertok(device_bind_by_name(uts->root, false,
+ &driver_info_act_dma_vital_clk,
+ &dma_vital));
+ ut_assertnonnull(dma_vital);
+
+ /* Probe the devices */
+ ut_assertok(device_probe(normal));
+ ut_assertok(device_probe(dma));
+ ut_assertok(device_probe(vital));
+ ut_assertok(device_probe(dma_vital));
+
+ /* Check that devices are active right now */
+ ut_asserteq(true, device_active(normal));
+ ut_asserteq(true, device_active(dma));
+ ut_asserteq(true, device_active(vital));
+ ut_asserteq(true, device_active(dma_vital));
+
+ /* Remove active devices in an ordered way */
+ dm_remove_devices_active();
+
+ /* Check that all devices are inactive right now */
+ ut_asserteq(true, device_active(normal));
+ ut_asserteq(false, device_active(dma));
+ ut_asserteq(true, device_active(vital));
+ ut_asserteq(false, device_active(dma_vital));
+
+ return 0;
+}
+DM_TEST(dm_test_remove_active, 0);
+
static int dm_test_uclass_before_ready(struct unit_test_state *uts)
{
struct uclass *uc;