These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / usb / dwc3 / gadget.c
index 333a7c0..69ffe6e 100644 (file)
@@ -388,24 +388,66 @@ static void dwc3_free_trb_pool(struct dwc3_ep *dep)
        dep->trb_pool_dma = 0;
 }
 
+static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep);
+
+/**
+ * dwc3_gadget_start_config - Configure EP resources
+ * @dwc: pointer to our controller context structure
+ * @dep: endpoint that is being enabled
+ *
+ * The assignment of transfer resources cannot perfectly follow the
+ * data book due to the fact that the controller driver does not have
+ * all knowledge of the configuration in advance. It is given this
+ * information piecemeal by the composite gadget framework after every
+ * SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook
+ * programming model in this scenario can cause errors. For two
+ * reasons:
+ *
+ * 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION
+ * and SET_INTERFACE (8.1.5). This is incorrect in the scenario of
+ * multiple interfaces.
+ *
+ * 2) The databook does not mention doing more DEPXFERCFG for new
+ * endpoint on alt setting (8.1.6).
+ *
+ * The following simplified method is used instead:
+ *
+ * All hardware endpoints can be assigned a transfer resource and this
+ * setting will stay persistent until either a core reset or
+ * hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and
+ * do DEPXFERCFG for every hardware endpoint as well. We are
+ * guaranteed that there are as many transfer resources as endpoints.
+ *
+ * This function is called for each endpoint when it is being enabled
+ * but is triggered only when called for EP0-out, which always happens
+ * first, and which should only happen in one of the above conditions.
+ */
 static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
 {
        struct dwc3_gadget_ep_cmd_params params;
        u32                     cmd;
+       int                     i;
+       int                     ret;
+
+       if (dep->number)
+               return 0;
 
        memset(&params, 0x00, sizeof(params));
+       cmd = DWC3_DEPCMD_DEPSTARTCFG;
 
-       if (dep->number != 1) {
-               cmd = DWC3_DEPCMD_DEPSTARTCFG;
-               /* XferRscIdx == 0 for ep0 and 2 for the remaining */
-               if (dep->number > 1) {
-                       if (dwc->start_config_issued)
-                               return 0;
-                       dwc->start_config_issued = true;
-                       cmd |= DWC3_DEPCMD_PARAM(2);
-               }
+       ret = dwc3_send_gadget_ep_cmd(dwc, 0, cmd, &params);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
+               struct dwc3_ep *dep = dwc->eps[i];
 
-               return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, &params);
+               if (!dep)
+                       continue;
+
+               ret = dwc3_gadget_set_xfer_resource(dwc, dep);
+               if (ret)
+                       return ret;
        }
 
        return 0;
@@ -519,10 +561,6 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
                struct dwc3_trb *trb_st_hw;
                struct dwc3_trb *trb_link;
 
-               ret = dwc3_gadget_set_xfer_resource(dwc, dep);
-               if (ret)
-                       return ret;
-
                dep->endpoint.desc = desc;
                dep->comp_desc = comp_desc;
                dep->type = usb_endpoint_type(desc);
@@ -547,6 +585,23 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
                trb_link->ctrl |= DWC3_TRB_CTRL_HWO;
        }
 
+       switch (usb_endpoint_type(desc)) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               strlcat(dep->name, "-control", sizeof(dep->name));
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               strlcat(dep->name, "-isoc", sizeof(dep->name));
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               strlcat(dep->name, "-bulk", sizeof(dep->name));
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               strlcat(dep->name, "-int", sizeof(dep->name));
+               break;
+       default:
+               dev_err(dwc->dev, "invalid endpoint transfer type\n");
+       }
+
        return 0;
 }
 
@@ -586,6 +641,8 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
        struct dwc3             *dwc = dep->dwc;
        u32                     reg;
 
+       dwc3_trace(trace_dwc3_gadget, "Disabling %s", dep->name);
+
        dwc3_remove_requests(dwc, dep);
 
        /* make sure HW endpoint isn't stalled */
@@ -602,6 +659,10 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
        dep->type = 0;
        dep->flags = 0;
 
+       snprintf(dep->name, sizeof(dep->name), "ep%d%s",
+                       dep->number >> 1,
+                       (dep->number & 1) ? "in" : "out");
+
        return 0;
 }
 
@@ -647,23 +708,6 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
                return 0;
        }
 
-       switch (usb_endpoint_type(desc)) {
-       case USB_ENDPOINT_XFER_CONTROL:
-               strlcat(dep->name, "-control", sizeof(dep->name));
-               break;
-       case USB_ENDPOINT_XFER_ISOC:
-               strlcat(dep->name, "-isoc", sizeof(dep->name));
-               break;
-       case USB_ENDPOINT_XFER_BULK:
-               strlcat(dep->name, "-bulk", sizeof(dep->name));
-               break;
-       case USB_ENDPOINT_XFER_INT:
-               strlcat(dep->name, "-int", sizeof(dep->name));
-               break;
-       default:
-               dev_err(dwc->dev, "invalid endpoint transfer type\n");
-       }
-
        spin_lock_irqsave(&dwc->lock, flags);
        ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false, false);
        spin_unlock_irqrestore(&dwc->lock, flags);
