Hi,
Dunno, seems like you're actually working around a different
bug. Looking at USB Reset handler we have:
if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) {
u32 usb_status = dwc2_readl(hsotg->regs + GOTGCTL);
u32 connected = hsotg->connected;
dev_dbg(hsotg->dev, "%s: USBRst\n", __func__);
dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",
dwc2_readl(hsotg->regs + GNPTXSTS));
dwc2_writel(GINTSTS_USBRST, hsotg->regs + GINTSTS);
/* Report disconnection if it is not already done. */
dwc2_hsotg_disconnect(hsotg);
if (usb_status & GOTGCTL_BSESVLD && connected)
dwc2_hsotg_core_init_disconnected(hsotg, true);
}
so, dwc2_hsotg_disconnect() is already called from Reset path. What
you're doing here is that you could, potentially, call
driver->disconnect() twice.
The real problem could be your implementation for ->pullup() which
duplicates part of what ->udc_start() does:
static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on)
{
struct dwc2_hsotg *hsotg = to_hsotg(gadget);
unsigned long flags = 0;
dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on,
hsotg->op_state);
/* Don't modify pullup state while in host mode */
if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) {
hsotg->enabled = is_on;
return 0;
}
spin_lock_irqsave(&hsotg->lock, flags);
if (is_on) {
hsotg->enabled = 1;
dwc2_hsotg_core_init_disconnected(hsotg, false);
dwc2_hsotg_core_connect(hsotg);
} else {
dwc2_hsotg_core_disconnect(hsotg);
dwc2_hsotg_disconnect(hsotg);
hsotg->enabled = 0;
}
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
spin_unlock_irqrestore(&hsotg->lock, flags);
return 0;
}
Here's what I think dwc2_hsotg_pullup() and dwc2_hsotg_udc_start()
should contain:
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 9dc6c482b89e..dbe28947d3a9 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -3388,6 +3388,7 @@ static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg)
dwc2_writel(0, hsotg->regs + DAINTMSK);
/* Be in disconnected state until gadget is registered */
+ /* REVISIT!!!! This should be done in probe()!!!! */
__orr32(hsotg->regs + DCTL, DCTL_SFTDISCON);
/* setup fifos */
@@ -3428,26 +3429,6 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget,
unsigned long flags;
int ret;
- if (!hsotg) {
- pr_err("%s: called with no device\n", __func__);
- return -ENODEV;
- }
-
- if (!driver) {
- dev_err(hsotg->dev, "%s: no driver\n", __func__);
- return -EINVAL;
- }
-
- if (driver->max_speed < USB_SPEED_FULL)
- dev_err(hsotg->dev, "%s: bad speed\n", __func__);
-
- if (!driver->setup) {
- dev_err(hsotg->dev, "%s: missing entry points\n", __func__);
- return -EINVAL;
- }
-
- WARN_ON(hsotg->driver);
-
driver->driver.bus = NULL;
hsotg->driver = driver;
hsotg->gadget.dev.of_node = hsotg->dev->of_node;
@@ -3550,17 +3531,15 @@ static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on)
/* Don't modify pullup state while in host mode */
if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) {
hsotg->enabled = is_on;
- return 0;
+ return -EINVAL;
}
spin_lock_irqsave(&hsotg->lock, flags);
if (is_on) {
hsotg->enabled = 1;
- dwc2_hsotg_core_init_disconnected(hsotg, false);
dwc2_hsotg_core_connect(hsotg);
} else {
dwc2_hsotg_core_disconnect(hsotg);
- dwc2_hsotg_disconnect(hsotg);
hsotg->enabled = 0;
}
And BTW, your usb_gadget_ops had indentation problems, here's a fix for
that:
@@ -3617,10 +3596,10 @@ static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned mA)
}
static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = {
- .get_frame = dwc2_hsotg_gadget_getframe,
+ .get_frame = dwc2_hsotg_gadget_getframe,
.udc_start = dwc2_hsotg_udc_start,
.udc_stop = dwc2_hsotg_udc_stop,
- .pullup = dwc2_hsotg_pullup,
+ .pullup = dwc2_hsotg_pullup,
.vbus_session = dwc2_hsotg_vbus_session,
.vbus_draw = dwc2_hsotg_vbus_draw,
};
John Y, it sees like dwc2 needs quite a bit of work when it comes to its
linkage to the Gadget API, please try to schedule some time to revisit
all of that. Also, the way debugging is done with dwc2 is rather bad,
with a few #ifdef DEBUG in the driver. Some of that information could be
exposed via tracepoints and some would make more sense with debugfs.
Anyway, I don't think $subject is the right fix for the problem
described so I'm not taking it, at least not at this moment or without a
better explanation of how we got to the conclusion that $subject is the
right fix ;-)
cheers
--
balbi