Commit 4199c5f8 authored by Felipe Balbi's avatar Felipe Balbi

usb: dwc3: ep0: improve handling of unaligned OUT requests

Just like we did for all other endpoint types, let's rely on a chained
TRB pointing to ep0_bounce_addr in order to align transfer size. This
will make the code simpler.
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent d686a5ff
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
#define DWC3_PULL_UP_TIMEOUT 500 /* ms */ #define DWC3_PULL_UP_TIMEOUT 500 /* ms */
#define DWC3_ZLP_BUF_SIZE 1024 /* size of a superspeed bulk */ #define DWC3_ZLP_BUF_SIZE 1024 /* size of a superspeed bulk */
#define DWC3_BOUNCE_SIZE 1024 /* size of a superspeed bulk */ #define DWC3_BOUNCE_SIZE 1024 /* size of a superspeed bulk */
#define DWC3_EP0_BOUNCE_SIZE 512 #define DWC3_EP0_SETUP_SIZE 512
#define DWC3_ENDPOINTS_NUM 32 #define DWC3_ENDPOINTS_NUM 32
#define DWC3_XHCI_RESOURCES_NUM 2 #define DWC3_XHCI_RESOURCES_NUM 2
...@@ -761,12 +761,10 @@ struct dwc3_scratchpad_array { ...@@ -761,12 +761,10 @@ struct dwc3_scratchpad_array {
/** /**
* struct dwc3 - representation of our controller * struct dwc3 - representation of our controller
* @ep0_trb: trb which is used for the ctrl_req * @ep0_trb: trb which is used for the ctrl_req
* @ep0_bounce: bounce buffer for ep0
* @zlp_buf: used when request->zero is set * @zlp_buf: used when request->zero is set
* @setup_buf: used while precessing STD USB requests * @setup_buf: used while precessing STD USB requests
* @ep0_trb: dma address of ep0_trb * @ep0_trb: dma address of ep0_trb
* @ep0_usb_req: dummy req used while handling STD USB requests * @ep0_usb_req: dummy req used while handling STD USB requests
* @ep0_bounce_addr: dma address of ep0_bounce
* @scratch_addr: dma address of scratchbuf * @scratch_addr: dma address of scratchbuf
* @ep0_in_setup: one control transfer is completed and enter setup phase * @ep0_in_setup: one control transfer is completed and enter setup phase
* @lock: for synchronizing * @lock: for synchronizing
...@@ -859,13 +857,11 @@ struct dwc3_scratchpad_array { ...@@ -859,13 +857,11 @@ struct dwc3_scratchpad_array {
struct dwc3 { struct dwc3 {
struct dwc3_trb *ep0_trb; struct dwc3_trb *ep0_trb;
void *bounce; void *bounce;
void *ep0_bounce;
void *zlp_buf; void *zlp_buf;
void *scratchbuf; void *scratchbuf;
u8 *setup_buf; u8 *setup_buf;
dma_addr_t ep0_trb_addr; dma_addr_t ep0_trb_addr;
dma_addr_t bounce_addr; dma_addr_t bounce_addr;
dma_addr_t ep0_bounce_addr;
dma_addr_t scratch_addr; dma_addr_t scratch_addr;
struct dwc3_request ep0_usb_req; struct dwc3_request ep0_usb_req;
struct completion ep0_in_setup; struct completion ep0_in_setup;
......
...@@ -836,7 +836,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, ...@@ -836,7 +836,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
struct usb_request *ur; struct usb_request *ur;
struct dwc3_trb *trb; struct dwc3_trb *trb;
struct dwc3_ep *ep0; struct dwc3_ep *ep0;
unsigned transfer_size = 0;
unsigned maxp; unsigned maxp;
unsigned remaining_ur_length; unsigned remaining_ur_length;
void *buf; void *buf;
...@@ -849,9 +848,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, ...@@ -849,9 +848,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
ep0 = dwc->eps[0]; ep0 = dwc->eps[0];
dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
trb = dwc->ep0_trb; trb = dwc->ep0_trb;
trace_dwc3_complete_trb(ep0, trb); trace_dwc3_complete_trb(ep0, trb);
r = next_request(&ep0->pending_list); r = next_request(&ep0->pending_list);
...@@ -872,39 +869,17 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, ...@@ -872,39 +869,17 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
remaining_ur_length = ur->length; remaining_ur_length = ur->length;
length = trb->size & DWC3_TRB_SIZE_MASK; length = trb->size & DWC3_TRB_SIZE_MASK;
maxp = ep0->endpoint.maxpacket; maxp = ep0->endpoint.maxpacket;
transferred = ur->length - length;
if (dwc->ep0_bounced) {
/*
* Handle the first TRB before handling the bounce buffer if
* the request length is greater than the bounce buffer size
*/
if (ur->length > DWC3_EP0_BOUNCE_SIZE) {
transfer_size = ALIGN(ur->length - maxp, maxp);
transferred = transfer_size - length;
buf = (u8 *)buf + transferred;
ur->actual += transferred; ur->actual += transferred;
remaining_ur_length -= transferred;
if (dwc->ep0_bounced) {
trb++; trb++;
length = trb->size & DWC3_TRB_SIZE_MASK; trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
ep0->trb_enqueue = 0; ep0->trb_enqueue = 0;
dwc->ep0_bounced = false;
} }
transfer_size = roundup((ur->length - transfer_size),
maxp);
transferred = min_t(u32, remaining_ur_length,
transfer_size - length);
memcpy(buf, dwc->ep0_bounce, transferred);
} else {
transferred = ur->length - length;
}
ur->actual += transferred;
if ((epnum & 1) && ur->actual < ur->length) { if ((epnum & 1) && ur->actual < ur->length) {
/* for some reason we did not get everything out */ /* for some reason we did not get everything out */
...@@ -1006,8 +981,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, ...@@ -1006,8 +981,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
ret = dwc3_ep0_start_trans(dep); ret = dwc3_ep0_start_trans(dep);
} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
&& (dep->number == 0)) { && (dep->number == 0)) {
u32 transfer_size = 0;
u32 maxpacket; u32 maxpacket;
u32 rem;
ret = usb_gadget_map_request_by_dev(dwc->sysdev, ret = usb_gadget_map_request_by_dev(dwc->sysdev,
&req->request, dep->number); &req->request, dep->number);
...@@ -1015,23 +990,19 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, ...@@ -1015,23 +990,19 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
return; return;
maxpacket = dep->endpoint.maxpacket; maxpacket = dep->endpoint.maxpacket;
rem = req->request.length % maxpacket;
dwc->ep0_bounced = true;
if (req->request.length > DWC3_EP0_BOUNCE_SIZE) { /* prepare normal TRB */
transfer_size = ALIGN(req->request.length - maxpacket,
maxpacket);
dwc3_ep0_prepare_one_trb(dep, req->request.dma, dwc3_ep0_prepare_one_trb(dep, req->request.dma,
transfer_size, req->request.length,
DWC3_TRBCTL_CONTROL_DATA, DWC3_TRBCTL_CONTROL_DATA,
true); true);
}
transfer_size = roundup((req->request.length - transfer_size),
maxpacket);
dwc->ep0_bounced = true; /* Now prepare one extra TRB to align transfer size */
dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
dwc3_ep0_prepare_one_trb(dep, dwc->ep0_bounce_addr, maxpacket - rem,
transfer_size, DWC3_TRBCTL_CONTROL_DATA, DWC3_TRBCTL_CONTROL_DATA,
false); false);
ret = dwc3_ep0_start_trans(dep); ret = dwc3_ep0_start_trans(dep);
} else { } else {
......
...@@ -171,7 +171,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, ...@@ -171,7 +171,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
int status) int status)
{ {
struct dwc3 *dwc = dep->dwc; struct dwc3 *dwc = dep->dwc;
unsigned int unmap_after_complete = false;
req->started = false; req->started = false;
list_del(&req->list); list_del(&req->list);
...@@ -181,19 +180,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, ...@@ -181,19 +180,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
if (req->request.status == -EINPROGRESS) if (req->request.status == -EINPROGRESS)
req->request.status = status; req->request.status = status;
/*
* NOTICE we don't want to unmap before calling ->complete() if we're
* dealing with a bounced ep0 request. If we unmap it here, we would end
* up overwritting the contents of req->buf and this could confuse the
* gadget driver.
*/
if (dwc->ep0_bounced && dep->number <= 1) {
dwc->ep0_bounced = false;
unmap_after_complete = true;
} else {
usb_gadget_unmap_request_by_dev(dwc->sysdev, usb_gadget_unmap_request_by_dev(dwc->sysdev,
&req->request, req->direction); &req->request, req->direction);
}
trace_dwc3_gadget_giveback(req); trace_dwc3_gadget_giveback(req);
...@@ -201,10 +189,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, ...@@ -201,10 +189,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
usb_gadget_giveback_request(&dep->endpoint, &req->request); usb_gadget_giveback_request(&dep->endpoint, &req->request);
spin_lock(&dwc->lock); spin_lock(&dwc->lock);
if (unmap_after_complete)
usb_gadget_unmap_request_by_dev(dwc->sysdev,
&req->request, req->direction);
if (dep->number > 1) if (dep->number > 1)
pm_runtime_put(dwc->dev); pm_runtime_put(dwc->dev);
} }
...@@ -3153,32 +3137,23 @@ int dwc3_gadget_init(struct dwc3 *dwc) ...@@ -3153,32 +3137,23 @@ int dwc3_gadget_init(struct dwc3 *dwc)
goto err0; goto err0;
} }
dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL); dwc->setup_buf = kzalloc(DWC3_EP0_SETUP_SIZE, GFP_KERNEL);
if (!dwc->setup_buf) { if (!dwc->setup_buf) {
ret = -ENOMEM; ret = -ENOMEM;
goto err1; goto err1;
} }
dwc->ep0_bounce = dma_alloc_coherent(dwc->sysdev,
DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr,
GFP_KERNEL);
if (!dwc->ep0_bounce) {
dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
ret = -ENOMEM;
goto err2;
}
dwc->zlp_buf = kzalloc(DWC3_ZLP_BUF_SIZE, GFP_KERNEL); dwc->zlp_buf = kzalloc(DWC3_ZLP_BUF_SIZE, GFP_KERNEL);
if (!dwc->zlp_buf) { if (!dwc->zlp_buf) {
ret = -ENOMEM; ret = -ENOMEM;
goto err3; goto err2;
} }
dwc->bounce = dma_alloc_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce = dma_alloc_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE,
&dwc->bounce_addr, GFP_KERNEL); &dwc->bounce_addr, GFP_KERNEL);
if (!dwc->bounce) { if (!dwc->bounce) {
ret = -ENOMEM; ret = -ENOMEM;
goto err4; goto err3;
} }
init_completion(&dwc->ep0_in_setup); init_completion(&dwc->ep0_in_setup);
...@@ -3218,7 +3193,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) ...@@ -3218,7 +3193,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
ret = dwc3_gadget_init_endpoints(dwc, dwc->num_eps); ret = dwc3_gadget_init_endpoints(dwc, dwc->num_eps);
if (ret) if (ret)
goto err5; goto err4;
ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
if (ret) { if (ret) {
...@@ -3228,16 +3203,14 @@ int dwc3_gadget_init(struct dwc3 *dwc) ...@@ -3228,16 +3203,14 @@ int dwc3_gadget_init(struct dwc3 *dwc)
return 0; return 0;
err5: err5:
dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce, dwc3_gadget_free_endpoints(dwc);
dwc->bounce_addr);
err4: err4:
kfree(dwc->zlp_buf); dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
dwc->bounce_addr);
err3: err3:
dwc3_gadget_free_endpoints(dwc); kfree(dwc->zlp_buf);
dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE,
dwc->ep0_bounce, dwc->ep0_bounce_addr);
err2: err2:
kfree(dwc->setup_buf); kfree(dwc->setup_buf);
...@@ -3260,9 +3233,6 @@ void dwc3_gadget_exit(struct dwc3 *dwc) ...@@ -3260,9 +3233,6 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce, dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
dwc->bounce_addr); dwc->bounce_addr);
dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE,
dwc->ep0_bounce, dwc->ep0_bounce_addr);
kfree(dwc->setup_buf); kfree(dwc->setup_buf);
kfree(dwc->zlp_buf); kfree(dwc->zlp_buf);
......
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