]> Pileus Git - ~andy/linux/blobdiff - drivers/usb/dwc3/ep0.c
Merge branch 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[~andy/linux] / drivers / usb / dwc3 / ep0.c
index 9e8a3dce69fd9e8bd76e27a36d2c95b741e22bf1..9b94886b66e589ee3040556bf284985a01a64bc6 100644 (file)
@@ -54,7 +54,9 @@
 #include "gadget.h"
 #include "io.h"
 
-static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum);
+static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
+static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
+               struct dwc3_ep *dep, struct dwc3_request *req);
 
 static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
 {
@@ -111,7 +113,7 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
        }
 
        dep->flags |= DWC3_EP_BUSY;
-       dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+       dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc,
                        dep->number);
 
        dwc->ep0_next_event = DWC3_EP0_COMPLETE;
@@ -150,16 +152,15 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
                        return 0;
                }
 
-               ret = dwc3_ep0_start_trans(dwc, direction,
-                               req->request.dma, req->request.length,
-                               DWC3_TRBCTL_CONTROL_DATA);
+               __dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req);
+
                dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
                                DWC3_EP0_DIR_IN);
        } else if (dwc->delayed_status) {
                dwc->delayed_status = false;
 
                if (dwc->ep0state == EP0_STATUS_PHASE)
-                       dwc3_ep0_do_control_status(dwc, 1);
+                       __dwc3_ep0_do_control_status(dwc, dwc->eps[1]);
                else
                        dev_dbg(dwc->dev, "too early for delayed status\n");
        }
@@ -224,6 +225,16 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
        dwc3_ep0_out_start(dwc);
 }
 
+int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
+{
+       struct dwc3_ep                  *dep = to_dwc3_ep(ep);
+       struct dwc3                     *dwc = dep->dwc;
+
+       dwc3_ep0_stall_and_restart(dwc);
+
+       return 0;
+}
+
 void dwc3_ep0_out_start(struct dwc3 *dwc)
 {
        int                             ret;
@@ -463,6 +474,7 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
 {
        u32 cfg;
        int ret;
+       u32 reg;
 
        dwc->start_config_issued = false;
        cfg = le16_to_cpu(ctrl->wValue);
@@ -477,6 +489,14 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
                /* if the cfg matches and the cfg is non zero */
                if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
                        dwc->dev_state = DWC3_CONFIGURED_STATE;
+                       /*
+                        * Enable transition to U1/U2 state when
+                        * nothing is pending from application.
+                        */
+                       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+                       reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
+                       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
                        dwc->resize_fifos = true;
                        dev_dbg(dwc->dev, "resize fifos flag SET\n");
                }
@@ -514,8 +534,8 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
 
        dwc->u1sel = timing.u1sel;
        dwc->u1pel = timing.u1pel;
-       dwc->u2sel = timing.u2sel;
-       dwc->u2pel = timing.u2pel;
+       dwc->u2sel = le16_to_cpu(timing.u2sel);
+       dwc->u2pel = le16_to_cpu(timing.u2pel);
 
        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
        if (reg & DWC3_DCTL_INITU2ENA)
@@ -640,11 +660,11 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
                const struct dwc3_event_depevt *event)
 {
        struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
-       int ret;
+       int ret = -EINVAL;
        u32 len;
 
        if (!dwc->gadget_driver)
-               goto err;
+               goto out;
 
        len = le16_to_cpu(ctrl->wLength);
        if (!len) {
@@ -665,11 +685,9 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
        if (ret == USB_GADGET_DELAYED_STATUS)
                dwc->delayed_status = true;
 
-       if (ret >= 0)
-               return;
-
-err:
-       dwc3_ep0_stall_and_restart(dwc);
+out:
+       if (ret < 0)
+               dwc3_ep0_stall_and_restart(dwc);
 }
 
 static void dwc3_ep0_complete_data(struct dwc3 *dwc,
@@ -723,7 +741,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
        }
 }
 
-static void dwc3_ep0_complete_req(struct dwc3 *dwc,
+static void dwc3_ep0_complete_status(struct dwc3 *dwc,
                const struct dwc3_event_depevt *event)
 {
        struct dwc3_request     *r;
@@ -745,6 +763,7 @@ static void dwc3_ep0_complete_req(struct dwc3 *dwc,
                        dev_dbg(dwc->dev, "Invalid Test #%d\n",
                                        dwc->test_mode_nr);
                        dwc3_ep0_stall_and_restart(dwc);
+                       return;
                }
        }
 
@@ -758,7 +777,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
        struct dwc3_ep          *dep = dwc->eps[event->endpoint_number];
 
        dep->flags &= ~DWC3_EP_BUSY;
-       dep->res_trans_idx = 0;
+       dep->resource_index = 0;
        dwc->setup_packet_pending = false;
 
        switch (dwc->ep0state) {
@@ -774,7 +793,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
 
        case EP0_STATUS_PHASE:
                dev_vdbg(dwc->dev, "Status Phase\n");
-               dwc3_ep0_complete_req(dwc, event);
+               dwc3_ep0_complete_status(dwc, event);
                break;
        default:
                WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state);
@@ -787,68 +806,81 @@ static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,
        dwc3_ep0_out_start(dwc);
 }
 
