Skip to content

Commit 2fc5a7d

Browse files
Peter Chengregkh
authored andcommitted
usb: chipidea: udc: using MultO at TD as real mult value for ISO-TX
We have met a bug that the high bandwidth ISO-TX transfer has failed at the last packet if it is less than 1024, the TD status shows it is "Transaction Error". The root cause of this problem is: the mult value at qh is not correct for current TD's transfer length. We use TD list to queue un-transfer TDs, and change mult for new adding TDs. If new adding TDs transfer length less than 1024, but the queued un-transfer TDs transfer length is larger than 1024, the transfer error will occur, and vice versa. Usually, this problem occurs at the last packet, and the first packet for new frame. We fixed this problem by setting Mult at QH as the largest value (3), and set MultO (Multiplier Override) at TD according to every transfer length. It can cover both hardware version less than 2.3 (the real mult is MultO if it is not 0) and 2.3+ (the real mult is min(qh.mult, td.multo)). Since the MultO bits are only existed at TX TD, we keep the ISO-RX behavior unchanged. For stable tree: 3.11+. Cc: stable <stable@vger.kernel.org> Cc: Michael Grzeschik <m.grzeschik@pengutronix.de> Reported-by: Matthieu Vanin <b47495@freescale.com> Tested-by: Matthieu Vanin <b47495@freescale.com> Signed-off-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 5332ff1 commit 2fc5a7d

File tree

1 file changed

+17
-2
lines changed
  • drivers/usb/chipidea

1 file changed

+17
-2
lines changed

drivers/usb/chipidea/udc.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,14 @@ static int add_td_to_list(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq,
393393
node->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES));
394394
node->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES);
395395
node->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE);
396+
if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == TX) {
397+
u32 mul = hwreq->req.length / hwep->ep.maxpacket;
398+
399+
if (hwreq->req.length == 0
400+
|| hwreq->req.length % hwep->ep.maxpacket)
401+
mul++;
402+
node->ptr->token |= mul << __ffs(TD_MULTO);
403+
}
396404

397405
temp = (u32) (hwreq->req.dma + hwreq->req.actual);
398406
if (length) {
@@ -515,10 +523,11 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
515523
hwep->qh.ptr->td.token &=
516524
cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE));
517525

518-
if (hwep->type == USB_ENDPOINT_XFER_ISOC) {
526+
if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == RX) {
519527
u32 mul = hwreq->req.length / hwep->ep.maxpacket;
520528

521-
if (hwreq->req.length % hwep->ep.maxpacket)
529+
if (hwreq->req.length == 0
530+
|| hwreq->req.length % hwep->ep.maxpacket)
522531
mul++;
523532
hwep->qh.ptr->cap |= mul << __ffs(QH_MULT);
524533
}
@@ -1173,6 +1182,12 @@ static int ep_enable(struct usb_ep *ep,
11731182
if (hwep->num)
11741183
cap |= QH_ZLT;
11751184
cap |= (hwep->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT;
1185+
/*
1186+
* For ISO-TX, we set mult at QH as the largest value, and use
1187+
* MultO at TD as real mult value.
1188+
*/
1189+
if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == TX)
1190+
cap |= 3 << __ffs(QH_MULT);
11761191

11771192
hwep->qh.ptr->cap = cpu_to_le32(cap);
11781193

0 commit comments

Comments
 (0)