[PATCH 2/3] at91-ohci: support overcurrent notification

Alan Stern stern at rowland.harvard.edu
Wed Jul 13 11:54:15 EDT 2011


On Wed, 13 Jul 2011, Thomas Petazzoni wrote:

> Now, I have a question about the behavior I observe with this code in
> place. In order to easily trigger the over-current situation, I have
> told in my board code that a button is the GPIO for the overcurrent_pin.
> 
> When I push the button, I enter the over-current situation, when I
> release the button, I exit the over-current situation.
> 
> With the code above in place, when I push the button, the power is shut
> off on the corresponding USB port and the device goes away. But
> immediately after that, the power is switched on at the USB port by the
> USB core, and the device is detected again. Is this normal behaviour ?
> I would have expected the USB core to wait for the over-current
> situation to disappear (i.e from me releasing the button). Maybe I am
> misunderstanding how over-current management works ?
> 
> Apparently, the behaviour I observe is implemented by the following
> piece of code in drivers/usb/core/hub.c :
> 
>                         if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
>                                 u16 status = 0;
>                                 u16 unused;
> 
>                                 dev_dbg(hub_dev, "over-current change on port "
>                                         "%d\n", i);
>                                 clear_port_feature(hdev, i,
>                                         USB_PORT_FEAT_C_OVER_CURRENT);
>                                 msleep(100);    /* Cool down */
>                                 hub_power_on(hub, true);
>                                 hub_port_status(hub, i, &status, &unused);
>                                 if (status & USB_PORT_STAT_OVERCURRENT)
>                                         dev_err(hub_dev, "over-current "
>                                                 "condition on port %d\n", i);
>                         }
> 
> So I don't see where it would wait for the over-current situation to be
> cleared.

That's what the "msleep(100)" is for.

>  However, the USB 2.0 specification says, in section 11.12.5 :
> 
> """
> Host recovery actions for an over-current event should include the
> following:
> 1. Host gets change notification from hub with over-current
>    event.
> 2. Host extracts appropriate hub or port change information
>    (depending on the information in the change bitmap).
> 3. Host waits for over-current status bit to be cleared to 0.
> 4. Host cycles power on to all of the necessary ports (e.g., issues a
>    SetPortFeature(PORT_POWER) request for each port).
> 5. Host re-enumerates all affected ports
> """
> 
> So, according to step 3), I would have expected the USB core to wait
> for the over-currrent status to be cleared, that is, wait until I
> release the button.

If there is no power to the port, the attached device can't draw any
current.  Right?  Therefore the port's over-current status isn't
meaningful until the power is restored.

