Commit 7012bf6d authored by Thinh Nguyen's avatar Thinh Nguyen Committed by Greg Kroah-Hartman

usb: dwc3: gadget: Fix handling ZLP

[ Upstream commit d2ee3ff7 ]

The usb_request->zero doesn't apply for isoc. Also, if we prepare a
0-length (ZLP) TRB for the OUT direction, we need to prepare an extra
TRB to pad up to the MPS alignment. Use the same bounce buffer for the
ZLP TRB and the extra pad TRB.

Cc: <stable@vger.kernel.org> # v4.5+
Fixes: d6e5a549 ("usb: dwc3: simplify ZLP handling")
Fixes: 04c03d10 ("usb: dwc3: gadget: handle request->zero")
Signed-off-by: default avatarThinh Nguyen <thinhn@synopsys.com>
Signed-off-by: default avatarFelipe Balbi <balbi@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent c4d7362a
...@@ -1159,6 +1159,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, ...@@ -1159,6 +1159,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
req->request.short_not_ok, req->request.short_not_ok,
req->request.no_interrupt); req->request.no_interrupt);
} else if (req->request.zero && req->request.length && } else if (req->request.zero && req->request.length &&
!usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
(IS_ALIGNED(req->request.length, maxp))) { (IS_ALIGNED(req->request.length, maxp))) {
struct dwc3 *dwc = dep->dwc; struct dwc3 *dwc = dep->dwc;
struct dwc3_trb *trb; struct dwc3_trb *trb;
...@@ -1168,13 +1169,23 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, ...@@ -1168,13 +1169,23 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
/* prepare normal TRB */ /* prepare normal TRB */
dwc3_prepare_one_trb(dep, req, length, true, 0); dwc3_prepare_one_trb(dep, req, length, true, 0);
/* Now prepare one extra TRB to handle ZLP */ /* Prepare one extra TRB to handle ZLP */
trb = &dep->trb_pool[dep->trb_enqueue]; trb = &dep->trb_pool[dep->trb_enqueue];
req->num_trbs++; req->num_trbs++;
__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0, __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0,
false, 1, req->request.stream_id, !req->direction, 1, req->request.stream_id,
req->request.short_not_ok, req->request.short_not_ok,
req->request.no_interrupt); req->request.no_interrupt);
/* Prepare one more TRB to handle MPS alignment for OUT */
if (!req->direction) {
trb = &dep->trb_pool[dep->trb_enqueue];
req->num_trbs++;
__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp,
false, 1, req->request.stream_id,
req->request.short_not_ok,
req->request.no_interrupt);
}
} else { } else {
dwc3_prepare_one_trb(dep, req, length, false, 0); dwc3_prepare_one_trb(dep, req, length, false, 0);
} }
...@@ -2347,8 +2358,17 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, ...@@ -2347,8 +2358,17 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep,
status); status);
if (req->needs_extra_trb) { if (req->needs_extra_trb) {
unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event, ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event,
status); status);
/* Reclaim MPS padding TRB for ZLP */
if (!req->direction && req->request.zero && req->request.length &&
!usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
(IS_ALIGNED(req->request.length, maxp)))
ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event, status);
req->needs_extra_trb = false; req->needs_extra_trb = false;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment