summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc3/ep0.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc3/ep0.c')
-rw-r--r--drivers/usb/dwc3/ep0.c139
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(&params, 0, sizeof(params));
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
- 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;
}
}