Re: [RFC][PATCH] usb: dwc2: Make sure we disconnect the gadget state on reset
On Mon, Oct 31, 2016 at 4:18 AM, Felipe Balbiwrote: > John Stultz writes: >> I had seen some odd behavior with HiKey's usb-gadget interface >> that I finally seemed to have chased down. Basically every other >> time I pluged in the OTG port, the gadget interface would >> properly initialize. The other times, I'd get a big WARN_ON >> in dwc2_hsotg_init_fifo() about the fifo_map not being clear. >> >> Ends up If we don't disconnect the gadget state on reset, the >> fifo-map doesn't get cleared properly, which causes WARN_ON >> messages and also results in the device not properly being >> setup as a gadget every other time the OTG port is connected. >> >> So this patch adds a call to dwc2_hsotg_disconnect() in the >> reset path so the state is properly cleared. >> >> With it, the gadget interface initializes properly on every >> plug in. >> >> I don't know if this is actually the right fix, but it seems >> to work well. Feedback would be greatly appreciated! >> [snip] >> --- >> drivers/usb/dwc2/gadget.c | 2 ++ >> 1 file changed, 2 insertions(+) >> >> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c >> index 24fbebc..5505001 100644 >> --- a/drivers/usb/dwc2/gadget.c >> +++ b/drivers/usb/dwc2/gadget.c >> @@ -2519,6 +2519,8 @@ void dwc2_hsotg_core_init_disconnected(struct >> dwc2_hsotg *hsotg, >> >> /* Kill any ep0 requests as controller will be reinitialized */ >> kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); >> + /* Make sure everything is disconnected */ >> + dwc2_hsotg_disconnect(hsotg); > > 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(>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(>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
Re: [RFC][PATCH] usb: dwc2: Make sure we disconnect the gadget state on reset
On Mon, Oct 31, 2016 at 4:18 AM, Felipe Balbi wrote: > John Stultz writes: >> I had seen some odd behavior with HiKey's usb-gadget interface >> that I finally seemed to have chased down. Basically every other >> time I pluged in the OTG port, the gadget interface would >> properly initialize. The other times, I'd get a big WARN_ON >> in dwc2_hsotg_init_fifo() about the fifo_map not being clear. >> >> Ends up If we don't disconnect the gadget state on reset, the >> fifo-map doesn't get cleared properly, which causes WARN_ON >> messages and also results in the device not properly being >> setup as a gadget every other time the OTG port is connected. >> >> So this patch adds a call to dwc2_hsotg_disconnect() in the >> reset path so the state is properly cleared. >> >> With it, the gadget interface initializes properly on every >> plug in. >> >> I don't know if this is actually the right fix, but it seems >> to work well. Feedback would be greatly appreciated! >> [snip] >> --- >> drivers/usb/dwc2/gadget.c | 2 ++ >> 1 file changed, 2 insertions(+) >> >> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c >> index 24fbebc..5505001 100644 >> --- a/drivers/usb/dwc2/gadget.c >> +++ b/drivers/usb/dwc2/gadget.c >> @@ -2519,6 +2519,8 @@ void dwc2_hsotg_core_init_disconnected(struct >> dwc2_hsotg *hsotg, >> >> /* Kill any ep0 requests as controller will be reinitialized */ >> kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); >> + /* Make sure everything is disconnected */ >> + dwc2_hsotg_disconnect(hsotg); > > 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(>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(>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;
Re: [RFC][PATCH] usb: dwc2: Make sure we disconnect the gadget state on reset
On 10/31/2016 4:19 AM, Felipe Balbi wrote: > > Hi, > > John Stultzwrites: >> I had seen some odd behavior with HiKey's usb-gadget interface >> that I finally seemed to have chased down. Basically every other >> time I pluged in the OTG port, the gadget interface would >> properly initialize. The other times, I'd get a big WARN_ON >> in dwc2_hsotg_init_fifo() about the fifo_map not being clear. >> >> Ends up If we don't disconnect the gadget state on reset, the >> fifo-map doesn't get cleared properly, which causes WARN_ON >> messages and also results in the device not properly being >> setup as a gadget every other time the OTG port is connected. >> >> So this patch adds a call to dwc2_hsotg_disconnect() in the >> reset path so the state is properly cleared. >> >> With it, the gadget interface initializes properly on every >> plug in. >> >> I don't know if this is actually the right fix, but it seems >> to work well. Feedback would be greatly appreciated! >> >> Cc: Wei Xu >> Cc: Guodong Xu >> Cc: Chen Yu >> Cc: Amit Pundir >> Cc: Rob Herring >> Cc: Mark Rutland >> Cc: John Youn >> Cc: Douglas Anderson >> Cc: Greg Kroah-Hartman >> Cc: linux-...@vger.kernel.org >> Signed-off-by: John Stultz >> --- >> drivers/usb/dwc2/gadget.c | 2 ++ >> 1 file changed, 2 insertions(+) >> >> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c >> index 24fbebc..5505001 100644 >> --- a/drivers/usb/dwc2/gadget.c >> +++ b/drivers/usb/dwc2/gadget.c >> @@ -2519,6 +2519,8 @@ void dwc2_hsotg_core_init_disconnected(struct >> dwc2_hsotg *hsotg, >> >> /* Kill any ep0 requests as controller will be reinitialized */ >> kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); >> +/* Make sure everything is disconnected */ >> +dwc2_hsotg_disconnect(hsotg); > > 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(>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(>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;
Re: [RFC][PATCH] usb: dwc2: Make sure we disconnect the gadget state on reset
On 10/31/2016 4:19 AM, Felipe Balbi wrote: > > Hi, > > John Stultz writes: >> I had seen some odd behavior with HiKey's usb-gadget interface >> that I finally seemed to have chased down. Basically every other >> time I pluged in the OTG port, the gadget interface would >> properly initialize. The other times, I'd get a big WARN_ON >> in dwc2_hsotg_init_fifo() about the fifo_map not being clear. >> >> Ends up If we don't disconnect the gadget state on reset, the >> fifo-map doesn't get cleared properly, which causes WARN_ON >> messages and also results in the device not properly being >> setup as a gadget every other time the OTG port is connected. >> >> So this patch adds a call to dwc2_hsotg_disconnect() in the >> reset path so the state is properly cleared. >> >> With it, the gadget interface initializes properly on every >> plug in. >> >> I don't know if this is actually the right fix, but it seems >> to work well. Feedback would be greatly appreciated! >> >> Cc: Wei Xu >> Cc: Guodong Xu >> Cc: Chen Yu >> Cc: Amit Pundir >> Cc: Rob Herring >> Cc: Mark Rutland >> Cc: John Youn >> Cc: Douglas Anderson >> Cc: Greg Kroah-Hartman >> Cc: linux-...@vger.kernel.org >> Signed-off-by: John Stultz >> --- >> drivers/usb/dwc2/gadget.c | 2 ++ >> 1 file changed, 2 insertions(+) >> >> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c >> index 24fbebc..5505001 100644 >> --- a/drivers/usb/dwc2/gadget.c >> +++ b/drivers/usb/dwc2/gadget.c >> @@ -2519,6 +2519,8 @@ void dwc2_hsotg_core_init_disconnected(struct >> dwc2_hsotg *hsotg, >> >> /* Kill any ep0 requests as controller will be reinitialized */ >> kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); >> +/* Make sure everything is disconnected */ >> +dwc2_hsotg_disconnect(hsotg); > > 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(>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(>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",
Re: [RFC][PATCH] usb: dwc2: Make sure we disconnect the gadget state on reset
Hi, John Stultzwrites: > I had seen some odd behavior with HiKey's usb-gadget interface > that I finally seemed to have chased down. Basically every other > time I pluged in the OTG port, the gadget interface would > properly initialize. The other times, I'd get a big WARN_ON > in dwc2_hsotg_init_fifo() about the fifo_map not being clear. > > Ends up If we don't disconnect the gadget state on reset, the > fifo-map doesn't get cleared properly, which causes WARN_ON > messages and also results in the device not properly being > setup as a gadget every other time the OTG port is connected. > > So this patch adds a call to dwc2_hsotg_disconnect() in the > reset path so the state is properly cleared. > > With it, the gadget interface initializes properly on every > plug in. > > I don't know if this is actually the right fix, but it seems > to work well. Feedback would be greatly appreciated! > > Cc: Wei Xu > Cc: Guodong Xu > Cc: Chen Yu > Cc: Amit Pundir > Cc: Rob Herring > Cc: Mark Rutland > Cc: John Youn > Cc: Douglas Anderson > Cc: Greg Kroah-Hartman > Cc: linux-...@vger.kernel.org > Signed-off-by: John Stultz > --- > drivers/usb/dwc2/gadget.c | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c > index 24fbebc..5505001 100644 > --- a/drivers/usb/dwc2/gadget.c > +++ b/drivers/usb/dwc2/gadget.c > @@ -2519,6 +2519,8 @@ void dwc2_hsotg_core_init_disconnected(struct > dwc2_hsotg *hsotg, > > /* Kill any ep0 requests as controller will be reinitialized */ > kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); > + /* Make sure everything is disconnected */ > + dwc2_hsotg_disconnect(hsotg); 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(>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(>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
Re: [RFC][PATCH] usb: dwc2: Make sure we disconnect the gadget state on reset
Hi, John Stultz writes: > I had seen some odd behavior with HiKey's usb-gadget interface > that I finally seemed to have chased down. Basically every other > time I pluged in the OTG port, the gadget interface would > properly initialize. The other times, I'd get a big WARN_ON > in dwc2_hsotg_init_fifo() about the fifo_map not being clear. > > Ends up If we don't disconnect the gadget state on reset, the > fifo-map doesn't get cleared properly, which causes WARN_ON > messages and also results in the device not properly being > setup as a gadget every other time the OTG port is connected. > > So this patch adds a call to dwc2_hsotg_disconnect() in the > reset path so the state is properly cleared. > > With it, the gadget interface initializes properly on every > plug in. > > I don't know if this is actually the right fix, but it seems > to work well. Feedback would be greatly appreciated! > > Cc: Wei Xu > Cc: Guodong Xu > Cc: Chen Yu > Cc: Amit Pundir > Cc: Rob Herring > Cc: Mark Rutland > Cc: John Youn > Cc: Douglas Anderson > Cc: Greg Kroah-Hartman > Cc: linux-...@vger.kernel.org > Signed-off-by: John Stultz > --- > drivers/usb/dwc2/gadget.c | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c > index 24fbebc..5505001 100644 > --- a/drivers/usb/dwc2/gadget.c > +++ b/drivers/usb/dwc2/gadget.c > @@ -2519,6 +2519,8 @@ void dwc2_hsotg_core_init_disconnected(struct > dwc2_hsotg *hsotg, > > /* Kill any ep0 requests as controller will be reinitialized */ > kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); > + /* Make sure everything is disconnected */ > + dwc2_hsotg_disconnect(hsotg); 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(>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(>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; - } - -
Re: [RFC][PATCH] usb: dwc2: Make sure we disconnect the gadget state on reset
On 10/25/2016 2:56 PM, John Stultz wrote: > On Tue, Oct 25, 2016 at 2:29 PM, John Younwrote: >> On 10/19/2016 11:00 PM, John Stultz wrote: >>> I had seen some odd behavior with HiKey's usb-gadget interface >>> that I finally seemed to have chased down. Basically every other >>> time I pluged in the OTG port, the gadget interface would >>> properly initialize. The other times, I'd get a big WARN_ON >>> in dwc2_hsotg_init_fifo() about the fifo_map not being clear. >>> >>> Ends up If we don't disconnect the gadget state on reset, the >>> fifo-map doesn't get cleared properly, which causes WARN_ON >>> messages and also results in the device not properly being >>> setup as a gadget every other time the OTG port is connected. >>> >>> So this patch adds a call to dwc2_hsotg_disconnect() in the >>> reset path so the state is properly cleared. >>> >>> With it, the gadget interface initializes properly on every >>> plug in. >>> >>> I don't know if this is actually the right fix, but it seems >>> to work well. Feedback would be greatly appreciated! >>> >>> Cc: Wei Xu >>> Cc: Guodong Xu >>> Cc: Chen Yu >>> Cc: Amit Pundir >>> Cc: Rob Herring >>> Cc: Mark Rutland >>> Cc: John Youn >>> Cc: Douglas Anderson >>> Cc: Greg Kroah-Hartman >>> Cc: linux-...@vger.kernel.org >>> Signed-off-by: John Stultz >>> --- >>> drivers/usb/dwc2/gadget.c | 2 ++ >>> 1 file changed, 2 insertions(+) >>> >>> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c >>> index 24fbebc..5505001 100644 >>> --- a/drivers/usb/dwc2/gadget.c >>> +++ b/drivers/usb/dwc2/gadget.c >>> @@ -2519,6 +2519,8 @@ void dwc2_hsotg_core_init_disconnected(struct >>> dwc2_hsotg *hsotg, >>> >>> /* Kill any ep0 requests as controller will be reinitialized */ >>> kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); >>> + /* Make sure everything is disconnected */ >>> + dwc2_hsotg_disconnect(hsotg); >>> >>> if (!is_usb_reset) >>> if (dwc2_core_reset(hsotg)) >>> >> >> Seems fine with our testing. >> >> Acked-by: John Youn > > Awesome! Thanks so much for the review and testing! > > I'm curious, did you happen to have any thoughts or objections on the > "dwc2: Force port resume on switching to device mode" patch > (https://patchwork.kernel.org/patch/9375965/ ) as well? Sorry, must have missed that one. We'll take a look. Regards, John
Re: [RFC][PATCH] usb: dwc2: Make sure we disconnect the gadget state on reset
On 10/25/2016 2:56 PM, John Stultz wrote: > On Tue, Oct 25, 2016 at 2:29 PM, John Youn wrote: >> On 10/19/2016 11:00 PM, John Stultz wrote: >>> I had seen some odd behavior with HiKey's usb-gadget interface >>> that I finally seemed to have chased down. Basically every other >>> time I pluged in the OTG port, the gadget interface would >>> properly initialize. The other times, I'd get a big WARN_ON >>> in dwc2_hsotg_init_fifo() about the fifo_map not being clear. >>> >>> Ends up If we don't disconnect the gadget state on reset, the >>> fifo-map doesn't get cleared properly, which causes WARN_ON >>> messages and also results in the device not properly being >>> setup as a gadget every other time the OTG port is connected. >>> >>> So this patch adds a call to dwc2_hsotg_disconnect() in the >>> reset path so the state is properly cleared. >>> >>> With it, the gadget interface initializes properly on every >>> plug in. >>> >>> I don't know if this is actually the right fix, but it seems >>> to work well. Feedback would be greatly appreciated! >>> >>> Cc: Wei Xu >>> Cc: Guodong Xu >>> Cc: Chen Yu >>> Cc: Amit Pundir >>> Cc: Rob Herring >>> Cc: Mark Rutland >>> Cc: John Youn >>> Cc: Douglas Anderson >>> Cc: Greg Kroah-Hartman >>> Cc: linux-...@vger.kernel.org >>> Signed-off-by: John Stultz >>> --- >>> drivers/usb/dwc2/gadget.c | 2 ++ >>> 1 file changed, 2 insertions(+) >>> >>> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c >>> index 24fbebc..5505001 100644 >>> --- a/drivers/usb/dwc2/gadget.c >>> +++ b/drivers/usb/dwc2/gadget.c >>> @@ -2519,6 +2519,8 @@ void dwc2_hsotg_core_init_disconnected(struct >>> dwc2_hsotg *hsotg, >>> >>> /* Kill any ep0 requests as controller will be reinitialized */ >>> kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); >>> + /* Make sure everything is disconnected */ >>> + dwc2_hsotg_disconnect(hsotg); >>> >>> if (!is_usb_reset) >>> if (dwc2_core_reset(hsotg)) >>> >> >> Seems fine with our testing. >> >> Acked-by: John Youn > > Awesome! Thanks so much for the review and testing! > > I'm curious, did you happen to have any thoughts or objections on the > "dwc2: Force port resume on switching to device mode" patch > (https://patchwork.kernel.org/patch/9375965/ ) as well? Sorry, must have missed that one. We'll take a look. Regards, John
Re: [RFC][PATCH] usb: dwc2: Make sure we disconnect the gadget state on reset
On Tue, Oct 25, 2016 at 2:29 PM, John Younwrote: > On 10/19/2016 11:00 PM, John Stultz wrote: >> I had seen some odd behavior with HiKey's usb-gadget interface >> that I finally seemed to have chased down. Basically every other >> time I pluged in the OTG port, the gadget interface would >> properly initialize. The other times, I'd get a big WARN_ON >> in dwc2_hsotg_init_fifo() about the fifo_map not being clear. >> >> Ends up If we don't disconnect the gadget state on reset, the >> fifo-map doesn't get cleared properly, which causes WARN_ON >> messages and also results in the device not properly being >> setup as a gadget every other time the OTG port is connected. >> >> So this patch adds a call to dwc2_hsotg_disconnect() in the >> reset path so the state is properly cleared. >> >> With it, the gadget interface initializes properly on every >> plug in. >> >> I don't know if this is actually the right fix, but it seems >> to work well. Feedback would be greatly appreciated! >> >> Cc: Wei Xu >> Cc: Guodong Xu >> Cc: Chen Yu >> Cc: Amit Pundir >> Cc: Rob Herring >> Cc: Mark Rutland >> Cc: John Youn >> Cc: Douglas Anderson >> Cc: Greg Kroah-Hartman >> Cc: linux-...@vger.kernel.org >> Signed-off-by: John Stultz >> --- >> drivers/usb/dwc2/gadget.c | 2 ++ >> 1 file changed, 2 insertions(+) >> >> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c >> index 24fbebc..5505001 100644 >> --- a/drivers/usb/dwc2/gadget.c >> +++ b/drivers/usb/dwc2/gadget.c >> @@ -2519,6 +2519,8 @@ void dwc2_hsotg_core_init_disconnected(struct >> dwc2_hsotg *hsotg, >> >> /* Kill any ep0 requests as controller will be reinitialized */ >> kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); >> + /* Make sure everything is disconnected */ >> + dwc2_hsotg_disconnect(hsotg); >> >> if (!is_usb_reset) >> if (dwc2_core_reset(hsotg)) >> > > Seems fine with our testing. > > Acked-by: John Youn Awesome! Thanks so much for the review and testing! I'm curious, did you happen to have any thoughts or objections on the "dwc2: Force port resume on switching to device mode" patch (https://patchwork.kernel.org/patch/9375965/ ) as well? thanks -john
Re: [RFC][PATCH] usb: dwc2: Make sure we disconnect the gadget state on reset
On Tue, Oct 25, 2016 at 2:29 PM, John Youn wrote: > On 10/19/2016 11:00 PM, John Stultz wrote: >> I had seen some odd behavior with HiKey's usb-gadget interface >> that I finally seemed to have chased down. Basically every other >> time I pluged in the OTG port, the gadget interface would >> properly initialize. The other times, I'd get a big WARN_ON >> in dwc2_hsotg_init_fifo() about the fifo_map not being clear. >> >> Ends up If we don't disconnect the gadget state on reset, the >> fifo-map doesn't get cleared properly, which causes WARN_ON >> messages and also results in the device not properly being >> setup as a gadget every other time the OTG port is connected. >> >> So this patch adds a call to dwc2_hsotg_disconnect() in the >> reset path so the state is properly cleared. >> >> With it, the gadget interface initializes properly on every >> plug in. >> >> I don't know if this is actually the right fix, but it seems >> to work well. Feedback would be greatly appreciated! >> >> Cc: Wei Xu >> Cc: Guodong Xu >> Cc: Chen Yu >> Cc: Amit Pundir >> Cc: Rob Herring >> Cc: Mark Rutland >> Cc: John Youn >> Cc: Douglas Anderson >> Cc: Greg Kroah-Hartman >> Cc: linux-...@vger.kernel.org >> Signed-off-by: John Stultz >> --- >> drivers/usb/dwc2/gadget.c | 2 ++ >> 1 file changed, 2 insertions(+) >> >> diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c >> index 24fbebc..5505001 100644 >> --- a/drivers/usb/dwc2/gadget.c >> +++ b/drivers/usb/dwc2/gadget.c >> @@ -2519,6 +2519,8 @@ void dwc2_hsotg_core_init_disconnected(struct >> dwc2_hsotg *hsotg, >> >> /* Kill any ep0 requests as controller will be reinitialized */ >> kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); >> + /* Make sure everything is disconnected */ >> + dwc2_hsotg_disconnect(hsotg); >> >> if (!is_usb_reset) >> if (dwc2_core_reset(hsotg)) >> > > Seems fine with our testing. > > Acked-by: John Youn Awesome! Thanks so much for the review and testing! I'm curious, did you happen to have any thoughts or objections on the "dwc2: Force port resume on switching to device mode" patch (https://patchwork.kernel.org/patch/9375965/ ) as well? thanks -john
Re: [RFC][PATCH] usb: dwc2: Make sure we disconnect the gadget state on reset
On 10/19/2016 11:00 PM, John Stultz wrote: > I had seen some odd behavior with HiKey's usb-gadget interface > that I finally seemed to have chased down. Basically every other > time I pluged in the OTG port, the gadget interface would > properly initialize. The other times, I'd get a big WARN_ON > in dwc2_hsotg_init_fifo() about the fifo_map not being clear. > > Ends up If we don't disconnect the gadget state on reset, the > fifo-map doesn't get cleared properly, which causes WARN_ON > messages and also results in the device not properly being > setup as a gadget every other time the OTG port is connected. > > So this patch adds a call to dwc2_hsotg_disconnect() in the > reset path so the state is properly cleared. > > With it, the gadget interface initializes properly on every > plug in. > > I don't know if this is actually the right fix, but it seems > to work well. Feedback would be greatly appreciated! > > Cc: Wei Xu> Cc: Guodong Xu > Cc: Chen Yu > Cc: Amit Pundir > Cc: Rob Herring > Cc: Mark Rutland > Cc: John Youn > Cc: Douglas Anderson > Cc: Greg Kroah-Hartman > Cc: linux-...@vger.kernel.org > Signed-off-by: John Stultz > --- > drivers/usb/dwc2/gadget.c | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c > index 24fbebc..5505001 100644 > --- a/drivers/usb/dwc2/gadget.c > +++ b/drivers/usb/dwc2/gadget.c > @@ -2519,6 +2519,8 @@ void dwc2_hsotg_core_init_disconnected(struct > dwc2_hsotg *hsotg, > > /* Kill any ep0 requests as controller will be reinitialized */ > kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); > + /* Make sure everything is disconnected */ > + dwc2_hsotg_disconnect(hsotg); > > if (!is_usb_reset) > if (dwc2_core_reset(hsotg)) > Seems fine with our testing. Acked-by: John Youn Regards, John
Re: [RFC][PATCH] usb: dwc2: Make sure we disconnect the gadget state on reset
On 10/19/2016 11:00 PM, John Stultz wrote: > I had seen some odd behavior with HiKey's usb-gadget interface > that I finally seemed to have chased down. Basically every other > time I pluged in the OTG port, the gadget interface would > properly initialize. The other times, I'd get a big WARN_ON > in dwc2_hsotg_init_fifo() about the fifo_map not being clear. > > Ends up If we don't disconnect the gadget state on reset, the > fifo-map doesn't get cleared properly, which causes WARN_ON > messages and also results in the device not properly being > setup as a gadget every other time the OTG port is connected. > > So this patch adds a call to dwc2_hsotg_disconnect() in the > reset path so the state is properly cleared. > > With it, the gadget interface initializes properly on every > plug in. > > I don't know if this is actually the right fix, but it seems > to work well. Feedback would be greatly appreciated! > > Cc: Wei Xu > Cc: Guodong Xu > Cc: Chen Yu > Cc: Amit Pundir > Cc: Rob Herring > Cc: Mark Rutland > Cc: John Youn > Cc: Douglas Anderson > Cc: Greg Kroah-Hartman > Cc: linux-...@vger.kernel.org > Signed-off-by: John Stultz > --- > drivers/usb/dwc2/gadget.c | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c > index 24fbebc..5505001 100644 > --- a/drivers/usb/dwc2/gadget.c > +++ b/drivers/usb/dwc2/gadget.c > @@ -2519,6 +2519,8 @@ void dwc2_hsotg_core_init_disconnected(struct > dwc2_hsotg *hsotg, > > /* Kill any ep0 requests as controller will be reinitialized */ > kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); > + /* Make sure everything is disconnected */ > + dwc2_hsotg_disconnect(hsotg); > > if (!is_usb_reset) > if (dwc2_core_reset(hsotg)) > Seems fine with our testing. Acked-by: John Youn Regards, John