raspberrypi / linux

Kernel source tree for Raspberry Pi-provided kernel builds. Issues unrelated to the linux kernel should be posted on the community forum at https://forums.raspberrypi.com/
Other
11.01k stars 4.95k forks source link

dwc2 does not detect host disconnect in device mode with rpi cm4 #5532

Open nicolasb565 opened 1 year ago

nicolasb565 commented 1 year ago

Describe the bug

The dwc2 driver does not detect that the rpi cm4 otg port was disconnected from host. This port is in peripheral mode.

I only see that we get an early suspend interrupt in dwc2_hsotg_irq: dwc2 fe980000.usb: GINTSTS_ErlySusp, otherwise we don't get any interrupts that indicate that usb was disconnected.

This cause issue because when we plug one of our product based on the cm4 into another similar or identical product based on the cm4, it complains about the fact some endpoints are not disabled. Note we use a renesas usb to pcie bridge in our board and maybe it is more picky about that for some reason. Jul 06 17:26:56 inogeni-cam230 kernel: usb 1-1: ERROR: Endpoint drop flag = 0, add flag = 1, and endpoint is not disabled. Jul 06 17:26:56 inogeni-cam230 kernel: xhci_hcd 0000:01:00.0: xhci_fixup_endpoint: Configure endpoint failed: -22

The end result is that our uvc gadget does not work and we can't get video frames.

dwc2 driver should detect straight away that usb was disconnected. There is a piece of code that look for some interupts flags in dwc2_hsotg_irq(): if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) We should either get inside that if condition, or detect the usb disconnect through other means.

What does the documentation for the otg of the rpi cm4 says about detecting disconnect in peripheral mode?

Steps to reproduce the behaviour

Create a uvc gadget on a rpi cm4 and notice that the uvc disconnect event is not raised until a new host is connected. This is because the disable function (uvc_function_disable) of the uvc gadget is not called at disconnection time, but when reconfiguring because we reconnected to the host. @disable: (REQUIRED) Indicates the function should be disabled. Reasons

It would also help to enable debug logs from dwc2 driver, especially the file gadget.c which would report if it detected a disconnect/suspend etc.

Device (s)

Raspberry Pi CM4

System

Yocto Kirkstone with linux 5.15.

Logs

No response

Additional context

No response

notro commented 8 months ago

Possible explanation: https://github.com/raspberrypi/linux/pull/3151#issuecomment-1146570510

Reply from Synopsys about the problem: Re: usb: dwc2: Detecting cable disconnection in OTG mode?

macmpi commented 8 months ago

FWIW, one trick to check connection status is to check /sys/class/udc/*/current_speed for relevant port: it reports UNKNOWN when disconnected.

EDIflyer commented 6 months ago

FWIW, one trick to check connection status is to check /sys/class/udc/*/current_speed for relevant port: it reports UNKNOWN when disconnected.

hmm for me on a Pi Zero W it seems to still just show high-speed regardless or connect or disconnect (similarly is_selfpowered remains 1 and state remains configured.

JeremyBCD commented 6 months ago

Seeing the same problem with RPi4. /sys/class/udc/*/current_speed is expected UNKNOWN on startup with no host connected. Once the host is connected, switches to high-speed as expected. Then, if the device is removed, it remains high-speed.

As a workaround, I found that I can look at /sys/bus/gadget/devices/gadget.0/suspended, and only pay attention to current_speed, etc if the device is not suspended.

EDIflyer commented 6 months ago

Oooh @JeremyBCD that's a very interesting little nugget you've found there! That looks like a usable workaround - the switch of current_speed from UNKNOWN to high-speed indicates initial connection and then thereafter use suspended=1 to identify USB disconnection and 0 to determine reconnection!

JeremyBCD commented 6 months ago

@EDIflyer Yes. Good catch there checking against UNKNOWN, because suspended will be false on startup when there is no connection.

EDIflyer commented 6 months ago

@JeremyBCD just to confirm now up and running using those two folders and able to detect connection/disconnection and trigger appropriate action as a result. Annoyingly watchdog can't monitor /sys folders so just having to poll instead but at least it does the trick!