summaryrefslogtreecommitdiff
path: root/drivers/usb/cdns3
diff options
context:
space:
mode:
authorLi Jun <jun.li@nxp.com>2018-06-21 18:35:46 +0800
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-24 12:41:33 +0300
commit910270c02b250695876ffb07c71dbba8736d8313 (patch)
tree37b18bafa892ff972e18d02ea7e808ed2eb96d6d /drivers/usb/cdns3
parent7d8b3d3fb4c82218d4fef1325b3ff742694b54dc (diff)
MLK-18656 usb: cdns3: gdaget: add hanlding of request->zero for non-EP0
In case a ZLP is required to finish the transfer, this patch implements it by adding a request with a preallocated buffer, which is shared with all EPs, please be noted this patch is only for non-EP0, ZLP for EP0 will be added later. Reported-by: Andy Tian <yang.tian@nxp.com> Acked-by: Peter Chen <peter.chen@nxp.com> Signed-off-by: Li Jun <jun.li@nxp.com>
Diffstat (limited to 'drivers/usb/cdns3')
-rw-r--r--drivers/usb/cdns3/gadget.c49
-rw-r--r--drivers/usb/cdns3/gadget.h2
2 files changed, 41 insertions, 10 deletions
diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c
index 80293a1ec5a0..eefcddca3901 100644
--- a/drivers/usb/cdns3/gadget.c
+++ b/drivers/usb/cdns3/gadget.c
@@ -1012,6 +1012,9 @@ static int cdns_check_ep_interrupt_proceed(struct usb_ss_endpoint *usb_ss_ep)
spin_lock(&usb_ss->lock);
}
+ if (request->buf == usb_ss->zlp_buf)
+ kfree(request);
+
/* handle deferred STALL */
if (usb_ss_ep->stalled_flag) {
cdns_ep_stall_flush(usb_ss_ep);
@@ -1750,18 +1753,15 @@ static void usb_ss_gadget_ep_free_request(struct usb_ep *ep,
*
* Returns 0 on success, error code elsewhere
*/
-static int usb_ss_gadget_ep_queue(struct usb_ep *ep,
+static int __usb_ss_gadget_ep_queue(struct usb_ep *ep,
struct usb_request *request, gfp_t gfp_flags)
{
struct usb_ss_endpoint *usb_ss_ep =
to_usb_ss_ep(ep);
struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
- unsigned long flags;
int ret = 0;
int empty_list = 0;
- spin_lock_irqsave(&usb_ss->lock, flags);
-
request->actual = 0;
request->status = -EINPROGRESS;
@@ -1774,24 +1774,46 @@ static int usb_ss_gadget_ep_queue(struct usb_ep *ep,
ret = usb_gadget_map_request_by_dev(usb_ss->sysdev, request,
ep->desc->bEndpointAddress & USB_DIR_IN);
- if (ret) {
- spin_unlock_irqrestore(&usb_ss->lock, flags);
+ if (ret)
return ret;
- }
empty_list = list_empty(&usb_ss_ep->request_list);
list_add_tail(&request->list, &usb_ss_ep->request_list);
- if (!usb_ss->hw_configured_flag) {
- spin_unlock_irqrestore(&usb_ss->lock, flags);
+ if (!usb_ss->hw_configured_flag)
return 0;
- }
if (empty_list) {
if (!usb_ss_ep->stalled_flag)
ret = cdns_ep_run_transfer(usb_ss_ep);
}
+ return ret;
+}
+
+static int usb_ss_gadget_ep_queue(struct usb_ep *ep,
+ struct usb_request *request, gfp_t gfp_flags)
+{
+ struct usb_ss_endpoint *usb_ss_ep = to_usb_ss_ep(ep);
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+ struct usb_request *zlp_request;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+
+ ret = __usb_ss_gadget_ep_queue(ep, request, gfp_flags);
+ if (ret == 0 && request->zero && request->length &&
+ (request->length % ep->maxpacket == 0)) {
+ zlp_request = usb_ss_gadget_ep_alloc_request(ep, GFP_ATOMIC);
+ zlp_request->length = 0;
+ zlp_request->buf = usb_ss->zlp_buf;
+
+ dev_dbg(&usb_ss->dev, "Queuing ZLP for endpoint: %s\n",
+ usb_ss_ep->name);
+ ret = __usb_ss_gadget_ep_queue(ep, zlp_request, gfp_flags);
+ }
+
spin_unlock_irqrestore(&usb_ss->lock, flags);
return ret;
}
@@ -2281,6 +2303,12 @@ static int __cdns3_gadget_init(struct cdns3 *cdns)
goto err4;
}
+ usb_ss->zlp_buf = kzalloc(ENDPOINT_ZLP_BUF_SIZE, GFP_KERNEL);
+ if (!usb_ss->zlp_buf) {
+ ret = -ENOMEM;
+ goto err4;
+ }
+
return 0;
err4:
dma_free_coherent(usb_ss->sysdev, 8, usb_ss->setup,
@@ -2316,6 +2344,7 @@ void cdns3_gadget_remove(struct cdns3 *cdns)
usb_ss->trb_ep0_dma);
device_unregister(cdns->gadget_dev);
cdns->gadget_dev = NULL;
+ kfree(usb_ss->zlp_buf);
}
static void __cdns3_gadget_start(struct usb_ss_dev *usb_ss)
diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h
index af8f33e16d60..b435e0130c2f 100644
--- a/drivers/usb/cdns3/gadget.h
+++ b/drivers/usb/cdns3/gadget.h
@@ -101,6 +101,7 @@
#define ENDPOINT_DIR_MASK 0x80
+#define ENDPOINT_ZLP_BUF_SIZE 1024
/*-------------------------------------------------------------------------*/
/**
@@ -193,6 +194,7 @@ struct usb_ss_dev {
dma_addr_t trb_ep0_dma;
u32 *trb_ep0;
u8 *setup;
+ void *zlp_buf;
struct usb_ss_endpoint *eps[USB_SS_ENDPOINTS_MAX_COUNT];
int ep_nums;