diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-11-18 16:02:15 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-11-18 16:02:15 +0100 |
commit | ae4d814bf1f2b0b7a37b3c30970d6974911f1377 (patch) | |
tree | d6332943d12e23432c8e455c2a9d71ac82cbc727 /drivers/usb/dwc3/gadget.c | |
parent | 37be66767e3cae4fd16e064d8bb7f9f72bf5c045 (diff) | |
parent | d5c024f3761dbd512329d3b7234a07dcf7580f0a (diff) | |
download | blackbird-op-linux-ae4d814bf1f2b0b7a37b3c30970d6974911f1377.tar.gz blackbird-op-linux-ae4d814bf1f2b0b7a37b3c30970d6974911f1377.zip |
Merge tag 'usb-for-v4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
Felipe writes:
usb: patches for v4.10 merge window
One big merge this time with a total of 166 non-merge commits.
Most of the work, by far, is on dwc2 this time (68.2%) with dwc3 a far
second (22.5%). The remaining 9.3% are scattered on gadget drivers.
The most important changes for dwc2 are the peripheral side DMA support
implemented by Synopsys folks and support for the new IOT dwc2
compatible core from Synopsys.
In dwc3 land we have support for high-bandwidth, high-speed isochronous
endpoints and some non-critical fixes for large scatter lists.
Apart from these, we have our usual set of cleanups, non-critical fixes,
etc.
Diffstat (limited to 'drivers/usb/dwc3/gadget.c')
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 576 |
1 files changed, 333 insertions, 243 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 1dfa56a5f1c5..678559525618 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -139,9 +139,6 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) udelay(5); } - dwc3_trace(trace_dwc3_gadget, - "link state change request timed out"); - return -ETIMEDOUT; } @@ -178,6 +175,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, req->started = false; list_del(&req->list); req->trb = NULL; + req->remaining = 0; if (req->request.status == -EINPROGRESS) req->request.status = status; @@ -185,8 +183,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, if (dwc->ep0_bounced && dep->number == 0) dwc->ep0_bounced = false; else - usb_gadget_unmap_request(&dwc->gadget, &req->request, - req->direction); + usb_gadget_unmap_request_by_dev(dwc->sysdev, + &req->request, req->direction); trace_dwc3_gadget_giveback(req); @@ -216,7 +214,7 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param) ret = -EINVAL; break; } - } while (timeout--); + } while (--timeout); if (!timeout) { ret = -ETIMEDOUT; @@ -233,6 +231,7 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc); int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) { + const struct usb_endpoint_descriptor *desc = dep->endpoint.desc; struct dwc3 *dwc = dep->dwc; u32 timeout = 500; u32 reg; @@ -258,7 +257,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, } } - if (cmd == DWC3_DEPCMD_STARTTRANSFER) { + if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) { int needs_wakeup; needs_wakeup = (dwc->link_state == DWC3_LINK_STATE_U1 || @@ -276,7 +275,28 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, dwc3_writel(dep->regs, DWC3_DEPCMDPAR1, params->param1); dwc3_writel(dep->regs, DWC3_DEPCMDPAR2, params->param2); - dwc3_writel(dep->regs, DWC3_DEPCMD, cmd | DWC3_DEPCMD_CMDACT); + /* + * Synopsys Databook 2.60a states in section 6.3.2.5.6 of that if we're + * not relying on XferNotReady, we can make use of a special "No + * Response Update Transfer" command where we should clear both CmdAct + * and CmdIOC bits. + * + * With this, we don't need to wait for command completion and can + * straight away issue further commands to the endpoint. + * + * NOTICE: We're making an assumption that control endpoints will never + * make use of Update Transfer command. This is a safe assumption + * because we can never have more than one request at a time with + * Control Endpoints. If anybody changes that assumption, this chunk + * needs to be updated accordingly. + */ + if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_UPDATETRANSFER && + !usb_endpoint_xfer_isoc(desc)) + cmd &= ~(DWC3_DEPCMD_CMDIOC | DWC3_DEPCMD_CMDACT); + else + cmd |= DWC3_DEPCMD_CMDACT; + + dwc3_writel(dep->regs, DWC3_DEPCMD, cmd); do { reg = dwc3_readl(dep->regs, DWC3_DEPCMD); if (!(reg & DWC3_DEPCMD_CMDACT)) { @@ -318,6 +338,20 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, trace_dwc3_gadget_ep_cmd(dep, cmd, params, cmd_status); + if (ret == 0) { + switch (DWC3_DEPCMD_CMD(cmd)) { + case DWC3_DEPCMD_STARTTRANSFER: + dep->flags |= DWC3_EP_TRANSFER_STARTED; + break; + case DWC3_DEPCMD_ENDTRANSFER: + dep->flags &= ~DWC3_EP_TRANSFER_STARTED; + break; + default: + /* nothing */ + break; + } + } + if (unlikely(susphy)) { reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg |= DWC3_GUSB2PHYCFG_SUSPHY; @@ -365,7 +399,7 @@ static int dwc3_alloc_trb_pool(struct dwc3_ep *dep) if (dep->trb_pool) return 0; - dep->trb_pool = dma_alloc_coherent(dwc->dev, + dep->trb_pool = dma_alloc_coherent(dwc->sysdev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM, &dep->trb_pool_dma, GFP_KERNEL); if (!dep->trb_pool) { @@ -381,7 +415,7 @@ static void dwc3_free_trb_pool(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; - dma_free_coherent(dwc->dev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM, + dma_free_coherent(dwc->sysdev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM, dep->trb_pool, dep->trb_pool_dma); dep->trb_pool = NULL; @@ -454,16 +488,19 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep) } static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, - const struct usb_endpoint_descriptor *desc, - const struct usb_ss_ep_comp_descriptor *comp_desc, bool modify, bool restore) { + const struct usb_ss_ep_comp_descriptor *comp_desc; + const struct usb_endpoint_descriptor *desc; struct dwc3_gadget_ep_cmd_params params; if (dev_WARN_ONCE(dwc->dev, modify && restore, "Can't modify and restore\n")) return -EINVAL; + comp_desc = dep->endpoint.comp_desc; + desc = dep->endpoint.desc; + memset(¶ms, 0x00, sizeof(params)); params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc)) @@ -542,24 +579,21 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep) * Caller should take care of locking */ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, - const struct usb_endpoint_descriptor *desc, - const struct usb_ss_ep_comp_descriptor *comp_desc, bool modify, bool restore) { + const struct usb_endpoint_descriptor *desc = dep->endpoint.desc; struct dwc3 *dwc = dep->dwc; + u32 reg; int ret; - dwc3_trace(trace_dwc3_gadget, "Enabling %s", dep->name); - if (!(dep->flags & DWC3_EP_ENABLED)) { ret = dwc3_gadget_start_config(dwc, dep); if (ret) return ret; } - ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, modify, - restore); + ret = dwc3_gadget_set_ep_config(dwc, dep, modify, restore); if (ret) return ret; @@ -567,17 +601,18 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, struct dwc3_trb *trb_st_hw; struct dwc3_trb *trb_link; - dep->endpoint.desc = desc; - dep->comp_desc = comp_desc; dep->type = usb_endpoint_type(desc); dep->flags |= DWC3_EP_ENABLED; + dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); reg |= DWC3_DALEPENA_EP(dep->number); dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); + init_waitqueue_head(&dep->wait_end_transfer); + if (usb_endpoint_xfer_control(desc)) - return 0; + goto out; /* Initialize the TRB ring */ dep->trb_dequeue = 0; @@ -595,6 +630,39 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, trb_link->ctrl |= DWC3_TRB_CTRL_HWO; } + /* + * Issue StartTransfer here with no-op TRB so we can always rely on No + * Response Update Transfer command. + */ + if (usb_endpoint_xfer_bulk(desc)) { + struct dwc3_gadget_ep_cmd_params params; + struct dwc3_trb *trb; + dma_addr_t trb_dma; + u32 cmd; + + memset(¶ms, 0, sizeof(params)); + trb = &dep->trb_pool[0]; + trb_dma = dwc3_trb_dma_offset(dep, trb); + + params.param0 = upper_32_bits(trb_dma); + params.param1 = lower_32_bits(trb_dma); + + cmd = DWC3_DEPCMD_STARTTRANSFER; + + ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); + if (ret < 0) + return ret; + + dep->flags |= DWC3_EP_BUSY; + + dep->resource_index = dwc3_gadget_ep_get_transfer_index(dep); + WARN_ON_ONCE(!dep->resource_index); + } + + +out: + trace_dwc3_gadget_ep_enable(dep); + return 0; } @@ -632,7 +700,7 @@ 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); + trace_dwc3_gadget_ep_disable(dep); dwc3_remove_requests(dwc, dep); @@ -645,10 +713,14 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); dep->stream_capable = false; - dep->endpoint.desc = NULL; - dep->comp_desc = NULL; dep->type = 0; - dep->flags = 0; + dep->flags &= DWC3_EP_END_TRANSFER_PENDING; + + /* Clear out the ep descriptors for non-ep0 */ + if (dep->number > 1) { + dep->endpoint.comp_desc = NULL; + dep->endpoint.desc = NULL; + } return 0; } @@ -695,7 +767,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, return 0; spin_lock_irqsave(&dwc->lock, flags); - ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false, false); + ret = __dwc3_gadget_ep_enable(dep, false, false); spin_unlock_irqrestore(&dwc->lock, flags); return ret; @@ -771,10 +843,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, unsigned length, unsigned chain, unsigned node) { struct dwc3_trb *trb; - - dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s", - dep->name, req, (unsigned long long) dma, - length, chain ? " chain" : ""); + struct dwc3 *dwc = dep->dwc; + struct usb_gadget *gadget = &dwc->gadget; + enum usb_device_speed speed = gadget->speed; trb = &dep->trb_pool[dep->trb_enqueue]; @@ -782,7 +853,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, dwc3_gadget_move_started_request(req); req->trb = trb; req->trb_dma = dwc3_trb_dma_offset(dep, trb); - req->first_trb_index = dep->trb_enqueue; dep->queued_requests++; } @@ -798,10 +868,16 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, break; case USB_ENDPOINT_XFER_ISOC: - if (!node) + if (!node) { trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST; - else + + if (speed == USB_SPEED_HIGH) { + struct usb_ep *ep = &dep->endpoint; + trb->size |= DWC3_TRB_SIZE_PCM1(ep->mult - 1); + } + } else { trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS; + } /* always enable Interrupt on Missed ISOC */ trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; @@ -816,15 +892,21 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, * This is only possible with faulty memory because we * checked it already :) */ - BUG(); + dev_WARN(dwc->dev, "Unknown endpoint type %d\n", + usb_endpoint_type(dep->endpoint.desc)); } /* always enable Continue on Short Packet */ - trb->ctrl |= DWC3_TRB_CTRL_CSP; + if (usb_endpoint_dir_out(dep->endpoint.desc)) { + trb->ctrl |= DWC3_TRB_CTRL_CSP; + + if (req->request.short_not_ok) + trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; + } if ((!req->request.no_interrupt && !chain) || (dwc3_calc_trbs_left(dep) == 0)) - trb->ctrl |= DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI; + trb->ctrl |= DWC3_TRB_CTRL_IOC; if (chain) trb->ctrl |= DWC3_TRB_CTRL_CHN; @@ -859,6 +941,7 @@ static struct dwc3_trb *dwc3_ep_prev_trb(struct dwc3_ep *dep, u8 index) static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) { struct dwc3_trb *tmp; + struct dwc3 *dwc = dep->dwc; u8 trbs_left; /* @@ -870,7 +953,8 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) */ if (dep->trb_enqueue == dep->trb_dequeue) { tmp = dwc3_ep_prev_trb(dep, dep->trb_enqueue); - if (tmp->ctrl & DWC3_TRB_CTRL_HWO) + if (dev_WARN_ONCE(dwc->dev, tmp->ctrl & DWC3_TRB_CTRL_HWO, + "%s No TRBS left\n", dep->name)) return 0; return DWC3_TRB_NUM - 1; @@ -941,6 +1025,24 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep) if (!dwc3_calc_trbs_left(dep)) return; + /* + * We can get in a situation where there's a request in the started list + * but there weren't enough TRBs to fully kick it in the first time + * around, so it has been waiting for more TRBs to be freed up. + * + * In that case, we should check if we have a request with pending_sgs + * in the started list and prepare TRBs for that request first, + * otherwise we will prepare TRBs completely out of order and that will + * break things. + */ + list_for_each_entry(req, &dep->started_list, list) { + if (req->num_pending_sgs > 0) + dwc3_prepare_one_trb_sg(dep, req); + + if (!dwc3_calc_trbs_left(dep)) + return; + } + list_for_each_entry_safe(req, n, &dep->pending_list, list) { if (req->num_pending_sgs > 0) dwc3_prepare_one_trb_sg(dep, req); @@ -956,7 +1058,6 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param) { struct dwc3_gadget_ep_cmd_params params; struct dwc3_request *req; - struct dwc3 *dwc = dep->dwc; int starting; int ret; u32 cmd; @@ -989,9 +1090,10 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param) * here and stop, unmap, free and del each of the linked * requests instead of what we do now. */ - usb_gadget_unmap_request(&dwc->gadget, &req->request, - req->direction); - list_del(&req->list); + if (req->trb) + memset(req->trb, 0, sizeof(struct dwc3_trb)); + dep->queued_requests--; + dwc3_gadget_giveback(dep, req, ret); return ret; } @@ -1005,14 +1107,21 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param) return 0; } +static int __dwc3_gadget_get_frame(struct dwc3 *dwc) +{ + u32 reg; + + reg = dwc3_readl(dwc->regs, DWC3_DSTS); + return DWC3_DSTS_SOFFN(reg); +} + static void __dwc3_gadget_start_isoc(struct dwc3 *dwc, struct dwc3_ep *dep, u32 cur_uf) { u32 uf; if (list_empty(&dep->pending_list)) { - dwc3_trace(trace_dwc3_gadget, - "ISOC ep %s run out for requests", + dev_info(dwc->dev, "%s: ran out of requests\n", dep->name); dep->flags |= DWC3_EP_PENDING_REQUEST; return; @@ -1041,16 +1150,15 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) int ret; if (!dep->endpoint.desc) { - dwc3_trace(trace_dwc3_gadget, - "trying to queue request %p to disabled %s", - &req->request, dep->endpoint.name); + dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n", + dep->name); return -ESHUTDOWN; } if (WARN(req->dep != dep, "request %p belongs to '%s'\n", &req->request, req->dep->name)) { - dwc3_trace(trace_dwc3_gadget, "request %p belongs to '%s'", - &req->request, req->dep->name); + dev_err(dwc->dev, "%s: request %p belongs to '%s'\n", + dep->name, &req->request, req->dep->name); return -EINVAL; } @@ -1063,8 +1171,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) trace_dwc3_ep_queue(req); - ret = usb_gadget_map_request(&dwc->gadget, &req->request, - dep->direction); + ret = usb_gadget_map_request_by_dev(dwc->sysdev, &req->request, + dep->direction); if (ret) return ret; @@ -1082,10 +1190,17 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) * errors which will force us issue EndTransfer command. */ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - if ((dep->flags & DWC3_EP_PENDING_REQUEST) && - list_empty(&dep->started_list)) { - dwc3_stop_active_transfer(dwc, dep->number, true); - dep->flags = DWC3_EP_ENABLED; + if ((dep->flags & DWC3_EP_PENDING_REQUEST)) { + if (dep->flags & DWC3_EP_TRANSFER_STARTED) { + dwc3_stop_active_transfer(dwc, dep->number, true); + dep->flags = DWC3_EP_ENABLED; + } else { + u32 cur_uf; + + cur_uf = __dwc3_gadget_get_frame(dwc); + __dwc3_gadget_start_isoc(dwc, dep, cur_uf); + dep->flags &= ~DWC3_EP_PENDING_REQUEST; + } } return 0; } @@ -1094,10 +1209,6 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) return 0; ret = __dwc3_gadget_kick_transfer(dep, 0); - if (ret && ret != -EBUSY) - dwc3_trace(trace_dwc3_gadget, - "%s: failed to kick transfers", - dep->name); if (ret == -EBUSY) ret = 0; @@ -1116,7 +1227,6 @@ static int __dwc3_gadget_ep_queue_zlp(struct dwc3 *dwc, struct dwc3_ep *dep) struct usb_request *request; struct usb_ep *ep = &dep->endpoint; - dwc3_trace(trace_dwc3_gadget, "queueing ZLP"); request = dwc3_gadget_ep_alloc_request(ep, GFP_ATOMIC); if (!request) return -ENOMEM; @@ -1235,9 +1345,6 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) if (!protocol && ((dep->direction && transfer_in_flight) || (!dep->direction && started))) { - dwc3_trace(trace_dwc3_gadget, - "%s: pending request, cannot halt", - dep->name); return -EAGAIN; } @@ -1331,10 +1438,8 @@ static const struct usb_ep_ops dwc3_gadget_ep_ops = { static int dwc3_gadget_get_frame(struct usb_gadget *g) { struct dwc3 *dwc = gadget_to_dwc(g); - u32 reg; - reg = dwc3_readl(dwc->regs, DWC3_DSTS); - return DWC3_DSTS_SOFFN(reg); + return __dwc3_gadget_get_frame(dwc); } static int __dwc3_gadget_wakeup(struct dwc3 *dwc) @@ -1357,10 +1462,8 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) speed = reg & DWC3_DSTS_CONNECTSPD; if ((speed == DWC3_DSTS_SUPERSPEED) || - (speed == DWC3_DSTS_SUPERSPEED_PLUS)) { - dwc3_trace(trace_dwc3_gadget, "no wakeup on SuperSpeed"); + (speed == DWC3_DSTS_SUPERSPEED_PLUS)) return 0; - } link_state = DWC3_DSTS_USBLNKST(reg); @@ -1369,9 +1472,6 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) case DWC3_LINK_STATE_U3: /* in HS, means SUSPEND */ break; default: - dwc3_trace(trace_dwc3_gadget, - "can't wakeup from '%s'", - dwc3_gadget_link_string(link_state)); return -EINVAL; } @@ -1476,11 +1576,6 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) if (!timeout) return -ETIMEDOUT; - dwc3_trace(trace_dwc3_gadget, "gadget %s data soft-%s", - dwc->gadget_driver - ? dwc->gadget_driver->function : "no-function", - is_on ? "connect" : "disconnect"); - return 0; } @@ -1492,6 +1587,21 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) is_on = !!is_on; + /* + * Per databook, when we want to stop the gadget, if a control transfer + * is still in process, complete it and get the core into setup phase. + */ + if (!is_on && dwc->ep0state != EP0_SETUP_PHASE) { + reinit_completion(&dwc->ep0_in_setup); + + ret = wait_for_completion_timeout(&dwc->ep0_in_setup, + msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT)); + if (ret == 0) { + dev_err(dwc->dev, "timed out waiting for SETUP phase\n"); + return -ETIMEDOUT; + } + } + spin_lock_irqsave(&dwc->lock, flags); ret = dwc3_gadget_run_stop(dwc, is_on, false); spin_unlock_irqrestore(&dwc->lock, flags); @@ -1509,11 +1619,13 @@ static void dwc3_gadget_enable_irq(struct dwc3 *dwc) DWC3_DEVTEN_CMDCMPLTEN | DWC3_DEVTEN_ERRTICERREN | DWC3_DEVTEN_WKUPEVTEN | - DWC3_DEVTEN_ULSTCNGEN | DWC3_DEVTEN_CONNECTDONEEN | DWC3_DEVTEN_USBRSTEN | DWC3_DEVTEN_DISCONNEVTEN); + if (dwc->revision < DWC3_REVISION_250A) + reg |= DWC3_DEVTEN_ULSTCNGEN; + dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); } @@ -1573,6 +1685,17 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) int ret = 0; u32 reg; + /* + * Use IMOD if enabled via dwc->imod_interval. Otherwise, if + * the core supports IMOD, disable it. + */ + if (dwc->imod_interval) { + dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval); + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB); + } else if (dwc3_has_imod(dwc)) { + dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), 0); + } + reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg &= ~(DWC3_DCFG_SPEED_MASK); @@ -1633,16 +1756,14 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); dep = dwc->eps[0]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, - false); + ret = __dwc3_gadget_ep_enable(dep, false, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); goto err0; } dep = dwc->eps[1]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, - false); + ret = __dwc3_gadget_ep_enable(dep, false, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); goto err1; @@ -1708,9 +1829,6 @@ err0: static void __dwc3_gadget_stop(struct dwc3 *dwc) { - if (pm_runtime_suspended(dwc->dev)) - return; - dwc3_gadget_disable_irq(dwc); __dwc3_gadget_ep_disable(dwc->eps[0]); __dwc3_gadget_ep_disable(dwc->eps[1]); @@ -1720,9 +1838,30 @@ static int dwc3_gadget_stop(struct usb_gadget *g) { struct dwc3 *dwc = gadget_to_dwc(g); unsigned long flags; + int epnum; spin_lock_irqsave(&dwc->lock, flags); + + if (pm_runtime_suspended(dwc->dev)) + goto out; + __dwc3_gadget_stop(dwc); + + for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) { + struct dwc3_ep *dep = dwc->eps[epnum]; + + if (!dep) + continue; + + if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) + continue; + + wait_event_lock_irq(dep->wait_end_transfer, + !(dep->flags & DWC3_EP_END_TRANSFER_PENDING), + dwc->lock); + } + +out: dwc->gadget_driver = NULL; spin_unlock_irqrestore(&dwc->lock, flags); @@ -1765,9 +1904,13 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, (epnum & 1) ? "in" : "out"); dep->endpoint.name = dep->name; - spin_lock_init(&dep->lock); - dwc3_trace(trace_dwc3_gadget, "initializing %s", dep->name); + if (!(dep->number > 1)) { + dep->endpoint.desc = &dwc3_gadget_ep0_desc; + dep->endpoint.comp_desc = NULL; + } + + spin_lock_init(&dep->lock); if (epnum == 0 || epnum == 1) { usb_ep_set_maxpacket_limit(&dep->endpoint, 512); @@ -1815,15 +1958,13 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc) ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0); if (ret < 0) { - dwc3_trace(trace_dwc3_gadget, - "failed to allocate OUT endpoints"); + dev_err(dwc->dev, "failed to initialize OUT endpoints\n"); return ret; } ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1); if (ret < 0) { - dwc3_trace(trace_dwc3_gadget, - "failed to allocate IN endpoints"); + dev_err(dwc->dev, "failed to initialize IN endpoints\n"); return ret; } @@ -1892,15 +2033,12 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, return 1; count = trb->size & DWC3_TRB_SIZE_MASK; - req->request.actual += count; + req->remaining += count; if (dep->direction) { if (count) { trb_status = DWC3_TRB_SIZE_TRBSTS(trb->size); if (trb_status == DWC3_TRBSTS_MISSED_ISOC) { - dwc3_trace(trace_dwc3_gadget, - "%s: incomplete IN transfer", - dep->name); /* * If missed isoc occurred and there is * no request queued then issue END @@ -1946,11 +2084,10 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req, *n; struct dwc3_trb *trb; bool ioc = false; - int ret; + int ret = 0; list_for_each_entry_safe(req, n, &dep->started_list, list) { unsigned length; - unsigned actual; int chain; length = req->request.length; @@ -1964,6 +2101,9 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, for_each_sg(sg, s, pending, i) { trb = &dep->trb_pool[dep->trb_dequeue]; + if (trb->ctrl & DWC3_TRB_CTRL_HWO) + break; + req->sg = sg_next(s); req->num_pending_sgs--; @@ -1978,17 +2118,9 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, event, status, chain); } - /* - * 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. - */ - actual = length - req->request.actual; - req->request.actual = actual; + req->request.actual = length - req->remaining; - if (ret && chain && (actual < length) && req->num_pending_sgs) + if ((req->request.actual < length) && req->num_pending_sgs) return __dwc3_gadget_kick_transfer(dep, 0); dwc3_gadget_giveback(dep, req, status); @@ -2096,10 +2228,12 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, { struct dwc3_ep *dep; u8 epnum = event->endpoint_number; + u8 cmd; dep = dwc->eps[epnum]; - if (!(dep->flags & DWC3_EP_ENABLED)) + if (!(dep->flags & DWC3_EP_ENABLED) && + !(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) return; if (epnum == 0 || epnum == 1) { @@ -2112,9 +2246,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dep->resource_index = 0; if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - dwc3_trace(trace_dwc3_gadget, - "%s is an Isochronous endpoint", - dep->name); + dev_err(dwc->dev, "XferComplete for Isochronous endpoint\n"); return; } @@ -2127,22 +2259,11 @@ 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, active ? "Transfer Active" - : "Transfer Not Active"); - ret = __dwc3_gadget_kick_transfer(dep, 0); if (!ret || ret == -EBUSY) return; - - dwc3_trace(trace_dwc3_gadget, - "%s: failed to kick transfers", - dep->name); } break; @@ -2152,26 +2273,16 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dep->name); return; } + break; + case DWC3_DEPEVT_EPCMDCMPLT: + cmd = DEPEVT_PARAMETER_CMD(event->parameters); - switch (event->status) { - case DEPEVT_STREAMEVT_FOUND: - dwc3_trace(trace_dwc3_gadget, - "Stream %d found and started", - event->parameters); - - break; - case DEPEVT_STREAMEVT_NOTFOUND: - /* FALLTHROUGH */ - default: - dwc3_trace(trace_dwc3_gadget, - "unable to find suitable stream"); + if (cmd == DWC3_DEPCMD_ENDTRANSFER) { + dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; + wake_up(&dep->wait_end_transfer); } break; case DWC3_DEPEVT_RXTXFIFOEVT: - dwc3_trace(trace_dwc3_gadget, "%s FIFO Overrun", dep->name); - break; - case DWC3_DEPEVT_EPCMDCMPLT: - dwc3_trace(trace_dwc3_gadget, "Endpoint Command Complete"); break; } } @@ -2224,7 +2335,8 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force) dep = dwc->eps[epnum]; - if (!dep->resource_index) + if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) || + !dep->resource_index) return; /* @@ -2268,25 +2380,9 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force) dep->resource_index = 0; dep->flags &= ~DWC3_EP_BUSY; - if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) + if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) { + dep->flags |= DWC3_EP_END_TRANSFER_PENDING; udelay(100); -} - -static void dwc3_stop_active_transfers(struct dwc3 *dwc) -{ - u32 epnum; - - for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) { - struct dwc3_ep *dep; - - dep = dwc->eps[epnum]; - if (!dep) - continue; - - if (!(dep->flags & DWC3_EP_ENABLED)) - continue; - - dwc3_remove_requests(dwc, dep); } } @@ -2375,8 +2471,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) reg &= ~DWC3_DCTL_TSTCTRL_MASK; dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc->test_mode = false; - - dwc3_stop_active_transfers(dwc); dwc3_clear_stall_all_ep(dwc); /* Reset device address to zero */ @@ -2385,32 +2479,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DCFG, reg); } -static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed) -{ - u32 reg; - u32 usb30_clock = DWC3_GCTL_CLK_BUS; - - /* - * We change the clock only at SS but I dunno why I would want to do - * this. Maybe it becomes part of the power saving plan. - */ - - if ((speed != DWC3_DSTS_SUPERSPEED) && - (speed != DWC3_DSTS_SUPERSPEED_PLUS)) - return; - - /* - * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed - * each time on Connect Done. - */ - if (!usb30_clock) - return; - - reg = dwc3_readl(dwc->regs, DWC3_GCTL); - reg |= DWC3_GCTL_RAMCLKSEL(usb30_clock); - dwc3_writel(dwc->regs, DWC3_GCTL, reg); -} - static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) { struct dwc3_ep *dep; @@ -2422,7 +2490,14 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) speed = reg & DWC3_DSTS_CONNECTSPD; dwc->speed = speed; - dwc3_update_ram_clk_sel(dwc, speed); + /* + * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed + * each time on Connect Done. + * + * Currently we always use the reset value. If any platform + * wants to set this to a different value, we need to add a + * setting and update GCTL.RAMCLKSEL here. + */ switch (speed) { case DWC3_DSTS_SUPERSPEED_PLUS: @@ -2504,16 +2579,14 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) } dep = dwc->eps[0]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true, - false); + ret = __dwc3_gadget_ep_enable(dep, true, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); return; } dep = dwc->eps[1]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true, - false); + ret = __dwc3_gadget_ep_enable(dep, true, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); return; @@ -2570,8 +2643,6 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, (pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) { if ((dwc->link_state == DWC3_LINK_STATE_U3) && (next == DWC3_LINK_STATE_RESUME)) { - dwc3_trace(trace_dwc3_gadget, - "ignoring transition U3 -> Resume"); return; } } @@ -2705,11 +2776,7 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, break; case DWC3_DEVICE_EVENT_EOPF: /* It changed to be suspend event for version 2.30a and above */ - if (dwc->revision < DWC3_REVISION_230A) { - dwc3_trace(trace_dwc3_gadget, "End of Periodic Frame"); - } else { - dwc3_trace(trace_dwc3_gadget, "U3/L1-L2 Suspend Event"); - + if (dwc->revision >= DWC3_REVISION_230A) { /* * Ignore suspend event until the gadget enters into * USB_STATE_CONFIGURED state. @@ -2720,16 +2787,9 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, } break; case DWC3_DEVICE_EVENT_SOF: - dwc3_trace(trace_dwc3_gadget, "Start of Periodic Frame"); - break; case DWC3_DEVICE_EVENT_ERRATIC_ERROR: - dwc3_trace(trace_dwc3_gadget, "Erratic Error"); - break; case DWC3_DEVICE_EVENT_CMD_CMPL: - dwc3_trace(trace_dwc3_gadget, "Command Complete"); - break; case DWC3_DEVICE_EVENT_OVERFLOW: - dwc3_trace(trace_dwc3_gadget, "Overflow"); break; default: dev_WARN(dwc->dev, "UNKNOWN IRQ %d\n", event->type); @@ -2739,7 +2799,7 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, static void dwc3_process_event_entry(struct dwc3 *dwc, const union dwc3_event *event) { - trace_dwc3_event(event->raw); + trace_dwc3_event(event->raw, dwc); /* Endpoint IRQ, handle it and return early */ if (event->type.is_devspec == 0) { @@ -2772,7 +2832,7 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt) while (left > 0) { union dwc3_event event; - event.raw = *(u32 *) (evt->buf + evt->lpos); + event.raw = *(u32 *) (evt->cache + evt->lpos); dwc3_process_event_entry(dwc, &event); @@ -2785,10 +2845,8 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt) * boundary so I worry about that once we try to handle * that. */ - evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE; + evt->lpos = (evt->lpos + 4) % evt->length; left -= 4; - - dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 4); } evt->count = 0; @@ -2800,6 +2858,11 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt) reg &= ~DWC3_GEVNTSIZ_INTMASK; dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg); + if (dwc->imod_interval) { + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB); + dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval); + } + return ret; } @@ -2820,6 +2883,7 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_evt) static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) { struct dwc3 *dwc = evt->dwc; + u32 amount; u32 count; u32 reg; @@ -2843,6 +2907,14 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) reg |= DWC3_GEVNTSIZ_INTMASK; dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg); + amount = min(count, evt->length - evt->lpos); + memcpy(evt->cache + evt->lpos, evt->buf + evt->lpos, amount); + + if (amount < count) + memcpy(evt->cache, evt->buf, count - amount); + + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count); + return IRQ_WAKE_THREAD; } @@ -2853,6 +2925,39 @@ static irqreturn_t dwc3_interrupt(int irq, void *_evt) return dwc3_check_event_buf(evt); } +static int dwc3_gadget_get_irq(struct dwc3 *dwc) +{ + struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); + int irq; + + irq = platform_get_irq_byname(dwc3_pdev, "peripheral"); + if (irq > 0) + goto out; + + if (irq == -EPROBE_DEFER) + goto out; + + irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3"); + if (irq > 0) + goto out; + + if (irq == -EPROBE_DEFER) + goto out; + + irq = platform_get_irq(dwc3_pdev, 0); + if (irq > 0) + goto out; + + if (irq != -EPROBE_DEFER) + dev_err(dwc->dev, "missing peripheral IRQ\n"); + + if (!irq) + irq = -EINVAL; + +out: + return irq; +} + /** * dwc3_gadget_init - Initializes gadget related registers * @dwc: pointer to our controller context structure @@ -2861,35 +2966,18 @@ static irqreturn_t dwc3_interrupt(int irq, void *_evt) */ int dwc3_gadget_init(struct dwc3 *dwc) { - int ret, irq; - struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); + int ret; + int irq; - irq = platform_get_irq_byname(dwc3_pdev, "peripheral"); - if (irq == -EPROBE_DEFER) - return irq; - - if (irq <= 0) { - irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3"); - if (irq == -EPROBE_DEFER) - return irq; - - if (irq <= 0) { - irq = platform_get_irq(dwc3_pdev, 0); - if (irq <= 0) { - if (irq != -EPROBE_DEFER) { - dev_err(dwc->dev, - "missing peripheral IRQ\n"); - } - if (!irq) - irq = -EINVAL; - return irq; - } - } + irq = dwc3_gadget_get_irq(dwc); + if (irq < 0) { + ret = irq; + goto err0; } dwc->irq_gadget = irq; - dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req), + dwc->ctrl_req = dma_alloc_coherent(dwc->sysdev, sizeof(*dwc->ctrl_req), &dwc->ctrl_req_addr, GFP_KERNEL); if (!dwc->ctrl_req) { dev_err(dwc->dev, "failed to allocate ctrl request\n"); @@ -2897,8 +2985,9 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err0; } - dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2, - &dwc->ep0_trb_addr, GFP_KERNEL); + dwc->ep0_trb = dma_alloc_coherent(dwc->sysdev, + 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"); ret = -ENOMEM; @@ -2911,7 +3000,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err2; } - dwc->ep0_bounce = dma_alloc_coherent(dwc->dev, + dwc->ep0_bounce = dma_alloc_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr, GFP_KERNEL); if (!dwc->ep0_bounce) { @@ -2926,6 +3015,8 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err4; } + init_completion(&dwc->ep0_in_setup); + dwc->gadget.ops = &dwc3_gadget_ops; dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.sg_supported = true; @@ -2949,8 +3040,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) * 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", + dev_info(dwc->dev, "changing max_speed on rev %08x\n", dwc->revision); dwc->gadget.max_speed = dwc->maximum_speed; @@ -2983,18 +3073,18 @@ err5: err4: dwc3_gadget_free_endpoints(dwc); - dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE, + dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE, dwc->ep0_bounce, dwc->ep0_bounce_addr); err3: kfree(dwc->setup_buf); err2: - dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2, + dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2, dwc->ep0_trb, dwc->ep0_trb_addr); err1: - dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req), + dma_free_coherent(dwc->sysdev, sizeof(*dwc->ctrl_req), dwc->ctrl_req, dwc->ctrl_req_addr); err0: @@ -3009,16 +3099,16 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dwc3_gadget_free_endpoints(dwc); - dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE, + dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE, dwc->ep0_bounce, dwc->ep0_bounce_addr); kfree(dwc->setup_buf); kfree(dwc->zlp_buf); - dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2, + dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2, dwc->ep0_trb, dwc->ep0_trb_addr); - dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req), + dma_free_coherent(dwc->sysdev, sizeof(*dwc->ctrl_req), dwc->ctrl_req, dwc->ctrl_req_addr); } |