From 4bc48c9747084dad4b258821a69026bcc552e8ff Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 10 Aug 2016 16:04:33 +0300 Subject: usb: dwc3: gadget: retire LST bit completely The only endpoint which actually requires LST bit and XferComplete is ep0/1. Let's save some time by completely removing LST bit support and XferComplete. This simplifies and consolidates endpoint handling for all other 3 transfer types while also avoiding extra interrupts. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 62 ++++++++++++----------------------------------- 1 file changed, 15 insertions(+), 47 deletions(-) (limited to 'drivers/usb/dwc3/gadget.c') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 1f5597ef945d..15df5ed546da 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -490,7 +490,8 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, params.param0 |= DWC3_DEPCFG_ACTION_INIT; } - params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN; + if (usb_endpoint_xfer_control(desc)) + params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN; if (dep->number <= 1 || usb_endpoint_xfer_isoc(desc)) params.param1 |= DWC3_DEPCFG_XFER_NOT_READY_EN; @@ -771,15 +772,13 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep, */ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_request *req, dma_addr_t dma, - unsigned length, unsigned last, unsigned chain, unsigned node) + unsigned length, unsigned chain, unsigned node) { struct dwc3_trb *trb; - dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s%s", + dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s", dep->name, req, (unsigned long long) dma, - length, last ? " last" : "", - chain ? " chain" : ""); - + length, chain ? " chain" : ""); trb = &dep->trb_pool[dep->trb_enqueue]; @@ -829,9 +828,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, if (!req->request.no_interrupt && !chain) trb->ctrl |= DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI; - if (last && !usb_endpoint_xfer_isoc(dep->endpoint.desc)) - trb->ctrl |= DWC3_TRB_CTRL_LST; - if (chain) trb->ctrl |= DWC3_TRB_CTRL_CHN; @@ -894,13 +890,11 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) } static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, - struct dwc3_request *req, unsigned int trbs_left, - unsigned int more_coming) + struct dwc3_request *req, unsigned int trbs_left) { struct usb_request *request = &req->request; struct scatterlist *sg = request->sg; struct scatterlist *s; - unsigned int last = false; unsigned int length; dma_addr_t dma; int i; @@ -911,48 +905,28 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, length = sg_dma_len(s); dma = sg_dma_address(s); - if (sg_is_last(s)) { - if (usb_endpoint_xfer_int(dep->endpoint.desc) || - !more_coming) - last = true; - - chain = false; - } - - if (!trbs_left--) - last = true; - - if (last) + if (sg_is_last(s)) chain = false; dwc3_prepare_one_trb(dep, req, dma, length, - last, chain, i); + chain, i); - if (last) + if (!trbs_left--) break; } } static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, - struct dwc3_request *req, unsigned int trbs_left, - unsigned int more_coming) + struct dwc3_request *req, unsigned int trbs_left) { - unsigned int last = false; unsigned int length; dma_addr_t dma; dma = req->request.dma; length = req->request.length; - if (!trbs_left) - last = true; - - /* Is this the last request? */ - if (usb_endpoint_xfer_int(dep->endpoint.desc) || !more_coming) - last = true; - dwc3_prepare_one_trb(dep, req, dma, length, - last, false, 0); + false, 0); } /* @@ -966,7 +940,6 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, static void dwc3_prepare_trbs(struct dwc3_ep *dep) { struct dwc3_request *req, *n; - unsigned int more_coming; u32 trbs_left; BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); @@ -975,15 +948,11 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep) if (!trbs_left) return; - more_coming = dep->allocated_requests - dep->queued_requests; - list_for_each_entry_safe(req, n, &dep->pending_list, list) { if (req->request.num_mapped_sgs > 0) - dwc3_prepare_one_trb_sg(dep, req, trbs_left--, - more_coming); + dwc3_prepare_one_trb_sg(dep, req, trbs_left--); else - dwc3_prepare_one_trb_linear(dep, req, trbs_left--, - more_coming); + dwc3_prepare_one_trb_linear(dep, req, trbs_left--); if (!trbs_left) return; @@ -1127,8 +1096,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) * This will save one IRQ (XFER_NOT_READY) and possibly make it a * little bit faster. */ - if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) && - !usb_endpoint_xfer_int(dep->endpoint.desc)) { + if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { ret = __dwc3_gadget_kick_transfer(dep, 0); goto out; } @@ -2045,7 +2013,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, int chain; req = next_request(&dep->started_list); - if (WARN_ON_ONCE(!req)) + if (!req) return 1; chain = req->request.num_mapped_sgs > 0; -- cgit v1.2.3 From 737f1ae2556a5d219c24fbea2e1c63b7d9e10869 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 11 Aug 2016 12:24:27 +0300 Subject: usb: dwc3: gadget: increment dequeue pointer on completion Instead of waiting until giveback before incrementing the dequeue pointer, we can increment it from dwc3_cleanup_done_reqs(), that way we avoid an extra loop over all TRBs during giveback. While at that, also avoid using req->first_trb_index as that's completely unnecessary. A follow-up patch will clean up further uses of that and remove the field altogether. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) (limited to 'drivers/usb/dwc3/gadget.c') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 15df5ed546da..18045997b593 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -174,15 +174,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, int status) { struct dwc3 *dwc = dep->dwc; - int i; - if (req->started) { - i = 0; - do { - dwc3_ep_inc_deq(dep); - } while(++i < req->request.num_mapped_sgs); - req->started = false; - } + req->started = false; list_del(&req->list); req->trb = NULL; @@ -2004,7 +1997,6 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, { struct dwc3_request *req; struct dwc3_trb *trb; - unsigned int slot; unsigned int i; int count = 0; int ret; @@ -2019,12 +2011,9 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, chain = req->request.num_mapped_sgs > 0; i = 0; do { - slot = req->first_trb_index + i; - if (slot == DWC3_TRB_NUM - 1) - slot++; - slot %= DWC3_TRB_NUM; - trb = &dep->trb_pool[slot]; + trb = &dep->trb_pool[dep->trb_dequeue]; count += trb->size & DWC3_TRB_SIZE_MASK; + dwc3_ep_inc_deq(dep); ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status, chain); -- cgit v1.2.3 From 45438a0cd9c2b80917047b77fab1ff46cf710748 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 11 Aug 2016 12:26:59 +0300 Subject: usb: dwc3: gadget: simplify dwc3_ep_prev_trb() We always need to decrement our index by at least one. Simplify the implementation by using a temporary local variable and making sure that we will always decrement one extra if tmp == 0. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/usb/dwc3/gadget.c') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 18045997b593..a310266abc20 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -845,12 +845,12 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, */ static struct dwc3_trb *dwc3_ep_prev_trb(struct dwc3_ep *dep, u8 index) { - if (!index) - index = DWC3_TRB_NUM - 2; - else - index = dep->trb_enqueue - 1; + u8 tmp = index; + + if (!tmp) + tmp = DWC3_TRB_NUM - 1; - return &dep->trb_pool[index]; + return &dep->trb_pool[tmp - 1]; } static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) -- cgit v1.2.3 From 08a36b543803b7fe39b66ca0529bea34a88dc77f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 11 Aug 2016 14:27:52 +0300 Subject: usb: dwc3: gadget: simplify __dwc3_gadget_ep_queue() Many of the comments in that function are really outdated and don't match what the driver is doing. Moreover, recent patches combined programming model for all non-control endpoints, this gives us an opportunity to get rid of our special cases in __dwc3_gadget_ep_queue(). Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 83 ++++------------------------------------------- 1 file changed, 7 insertions(+), 76 deletions(-) (limited to 'drivers/usb/dwc3/gadget.c') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index a310266abc20..3cf4c9016b75 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1063,18 +1063,6 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) trace_dwc3_ep_queue(req); - /* - * We only add to our list of requests now and - * start consuming the list once we get XferNotReady - * IRQ. - * - * That way, we avoid doing anything that we don't need - * to do now and defer it until the point we receive a - * particular token from the Host side. - * - * This will also avoid Host cancelling URBs due to too - * many NAKs. - */ ret = usb_gadget_map_request(&dwc->gadget, &req->request, dep->direction); if (ret) @@ -1082,73 +1070,16 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) list_add_tail(&req->list, &dep->pending_list); - /* - * If there are no pending requests and the endpoint isn't already - * busy, we will just start the request straight away. - * - * This will save one IRQ (XFER_NOT_READY) and possibly make it a - * little bit faster. - */ - if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - ret = __dwc3_gadget_kick_transfer(dep, 0); - goto out; - } - - /* - * There are a few special cases: - * - * 1. XferNotReady with empty list of requests. We need to kick the - * transfer here in that situation, otherwise we will be NAKing - * forever. If we get XferNotReady before gadget driver has a - * chance to queue a request, we will ACK the IRQ but won't be - * able to receive the data until the next request is queued. - * The following code is handling exactly that. - * - */ - if (dep->flags & DWC3_EP_PENDING_REQUEST) { - /* - * If xfernotready is already elapsed and it is a case - * of isoc transfer, then issue END TRANSFER, so that - * you can receive xfernotready again and can have - * notion of current microframe. - */ - if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - if (list_empty(&dep->started_list)) { - dwc3_stop_active_transfer(dwc, dep->number, true); - dep->flags = DWC3_EP_ENABLED; - } - return 0; - } - - ret = __dwc3_gadget_kick_transfer(dep, 0); - if (!ret) - dep->flags &= ~DWC3_EP_PENDING_REQUEST; - - goto out; - } - - /* - * 2. XferInProgress on Isoc EP with an active transfer. We need to - * kick the transfer here after queuing a request, otherwise the - * core may not see the modified TRB(s). - */ if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && - (dep->flags & DWC3_EP_BUSY) && - !(dep->flags & DWC3_EP_MISSED_ISOC)) { - WARN_ON_ONCE(!dep->resource_index); - ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index); - goto out; + dep->flags & DWC3_EP_PENDING_REQUEST) { + if (list_empty(&dep->started_list)) { + dwc3_stop_active_transfer(dwc, dep->number, true); + dep->flags = DWC3_EP_ENABLED; + } + return 0; } - /* - * 4. Stream Capable Bulk Endpoints. We need to start the transfer - * right away, otherwise host will not know we have streams to be - * handled. - */ - if (dep->stream_capable) - ret = __dwc3_gadget_kick_transfer(dep, 0); - -out: + ret = __dwc3_gadget_kick_transfer(dep, 0); if (ret && ret != -EBUSY) dwc3_trace(trace_dwc3_gadget, "%s: failed to kick transfers", -- cgit v1.2.3 From 31162af447d7afba6820e42ed9cf968ed74c64cd Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 11 Aug 2016 14:38:37 +0300 Subject: usb: dwc3: gadget: avoid while (1) loop on completion We know that we have to iterate over the list of started requests. Instead of looping forever, we can rely on list_for_each_entry(). Likewise, instead of a do {} while loop over all, maybe available, scatterlist entries, we can detect if $this request uses scatterlist and rely on for_each_sg(). This makes the code easier to follow while making sure that we will *always* break out of the loop. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'drivers/usb/dwc3/gadget.c') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3cf4c9016b75..c776fb7f524a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1926,31 +1926,37 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, const struct dwc3_event_depevt *event, int status) { - struct dwc3_request *req; + struct dwc3_request *req, *n; struct dwc3_trb *trb; - unsigned int i; int count = 0; int ret; - do { - int chain; + list_for_each_entry_safe(req, n, &dep->started_list, list) { - req = next_request(&dep->started_list); - if (!req) - return 1; + int chain; chain = req->request.num_mapped_sgs > 0; - i = 0; - do { + if (chain) { + struct scatterlist *sg = req->request.sg; + struct scatterlist *s; + unsigned int i; + + for_each_sg(sg, s, req->request.num_mapped_sgs, i) { + trb = &dep->trb_pool[dep->trb_dequeue]; + count += trb->size & DWC3_TRB_SIZE_MASK; + dwc3_ep_inc_deq(dep); + + ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, + event, status, chain); + } + } else { trb = &dep->trb_pool[dep->trb_dequeue]; count += trb->size & DWC3_TRB_SIZE_MASK; dwc3_ep_inc_deq(dep); ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status, chain); - if (ret) - break; - } while (++i < req->request.num_mapped_sgs); + } /* * We assume here we will always receive the entire data block @@ -1964,7 +1970,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, if (ret) break; - } while (1); + } /* * Our endpoint might get disabled by another thread during -- cgit v1.2.3 From 2c78c0295fd8e4e3fef74dcddecc9cabf44a81a5 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 12 Aug 2016 13:13:10 +0300 Subject: usb: dwc3: gadget: interrupt on ring full too If the ring is full and we are processing a big sglist, then let's interrupt so we can, later, add more TRBs to the ring. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/usb/dwc3/gadget.c') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index c776fb7f524a..90b3d7965136 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -758,6 +758,8 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep, kfree(req); } +static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep); + /** * dwc3_prepare_one_trb - setup one TRB from one request * @dep: endpoint for which this request is prepared @@ -818,7 +820,8 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, /* always enable Continue on Short Packet */ trb->ctrl |= DWC3_TRB_CTRL_CSP; - if (!req->request.no_interrupt && !chain) + if ((!req->request.no_interrupt && !chain) || + (dwc3_calc_trbs_left(dep) == 0)) trb->ctrl |= DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI; if (chain) -- cgit v1.2.3 From 1f512119a08c0d4d37c6f7865da378349d244ecc Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 12 Aug 2016 13:17:27 +0300 Subject: usb: dwc3: gadget: add remaining sg entries to ring Upon transfer completion after a full ring, let's add more TRBs to our ring in order to complete our request successfully. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) (limited to 'drivers/usb/dwc3/gadget.c') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 90b3d7965136..c18bf1caad54 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -888,14 +888,13 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, struct dwc3_request *req, unsigned int trbs_left) { - struct usb_request *request = &req->request; - struct scatterlist *sg = request->sg; + struct scatterlist *sg = req->sg; struct scatterlist *s; unsigned int length; dma_addr_t dma; int i; - for_each_sg(sg, s, request->num_mapped_sgs, i) { + for_each_sg(sg, s, req->num_pending_sgs, i) { unsigned chain = true; length = sg_dma_len(s); @@ -945,7 +944,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep) return; list_for_each_entry_safe(req, n, &dep->pending_list, list) { - if (req->request.num_mapped_sgs > 0) + if (req->num_pending_sgs > 0) dwc3_prepare_one_trb_sg(dep, req, trbs_left--); else dwc3_prepare_one_trb_linear(dep, req, trbs_left--); @@ -1071,6 +1070,9 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) if (ret) return ret; + req->sg = req->request.sg; + req->num_pending_sgs = req->request.num_mapped_sgs; + list_add_tail(&req->list, &dep->pending_list); if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && @@ -1935,22 +1937,30 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, int ret; list_for_each_entry_safe(req, n, &dep->started_list, list) { - + unsigned length; + unsigned actual; int chain; - chain = req->request.num_mapped_sgs > 0; + length = req->request.length; + chain = req->num_pending_sgs > 0; if (chain) { - struct scatterlist *sg = req->request.sg; + struct scatterlist *sg = req->sg; struct scatterlist *s; + unsigned int pending = req->num_pending_sgs; unsigned int i; - for_each_sg(sg, s, req->request.num_mapped_sgs, i) { + for_each_sg(sg, s, pending, i) { trb = &dep->trb_pool[dep->trb_dequeue]; count += trb->size & DWC3_TRB_SIZE_MASK; dwc3_ep_inc_deq(dep); + req->sg = sg_next(s); + req->num_pending_sgs--; + ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status, chain); + if (ret) + break; } } else { trb = &dep->trb_pool[dep->trb_dequeue]; @@ -1968,7 +1978,12 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, * should receive and we simply bounce the request back to the * gadget driver for further processing. */ - req->request.actual += req->request.length - count; + actual = length - req->request.actual; + req->request.actual = actual; + + if (ret && chain && (actual < length) && req->num_pending_sgs) + return __dwc3_gadget_kick_transfer(dep, 0); + dwc3_gadget_giveback(dep, req, status); if (ret) -- cgit v1.2.3 From f99f53f24d87d88c1f6e7c7785599cb3e4015839 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 12 Aug 2016 13:19:20 +0300 Subject: usb: dwc3: gadget: remove condition that never happens We don't use LST bit anymore, so this condition will never trigger. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/usb/dwc3/gadget.c') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index c18bf1caad54..835a5dcb8460 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1918,13 +1918,11 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, if (s_pkt && !chain) return 1; - if ((event->status & DEPEVT_STATUS_LST) && - (trb->ctrl & (DWC3_TRB_CTRL_LST | - DWC3_TRB_CTRL_HWO))) - return 1; + if ((event->status & DEPEVT_STATUS_IOC) && (trb->ctrl & DWC3_TRB_CTRL_IOC)) return 1; + return 0; } -- cgit v1.2.3 From dc55c67e9c95e89ef5e384fb1f70520a5383c9dd Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 12 Aug 2016 13:20:32 +0300 Subject: usb: dwc3: gadget: improve increment request->actual No functional changes, just a slight cosmetic change. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/usb/dwc3/gadget.c') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 835a5dcb8460..0288ea99c85a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1860,6 +1860,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, unsigned int trb_status; dep->queued_requests--; + dwc3_ep_inc_deq(dep); trace_dwc3_complete_trb(dep, trb); /* @@ -1879,6 +1880,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, return 1; count = trb->size & DWC3_TRB_SIZE_MASK; + req->request.actual += count; if (dep->direction) { if (count) { @@ -1931,7 +1933,6 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, { struct dwc3_request *req, *n; struct dwc3_trb *trb; - int count = 0; int ret; list_for_each_entry_safe(req, n, &dep->started_list, list) { @@ -1949,8 +1950,6 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, for_each_sg(sg, s, pending, i) { trb = &dep->trb_pool[dep->trb_dequeue]; - count += trb->size & DWC3_TRB_SIZE_MASK; - dwc3_ep_inc_deq(dep); req->sg = sg_next(s); req->num_pending_sgs--; @@ -1962,9 +1961,6 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, } } else { trb = &dep->trb_pool[dep->trb_dequeue]; - count += trb->size & DWC3_TRB_SIZE_MASK; - dwc3_ep_inc_deq(dep); - ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status, chain); } -- cgit v1.2.3 From 06281d460fc5d8df843786341ded16d85f50dd3d Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 22 Aug 2016 15:39:13 -0700 Subject: usb: dwc3: Add ENDXFER command polling ENDXFER polling is available on version 3.10a and later of the DWC_usb3 (USB 3.0) controller. With this feature, the software can poll the CMDACT bit in the DEPCMD register after issuing an ENDXFER command. This feature is enabled by writing GUCTL2[14]. This feature is NOT available on the DWC_usb31 (USB 3.1) IP. Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 11 +++++++++++ drivers/usb/dwc3/core.h | 4 ++++ drivers/usb/dwc3/gadget.c | 16 +++++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers/usb/dwc3/gadget.c') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 25e424e40462..d6d3fa0fa528 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -704,6 +704,17 @@ static int dwc3_core_init(struct dwc3 *dwc) break; } + /* + * ENDXFER polling is available on version 3.10a and later of + * the DWC_usb3 controller. It is NOT available in the + * DWC_usb31 controller. + */ + if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) { + reg = dwc3_readl(dwc->regs, DWC3_GUCTL2); + reg |= DWC3_GUCTL2_RST_ACTBITLATER; + dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); + } + return 0; err4: diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 002e6477d586..b2317e702f57 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -109,6 +109,7 @@ #define DWC3_GPRTBIMAP_HS1 0xc184 #define DWC3_GPRTBIMAP_FS0 0xc188 #define DWC3_GPRTBIMAP_FS1 0xc18c +#define DWC3_GUCTL2 0xc19c #define DWC3_VER_NUMBER 0xc1a0 #define DWC3_VER_TYPE 0xc1a4 @@ -288,6 +289,9 @@ #define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7) #define DWC3_GFLADJ_30MHZ_MASK 0x3f +/* Global User Control Register 2 */ +#define DWC3_GUCTL2_RST_ACTBITLATER (1 << 14) + /* Device Configuration Register */ #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 0288ea99c85a..161a6bfcb84e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2228,6 +2228,18 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force) * * - Issue EndTransfer WITH CMDIOC bit set * - Wait 100us + * + * As of IP version 3.10a of the DWC_usb3 IP, the controller + * supports a mode to work around the above limitation. The + * software can poll the CMDACT bit in the DEPCMD register + * after issuing a EndTransfer command. This mode is enabled + * by writing GUCTL2[14]. This polling is already done in the + * dwc3_send_gadget_ep_cmd() function so if the mode is + * enabled, the EndTransfer command will have completed upon + * returning from this function and we don't need to delay for + * 100us. + * + * This mode is NOT available on the DWC_usb31 IP. */ cmd = DWC3_DEPCMD_ENDTRANSFER; @@ -2239,7 +2251,9 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force) WARN_ON_ONCE(ret); dep->resource_index = 0; dep->flags &= ~DWC3_EP_BUSY; - udelay(100); + + if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) + udelay(100); } static void dwc3_stop_active_transfers(struct dwc3 *dwc) -- cgit v1.2.3 From 7ae7df4982af6aed25c5e9e71b91027a494149de Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 24 Aug 2016 14:37:22 +0300 Subject: usb: dwc3: gadget: abolish trbs_left Instead, we can always rely on dwc3_calc_trbs_left() directly. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers/usb/dwc3/gadget.c') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 161a6bfcb84e..104b145f506d 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -886,7 +886,7 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) } static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, - struct dwc3_request *req, unsigned int trbs_left) + struct dwc3_request *req) { struct scatterlist *sg = req->sg; struct scatterlist *s; @@ -906,13 +906,13 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, dwc3_prepare_one_trb(dep, req, dma, length, chain, i); - if (!trbs_left--) + if (!dwc3_calc_trbs_left(dep)) break; } } static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, - struct dwc3_request *req, unsigned int trbs_left) + struct dwc3_request *req) { unsigned int length; dma_addr_t dma; @@ -935,21 +935,19 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, static void dwc3_prepare_trbs(struct dwc3_ep *dep) { struct dwc3_request *req, *n; - u32 trbs_left; BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); - trbs_left = dwc3_calc_trbs_left(dep); - if (!trbs_left) + if (!dwc3_calc_trbs_left(dep)) return; list_for_each_entry_safe(req, n, &dep->pending_list, list) { if (req->num_pending_sgs > 0) - dwc3_prepare_one_trb_sg(dep, req, trbs_left--); + dwc3_prepare_one_trb_sg(dep, req); else - dwc3_prepare_one_trb_linear(dep, req, trbs_left--); + dwc3_prepare_one_trb_linear(dep, req); - if (!trbs_left) + if (!dwc3_calc_trbs_left(dep)) return; } } -- cgit v1.2.3 From 594e121f25689baaf1c8c9b006701e66744d5838 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 24 Aug 2016 14:38:10 +0300 Subject: usb: dwc3: gadget: stop kicking if we run out of space In case our TRB ring is full, we can avoid trying to kick transfers which won't start and just add requests to the queue. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/usb/dwc3/gadget.c') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 104b145f506d..37a86522fa88 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1082,6 +1082,9 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) return 0; } + if (!dwc3_calc_trbs_left(dep)) + return 0; + ret = __dwc3_gadget_kick_transfer(dep, 0); if (ret && ret != -EBUSY) dwc3_trace(trace_dwc3_gadget, -- cgit v1.2.3 From d6e10bf2ba4783881670731faf8d3705cad488eb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Sep 2016 12:01:51 +0200 Subject: usb: dwc3: avoid -Wmaybe-uninitialized warning Cleaning up the loop in dwc3_cleanup_done_reqs() introduced a gcc warning if built with "-Wmaybe-uninitialized": drivers/usb/dwc3/gadget.c: In function 'dwc3_endpoint_transfer_complete': drivers/usb/dwc3/gadget.c:2015:9: 'trb' may be used uninitialized in this function [-Wmaybe-uninitialized] I believe it is a false positive and we always have a valid 'trb' pointer at the end of the function, but neither I nor the compiler are able to prove that. This works around the warning by computing a flag earlier in the function when it's guaranteed to be valid, which tells the compiler that it's safe and makes it easier to understand to me. Signed-off-by: Arnd Bergmann Fixes: 31162af447d7 ("usb: dwc3: gadget: avoid while (1) loop on completion") Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/usb/dwc3/gadget.c') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 37a86522fa88..a5d496dd53b2 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1934,6 +1934,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, { struct dwc3_request *req, *n; struct dwc3_trb *trb; + bool ioc = false; int ret; list_for_each_entry_safe(req, n, &dep->started_list, list) { @@ -1981,8 +1982,12 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, dwc3_gadget_giveback(dep, req, status); - if (ret) + if (ret) { + if ((event->status & DEPEVT_STATUS_IOC) && + (trb->ctrl & DWC3_TRB_CTRL_IOC)) + ioc = true; break; + } } /* @@ -2010,10 +2015,9 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, return 1; } - if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) - if ((event->status & DEPEVT_STATUS_IOC) && - (trb->ctrl & DWC3_TRB_CTRL_IOC)) - return 0; + if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && ioc) + return 0; + return 1; } -- cgit v1.2.3 From 5e6c88d28ccbe72bedee1fbf4f9fea4764208598 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Fri, 9 Sep 2016 12:51:27 +0800 Subject: usb: dwc3: fix Clear Stall EP command failure Commit 50c763f8c1bac ("usb: dwc3: Set the ClearPendIN bit on Clear Stall EP command") sets ClearPendIN bit for all IN endpoints of v2.60a+ cores. This causes ClearStall command fails on 2.60+ cores operating in HighSpeed mode. In page 539 of 2.60a specification: "When issuing Clear Stall command for IN endpoints in SuperSpeed mode, the software must set the "ClearPendIN" bit to '1' to clear any pending IN transcations, so that the device does not expect any ACK TP from the host for the data sent earlier." It's obvious that we only need to apply this rule to those IN endpoints that currently operating in SuperSpeed mode. Fixes: 50c763f8c1bac ("usb: dwc3: Set the ClearPendIN bit on Clear Stall EP command") Cc: # v4.7+ Signed-off-by: Lu Baolu Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb/dwc3/gadget.c') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index a5d496dd53b2..e49082f9edeb 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -341,7 +341,8 @@ static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep) * IN transfers due to a mishandled error condition. Synopsys * STAR 9000614252. */ - if (dep->direction && (dwc->revision >= DWC3_REVISION_260A)) + if (dep->direction && (dwc->revision >= DWC3_REVISION_260A) && + (dwc->gadget.speed >= USB_SPEED_SUPER)) cmd |= DWC3_DEPCMD_CLEARPENDIN; memset(¶ms, 0, sizeof(params)); -- cgit v1.2.3