AnsweredAssumed Answered

iMX28 USB wakeup interrupt stops waking platform after kernel "nobody cared" IRQ event

Question asked by Bruno De Paoli on Sep 30, 2016
Latest reply on Oct 5, 2016 by Yuri Muhin

We have an imx28-based platform (The BSP is based on the Freescale Linux kernel 2.6.35) with power-management enabled and is configured to wake up from suspend on USB interrupts. The works correctly but after some time the interrupts stops waking up the platform and this coincides with a "nobody cared" IRQ event for IRQ 94 (USB wakeup). The interrupt is disabled at this point and so the platform no longer wakes up. This event is random and can take quite a while to happen.  I've attached the stack trace that the kernel dumps out when this happens.

 

What seems to be happening (based on the stack trace) is that the platform gets a USB wakeup interrupt while it is in the process of suspending and sometimes this results in the "nobody cared" event. After some digging it seems that the wakeup irq handler (in usb_wakeup.c) checks for the value of a usb-specific flag (lowpower defined in fsl_usb2_platform_data ) and if this is not set it then returns status indicating that the IRQ is not handled, leading to the "nobody card" stack dump. This flag is set on suspend and cleared on resume.

 

I've seen the following code in the function ehci_fsl_drv_suspend in the file ehci-arc.c

 

/* clear the W1C bits */
    pdata->pm_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS);

 

    /* clear PHCD bit */
    pdata->pm_portsc &= ~PORT_PTS_PHCD;


    usb_host_set_wakeup(hcd->self.controller, true);
    fsl_usb_lowpower_mode(pdata, true);

 

    if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
        clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
        fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
    }
    printk(KERN_DEBUG "host suspend ends\n");
    return 0;

 

The functions in red are the important ones here. "usb_host_set_wakeup" enables the wakeup interrupt while "fsl_usb_lowpower_mode" sets the lowpower flag. The order of these calls seems the wrong way around as the interrupt is enabled just before the flag is set and this can create a small window where the interrupt can trigger but the flag is still clear, and could explain the problem I am seeing. This also hangs together with the stack trace since the trace shows that the problem happens in  "_phy_lowpower_suspend" which is called by the function fsl_usb_lowpower_mode.

You would think that the flag should be set first and then the interrupt enabled.

 

Does this make sense? Has anyone seen this issue before? I've looked around but could not find a mention or any fix.

 

Thanks,

Bruno

Original Attachment has been moved to: usb_wakeup_log.txt.zip

Outcomes