This is a note to let you know that I've just added the patch titled usb: chipidea: udc: using MultO at TD as real mult value for ISO-TX to my usb git tree which can be found at git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git in the usb-next branch. The patch will show up in the next release of the linux-next tree (usually sometime within the next 24 hours during the week.) The patch will also be merged in the next major kernel release during the merge window. If you have any questions about this process, please let me know. >From 2fc5a7dace3c43e62402ab4e8800a8f1834ffe2a Mon Sep 17 00:00:00 2001 From: Peter Chen <peter.chen@xxxxxxxxxxxxx> Date: Fri, 10 Jan 2014 13:51:32 +0800 Subject: 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@xxxxxxxxxxxxxxx> Cc: Michael Grzeschik <m.grzeschik@xxxxxxxxxxxxxx> Reported-by: Matthieu Vanin <b47495@xxxxxxxxxxxxx> Tested-by: Matthieu Vanin <b47495@xxxxxxxxxxxxx> Signed-off-by: Peter Chen <peter.chen@xxxxxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/usb/chipidea/udc.c | 19 +++++++++++++++++-- 1 file 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, node->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES)); node->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES); node->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE); + if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == TX) { + u32 mul = hwreq->req.length / hwep->ep.maxpacket; + + if (hwreq->req.length == 0 + || hwreq->req.length % hwep->ep.maxpacket) + mul++; + node->ptr->token |= mul << __ffs(TD_MULTO); + } temp = (u32) (hwreq->req.dma + hwreq->req.actual); if (length) { @@ -515,10 +523,11 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) hwep->qh.ptr->td.token &= cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE)); - if (hwep->type == USB_ENDPOINT_XFER_ISOC) { + if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == RX) { u32 mul = hwreq->req.length / hwep->ep.maxpacket; - if (hwreq->req.length % hwep->ep.maxpacket) + if (hwreq->req.length == 0 + || hwreq->req.length % hwep->ep.maxpacket) mul++; hwep->qh.ptr->cap |= mul << __ffs(QH_MULT); } @@ -1173,6 +1182,12 @@ static int ep_enable(struct usb_ep *ep, if (hwep->num) cap |= QH_ZLT; cap |= (hwep->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT; + /* + * For ISO-TX, we set mult at QH as the largest value, and use + * MultO at TD as real mult value. + */ + if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == TX) + cap |= 3 << __ffs(QH_MULT); hwep->qh.ptr->cap = cpu_to_le32(cap); -- 1.8.5.1.163.gd7aced9 -- To unsubscribe from this list: send the line "unsubscribe stable" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html