diff options
Diffstat (limited to 'drivers/usb/dwc3/ep0.c')
-rw-r--r-- | drivers/usb/dwc3/ep0.c | 139 |
1 files changed, 111 insertions, 28 deletions
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index f13e9e9fb834..c244d908fa4f 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/spinlock.h> @@ -34,6 +35,12 @@ #include "debug.h" #include "gadget.h" #include "io.h" +#include "debug.h" + + +static bool enable_dwc3_u1u2; +module_param(enable_dwc3_u1u2, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(enable_dwc3_u1u2, "Enable support for U1U2 low power modes"); static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, @@ -232,11 +239,13 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, unsigned long flags; int ret; + enum dwc3_link_state link_state; + u32 reg; spin_lock_irqsave(&dwc->lock, flags); if (!dep->endpoint.desc) { dwc3_trace(trace_dwc3_ep0, - "trying to queue request %p to disabled %s", + "trying to queue request %pK to disabled %s", request, dep->name); ret = -ESHUTDOWN; goto out; @@ -248,8 +257,20 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, goto out; } + /* if link stats is in L1 initiate remote wakeup before queuing req */ + if (dwc->speed != DWC3_DSTS_SUPERSPEED) { + link_state = dwc3_get_link_state(dwc); + /* in HS this link state is same as L1 */ + if (link_state == DWC3_LINK_STATE_U2) { + dwc->l1_remote_wakeup_cnt++; + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + reg |= DWC3_DCTL_ULSTCHNG_RECOVERY; + dwc3_writel(dwc->regs, DWC3_DCTL, reg); + } + } + dwc3_trace(trace_dwc3_ep0, - "queueing request %p to %s length %d state '%s'", + "queueing request %pK to %s length %d state '%s'", request, dep->name, request->length, dwc3_ep0_state_string(dwc->ep0state)); @@ -291,6 +312,7 @@ 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; + dbg_event(dep->number, "EP0STAL", value); dwc3_ep0_stall_and_restart(dwc); return 0; @@ -317,7 +339,8 @@ void dwc3_ep0_out_start(struct dwc3 *dwc) dwc3_ep0_prepare_one_trb(dwc, 0, dwc->ctrl_req_addr, 8, DWC3_TRBCTL_CONTROL_SETUP, false); ret = dwc3_ep0_start_trans(dwc, 0); - WARN_ON(ret < 0); + if (WARN_ON_ONCE(ret < 0)) + dbg_event(dwc->eps[0]->number, "EOUTSTART", ret); } static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le) @@ -340,12 +363,24 @@ static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le) static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req) { } + +static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) +{ + int ret; + + spin_unlock(&dwc->lock); + ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl); + spin_lock(&dwc->lock); + return ret; +} + /* * ch 9.4.5 */ static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { + int ret; struct dwc3_ep *dep; u32 recip; u32 reg; @@ -366,6 +401,9 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, usb_status |= 1 << USB_DEV_STAT_U1_ENABLED; if (reg & DWC3_DCTL_INITU2ENA) usb_status |= 1 << USB_DEV_STAT_U2_ENABLED; + } else { + usb_status |= dwc->gadget.remote_wakeup << + USB_DEVICE_REMOTE_WAKEUP; } break; @@ -375,6 +413,10 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, * Function Remote Wake Capable D0 * Function Remote Wakeup D1 */ + + ret = dwc3_ep0_delegate_req(dwc, ctrl); + if (ret) + return ret; break; case USB_RECIP_ENDPOINT: @@ -397,6 +439,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, dwc->ep0_usb_req.request.length = sizeof(*response_pkt); dwc->ep0_usb_req.request.buf = dwc->setup_buf; dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl; + dwc->ep0_usb_req.request.dma = DMA_ERROR_CODE; return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); } @@ -422,6 +465,9 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, switch (wValue) { case USB_DEVICE_REMOTE_WAKEUP: + pr_debug("%s(): remote wakeup :%s\n", __func__, + (set ? "enabled" : "disabled")); + dwc->gadget.remote_wakeup = set; break; /* * 9.4.1 says only only for SS, in AddressState only for @@ -433,6 +479,9 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, if (dwc->speed != DWC3_DSTS_SUPERSPEED) return -EINVAL; + if (dwc->usb3_u1u2_disable && !enable_dwc3_u1u2) + return -EINVAL; + reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (set) reg |= DWC3_DCTL_INITU1ENA; @@ -447,6 +496,9 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, if (dwc->speed != DWC3_DSTS_SUPERSPEED) return -EINVAL; + if (dwc->usb3_u1u2_disable && !enable_dwc3_u1u2) + return -EINVAL; + reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (set) reg |= DWC3_DCTL_INITU2ENA; @@ -481,6 +533,9 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, if (wIndex & USB_INTRF_FUNC_SUSPEND_RW) /* XXX enable remote wakeup */ ; + ret = dwc3_ep0_delegate_req(dwc, ctrl); + if (ret) + return ret; break; default: return -EINVAL; @@ -542,16 +597,6 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) return 0; } -static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) -{ - int ret; - - spin_unlock(&dwc->lock); - ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl); - spin_lock(&dwc->lock); - return ret; -} - static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { enum usb_device_state state = dwc->gadget.state; @@ -580,13 +625,16 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) usb_gadget_set_state(&dwc->gadget, USB_STATE_CONFIGURED); - /* - * 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); + if (!dwc->usb3_u1u2_disable || enable_dwc3_u1u2) { + /* + * 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; dwc3_trace(trace_dwc3_ep0, "resize FIFOs flag SET"); @@ -646,7 +694,8 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req) /* now that we have the time, issue DGCMD Set Sel */ ret = dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_SET_PERIODIC_PAR, param); - WARN_ON(ret < 0); + if (WARN_ON_ONCE(ret < 0)) + dbg_event(dep->number, "ESET_SELCMPL", ret); } static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) @@ -681,6 +730,7 @@ static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket; dwc->ep0_usb_req.request.buf = dwc->setup_buf; dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl; + dwc->ep0_usb_req.request.dma = DMA_ERROR_CODE; return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); } @@ -772,6 +822,7 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, dwc->ep0_next_event = DWC3_EP0_NRDY_DATA; } + dbg_setup(0x00, ctrl); if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) ret = dwc3_ep0_std_request(dwc, ctrl); else @@ -781,8 +832,10 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, dwc->delayed_status = true; out: - if (ret < 0) + if (ret < 0) { + dbg_event(0x0, "ERRSTAL", ret); dwc3_ep0_stall_and_restart(dwc); + } } static void dwc3_ep0_complete_data(struct dwc3 *dwc, @@ -864,7 +917,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, if ((epnum & 1) && ur->actual < ur->length) { /* for some reason we did not get everything out */ - + dbg_event(epnum, "INDATSTAL", 0); dwc3_ep0_stall_and_restart(dwc); } else { dwc3_gadget_giveback(ep0, r, 0); @@ -878,7 +931,8 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, dwc3_ep0_prepare_one_trb(dwc, epnum, dwc->ctrl_req_addr, 0, DWC3_TRBCTL_CONTROL_DATA, false); ret = dwc3_ep0_start_trans(dwc, epnum); - WARN_ON(ret < 0); + if (WARN_ON_ONCE(ret < 0)) + dbg_event(epnum, "ECTRL_DATA", ret); } } } @@ -909,6 +963,7 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc, if (ret < 0) { dwc3_trace(trace_dwc3_ep0, "Invalid Test #%d", dwc->test_mode_nr); + dbg_event(0x00, "INVALTEST", ret); dwc3_ep0_stall_and_restart(dwc); return; } @@ -918,6 +973,7 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc, if (status == DWC3_TRBSTS_SETUP_PENDING) dwc3_trace(trace_dwc3_ep0, "Setup Pending received"); + dbg_print(dep->number, "DONE", status, "STATUS"); dwc->ep0state = EP0_SETUP_PHASE; dwc3_ep0_out_start(dwc); } @@ -1010,7 +1066,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, ret = dwc3_ep0_start_trans(dwc, dep->number); } - WARN_ON(ret < 0); + dbg_queue(dep->number, &req->request, ret); } static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) @@ -1028,13 +1084,16 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep) { + int ret; if (dwc->resize_fifos) { dwc3_trace(trace_dwc3_ep0, "Resizing FIFOs"); dwc3_gadget_resize_tx_fifos(dwc); dwc->resize_fifos = 0; } - WARN_ON(dwc3_ep0_start_control_status(dep)); + ret = dwc3_ep0_start_control_status(dep); + if (WARN_ON_ONCE(ret)) + dbg_event(dep->number, "ECTRLSTATUS", ret); } static void dwc3_ep0_do_control_status(struct dwc3 *dwc, @@ -1059,18 +1118,28 @@ static void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep) cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); memset(¶ms, 0, sizeof(params)); ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); - WARN_ON_ONCE(ret); + if (ret) { + dev_dbg(dwc->dev, "%s: send ep cmd ENDTRANSFER failed", + dep->name); + dbg_event(dep->number, "EENDXFER", ret); + } dep->resource_index = 0; } static void dwc3_ep0_xfernotready(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { + u8 epnum; + struct dwc3_ep *dep; + dwc->setup_packet_pending = true; + epnum = event->endpoint_number; + dep = dwc->eps[epnum]; switch (event->status) { case DEPEVT_STATUS_CONTROL_DATA: dwc3_trace(trace_dwc3_ep0, "Control Data"); + dep->dbg_ep_events.control_data++; /* * We already have a DATA transfer in the controller's cache, @@ -1087,6 +1156,7 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, dwc3_trace(trace_dwc3_ep0, "Wrong direction for Data phase"); dwc3_ep0_end_control_data(dwc, dep); + dbg_event(epnum, "WRONGDR", 0); dwc3_ep0_stall_and_restart(dwc); return; } @@ -1094,6 +1164,7 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, break; case DEPEVT_STATUS_CONTROL_STATUS: + dep->dbg_ep_events.control_status++; if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) return; @@ -1102,7 +1173,8 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, dwc->ep0state = EP0_STATUS_PHASE; if (dwc->delayed_status) { - WARN_ON_ONCE(event->endpoint_number != 1); + if (event->endpoint_number != 1) + dbg_event(epnum, "EEPNUM", event->status); dwc3_trace(trace_dwc3_ep0, "Delayed Status"); return; } @@ -1115,25 +1187,36 @@ void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { u8 epnum = event->endpoint_number; + struct dwc3_ep *dep; dwc3_trace(trace_dwc3_ep0, "%s while ep%d%s in state '%s'", dwc3_ep_event_string(event->endpoint_event), epnum >> 1, (epnum & 1) ? "in" : "out", dwc3_ep0_state_string(dwc->ep0state)); + dep = dwc->eps[epnum]; switch (event->endpoint_event) { case DWC3_DEPEVT_XFERCOMPLETE: dwc3_ep0_xfer_complete(dwc, event); + dep->dbg_ep_events.xfercomplete++; break; case DWC3_DEPEVT_XFERNOTREADY: dwc3_ep0_xfernotready(dwc, event); + dep->dbg_ep_events.xfernotready++; break; case DWC3_DEPEVT_XFERINPROGRESS: + dep->dbg_ep_events.xferinprogress++; + break; case DWC3_DEPEVT_RXTXFIFOEVT: + dep->dbg_ep_events.rxtxfifoevent++; + break; case DWC3_DEPEVT_STREAMEVT: + dep->dbg_ep_events.streamevent++; + break; case DWC3_DEPEVT_EPCMDCMPLT: + dep->dbg_ep_events.epcmdcomplete++; break; } } |