@@ -692,10 +736,6 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep)
                return 0;
        }
 
-       snprintf(dep->name, sizeof(dep->name), "ep%d%s",
-                       dep->number >> 1,
-                       (dep->number & 1) ? "in" : "out");
-
        spin_lock_irqsave(&dwc->lock, flags);
        ret = __dwc3_gadget_ep_disable(dep);
        spin_unlock_irqrestore(&dwc->lock, flags);
@@ -946,7 +986,6 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
                dwc3_trace(trace_dwc3_gadget, "%s: endpoint busy", dep->name);
                return -EBUSY;
        }
-       dep->flags &= ~DWC3_EP_PENDING_REQUEST;
 
        /*
         * If we are getting here after a short-out-packet we don't enqueue any
@@ -1048,6 +1087,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
        req->direction          = dep->direction;
        req->epnum              = dep->number;
 
+       trace_dwc3_ep_queue(req);
+
        /*
         * We only add to our list of requests now and
         * start consuming the list once we get XferNotReady
@@ -1067,6 +1108,20 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 
        list_add_tail(&req->list, &dep->request_list);
 
+       /*
+        * If there are no pending requests and the endpoint isn't already
+        * busy, we will just start the request straight away.
+        *
+        * This will save one IRQ (XFER_NOT_READY) and possibly make it a
+        * little bit faster.
+        */
+       if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+                       !usb_endpoint_xfer_int(dep->endpoint.desc) &&
+                       !(dep->flags & DWC3_EP_BUSY)) {
+               ret = __dwc3_gadget_kick_transfer(dep, 0, true);
+               goto out;
+       }
+
        /*
         * There are a few special cases:
         *
@@ -1094,10 +1149,10 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
                }
 
                ret = __dwc3_gadget_kick_transfer(dep, 0, true);
-               if (ret && ret != -EBUSY)
-                       dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
-                                       dep->name);
-               return ret;
+               if (!ret)
+                       dep->flags &= ~DWC3_EP_PENDING_REQUEST;
+
+               goto out;
        }
 
        /*
@@ -1111,10 +1166,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
                WARN_ON_ONCE(!dep->resource_index);
                ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index,
                                false);
-               if (ret && ret != -EBUSY)
-                       dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
-                                       dep->name);
-               return ret;
+               goto out;
        }
 
        /*
@@ -1122,14 +1174,17 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
         * right away, otherwise host will not know we have streams to be
         * handled.
         */
-       if (dep->stream_capable) {
+       if (dep->stream_capable)
                ret = __dwc3_gadget_kick_transfer(dep, 0, true);
-               if (ret && ret != -EBUSY)
-                       dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
-                                       dep->name);
-       }
 
-       return 0;
+out:
+       if (ret && ret != -EBUSY)
+               dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+                               dep->name);
+       if (ret == -EBUSY)
+               ret = 0;
+
+       return ret;
 }
 
 static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
@@ -1157,8 +1212,6 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
                goto out;
        }
 
-       trace_dwc3_ep_queue(req);
-
        ret = __dwc3_gadget_ep_queue(dep, req);
 
 out:
@@ -1589,8 +1642,6 @@ static int dwc3_gadget_start(struct usb_gadget *g,
        }
        dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 
-       dwc->start_config_issued = false;
-
        /* Start with SuperSpeed Default */
        dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
 
@@ -1713,6 +1764,17 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
                                return ret;
                }
 
+               if (epnum == 0 || epnum == 1) {
+                       dep->endpoint.caps.type_control = true;
+               } else {
+                       dep->endpoint.caps.type_iso = true;
+                       dep->endpoint.caps.type_bulk = true;
+                       dep->endpoint.caps.type_int = true;
+               }
+
+               dep->endpoint.caps.dir_in = !!direction;
+               dep->endpoint.caps.dir_out = !direction;
+
                INIT_LIST_HEAD(&dep->request_list);
                INIT_LIST_HEAD(&dep->req_queued);
        }
@@ -1859,27 +1921,32 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
        unsigned int            i;
        int                     ret;
 
