aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@freescale.com>2014-01-10 00:51:32 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-13 18:55:19 -0500
commit2fc5a7dace3c43e62402ab4e8800a8f1834ffe2a (patch)
tree1ca8f7921e82ad7beb4ec883948c4e36e0438b0d
parent5332ff1fb63c46588656e4208201bc131627c878 (diff)
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>
-rw-r--r--drivers/usb/chipidea/udc.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 73a39ef93ec5..80de2f88ed2c 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -393,6 +393,14 @@ static int add_td_to_list(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq,
393 node->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES)); 393 node->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES));
394 node->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES); 394 node->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES);
395 node->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE); 395 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 }
396 404
397 temp = (u32) (hwreq->req.dma + hwreq->req.actual); 405 temp = (u32) (hwreq->req.dma + hwreq->req.actual);
398 if (length) { 406 if (length) {
@@ -515,10 +523,11 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
515 hwep->qh.ptr->td.token &= 523 hwep->qh.ptr->td.token &=
516 cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE)); 524 cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE));
517 525
518 if (hwep->type == USB_ENDPOINT_XFER_ISOC) { 526 if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == RX) {
519 u32 mul = hwreq->req.length / hwep->ep.maxpacket; 527 u32 mul = hwreq->req.length / hwep->ep.maxpacket;
520 528
521 if (hwreq->req.length % hwep->ep.maxpacket) 529 if (hwreq->req.length == 0
530 || hwreq->req.length % hwep->ep.maxpacket)
522 mul++; 531 mul++;
523 hwep->qh.ptr->cap |= mul << __ffs(QH_MULT); 532 hwep->qh.ptr->cap |= mul << __ffs(QH_MULT);
524 } 533 }
@@ -1173,6 +1182,12 @@ static int ep_enable(struct usb_ep *ep,
1173 if (hwep->num) 1182 if (hwep->num)
1174 cap |= QH_ZLT; 1183 cap |= QH_ZLT;
1175 cap |= (hwep->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT; 1184 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);
1176 1191
1177 hwep->qh.ptr->cap = cpu_to_le32(cap); 1192 hwep->qh.ptr->cap = cpu_to_le32(cap);
1178 1193