Skip to content

Commit c6267a5

Browse files
author
Felipe Balbi
committed
usb: dwc3: gadget: align transfers to wMaxPacketSize
Instead of passing quirk_ep_out_aligned_size, we can use one extra TRB to align transfer to wMaxPacketSize. Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
1 parent 905dc04 commit c6267a5

File tree

2 files changed

+63
-8
lines changed

2 files changed

+63
-8
lines changed

drivers/usb/dwc3/core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,7 @@ struct dwc3_hwparams {
725725
* @epnum: endpoint number to which this request refers
726726
* @trb: pointer to struct dwc3_trb
727727
* @trb_dma: DMA address of @trb
728+
* @unaligned: true for OUT endpoints with length not divisible by maxp
728729
* @direction: IN or OUT direction flag
729730
* @mapped: true when request has been dma-mapped
730731
* @queued: true when request has been queued to HW
@@ -741,6 +742,7 @@ struct dwc3_request {
741742
struct dwc3_trb *trb;
742743
dma_addr_t trb_dma;
743744

745+
unsigned unaligned:1;
744746
unsigned direction:1;
745747
unsigned mapped:1;
746748
unsigned started:1;

drivers/usb/dwc3/gadget.c

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -992,12 +992,33 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
992992
int i;
993993

994994
for_each_sg(sg, s, req->num_pending_sgs, i) {
995+
unsigned int length = req->request.length;
996+
unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
997+
unsigned int rem = length % maxp;
995998
unsigned chain = true;
996999

9971000
if (sg_is_last(s))
9981001
chain = false;
9991002

1000-
dwc3_prepare_one_trb(dep, req, chain, i);
1003+
if (rem && usb_endpoint_dir_out(dep->endpoint.desc) && !chain) {
1004+
struct dwc3 *dwc = dep->dwc;
1005+
struct dwc3_trb *trb;
1006+
1007+
req->unaligned = true;
1008+
1009+
/* prepare normal TRB */
1010+
dwc3_prepare_one_trb(dep, req, true, i);
1011+
1012+
/* Now prepare one extra TRB to align transfer size */
1013+
trb = &dep->trb_pool[dep->trb_enqueue];
1014+
__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr,
1015+
maxp - rem, false, 0,
1016+
req->request.stream_id,
1017+
req->request.short_not_ok,
1018+
req->request.no_interrupt);
1019+
} else {
1020+
dwc3_prepare_one_trb(dep, req, chain, i);
1021+
}
10011022

10021023
if (!dwc3_calc_trbs_left(dep))
10031024
break;
@@ -1007,7 +1028,28 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
10071028
static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
10081029
struct dwc3_request *req)
10091030
{
1010-
dwc3_prepare_one_trb(dep, req, false, 0);
1031+
unsigned int length = req->request.length;
1032+
unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
1033+
unsigned int rem = length % maxp;
1034+
1035+
if (rem && usb_endpoint_dir_out(dep->endpoint.desc)) {
1036+
struct dwc3 *dwc = dep->dwc;
1037+
struct dwc3_trb *trb;
1038+
1039+
req->unaligned = true;
1040+
1041+
/* prepare normal TRB */
1042+
dwc3_prepare_one_trb(dep, req, true, 0);
1043+
1044+
/* Now prepare one extra TRB to align transfer size */
1045+
trb = &dep->trb_pool[dep->trb_enqueue];
1046+
__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp - rem,
1047+
false, 0, req->request.stream_id,
1048+
req->request.short_not_ok,
1049+
req->request.no_interrupt);
1050+
} else {
1051+
dwc3_prepare_one_trb(dep, req, false, 0);
1052+
}
10111053
}
10121054

10131055
/*
@@ -2031,6 +2073,16 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
20312073
if (chain && (trb->ctrl & DWC3_TRB_CTRL_HWO))
20322074
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
20332075

2076+
/*
2077+
* If we're dealing with unaligned size OUT transfer, we will be left
2078+
* with one TRB pending in the ring. We need to manually clear HWO bit
2079+
* from that TRB.
2080+
*/
2081+
if (req->unaligned && (trb->ctrl & DWC3_TRB_CTRL_HWO)) {
2082+
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
2083+
return 1;
2084+
}
2085+
20342086
if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
20352087
return 1;
20362088

@@ -2120,6 +2172,13 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
21202172
event, status, chain);
21212173
}
21222174

2175+
if (req->unaligned) {
2176+
trb = &dep->trb_pool[dep->trb_dequeue];
2177+
ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
2178+
event, status, false);
2179+
req->unaligned = false;
2180+
}
2181+
21232182
req->request.actual = length - req->remaining;
21242183

21252184
if ((req->request.actual < length) && req->num_pending_sgs)
@@ -3058,12 +3117,6 @@ int dwc3_gadget_init(struct dwc3 *dwc)
30583117

30593118
dwc->gadget.max_speed = dwc->maximum_speed;
30603119

3061-
/*
3062-
* Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize
3063-
* on ep out.
3064-
*/
3065-
dwc->gadget.quirk_ep_out_aligned_size = true;
3066-
30673120
/*
30683121
* REVISIT: Here we should clear all pending IRQs to be
30693122
* sure we're starting from a well known location.

0 commit comments

Comments
 (0)