X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=kernel%2Fdrivers%2Fusb%2Fdwc3%2Fgadget.c;h=210ff64857e1992cc62e3c3a8eed91bda1eb1ebc;hb=52f993b8e89487ec9ee15a7fb4979e0f09a45b27;hp=333a7c0078fcf922b9effaae3deff795d8b0f63e;hpb=41f827bfbb10e03c4d228fbcc801dd51fb9983b0;p=kvmfornfv.git diff --git a/kernel/drivers/usb/dwc3/gadget.c b/kernel/drivers/usb/dwc3/gadget.c index 333a7c007..210ff6485 100644 --- a/kernel/drivers/usb/dwc3/gadget.c +++ b/kernel/drivers/usb/dwc3/gadget.c @@ -259,11 +259,11 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, if (req->request.status == -EINPROGRESS) req->request.status = status; - if (dwc->ep0_bounced && dep->number == 0) + if (dwc->ep0_bounced && dep->number <= 1) dwc->ep0_bounced = false; - else - usb_gadget_unmap_request(&dwc->gadget, &req->request, - req->direction); + + usb_gadget_unmap_request(&dwc->gadget, &req->request, + req->direction); dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n", req, dep->name, req->request.actual, @@ -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(¶ms, 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, ¶ms); + if (ret) + return ret; + + for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) { + struct dwc3_ep *dep = dwc->eps[i]; + + if (!dep) + continue; - return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, ¶ms); + 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); } @@ -1830,14 +1892,6 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, s_pkt = 1; } - /* - * We assume here we will always receive the entire data block - * which we should receive. Meaning, if we program RX to - * receive 4K but we receive only 2K, we assume that's all we - * should receive and we simply bounce the request back to the - * gadget driver for further processing. - */ - req->request.actual += req->request.length - count; if (s_pkt) return 1; if ((event->status & DEPEVT_STATUS_LST) && @@ -1857,29 +1911,45 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_trb *trb; unsigned int slot; unsigned int i; + int count = 0; 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]; + count += trb->size & DWC3_TRB_SIZE_MASK; + + + ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, + event, status); + if (ret) + break; + } while (++i < req->request.num_mapped_sgs); + + /* + * We assume here we will always receive the entire data block + * which we should receive. Meaning, if we program RX to + * receive 4K but we receive only 2K, we assume that's all we + * should receive and we simply bounce the request back to the + * gadget driver for further processing. + */ + req->request.actual += req->request.length - count; + 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)) { @@ -1898,6 +1968,10 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, return 1; } + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) + if ((event->status & DEPEVT_STATUS_IOC) && + (trb->ctrl & DWC3_TRB_CTRL_IOC)) + return 0; return 1; } @@ -1942,6 +2016,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 +2061,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 +2245,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 +2295,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 +2733,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 +2741,6 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc) ret = status; } - spin_unlock(&dwc->lock); - return ret; } @@ -2685,7 +2762,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 +2786,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 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. @@ -2746,7 +2845,7 @@ err3: kfree(dwc->setup_buf); err2: - dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb), + dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2, dwc->ep0_trb, dwc->ep0_trb_addr); err1: @@ -2770,7 +2869,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc) kfree(dwc->setup_buf); - dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb), + dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2, dwc->ep0_trb, dwc->ep0_trb_addr); dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),