diff mbox series

[1/2] usb: dwc3: gadget: Enable suspend events

Message ID 20210428090111.3370-1-jackp@codeaurora.org (mailing list archive)
State Accepted
Commit d1d90dd27254c44d087ad3f8b5b3e4fff0571f45
Headers show
Series [1/2] usb: dwc3: gadget: Enable suspend events | expand

Commit Message

Jack Pham April 28, 2021, 9:01 a.m. UTC
commit 72704f876f50 ("dwc3: gadget: Implement the suspend entry event
handler") introduced (nearly 5 years ago!) an interrupt handler for
U3/L1-L2 suspend events.  The problem is that these events aren't
currently enabled in the DEVTEN register so the handler is never
even invoked.  Fix this simply by enabling the corresponding bit
in dwc3_gadget_enable_irq() using the same revision check as found
in the handler.

Fixes: 72704f876f50 ("dwc3: gadget: Implement the suspend entry event handler")
Signed-off-by: Jack Pham <jackp@codeaurora.org>
---
 drivers/usb/dwc3/gadget.c | 4 ++++
 1 file changed, 4 insertions(+)

Comments

Felipe Balbi April 28, 2021, 10:19 a.m. UTC | #1
Hi,

Jack Pham <jackp@codeaurora.org> writes:
> commit 72704f876f50 ("dwc3: gadget: Implement the suspend entry event
> handler") introduced (nearly 5 years ago!) an interrupt handler for
> U3/L1-L2 suspend events.  The problem is that these events aren't

look deeper. They *were* enabled. We've removed because, as it turns
out, they just add a TON of interrupts and don't give us much extra
information. The only reason why the state change interrupts are still
there is because of a known silicon bug in versions < 2.50a. That's all
documented in the driver itself.

For anything that works, we *don't* want link state change interrupts.

> currently enabled in the DEVTEN register so the handler is never
> even invoked.  Fix this simply by enabling the corresponding bit
> in dwc3_gadget_enable_irq() using the same revision check as found
> in the handler.

More importantly, *why* do you think you need these interrupts?

> Fixes: 72704f876f50 ("dwc3: gadget: Implement the suspend entry event handler")
> Signed-off-by: Jack Pham <jackp@codeaurora.org>
> ---
>  drivers/usb/dwc3/gadget.c | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> index dd80e5ca8c78..cab3a9184068 100644
> --- a/drivers/usb/dwc3/gadget.c
> +++ b/drivers/usb/dwc3/gadget.c
> @@ -2323,6 +2323,10 @@ static void dwc3_gadget_enable_irq(struct dwc3 *dwc)
>  	if (DWC3_VER_IS_PRIOR(DWC3, 250A))
>  		reg |= DWC3_DEVTEN_ULSTCNGEN;
>  
> +	/* On 2.30a and above this bit enables U3/L2-L1 Suspend Events */
> +	if (!DWC3_VER_IS_PRIOR(DWC3, 230A))
> +		reg |= DWC3_DEVTEN_EOPFEN;

look at cpu usage for dwc3's interrupt before and after this
IRQ. Specially when connected to a host that fully supports LPM. IIRC,
recent xhci should trigger state changes fairly often.

Still, why do you think you need these events?
Jack Pham April 28, 2021, 3:34 p.m. UTC | #2
Hi Felipe,

On Wed, Apr 28, 2021 at 01:19:51PM +0300, Felipe Balbi wrote:
> Jack Pham <jackp@codeaurora.org> writes:
> > commit 72704f876f50 ("dwc3: gadget: Implement the suspend entry event
> > handler") introduced (nearly 5 years ago!) an interrupt handler for
> > U3/L1-L2 suspend events.  The problem is that these events aren't
> 
> look deeper. They *were* enabled. We've removed because, as it turns
> out, they just add a TON of interrupts and don't give us much extra
> information. The only reason why the state change interrupts are still
> there is because of a known silicon bug in versions < 2.50a. That's all
> documented in the driver itself.

I did go through the commit history. Are you referring to your change
799e9dc82968 ("usb: dwc3: gadget: conditionally disable Link State
change events")?  If so then it sounds like you are talking about the
link state change event, defined as event value 3 and enabled with
DEVTEN bit 3.

The "link state change event" is *not* the same as the one I'm referring
to in this patch which is documented in newer revisions of the databook
(both DWC3 and DWC3.1) as "USB Suspend Entry" (event 6). It's described
as only getting generated when the link enters U3, L2 or L1 states.

> For anything that works, we *don't* want link state change interrupts.

Fully agree. I've seen the "link state change" interrupts in action and
they are very noisy as they get generated for every single link event,
particularly the USB 3.x LTSSM, including U0, U1, U2, Compliance,
Polling, etc. in addition to the above U3, L2 & L1.

But I am not proposing re-enabling that particular event type here.

> > currently enabled in the DEVTEN register so the handler is never
> > even invoked.  Fix this simply by enabling the corresponding bit
> > in dwc3_gadget_enable_irq() using the same revision check as found
> > in the handler.
> 
> More importantly, *why* do you think you need these interrupts?

Bus suspend and resume are useful conditions to be notified about--
that's why we have the .suspend() & .resume() callbacks in struct
usb_gadget_driver.  But currently the dwc3 gadget does not have any
interrupt generated for suspend, and as of now the dwc3_gadget_suspend()
does not get called, so it will never invoke the gadget driver's (let's
say composite.c) .suspend() routine.

dwc3_gadget_suspend() is called from two places:

  1. dwc3_gadget_linksts_change_interrupt() - which is the handler for
     DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE, the one I believe you are
     referring to and is only enabled on revisions < 2.50a.

  2. dwc3_gadget_suspend_interrupt() - which is the handler for the
     DWC3_DEVICE_EVENT_EOPF (which I'm promptly renaming to
     DWC3_DEVICE_EVENT_SUSPEND in patch 2/2)

> > Fixes: 72704f876f50 ("dwc3: gadget: Implement the suspend entry event handler")
> > Signed-off-by: Jack Pham <jackp@codeaurora.org>
> > ---
> >  drivers/usb/dwc3/gadget.c | 4 ++++
> >  1 file changed, 4 insertions(+)
> >
> > diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> > index dd80e5ca8c78..cab3a9184068 100644
> > --- a/drivers/usb/dwc3/gadget.c
> > +++ b/drivers/usb/dwc3/gadget.c
> > @@ -2323,6 +2323,10 @@ static void dwc3_gadget_enable_irq(struct dwc3 *dwc)
> >  	if (DWC3_VER_IS_PRIOR(DWC3, 250A))
> >  		reg |= DWC3_DEVTEN_ULSTCNGEN;
> >  
> > +	/* On 2.30a and above this bit enables U3/L2-L1 Suspend Events */
> > +	if (!DWC3_VER_IS_PRIOR(DWC3, 230A))
> > +		reg |= DWC3_DEVTEN_EOPFEN;
> 
> look at cpu usage for dwc3's interrupt before and after this
> IRQ. Specially when connected to a host that fully supports LPM. IIRC,
> recent xhci should trigger state changes fairly often.

In our experience for U3 & L2 they are only as frequent as the host
enters suspend, which is not that frequent unless the user is toggling
system suspend/resume like crazy or has autosuspend enabled with a very
short timeout.

You are right that LPM L1 might happen more often when connected to a
host that supports it. I'll try to collect some stats in that case to
see what is a typical count for a given connection. It's worth noting
that the dwc3_gadget_suspend_interrupt() handler specifically checks
whether it is U3 (L2 if 2.0) before calling dwc3_gadget_suspend()
otherwise it just stores the current link_state and exits.  So almost a
no-op but not quite since it does incur the cost of an interrupt every
time it happens.

> Still, why do you think you need these events?

Answered above. I'll add that specifically composite_suspend() also
invokes each function driver's .suspend() callback which is needed in
case functions have to stop any outstanding endpoint requests and
restart them in the .resume() handler. And finally composite_suspend()
also invokes the vbus_draw() callback which is needed to properly
inform a power supply or charger to stop drawing current to comply with
USB suspend power requirements.

Thanks,
Jack
Felipe Balbi April 30, 2021, 8:39 a.m. UTC | #3
Hi,

Jack Pham <jackp@codeaurora.org> writes:
> Hi Felipe,
>
> On Wed, Apr 28, 2021 at 01:19:51PM +0300, Felipe Balbi wrote:
>> Jack Pham <jackp@codeaurora.org> writes:
>> > commit 72704f876f50 ("dwc3: gadget: Implement the suspend entry event
>> > handler") introduced (nearly 5 years ago!) an interrupt handler for
>> > U3/L1-L2 suspend events.  The problem is that these events aren't
>> 
>> look deeper. They *were* enabled. We've removed because, as it turns
>> out, they just add a TON of interrupts and don't give us much extra
>> information. The only reason why the state change interrupts are still
>> there is because of a known silicon bug in versions < 2.50a. That's all
>> documented in the driver itself.
>
> I did go through the commit history. Are you referring to your change
> 799e9dc82968 ("usb: dwc3: gadget: conditionally disable Link State
> change events")?  If so then it sounds like you are talking about the
> link state change event, defined as event value 3 and enabled with
> DEVTEN bit 3.
>
> The "link state change event" is *not* the same as the one I'm referring
> to in this patch which is documented in newer revisions of the databook
> (both DWC3 and DWC3.1) as "USB Suspend Entry" (event 6). It's described
> as only getting generated when the link enters U3, L2 or L1 states.

heh, I need some sleep, apparently :-)

>> > currently enabled in the DEVTEN register so the handler is never
>> > even invoked.  Fix this simply by enabling the corresponding bit
>> > in dwc3_gadget_enable_irq() using the same revision check as found
>> > in the handler.
>> 
>> More importantly, *why* do you think you need these interrupts?
>
> Bus suspend and resume are useful conditions to be notified about--
> that's why we have the .suspend() & .resume() callbacks in struct
> usb_gadget_driver.  But currently the dwc3 gadget does not have any
> interrupt generated for suspend, and as of now the dwc3_gadget_suspend()
> does not get called, so it will never invoke the gadget driver's (let's
> say composite.c) .suspend() routine.
>
> dwc3_gadget_suspend() is called from two places:

understood.

>   1. dwc3_gadget_linksts_change_interrupt() - which is the handler for
>      DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE, the one I believe you are
>      referring to and is only enabled on revisions < 2.50a.
>
>   2. dwc3_gadget_suspend_interrupt() - which is the handler for the
>      DWC3_DEVICE_EVENT_EOPF (which I'm promptly renaming to
>      DWC3_DEVICE_EVENT_SUSPEND in patch 2/2)

Right, now it all makes sense. Thanks for clarifying.
Felipe Balbi April 30, 2021, 8:39 a.m. UTC | #4
Jack Pham <jackp@codeaurora.org> writes:

> commit 72704f876f50 ("dwc3: gadget: Implement the suspend entry event
> handler") introduced (nearly 5 years ago!) an interrupt handler for
> U3/L1-L2 suspend events.  The problem is that these events aren't
> currently enabled in the DEVTEN register so the handler is never
> even invoked.  Fix this simply by enabling the corresponding bit
> in dwc3_gadget_enable_irq() using the same revision check as found
> in the handler.
>
> Fixes: 72704f876f50 ("dwc3: gadget: Implement the suspend entry event handler")
> Signed-off-by: Jack Pham <jackp@codeaurora.org>

Acked-by: Felipe Balbi <balbi@kernel.org>
diff mbox series

Patch

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index dd80e5ca8c78..cab3a9184068 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2323,6 +2323,10 @@  static void dwc3_gadget_enable_irq(struct dwc3 *dwc)
 	if (DWC3_VER_IS_PRIOR(DWC3, 250A))
 		reg |= DWC3_DEVTEN_ULSTCNGEN;
 
+	/* On 2.30a and above this bit enables U3/L2-L1 Suspend Events */
+	if (!DWC3_VER_IS_PRIOR(DWC3, 230A))
+		reg |= DWC3_DEVTEN_EOPFEN;
+
 	dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
 }