-       req = next_request(&dep->req_queued);
-       if (!req) {
-               WARN_ON_ONCE(1);
-               return 1;
-       }
-       i = 0;
        do {
-               slot = req->start_slot + i;
-               if ((slot == DWC3_TRB_NUM - 1) &&
+               req = next_request(&dep->req_queued);
+               if (!req) {
+                       WARN_ON_ONCE(1);
+                       return 1;
+               }
+               i = 0;
+               do {
+                       slot = req->start_slot + i;
+                       if ((slot == DWC3_TRB_NUM - 1) &&
                                usb_endpoint_xfer_isoc(dep->endpoint.desc))
-                       slot++;
-               slot %= DWC3_TRB_NUM;
-               trb = &dep->trb_pool[slot];
+                               slot++;
+                       slot %= DWC3_TRB_NUM;
+                       trb = &dep->trb_pool[slot];
+
+                       ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
+                                       event, status);
+                       if (ret)
+                               break;
+               } while (++i < req->request.num_mapped_sgs);
+
+               dwc3_gadget_giveback(dep, req, status);
 
-               ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
-                               event, status);
                if (ret)
                        break;
-       } while (++i < req->request.num_mapped_sgs);
-
-       dwc3_gadget_giveback(dep, req, status);
+       } while (1);
 
        if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
                        list_empty(&dep->req_queued)) {
@@ -1942,6 +2009,14 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
 
                dwc->u1u2 = 0;
        }
+
+       if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+               int ret;
+
+               ret = __dwc3_gadget_kick_transfer(dep, 0, is_xfer_complete);
+               if (!ret || ret == -EBUSY)
+                       return;
+       }
 }
 
 static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
@@ -1979,15 +2054,16 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
                if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
                        dwc3_gadget_start_isoc(dwc, dep, event);
                } else {
+                       int active;
                        int ret;
 
+                       active = event->status & DEPEVT_STATUS_TRANSFER_ACTIVE;
+
                        dwc3_trace(trace_dwc3_gadget, "%s: reason %s",
-                                       dep->name, event->status &
-                                       DEPEVT_STATUS_TRANSFER_ACTIVE
-                                       ? "Transfer Active"
+                                       dep->name, active ? "Transfer Active"
                                        : "Transfer Not Active");
 
-                       ret = __dwc3_gadget_kick_transfer(dep, 0, 1);
+                       ret = __dwc3_gadget_kick_transfer(dep, 0, !active);
                        if (!ret || ret == -EBUSY)
                                return;
 
@@ -2162,7 +2238,6 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
        dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
        dwc3_disconnect_gadget(dwc);
-       dwc->start_config_issued = false;
 
        dwc->gadget.speed = USB_SPEED_UNKNOWN;
        dwc->setup_packet_pending = false;
@@ -2213,7 +2288,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 
        dwc3_stop_active_transfers(dwc);
        dwc3_clear_stall_all_ep(dwc);
-       dwc->start_config_issued = false;
 
        /* Reset device address to zero */
        reg = dwc3_readl(dwc->regs, DWC3_DCFG);
@@ -2652,8 +2726,6 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
        int                             i;
        irqreturn_t                     ret = IRQ_NONE;
 
-       spin_lock(&dwc->lock);
-
        for (i = 0; i < dwc->num_event_buffers; i++) {
                irqreturn_t status;
 
@@ -2662,8 +2734,6 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
                        ret = status;
        }
 
-       spin_unlock(&dwc->lock);
-
        return ret;
 }
 
@@ -2685,7 +2755,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
                goto err0;
        }
 
-       dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+       dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2,
                        &dwc->ep0_trb_addr, GFP_KERNEL);
        if (!dwc->ep0_trb) {
                dev_err(dwc->dev, "failed to allocate ep0 trb\n");
@@ -2709,11 +2779,33 @@ int dwc3_gadget_init(struct dwc3 *dwc)
        }
 
        dwc->gadget.ops                 = &dwc3_gadget_ops;
-       dwc->gadget.max_speed           = USB_SPEED_SUPER;
        dwc->gadget.speed               = USB_SPEED_UNKNOWN;
        dwc->gadget.sg_supported        = true;
        dwc->gadget.name                = "dwc3-gadget";
 
+       /*
+        * FIXME We might be setting max_speed to <SUPER, however versions
+        * <2.20a of dwc3 have an issue with metastability (documented
+        * elsewhere in this driver) which tells us we can't set max speed to
+        * anything lower than SUPER.
+        *
+        * Because gadget.max_speed is only used by composite.c and function
+        * drivers (i.e. it won't go into dwc3's registers) we are allowing this
+        * to happen so we avoid sending SuperSpeed Capability descriptor
+        * together with our BOS descriptor as that could confuse host into
+        * thinking we can handle super speed.
+        *
+        * Note that, in fact, we won't even support GetBOS requests when speed
+        * is less than super speed because we don't have means, yet, to tell
+        * composite.c that we are USB 2.0 + LPM ECN.
+        */
+       if (dwc->revision < DWC3_REVISION_220A)
+               dwc3_trace(trace_dwc3_gadget,
+                               "Changing max_speed on rev %08x\n",
+                               dwc->revision);
+
+       dwc->gadget.max_speed           = dwc->maximum_speed;
+
        /*
         * Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize
         * on ep out.