-static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
-               const struct dwc3_event_depevt *event)
+static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
+               struct dwc3_ep *dep, struct dwc3_request *req)
 {
-       struct dwc3_ep          *dep;
-       struct dwc3_request     *req;
        int                     ret;
 
-       dep = dwc->eps[0];
-
-       if (list_empty(&dep->request_list)) {
-               dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
-               dep->flags |= DWC3_EP_PENDING_REQUEST;
-
-               if (event->endpoint_number)
-                       dep->flags |= DWC3_EP0_DIR_IN;
-               return;
-       }
-
-       req = next_request(&dep->request_list);
-       req->direction = !!event->endpoint_number;
+       req->direction = !!dep->number;
 
        if (req->request.length == 0) {
-               ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+               ret = dwc3_ep0_start_trans(dwc, dep->number,
                                dwc->ctrl_req_addr, 0,
                                DWC3_TRBCTL_CONTROL_DATA);
-       } else if ((req->request.length % dep->endpoint.maxpacket)
-                       && (event->endpoint_number == 0)) {
+       } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
+                       && (dep->number == 0)) {
+               u32             transfer_size;
+
                ret = usb_gadget_map_request(&dwc->gadget, &req->request,
-                               event->endpoint_number);
+                               dep->number);
                if (ret) {
                        dev_dbg(dwc->dev, "failed to map request\n");
                        return;
                }
 
-               WARN_ON(req->request.length > dep->endpoint.maxpacket);
+               WARN_ON(req->request.length > DWC3_EP0_BOUNCE_SIZE);
+
+               transfer_size = roundup(req->request.length,
+                               (u32) dep->endpoint.maxpacket);
 
                dwc->ep0_bounced = true;
 
                /*
-                * REVISIT in case request length is bigger than EP0
-                * wMaxPacketSize, we will need two chained TRBs to handle
-                * the transfer.
+                * REVISIT in case request length is bigger than
+                * DWC3_EP0_BOUNCE_SIZE we will need two chained
+                * TRBs to handle the transfer.
                 */
-               ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
-                               dwc->ep0_bounce_addr, dep->endpoint.maxpacket,
+               ret = dwc3_ep0_start_trans(dwc, dep->number,
+                               dwc->ep0_bounce_addr, transfer_size,
                                DWC3_TRBCTL_CONTROL_DATA);
        } else {
                ret = usb_gadget_map_request(&dwc->gadget, &req->request,
-                               event->endpoint_number);
+                               dep->number);
                if (ret) {
                        dev_dbg(dwc->dev, "failed to map request\n");
                        return;
                }
 
-               ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
-                               req->request.dma, req->request.length,
-                               DWC3_TRBCTL_CONTROL_DATA);
+               ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma,
+                               req->request.length, DWC3_TRBCTL_CONTROL_DATA);
        }
 
        WARN_ON(ret < 0);
 }
 
+static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
+               const struct dwc3_event_depevt *event)
+{
+       struct dwc3_ep          *dep;
+       struct dwc3_request     *req;
+
+       dep = dwc->eps[0];
+
+       if (list_empty(&dep->request_list)) {
+               dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
+               dep->flags |= DWC3_EP_PENDING_REQUEST;
+
+               if (event->endpoint_number)
+                       dep->flags |= DWC3_EP0_DIR_IN;
+               return;
+       }
+
+       req = next_request(&dep->request_list);
+       dep = dwc->eps[event->endpoint_number];
+
+       __dwc3_ep0_do_control_data(dwc, dep, req);
+}
+
 static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
 {
        struct dwc3             *dwc = dep->dwc;
@@ -861,10 +893,8 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
                        dwc->ctrl_req_addr, 0, type);
 }
 
-static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
+static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
 {
-       struct dwc3_ep          *dep = dwc->eps[epnum];
-
        if (dwc->resize_fifos) {
                dev_dbg(dwc->dev, "starting to resize fifos\n");
                dwc3_gadget_resize_tx_fifos(dwc);
@@ -874,13 +904,21 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
        WARN_ON(dwc3_ep0_start_control_status(dep));
 }
 
+static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
+               const struct dwc3_event_depevt *event)
+{
+       struct dwc3_ep          *dep = dwc->eps[event->endpoint_number];
+
+       __dwc3_ep0_do_control_status(dwc, dep);
+}
+
 static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
                const struct dwc3_event_depevt *event)
 {
        dwc->setup_packet_pending = true;
 
        /*
-        * This part is very tricky: If we has just handled
+        * This part is very tricky: If we have just handled
         * XferNotReady(Setup) and we're now expecting a
         * XferComplete but, instead, we receive another
         * XferNotReady(Setup), we should STALL and restart
@@ -974,7 +1012,7 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
                        return;
                }
 
-               dwc3_ep0_do_control_status(dwc, event->endpoint_number);
+               dwc3_ep0_do_control_status(dwc, event);
        }
 }