> Below is the log of what happens between the moment I press the button
> (message "overcurrent situation notified" from the GPIO interrupt
> handler) and the moment I release the button (message "overcurrent
> situation exited" from the GPIO interrupt handler).
> 
> [   41.750000] at91_ohci at91_ohci: overcurrent situation notified
> [   41.790000] hub 1-0:1.0: state 7 ports 2 chg 0000 evt 0006
> [   41.790000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0xa300,0x0000,0x0001,c7861e48,0004)
> [   41.790000] at91_ohci at91_ohci: GetPortStatus(1)
> [   41.790000] hub 1-0:1.0: over-current change on port 1
> [   41.790000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0x2301,0x0013,0x0001,c7861e70,0000)
> [   41.790000] at91_ohci at91_ohci: ClearPortFeature: C_OVER_CURRENT
> [   41.790000] at91_ohci at91_ohci: CTRL: TypeReq=0x2301 val=0x13 idx=0x1 len=0 ==> -22
> [   41.900000] hub 1-0:1.0: enabling power on all ports
> [   41.900000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0x2303,0x0008,0x0001,c7861e58,0000)
> [   41.900000] at91_ohci at91_ohci: SetPortFeat: POWER
> [   41.900000] at91_ohci at91_ohci: CTRL: TypeReq=0x2303 val=0x8 idx=0x1 len=0 ==> -22
> [   41.900000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0x2303,0x0008,0x0002,c7861e58,0000)
> [   41.900000] at91_ohci at91_ohci: SetPortFeat: POWER
> [   41.900000] at91_ohci at91_ohci: CTRL: TypeReq=0x2303 val=0x8 idx=0x2 len=0 ==> -22
> [   42.010000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0xa300,0x0000,0x0001,c7861e48,0004)
> [   42.010000] at91_ohci at91_ohci: GetPortStatus(1)
> [   42.010000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0xa300,0x0000,0x0002,c7861e48,0004)
> [   42.010000] at91_ohci at91_ohci: GetStatus roothub.portstatus [1] = 0x00030301 PESC CSC LSDA PPS CCS

At this point the "over-current condition on port 1" error message
should have appeared, and the power to port 1 should have been turned
off again by the hardware.

> [   42.010000] at91_ohci at91_ohci: GetPortStatus(2)
> [   42.010000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0x2301,0x0010,0x0002,c7861e70,0000)
> [   42.010000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0x2301,0x0011,0x0002,c7861e70,0000)
> [   42.010000] hub 1-0:1.0: port 2, status 0301, change 0003, 1.5 Mb/s
> [   42.010000] usb 1-2: USB disconnect, device number 2
> [   42.010000] usb 1-2: unregistering device
> [   42.010000] usb 1-2: unregistering interface 1-2:1.0
> [   42.010000] usb 1-2: usb_disable_device nuking all URBs
> [   42.010000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0xa300,0x0000,0x0002,c7861e48,0004)
> [   42.010000] at91_ohci at91_ohci: GetPortStatus(2)
> [   42.050000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0xa300,0x0000,0x0002,c7861e48,0004)
> [   42.050000] at91_ohci at91_ohci: GetPortStatus(2)
> [   42.090000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0xa300,0x0000,0x0002,c7861e48,0004)
> [   42.090000] at91_ohci at91_ohci: GetPortStatus(2)
> [   42.130000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0xa300,0x0000,0x0002,c7861e48,0004)
> [   42.130000] at91_ohci at91_ohci: GetPortStatus(2)
> [   42.170000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0xa300,0x0000,0x0002,c7861e48,0004)
> [   42.170000] at91_ohci at91_ohci: GetPortStatus(2)
> [   42.170000] hub 1-0:1.0: debounce: port 2: total 100ms stable 100ms status 0x301
> [   42.170000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0x2303,0x0004,0x0002,c7861de0,0000)
> [   42.290000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0xa300,0x0000,0x0002,c7861db8,0004)
> [   42.290000] at91_ohci at91_ohci: GetStatus roothub.portstatus [1] = 0x00100303 PRSC LSDA PPS PES CCS
> [   42.290000] at91_ohci at91_ohci: GetPortStatus(2)
> [   42.350000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0x2301,0x0014,0x0002,c7861de0,0000)
> [   42.350000] usb 1-2: new low speed USB device number 3 using at91_ohci
> [   42.350000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0x2303,0x0004,0x0002,c7861de0,0000)
> [   42.470000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0xa300,0x0000,0x0002,c7861db8,0004)
> [   42.470000] at91_ohci at91_ohci: GetStatus roothub.portstatus [1] = 0x00100303 PRSC LSDA PPS PES CCS
> [   42.470000] at91_ohci at91_ohci: GetPortStatus(2)
> [   42.530000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0x2301,0x0014,0x0002,c7861de0,0000)
> [   42.560000] usb 1-2: skipped 1 descriptor after interface
> [   42.560000] usb 1-2: default language 0x0409
> [   42.570000] usb 1-2: udev 3, busnum 1, minor = 2
> [   42.570000] usb 1-2: New USB device found, idVendor=0a81, idProduct=0701
> [   42.570000] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
> [   42.580000] usb 1-2: Product: USB Missile Launcher v1.0
> [   42.590000] usb 1-2: Manufacturer: Dream Link
> [   42.590000] usb 1-2: usb_probe_device
> [   42.590000] usb 1-2: configuration #1 chosen from 1 choice
> [   42.590000] usb 1-2: adding 1-2:1.0 (config #1, interface 0)
> [   42.600000] usbhid 1-2:1.0: usb_probe_interface
> [   42.600000] usbhid 1-2:1.0: usb_probe_interface - got id
> [   42.610000] generic-usb 0003:0A81:0701.0002: claimed by neither input, hiddev nor hidraw
> [   42.610000] /home/thomas/projets/linux-2.6/drivers/usb/core/inode.c: creating file '003'
> [   42.610000] hub 1-0:1.0: state 7 ports 2 chg 0000 evt 0004
> [   42.610000] at91_ohci at91_ohci: ohci_at91_hub_control(c79ccc00,0xa300,0x0000,0x0002,c7861e48,0004)
> [   42.610000] at91_ohci at91_ohci: GetPortStatus(2)
> [   43.850000] at91_ohci at91_ohci: overcurrent situation exited
> 
> Could you enlighten me on how this over-current mechanism is supposed
> to work ?

We don't have any good way of waiting for the over-current status to
clear, because the hub driver is single-threaded.  It wouldn't be able
to respond to any other USB events while waiting.

If the port is still over-current when the power is turned back on, the 
hub is expected to turn the port power off again and signal another 
over-current status change.

Alan Stern




More information about the linux-arm-kernel mailing list