Skip to content

Commit

Permalink
usb: dwc3: add a bounce buffer for control endpoints
Browse files Browse the repository at this point in the history
This core cannot handle OUT transfers which aren't
aligned to wMaxPacketSize, but that can happen at
least on control endpoint with the USB Audio Class.

This patch adds a bounce buffer to be used on the
case of a non-aligned ep0out request is queued.

Signed-off-by: Felipe Balbi <balbi@ti.com>
  • Loading branch information
Felipe Balbi committed Sep 9, 2011
1 parent dc137f0 commit 5812b1c
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 7 deletions.
6 changes: 6 additions & 0 deletions drivers/usb/dwc3/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -505,11 +505,13 @@ static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat)
* struct dwc3 - representation of our controller
* @ctrl_req: usb control request which is used for ep0
* @ep0_trb: trb which is used for the ctrl_req
* @ep0_bounce: bounce buffer for ep0
* @setup_buf: used while precessing STD USB requests
* @ctrl_req_addr: dma address of ctrl_req
* @ep0_trb: dma address of ep0_trb
* @ep0_usb_req: dummy req used while handling STD USB requests
* @setup_buf_addr: dma address of setup_buf
* @ep0_bounce_addr: dma address of ep0_bounce
* @lock: for synchronizing
* @dev: pointer to our struct device
* @event_buffer_list: a list of event buffers
Expand All @@ -522,6 +524,7 @@ static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat)
* @is_selfpowered: true when we are selfpowered
* @three_stage_setup: set if we perform a three phase setup
* @ep0_status_pending: ep0 status response without a req is pending
* @ep0_bounced: true when we used bounce buffer
* @ep0state: state of endpoint zero
* @link_state: link state
* @speed: device speed (super, high, full, low)
Expand All @@ -531,10 +534,12 @@ static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat)
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
struct dwc3_trb_hw *ep0_trb;
void *ep0_bounce;
u8 *setup_buf;
dma_addr_t ctrl_req_addr;
dma_addr_t ep0_trb_addr;
dma_addr_t setup_buf_addr;
dma_addr_t ep0_bounce_addr;
struct usb_request ep0_usb_req;
/* device lock */
spinlock_t lock;
Expand Down Expand Up @@ -564,6 +569,7 @@ struct dwc3 {
unsigned is_selfpowered:1;
unsigned three_stage_setup:1;
unsigned ep0_status_pending:1;
unsigned ep0_bounced:1;

enum dwc3_ep0_state ep0state;
enum dwc3_link_state link_state;
Expand Down
29 changes: 22 additions & 7 deletions drivers/usb/dwc3/gadget.c
Original file line number Diff line number Diff line change
Expand Up @@ -1957,6 +1957,14 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
goto err2;
}

dwc->ep0_bounce = dma_alloc_coherent(dwc->dev,
512, &dwc->ep0_bounce_addr, GFP_KERNEL);
if (!dwc->ep0_bounce) {
dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
ret = -ENOMEM;
goto err3;
}

dev_set_name(&dwc->gadget.dev, "gadget");

dwc->gadget.ops = &dwc3_gadget_ops;
Expand All @@ -1978,7 +1986,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)

ret = dwc3_gadget_init_endpoints(dwc);
if (ret)
goto err3;
goto err4;

irq = platform_get_irq(to_platform_device(dwc->dev), 0);

Expand All @@ -1987,7 +1995,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
if (ret) {
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
irq, ret);
goto err4;
goto err5;
}

/* Enable all but Start and End of Frame IRQs */
Expand All @@ -2006,27 +2014,31 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
if (ret) {
dev_err(dwc->dev, "failed to register gadget device\n");
put_device(&dwc->gadget.dev);
goto err5;
goto err6;
}

ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
if (ret) {
dev_err(dwc->dev, "failed to register udc\n");
goto err6;
goto err7;
}

return 0;

err6:
err7:
device_unregister(&dwc->gadget.dev);

err5:
err6:
dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
free_irq(irq, dwc);

err4:
err5:
dwc3_gadget_free_endpoints(dwc);

err4:
dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
dwc->ep0_bounce_addr);

err3:
dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
dwc->setup_buf, dwc->setup_buf_addr);
Expand Down Expand Up @@ -2059,6 +2071,9 @@ void dwc3_gadget_exit(struct dwc3 *dwc)

dwc3_gadget_free_endpoints(dwc);

dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
dwc->ep0_bounce_addr);

dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
dwc->setup_buf, dwc->setup_buf_addr);

Expand Down

0 comments on commit 5812b1c

Please sign in to comment.