mirror of
https://github.com/torvalds/linux.git
synced 2024-12-03 09:31:26 +00:00
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: Felipe Balbi <felipe.balbi@linux.intel.com>
This commit is contained in:
parent
d686a5ff6a
commit
4199c5f8bc
@ -42,7 +42,7 @@
|
||||
#define DWC3_PULL_UP_TIMEOUT 500 /* ms */
|
||||
#define DWC3_ZLP_BUF_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_XHCI_RESOURCES_NUM 2
|
||||
|
||||
@ -761,12 +761,10 @@ struct dwc3_scratchpad_array {
|
||||
/**
|
||||
* struct dwc3 - representation of our controller
|
||||
* @ep0_trb: trb which is used for the ctrl_req
|
||||
* @ep0_bounce: bounce buffer for ep0
|
||||
* @zlp_buf: used when request->zero is set
|
||||
* @setup_buf: used while precessing STD USB requests
|
||||
* @ep0_trb: dma address of ep0_trb
|
||||
* @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
|
||||
* @ep0_in_setup: one control transfer is completed and enter setup phase
|
||||
* @lock: for synchronizing
|
||||
@ -859,13 +857,11 @@ struct dwc3_scratchpad_array {
|
||||
struct dwc3 {
|
||||
struct dwc3_trb *ep0_trb;
|
||||
void *bounce;
|
||||
void *ep0_bounce;
|
||||
void *zlp_buf;
|
||||
void *scratchbuf;
|
||||
u8 *setup_buf;
|
||||
dma_addr_t ep0_trb_addr;
|
||||
dma_addr_t bounce_addr;
|
||||
dma_addr_t ep0_bounce_addr;
|
||||
dma_addr_t scratch_addr;
|
||||
struct dwc3_request ep0_usb_req;
|
||||
struct completion ep0_in_setup;
|
||||
|
@ -836,7 +836,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
||||
struct usb_request *ur;
|
||||
struct dwc3_trb *trb;
|
||||
struct dwc3_ep *ep0;
|
||||
unsigned transfer_size = 0;
|
||||
unsigned maxp;
|
||||
unsigned remaining_ur_length;
|
||||
void *buf;
|
||||
@ -849,9 +848,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
||||
ep0 = dwc->eps[0];
|
||||
|
||||
dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
|
||||
|
||||
trb = dwc->ep0_trb;
|
||||
|
||||
trace_dwc3_complete_trb(ep0, trb);
|
||||
|
||||
r = next_request(&ep0->pending_list);
|
||||
@ -872,39 +869,17 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
||||
remaining_ur_length = ur->length;
|
||||
|
||||
length = trb->size & DWC3_TRB_SIZE_MASK;
|
||||
|
||||
maxp = ep0->endpoint.maxpacket;
|
||||
transferred = ur->length - length;
|
||||
ur->actual += transferred;
|
||||
|
||||
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;
|
||||
remaining_ur_length -= transferred;
|
||||
|
||||
trb++;
|
||||
length = trb->size & DWC3_TRB_SIZE_MASK;
|
||||
|
||||
ep0->trb_enqueue = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
trb++;
|
||||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||
ep0->trb_enqueue = 0;
|
||||
dwc->ep0_bounced = false;
|
||||
}
|
||||
|
||||
ur->actual += transferred;
|
||||
|
||||
if ((epnum & 1) && ur->actual < ur->length) {
|
||||
/* for some reason we did not get everything out */
|
||||
|
||||
@ -1006,8 +981,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
ret = dwc3_ep0_start_trans(dep);
|
||||
} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
|
||||
&& (dep->number == 0)) {
|
||||
u32 transfer_size = 0;
|
||||
u32 maxpacket;
|
||||
u32 rem;
|
||||
|
||||
ret = usb_gadget_map_request_by_dev(dwc->sysdev,
|
||||
&req->request, dep->number);
|
||||
@ -1015,23 +990,19 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
return;
|
||||
|
||||
maxpacket = dep->endpoint.maxpacket;
|
||||
|
||||
if (req->request.length > DWC3_EP0_BOUNCE_SIZE) {
|
||||
transfer_size = ALIGN(req->request.length - maxpacket,
|
||||
maxpacket);
|
||||
dwc3_ep0_prepare_one_trb(dep, req->request.dma,
|
||||
transfer_size,
|
||||
DWC3_TRBCTL_CONTROL_DATA,
|
||||
true);
|
||||
}
|
||||
|
||||
transfer_size = roundup((req->request.length - transfer_size),
|
||||
maxpacket);
|
||||
|
||||
rem = req->request.length % maxpacket;
|
||||
dwc->ep0_bounced = true;
|
||||
|
||||
dwc3_ep0_prepare_one_trb(dep, dwc->ep0_bounce_addr,
|
||||
transfer_size, DWC3_TRBCTL_CONTROL_DATA,
|
||||
/* prepare normal TRB */
|
||||
dwc3_ep0_prepare_one_trb(dep, req->request.dma,
|
||||
req->request.length,
|
||||
DWC3_TRBCTL_CONTROL_DATA,
|
||||
true);
|
||||
|
||||
/* Now prepare one extra TRB to align transfer size */
|
||||
dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
|
||||
maxpacket - rem,
|
||||
DWC3_TRBCTL_CONTROL_DATA,
|
||||
false);
|
||||
ret = dwc3_ep0_start_trans(dep);
|
||||
} else {
|
||||
|
@ -171,7 +171,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||||
int status)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned int unmap_after_complete = false;
|
||||
|
||||
req->started = false;
|
||||
list_del(&req->list);
|
||||
@ -181,19 +180,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||||
if (req->request.status == -EINPROGRESS)
|
||||
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,
|
||||
&req->request, req->direction);
|
||||
}
|
||||
usb_gadget_unmap_request_by_dev(dwc->sysdev,
|
||||
&req->request, req->direction);
|
||||
|
||||
trace_dwc3_gadget_giveback(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);
|
||||
spin_lock(&dwc->lock);
|
||||
|
||||
if (unmap_after_complete)
|
||||
usb_gadget_unmap_request_by_dev(dwc->sysdev,
|
||||
&req->request, req->direction);
|
||||
|
||||
if (dep->number > 1)
|
||||
pm_runtime_put(dwc->dev);
|
||||
}
|
||||
@ -3153,32 +3137,23 @@ int dwc3_gadget_init(struct dwc3 *dwc)
|
||||
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) {
|
||||
ret = -ENOMEM;
|
||||
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);
|
||||
if (!dwc->zlp_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto err3;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
dwc->bounce = dma_alloc_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE,
|
||||
&dwc->bounce_addr, GFP_KERNEL);
|
||||
if (!dwc->bounce) {
|
||||
ret = -ENOMEM;
|
||||
goto err4;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
init_completion(&dwc->ep0_in_setup);
|
||||
@ -3218,7 +3193,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
|
||||
|
||||
ret = dwc3_gadget_init_endpoints(dwc, dwc->num_eps);
|
||||
if (ret)
|
||||
goto err5;
|
||||
goto err4;
|
||||
|
||||
ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
|
||||
if (ret) {
|
||||
@ -3228,16 +3203,14 @@ int dwc3_gadget_init(struct dwc3 *dwc)
|
||||
|
||||
return 0;
|
||||
err5:
|
||||
dwc3_gadget_free_endpoints(dwc);
|
||||
|
||||
err4:
|
||||
dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
|
||||
dwc->bounce_addr);
|
||||
|
||||
err4:
|
||||
kfree(dwc->zlp_buf);
|
||||
|
||||
err3:
|
||||
dwc3_gadget_free_endpoints(dwc);
|
||||
dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE,
|
||||
dwc->ep0_bounce, dwc->ep0_bounce_addr);
|
||||
kfree(dwc->zlp_buf);
|
||||
|
||||
err2:
|
||||
kfree(dwc->setup_buf);
|
||||
@ -3260,9 +3233,6 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
|
||||
|
||||
dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
|
||||
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->zlp_buf);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user