This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/AM5718: USB overcurrent issues

Part Number: AM5718
Other Parts Discussed in Thread: DM3730,

Tool/software: Linux

HI everybody ,

I am using a configuration  used in the past on DM3730 and working there .

Now  in my  boards is presents a USB hub, with 2 USB ports, connected to an AM5718 processor; we need to test the USB overcurrent functionality in two different cases:

A - when a generic load is plugged in the USB connector, e.g. a LED lamp
B - when a standard USB device is used

We have these results with Kernel 4.9 rt:

- case A: overcurrent event is not generated
- case B: overcurrent event is correctly generated
- case A in one port and B in the second port: overcurrent event is correctly generated

This behaviour is different from the one we have in one of our boards with the same hardware but for the DM3730 processor with Kernel 2.6.32 where USB OVERCURRENT always occurs.

 thank you very much

regards

Carlo

  • Carlo,

    Please explain how the over current condition is examined.
    Please also post the USB portion of the schematics.

  • Carlo,

    Thanks for sending me the diagram offline.
    Any information such as kernel log showing the over current event is not generated?
  • And has the customer measured the hub downstream port that over current condition does happen when a LED lamp is plugged in?
  • Carlo,

    I haven’t heard back from you, I’m assuming you were able to resolve your issue. If not, just post a reply below (or create a new thread if the thread has locked due to time-out). thanks.
  • Hi Bin ,

    Issue is not cosed  , I m waiting customer currents and be back asap

    please could you suggest anything form schemtics ? plus same configuration was perfect on DM3730  ( many 10Ks sold)

    thank you

    regrads

    Carlo

  • Hi Carlo,

    I think to have resolved this issue by the following patch which deals with USB_PORT_STAT_C_OVERCURRENT event at the "hub level" of the driver (Kernel 4.9.45-rt23).

    Otherwise with the current driver this event (at the "port level) is discharged.

    Alessandro

    --
    drivers/usb/core/hub.c | 11 ++++++++++++++


    diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
    index 80d4ef3..ef4f1f7 100644
    --- a/drivers/usb/core/hub.c
    +++ b/drivers/usb/core/hub.c
    @@ -5167,6 +5168,19 @@ static void hub_event(struct work_struct *work)
    for (i = 1; i <= hdev->maxchild; i++) {
    struct usb_port *port_dev = hub->ports[i - 1];

    + u16 portstatus, portchange;
    + if( hub_port_status(hub, i, &portstatus, &portchange) == 0)
    + {
    + if (portchange & USB_PORT_STAT_C_OVERCURRENT)
    + {
    + usb_clear_port_feature(hdev, i,
    + USB_PORT_FEAT_C_OVER_CURRENT);
    + msleep(100); /* Cool down */
    + hub_power_on(hub, true);
    + }
    + }
    if (test_bit(i, hub->event_bits)
    || test_bit(i, hub->change_bits)
    || test_bit(i, hub->wakeup_bits)) {

  • Alessandro,

    Glad to hear the issue is solved. Thanks for the update.

    I looked at the patch you posted, basically it tries to handle the event in the hub level instead of the port level.
    Have you debugged the driver to understand why the event is not handed in the port level?
  • Hi Bin Liu, I did some debug and what happens is that when an Overcurrent occurs (case A) no hub->event_bits or
    hub->change_bits is raised.

    ---

    drivers/usb/core/hub.c:

    static void hub_event(struct work_struct *work)
    {

    ...
    if (test_bit(i, hub->event_bits)
    || test_bit(i, hub->change_bits)
    || test_bit(i, hub->wakeup_bits)) {
    /*
    * The get_noresume and barrier ensure that if
    * the port was in the process of resuming, we
    * flush that work and keep the port active for
    * the duration of the port_event(). However,
    * if the port is runtime pm suspended
    * (powered-off), we leave it in that state, run
    * an abbreviated port_event(), and move on.
    */
    pm_runtime_get_noresume(&port_dev->dev);
    pm_runtime_barrier(&port_dev->dev);
    usb_lock_port(port_dev);
    port_event(hub, i);
    usb_unlock_port(port_dev);
    pm_runtime_put_sync(&port_dev->dev);
    }
    ---

    so port_event() is never called and consequently hub_port_status() is not enquired so that
    not reading wPortChange the C_PORT_OVER_CURRENT is not handled.
    The reason why event_bits or change_bits don't change their status it is obscure to me,
    this should be done at irq level anyway ... May be it depends on DCW3 IP ?

    I would like to find an explanation to this behavior in order to be sure of my patch.

    Thanks

    to

  • Hi Alessandro,

    The host receives the hub port status through a SETUP transaction on endpoint0, so I don't think it has anything to do with the DWC3 IP. But I haven't examined the hub driver and am unable to explain why hub->change_bits is not set when the overcurrent condition happened.

    Maybe you could put some printk() in hub.c on the working DM3730 platform to compare the same test with AM57x to see why hub->change_bits is not set.

    I think it is okay to retrieve the port status and handle the overcurrent condition in the hub level instead of the port level, as what your patch does, but the only concern I have is the original handling which calls port_event() wrapped with those pm_runtime_*() and usb_lock_port() calls, but your patch doesn't have those.
  • Hi Bin Liu,

    Kernel 2.6.32 's hub.c (the one working in the  DM3730 platform) is quite different from Kernel 4.9 rt 's one but there is in both a test on hub->change_bits and only in the former it succeeds when

    an Overcurrent occurs. I think that a big difference may be that the latter is a Real Time kernel so interrupts are treated differently (as threads) but I can't prove it though. What do you think about it ?

    I wrapped my patch with "pm_runtime_*() and usb_lock_port() calls" as you suggested.

  • Alessandro,

    I barely play with the RT kernel, but I am wondering if this is due to RT nature or just a difference in regular v4.9 vs. v2.6.32...
    But I think you are good to go with your new patch which adds the pm_runtime_*() cand usb_lock_port() calls.
  • Hi Bin Liu,

    I studied drivers/usb/core/hub.c and I reckoned that the function "hub_activate" checks out hub portstatus and portchange setting hub->change_bits when certain conditions are satisfied, finally it calls  "kick_hub_wq(hub)" to make hub_event work, but this does not happen in my case when OVERCURRENT occurs.

    So I would suggest the following patch instead of the previous one:

    drivers/usb/core/hub.c

    @@ -1137,7 +1137,7 @@
    * check for a new connection
    */
    if (udev || (portstatus & USB_PORT_STAT_CONNECTION) ||

    - (portstatus & USB_PORT_STAT_OVERCURRENT))
    + (portstatus & USB_PORT_STAT_OVERCURRENT) || (portchange && USB_PORT_STAT_C_OVERCURRENT))

    set_bit(port1, hub->change_bits);


    } else if (portstatus & USB_PORT_STAT_ENABLE) {

    This should comply to USB 2.0 spec 11.12.5: "...If a hub has per-port power switching and per-port current limiting, an over-current on one port may still cause the power on another port to fall below specified minimums. In this case, the affected port is placed in the Powered-off state and C_PORT_OVER_CURRENT is set for the port, but PORT_OVER_CURRENT is not set..."

    And it seems to me this is what actually happens when OVERCURRENT occurs as I could verify that portstatus = 0 and portchange = 8.

    Applying this patch everything seems to be working fine but I would be very grateful to you to have your opinion. 

    Thanks

  • Alessandro Antenucci said:
    - (portstatus & USB_PORT_STAT_OVERCURRENT))
    + (portstatus & USB_PORT_STAT_OVERCURRENT) || (portchange && USB_PORT_STAT_C_OVERCURRENT))

    Should the new condition be "(portchange & USB_PORT_STAT_C_OVERCURRENT)"?

  • Alessandro,

    I think this is the right fix. But I have posted your information to the kernel community mailing list to confirm.

    By the way, I just read the v3.2 kernel code and understood why your system worked in v3.2.

    hub_events() in v3.2 kernel checks for either hub->event_bits or hub->change_bits, then queries for port status from the hub, and handles the over-current condition.

    3514                         connect_change = test_bit(i, hub->change_bits);         
    3515                         if (!test_and_clear_bit(i, hub->event_bits) &&          
    3516                                         !connect_change)                        
    3517                                 continue;                                       
    3518                                                                                 
    3519                         ret = hub_port_status(hub, i,                           
    3520                                         &portstatus, &portchange);
    ...
    3582                         if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
    
  • Alessandro,

    I got a confirmation from the kernel mailing list that your patch is the right thing to do (of cause with a single & in the new condition).

    Do you want to send the patch directly to linux-usb@vger.kernel.org so that you get the credit? Or I can send the patch and add your name and email address as Reported-By?

  • Hi Bin Liu,

     I'm very happy about it ! You can send the patch on my behalf (it's for sure the fastest thing to do), my email is antenucci@korg.it.

     Thank you a lot for your support,

     Alessandro

  • Alessandro,

    The code change you posted above is just a 'diff', not a complete kernel 'patch', (a kernel patch has 4 major sections: subject, commit message, sign-offs, and the code change.) so a patch has to be created first based on your code change, I cannot create the patch and send it upstream 'on your behalf'.

    We have two options here:

    1. You directly create and send the patch to the community;
    2. I create and send the patch, and adding 'Reported-by: Alessandro Antenucci <antenucci@korg.it>' in the patch sign-off section.

    Please let me know which one you prefer.
  • Actually in the 2nd option adding 'Tested-by: Alessandro Antenucci <antenucci@korg.it>' would be better.

  • Hi Bin Liu,

     it's ok if you create and send the patch (2nd option).

     Thanks,

    Alessandro

  • Sounds good. I will copy you when sending the patch.