aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/dwc3
diff options
context:
space:
mode:
authorFelipe Balbi2011-08-27 22:07:53 +0300
committerFelipe Balbi2011-09-09 13:02:04 +0300
commit5812b1c236774ea580b6af39411eb4f7297d7623 (patch)
treef25e68599057b95f7f0302922a17566b1e67e303 /drivers/usb/dwc3
parentdc137f01aca23ceb196945130a960e2a01b95890 (diff)
usb: dwc3: add a bounce buffer for control endpoints
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>
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r--drivers/usb/dwc3/core.h6
-rw-r--r--drivers/usb/dwc3/gadget.c29
2 files changed, 28 insertions, 7 deletions
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 08d8ff6b943a..8688b5a809d2 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -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
@@ -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)
@@ -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;
@@ -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;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 56ccd97000a6..569473bcfb50 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -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;
@@ -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);
@@ -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 */
@@ -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);
@@ -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);