About device_links_purge() warning

From: Xu Yang

Date: Wed May 27 2026 - 02:19:22 EST


Hi,

I meet a kernel warning dump in device_del() -> device_links_purge():

list_for_each_entry_safe_reverse(link, ln, &dev->links.consumers, s_node) {
-> WARN_ON(link->status != DL_STATE_DORMANT &&
link->status != DL_STATE_NONE);
__device_link_del(&link->kref);
}

[ 128.196320] ------------[ cut here ]------------
[ 128.200932] WARNING: drivers/base/core.c:1641 at device_del+0x2b0/0x398, CPU#0: insmod/704
[ 128.209188] Modules linked in: tcpci(+) dwc3_imx8mp(+) overlay snd_soc_fsl_asoc_card phy_fsl_imx8mq_usb snd_soc_imx_audmux mxc_jpeg_encdec tcpm v4l2_jpeg snd_soc_imx_card typec snd_soc_fsl_micfil snd_soc_wm8962 snd_soc_fsl_sai imx_pcm_dma flexcan can_dev snd_soc_fsl_utils pwm_fan fuse
[ 128.234387] CPU: 0 UID: 0 PID: 704 Comm: insmod Not tainted 7.1.0-rc1-00016-g9186b1f497a9-dirty #505 PREEMPT
[ 128.244281] Hardware name: NXP i.MX95 19X19 board (DT)
[ 128.249403] pstate: 20400009 (nzCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 128.256351] pc : device_del+0x2b0/0x398
[ 128.260184] lr : device_del+0x1cc/0x398
[ 128.264014] sp : ffff800082983720
[ 128.267314] x29: ffff800082983750 x28: ffffbbdae88f80e0 x27: 0000000000000000
[ 128.274438] x26: 0000000000000000 x25: ffff800082983cb0 x24: ffff000080a58810
[ 128.281562] x23: 0000000000400100 x22: ffff00008bb65cc8 x21: ffff00008bb65cc0
[ 128.288686] x20: ffffbbdae8ec4c40 x19: ffff00008bb65c10 x18: 0000000000000000
[ 128.295810] x17: 3034303066316334 x16: 3a6d726f6674616c x15: 005708e68a088db3
[ 128.302934] x14: 00000000000001e2 x13: 0000000000000000 x12: 0000000000000022
[ 128.310058] x11: 00000000000000c0 x10: 0000000000000b20 x9 : 000000000000003c
[ 128.317182] x8 : ffff800082983630 x7 : ffff000080001700 x6 : fffffdffc22bd380
[ 128.324306] x5 : ffffbbdae6caef6c x4 : ffff00008ae7c000 x3 : ffff00008af4e1c0
[ 128.331430] x2 : ffff00008bb65cb8 x1 : 0000000000000003 x0 : ffff000093330400
[ 128.338557] Call trace:
[ 128.340993] device_del+0x2b0/0x398 (P)
[ 128.344823] platform_device_del+0x2c/0xa0
[ 128.348913] platform_device_unregister+0x14/0x3c
[ 128.353611] of_platform_device_destroy+0xf0/0x100
[ 128.358392] device_for_each_child_reverse+0x70/0xc8
[ 128.363352] of_platform_depopulate+0x34/0x80
[ 128.367703] dwc3_imx8mp_probe+0x24c/0x3dc [dwc3_imx8mp]
[ 128.373004] platform_probe+0x5c/0xa4
[ 128.376664] really_probe+0x15c/0x384
[ 128.380319] __driver_probe_device+0x1a0/0x1c0
[ 128.384759] driver_probe_device+0x3c/0x11c
[ 128.388936] __driver_attach+0x74/0x1a0
[ 128.392767] bus_for_each_dev+0x7c/0xdc
[ 128.396597] driver_attach+0x24/0x30
[ 128.400168] bus_add_driver+0x138/0x2ac
[ 128.403996] driver_register+0x68/0x130
[ 128.407829] __platform_driver_register+0x20/0x2c
[ 128.412527] dwc3_imx8mp_driver_init+0x20/0x1000 [dwc3_imx8mp]
[ 128.418348] do_one_initcall+0x60/0x1d4
[ 128.422181] do_init_module+0x54/0x244
[ 128.425923] load_module+0x16c4/0x1dc0
[ 128.429669] init_module_from_file+0xd8/0xf0
[ 128.433933] __arm64_sys_finit_module+0x1b8/0x334
[ 128.438631] invoke_syscall.constprop.0+0x40/0x108
[ 128.443414] el0_svc_common.constprop.0+0x38/0xd8
[ 128.448112] do_el0_svc+0x1c/0x28
[ 128.451423] el0_svc+0x38/0x140
[ 128.454558] el0t_64_sync_handler+0xa0/0xe4
[ 128.458735] el0t_64_sync+0x198/0x19c
[ 128.462395] ---[ end trace 0000000000000000 ]---

Simply speaking, this happens when a supplier device is removed while a
consumer device is probing, particularly when their modules are loaded
at the same time.

The case as below:

usb@4c010010 {
compatible = "fsl,imx95-dwc3", "fsl,imx8mp-dwc3";

usb@4c100000 {
compatible = "snps,dwc3";

port {
usb3_data_hs: endpoint {
remote-endpoint = <&typec_con_hs>; <---+ (supplier)
}; |
}; |
}; |
}; |
|
tcpc@50 { |
compatible = "nxp,ptn5110", "tcpci"; |
|
connector { |
compatible = "usb-c-connector"; |
|
port { |
typec_con_hs: endpoint { |
remote-endpoint = <&usb3_data_hs>; ----+ (consumer)
};
};
};
};

Node usb@4c010010 will be populated as device 4c010010.usb.
Node usb@4c100000 will be populated as device 4c100000.usb.
Node tcpc@50 will be populated as device 6-0050.

Issue Description:

1. The system adds devices 4c010010.usb and 6-0050 when it parses the OF tree.
2. When the imx8mp-dwc3 module is loaded, device 4c010010.usb gets probed,
then dwc3_imx8mp_probe() populates a child device 4c100000.usb.
3. When 4c100000.usb is added, it creates a device link:
[ 126.021683] i2c 6-0050: Linked as a sync state only consumer to 4c100000.usb
4. During the probing of device 4c010010.usb, tcpci module is loaded, device
6-0050 gets probed, and device_links_check_suppliers() sets the above device
linke status as DL_STATE_CONSUMER_PROBE.
5. Probing device 4c010010.usb encounters an error, then dwc3_imx8mp_probe()
depopulates the child device 4c100000.usb in the cleanup path. However,
tcpci_probe() hasn't finished yet. The warning occurs.

The system doesn't prevent device 6-0050 from being probed because 6-0050
is a sync only consumer of 4c100000.usb.

Any ideas on how to avoid the warning?

Thanks,
Xu Yang