Pinephone: musb_hdrc driver prevents suspend
The following is an analysis from @bshah (previously posted here !1636 (comment 435448853)):
#############################################################################################################
I did bit more debugging of why or where it seems to be hanging in the musb driver,
- Enable the magic sysrq over serial
- Add the ignore_loglevel in the none image's kernel cmdline
- Reproduce the hang over none image
- Once system is hanged, send the Magic sysrq sequence and
l
key
That would print the backtrace of various active tasks,
Most useful one is,
[ 440.222462] __schedule+0x234/0x6b4
[ 440.225947] schedule+0x50/0xdc
[ 440.229085] schedule_timeout+0xc4/0xfc
[ 440.232915] __wait_for_common+0xd4/0x210
[ 440.236919] wait_for_completion+0x20/0x30
[ 440.241012] __flush_work.isra.0+0x190/0x314
[ 440.245277] flush_delayed_work+0x38/0x60
[ 440.249285] musb_suspend+0x60/0x140
[ 440.252857] platform_pm_suspend+0x30/0x70
[ 440.256949] dpm_run_callback+0x50/0x100
[ 440.260869] __device_suspend+0x104/0x460
[ 440.264872] dpm_suspend+0x10c/0x1e0
[ 440.268443] dpm_suspend_start+0x9c/0xa4
[ 440.272362] suspend_devices_and_enter+0xf0/0x61c
[ 440.277060] pm_suspend+0x324/0x3f8
[ 440.280543] state_store+0x64/0xd0
[ 440.283944] kobj_attr_store+0x1c/0x30
[ 440.287691] sysfs_kf_write+0x48/0x60
[ 440.291349] kernfs_fop_write+0xfc/0x220
[ 440.295270] do_iter_write+0x168/0x1f0
[ 440.299015] vfs_writev+0xb0/0xfc
[ 440.302327] do_writev+0x74/0x130
[ 440.305639] __arm64_sys_writev+0x20/0x30
[ 440.309646] el0_svc_common.constprop.0+0x6c/0x170
[ 440.314431] do_el0_svc+0x24/0x90
[ 440.317742] el0_sync_handler+0x90/0x19c
[ 440.321659] el0_sync+0x158/0x180
Which seems to point that kernel is hanging at the,
static int musb_suspend(struct device *dev)
{
struct musb *musb = dev_to_musb(dev);
unsigned long flags;
int ret;
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
pm_runtime_put_noidle(dev);
return ret;
}
musb_platform_disable(musb);
musb_disable_interrupts(musb);
musb->flush_irq_work = true;
while (flush_delayed_work(&musb->irq_work))
;
musb->flush_irq_work = false;
if (!(musb->ops->quirks & MUSB_PRESERVE_SESSION))
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
WARN_ON(!list_empty(&musb->pending_list));
spin_lock_irqsave(&musb->lock, flags);
if (is_peripheral_active(musb)) {
/* FIXME force disconnect unless we know USB will wake
* the system up quickly enough to respond ...
*/
} else if (is_host_active(musb)) {
/* we know all the children are suspended; sometimes
* they will even be wakeup-enabled.
*/
}
musb_save_context(musb);
spin_unlock_irqrestore(&musb->lock, flags);
return 0;
}
https://megous.com/git/linux/tree/drivers/usb/musb/musb_core.c?h=orange-pi-5.9#n2824
In specific line,
musb->flush_irq_work = true;
while (flush_delayed_work(&musb->irq_work))
;
musb->flush_irq_work = false;
Looking at the source bit more closely,
/*
* Check the musb devctl session bit to determine if we want to
* allow PM runtime for the device. In general, we want to keep things
* active when the session bit is set except after host disconnect.
*
* Only called from musb_irq_work. If this ever needs to get called
* elsewhere, proper locking must be implemented for musb->session.
*/
static void musb_pm_runtime_check_session(struct musb *musb)
This function seems to be the one which schedules the tasks in the work queue, and to me it seems that it is intended behavior that it does not allow suspending when USB is active?
I think this needs further debugging.