Skip to main content
Visitor II
March 11, 2022
Solved

USB ethernet gadget stops working after replugging cable

  • March 11, 2022
  • 11 replies
  • 6190 views

Not sure if this is the best forum for this question but I am using the USB OTG port in device mode as ethernet gadget. It works fine if plugged in from boot, or first plug in anytime after.

But if unplugged and plugged in again it will not come back without a board reboot:

[ 46.766872] dwc2 49000000.usb-otg: new device is high-speed
[ 46.771014] dwc2 49000000.usb-otg: dwc2_hsotg_enqueue_setup: failed queue (-11)

Error -11 is something like "resource temporarily unavailable". Ever seen this before?

    This topic has been closed for replies.
    Best answer by BillR

    I decided it was time to take the dive into the kernel and then confirmed there is no disconnect interrupt in device mode, only suspend due to no activity on D lines.  

    0693W00000Lvm1AQAR.pngThis isn't a problem on the DK2 I believe because its using the STMUSB1600 which gives disconnected indication. Since we only needed device mode and that chip was not available, we thought it wouldn't be a problem to leave out.

    So, in

    drivers/usb/dwc2/core_intr.c

    we have the following:

    /*
     * Change to L2 (suspend) state before releasing
     * spinlock
     */
    hsotg->lx_state = DWC2_L2;
     
    /* Call gadget suspend callback */
    call_gadget(hsotg, suspend);

    Change to:

    dwc2_hsotg_disconnect(hsotg); 

    I am going to test this next week.

    Bill

    11 replies

    Technical Moderator
    March 17, 2022

    Hi @BillR​ ,

    Yes, it can be due to wrong DTS setting which depends on your software version.

    Can you please share the OpenSTLinux version you are using and kernel dts ?

    Thanks

    Olivier

    Technical Moderator
    March 18, 2022

    Hello @BillR​ ,

    In top of the request of Olivier, I will also need to know the content of your shell script that makes the configuration of USB Gadget.

    Below you have the wiki page with an example script "stm32_usbotg_eth_config.sh" :

    https://wiki.st.com/stm32mpu/wiki/USB_overview#How_to_configure_USB_Gadget_through_configfs

    Can I also have your complete bootlog traces please.

    Regards,

    Kevin

    BillRAuthor
    Visitor II
    March 18, 2022

    Thanks for the responses so far. I am away from the project for a few days and will be getting back to this next week. I did notice that calling the script with stop and then start, it will work again. I'll get back to you with some info soon, thanks!

    BillRAuthor
    Visitor II
    March 22, 2022

    I am using the kernel from OpenSTLinux 5.4 Dunfell 20-06-24.

    Attached is a zip file with kernel config, boot log, shell script, and kernel device tree.

    If I run the script (stm32_usbotg_eth_config.sh) with stop and start, that will restart the RNDIS OK but no udev unplug or plug event is detected so I wouldn't know when to run the script to restart it.

    Thanks!

    BillRAuthor
    Visitor II
    March 24, 2022

    0693W00000Lvct2QAB.pngI don't think I mentioned that we are only using this Type C port as device role. I notice other designs use a USB1600 chip to support dual role for Type C. I don't understand why the driver wouldn't be able to know that the cable gets unplugged, just by the removal of Vbus from the host or something.

    -Bill

    BillRAuthor
    Visitor II
    March 24, 2022

    I compared to a DK2 using udevadm and we see a 'remove' event. I do not get this event on my board.

    root@stm32mp1:~# udevadm monitor -u
    monitor will print the received events for:
    UDEV - the event which udev sends out after rule processing
     
    UDEV [72314.380603] remove /devices/platform/soc/5c002000.i2c/i2c-1/1-0028/typec/port0/port0-partner (typec)
     

    BillRAuthorAnswer
    Visitor II
    March 25, 2022

    I decided it was time to take the dive into the kernel and then confirmed there is no disconnect interrupt in device mode, only suspend due to no activity on D lines.  

    0693W00000Lvm1AQAR.pngThis isn't a problem on the DK2 I believe because its using the STMUSB1600 which gives disconnected indication. Since we only needed device mode and that chip was not available, we thought it wouldn't be a problem to leave out.

    So, in

    drivers/usb/dwc2/core_intr.c

    we have the following:

    /*
     * Change to L2 (suspend) state before releasing
     * spinlock
     */
    hsotg->lx_state = DWC2_L2;
     
    /* Call gadget suspend callback */
    call_gadget(hsotg, suspend);

    Change to:

    dwc2_hsotg_disconnect(hsotg); 

    I am going to test this next week.

    Bill

    BillRAuthor
    Visitor II
    March 30, 2022

    The above kernel patch works but does not completely solve the problem on its own. Also required is a daemon program to poll on:

    /sys/class/udc/49000000.usb-otg/state

    and when it now changes from "configured" to "not attached" (as a result of above kernel patch) that gives the indication to stop and start the script, and then ethernet gadget works fine now.

    /sbin/stm32_usbotg_eth_config.sh stop
    /sbin/stm32_usbotg_eth_config.sh start

    This is the best I can come up with at this time, I don't have time to figure out a more proper kernel-only solution.

    Bill

    Technical Moderator
    April 4, 2022

    Hello @BillR​ ,

    I am not an USB expert, but I think I found something for you.

    You are right, the USB DISC_INT is not available in device mode as explained in the refman.

    But since you are able to detect the suspend operation and call the modified part of code that you made, it is because there is an interrupt.

    in "drivers/usb/dwc2/core_intr.c"

    The function that you changed "dwc2_handle_usb_suspend_intr" is called on an interrupt

    #define GINTSTS_USBSUSP			BIT(11)

    This interrupt is described in the refman v5.0 page 3168: https://www.st.com/resource/en/reference_manual/DM00327659-.pdf

    0693W00000LwqKwQAJ.png 

    And then you can see in the function "dwc2_handle_usb_suspend_intr" that you called your code when the status register "DSTS" has its bit DSTS_SUSPSTS to 1.

    This register is described page 3208 of the refman v5.0:

    0693W00000LwqMEQAZ.png 

    So like the usb driver, you can watch this interrupt and verify the status of the register "DSTS" to know if you need to stop and start your usbotg shell script.

    I think this is cleaner than changing an existing device.

    Hope it helps,

    Regards,

    Kevin

    BillRAuthor
    Visitor II
    April 6, 2022

    Thanks, Kevin.

    I am a little confused though. That suspend interrupt handler is already where I insert the code to act as though its disconnected. 

    Also I'm not sure what you mean by "changing an existing device". 

    Bill

    Technical Moderator
    April 7, 2022

    Hello @BillR​ ,

    I understand that it is confused, my answer was not so clear.

    Yes, you added your code to disconnect the hsotg in the existing driver usb: drivers/usb/dwc2/core_intr.c

    So you modified the usb driver to behave like if it was disconnected when it is suspended.

    Then you made a daemon program that periodically checks the file "/sys/class/udc/49000000.usb-otg/state".

    It works and it is maybe enough for your case.

    But since you asked for a proper way of doing, I think it will be better to do your own kernel module, that configures an Interrupt Service Route (ISR) for the same IRQ (GINTSTS_USBSUSP) and that notifies your daemon process with a signal when you have to stop or start you script shell. Instead of watching for a change on the file "/sys/class/udc/49000000.usb-otg/state".

    Otherwise, your solution is good too :).

    Regards,

    Kevin

    In order to give better visibility on the answered topics, please click on 'Select as Best' on the reply which solved your issue or answered your question. See also 'Best Answers'