On Wed, Apr 17, 2013 at 3:07 PM, B, Ravi <ravib...@ti.com> wrote:
> Ruslan
>
>> >> Subject: [PATCH] usb: musb: gadget: fix enumeration on heavy-loaded
>> >> systems
>> >>
>> >> From musb point of view, the Address Assignment sequence during
>> >> device enumeration is next:
>> >>  - first ep0 interrupt:
>> >>       * read the address from USB_REQ_SET_ADDRESS request
>> >>       * set up CSR0L.DataEnd bit (that is ACK
>> >>         signalization for the host)
>> >>  - second ep0 interrupt:
>> >>       * indicates that the request completed successfully
>> >>       * set up musb device address
>> >>         Now musb device should answer to this address
>> >>
>> >> From the host perspective, if peripheral device acquires
>> >> SET_ADDRESS request, it now may be accessed only using that address.
>> >> However, on heavy loaded systems, time between first and
>> >> second musb ep0 interrupts may be too long and musb controller
>> >> misses requests between.
>> >
>> > What is meant by heavily loaded system? Is the device is heavily loaded
>> during enumeration stage? Why second ep0 interrupt is too long? whether
>> interrupt occurrence to interrupt service is taking too long?
>>
>> I mean production system with aggressive power management and tens of
>> interrupt sources.
>> On such systems and in low CPU frequency case, you may meet condition
>> when time between
>> IRQ firing and ISR entering is increased in few times.
>>
>> In particular case of OMAP4 where I met this issue, time between first
>> and second ep0 interrupt
>> sometimes may be up to 800-900 uS and in this case the USB30CV test fails.
>> If this time is 200-300 uS, the test successfully passes.
>>
>> Unfortunately, this time is not predictable and depends on many factors so
>> this patch ensures we change the address as soon as sent ACK to the host.
>>
>> >
>> > As result, device enumeration may be
>> >> unsuccessful. This can be checked on USB3.0 Host and
>> >> using USB3.0 test suite (from usb.org) running ch9 tests
>> >> for USB2.0 devices.
>> >
>> > You mean the usb2.0 musb controller (in device mode) connected to USB3.0
>> host?
>>
>> Correct. USB2.0 musb controller in device mode, connected to USB3.0
>> host that runs
>> USB30CV utility for USB2.0 devices
>>
>> >
>> >> Usually 'Addressed state/TD9.1: Device Descriptor Test' will fail
>> >>
>> >> The fix consists in checking CSR0L.DataEnd state and assigning
>> >> the device address in the first ep0 interrupt handling, so
>> >> delay is as minimal as possible
>> >>
>> >> Signed-off-by: Ruslan Bilovol <ruslan.bilo...@ti.com>
>> >> ---
>> >>  drivers/usb/musb/musb_gadget_ep0.c |   31
>> +++++++++++++++++++++++++++++++
>> >>  1 file changed, 31 insertions(+)
>> >>
>> >> diff --git a/drivers/usb/musb/musb_gadget_ep0.c
>> >> b/drivers/usb/musb/musb_gadget_ep0.c
>> >> index c9c1ac4..59bc5a5 100644
>> >> --- a/drivers/usb/musb/musb_gadget_ep0.c
>> >> +++ b/drivers/usb/musb/musb_gadget_ep0.c
>> >> @@ -885,6 +885,37 @@ stall:
>> >>  finish:
>> >>                               musb_writew(regs, MUSB_CSR0,
>> >>                                               musb->ackpend);
>> >> +
>> >> +                             /*
>> >> +                              * If we are at end of SET_ADDRESS
>> sequence,
>> >> +                              * update the address immediately if
>> possible,
>> >> +                              * otherwise we may miss packets between
>> >> +                              * sending ACK from musb side and musb's
>> next
>> >> +                              * interrupt handler firing (in which we
>> update
>> >> +                              * the address). At least this fixes next
>> >> +                              * USB2.0 ch9 test of USB30CV utility:
>> >> +                              * "Addressed state - Device Descriptor
>> test"
>> >> +                              */
>> >> +                             if (musb->set_address && (musb->ackpend &
>> >> +
>> MUSB_CSR0_P_DATAEND) &&
>> >> +                                             (musb->ep0_state ==
>> >> +                                             MUSB_EP0_STAGE_STATUSIN))
>> {
>> >> +                                     u16 ack_delay = 500;
>> >> +
>> >> +                                     while ((musb_readw(regs,
>> MUSB_CSR0) &
>> >> +
>> MUSB_CSR0_P_DATAEND) &&
>> >> +                                                     --ack_delay) {
>> >> +                                             cpu_relax();
>> >> +                                             udelay(1);
>> >> +                                     }
>> >> +
>
> No need to loop here. It is self clearing bit.

Yes, it is self-clearing bit and this is what we exactly use here. We
are waiting for this bit
self-clearing (that signalizes the end of Status Phase) or waiting for
end of our timeout (when ack_delay == 0)

>
>> >> +                                     if (ack_delay) {
>> >> +                                             musb->set_address =
>> false;
>> >> +                                             musb_writeb(mbase,
>> MUSB_FADDR,
>> >> +                                                             musb-
>> >address);
>> >> +                                     }
>
> Setting the address before status phase could lead to dropping of status  
> packet(IN token) by controller, because the status phase is addressed to 
> device with zero address by host, but device controller already changed to 
> new address.
> I believe above delay loop is saving you in this case.

You correctly described the sequence of a failure, but it is not this case.
In short, when we set CSR0.DATAEND bit, this is an indication that we start
Status Phase. When the Status Phase ends, the CSR0.DATAEND self-clears
and we receive second ep0 interrupt.
In my patch, we are waiting (up to 500 us that is defined by
"ack_delay") for CSR0.DATAEND self-clearing and set up
the musb address immediately and do not rely on second ep0 interrupt -
it is used as
backup way (if CSR0.DATAEND wasn't self-cleared after "ack_delay" timeout).

-- 
Best regards,
Ruslan Bilvol
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to