usb: dwc_otg_310: core: do not disable non-split periodic channels

The dwc2 programming guide section 3.5 'Halting a Channel'
says that the application can disable any channel by
programming the HCCHARn register with the HCCHARn.ChDis
and HCCHARn.ChEna bits set to 1'b1. This enables the
dwc_otg host to flush the posted requests (if any) and
generates a Channel Halted interrupt.

But it also requires that channel disable must not be
programmed for non-split periodic channels. At the end
of the next uframe/frame (in the worst case), the core
generates a channel halted and disables the channel
automatically.

If we disable non-spilt periodic channels to halt the
channels, it will easily to cause data transfer fail.
A typical case is take photo with usb camera or close
usb camera, Specifically, the observed order is:
1. uvc driver calls usb_kill_urb
2. usb_kill_urb calls urb_dequeue to cancel urb
3. urb_dequeue call dwc_otg_hc_halt to disable
   non-spilt periodic channels
4. usb core doesn't halt the non-spilt periodic
   channels immediately, and the application
   reallocates the channels for other transactions
   without waiting for the HCINTn.ChHltd interrupt.
5. uvc driver calls usb_set_interface to start
   control transfer, and gets a channel which used
   for non-spilt periodic transfer before. The core
   generates a channel halted and disables the channel
   automatically. This cause control transfer fail.

Change-Id: I9f951bbd19d3568d9342973a1a25dba469505154
Signed-off-by: Wu Liang feng <wulf@rock-chips.com>
This commit is contained in:
Wu Liang feng
2016-01-25 20:12:23 +08:00
committed by Tao Huang
parent 2c7ae82487
commit 93ddcde5f2

View File

@@ -2855,8 +2855,12 @@ void dwc_otg_hc_halt(dwc_otg_core_if_t *core_if,
hc->halt_status = halt_status;
hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar);
if (hcchar.b.chen == 0) {
if ((hcchar.b.chen == 0) ||
(!hc->do_split &&
((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) ||
(hc->ep_type == DWC_OTG_EP_TYPE_INTR)))) {
/*
* hcchar.b.chen is 0 means that:
* The channel is either already halted or it hasn't
* started yet. In DMA mode, the transfer may halt if
* it finishes normally or a condition occurs that
@@ -2866,7 +2870,16 @@ void dwc_otg_hc_halt(dwc_otg_core_if_t *core_if,
* to a channel, but not started yet when an URB is
* dequeued. Don't want to halt a channel that hasn't
* started yet.
* If channel is used for non-split periodic transfer
* according to DWC Programming Guide:
* '3.5 Halting a Channel': Channel disable must not
* be programmed for non-split periodic channels. At
* the end of the next uframe/frame (in the worst
* case), the core generates a channel halted and
* disables the channel automatically.
*/
DWC_PRINTF("%s: hcchar.b.chen %d, ep_type %d\n",
__func__, hcchar.b.chen, hc->ep_type);
return;
}
}