RE: [PATCH v5] usb: ohci-at91: Forcibly suspend ports while USB suspend

From: Wenyou.Yang
Date: Tue Aug 16 2016 - 05:06:10 EST


Hi Alan,

As you saw, I think the version 4 is better than this, can we take the version 4?


Best Regards,
Wenyou Yang

> -----Original Message-----
> From: Wenyou.Yang@xxxxxxxxxxxxx [mailto:Wenyou.Yang@xxxxxxxxxxxxx]
> Sent: 2016年8月5日 11:46
> To: stern@xxxxxxxxxxxxxxxxxxx; wenyou.yang@xxxxxxxxx
> Cc: gregkh@xxxxxxxxxxxxxxxxxxx; nicolas.ferre@xxxxxxxxx;
> alexandre.belloni@xxxxxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx; linux-arm-
> kernel@xxxxxxxxxxxxxxxxxxx; linux-usb@xxxxxxxxxxxxxxx
> Subject: RE: [PATCH v5] usb: ohci-at91: Forcibly suspend ports while USB
> suspend
>
> Hi Alan,
>
> > -----Original Message-----
> > From: Alan Stern [mailto:stern@xxxxxxxxxxxxxxxxxxx]
> > Sent: 2016年8月4日 23:02
> > To: Wenyou Yang <wenyou.yang@xxxxxxxxx>
> > Cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>; Nicolas Ferre
> > <nicolas.ferre@xxxxxxxxx>; Alexandre Belloni <alexandre.belloni@free-
> > electrons.com>; linux-kernel@xxxxxxxxxxxxxxx; linux-arm-
> > kernel@xxxxxxxxxxxxxxxxxxx; linux-usb@xxxxxxxxxxxxxxx
> > Subject: Re: [PATCH v5] usb: ohci-at91: Forcibly suspend ports while
> > USB suspend
> >
> > On Thu, 4 Aug 2016, Wenyou Yang wrote:
> >
> > > The usb controller does not managed correctly the suspend mode for
> > > the ehci. In echi mode, there is no way to have utmi_suspend_o_n[1]
> > > suspend without any device connected to it. This is why this
> > > specific control is added to fix this issue. The suspend mode works
> > > in ohci mode.
> >
> > Why are you talking about EHCI mode? This patch is only for the
> > ohci-at91 driver.
>
> Actually I described the issue according to the documents from our IP, and this
> specific control is recommended to do in ohci mode.
>
> >
> > > This specific control is by setting the SUSPEND_A/B/C fields of
> > > SFR_OHCIICR(OHCI Interrupt Configuration Register) in the SFR while
> > > OHCI USB suspend.
> > >
> > > This setting operation must be done before the USB clock disabled,
> > > clear them after the USB clock enabled.
> > >
> > > Signed-off-by: Wenyou Yang <wenyou.yang@xxxxxxxxx>
> > > Reviewed-by: Alexandre Belloni
> > > <alexandre.belloni@xxxxxxxxxxxxxxxxxx>
> > > Acked-by: Nicolas Ferre <nicolas.ferre@xxxxxxxxx>
> >
> > I don't know if this is any better than before! See the comments below.
>
> Yes, I think so.
>
> What else advice?
>
> >
> > > ---
> > >
> > > Changes in v5:
> > > - Use the USB_PORT_FEAT_SUSPEND subcase of the SetPortFeature case
> > > to take care it.
> > > - Update the commit log.
> > >
> > > Changes in v4:
> > > - To check whether the SFR node with "atmel,sama5d2-sfr" compatible
> > > is present or not to decide if this feature is applied or not
> > > when USB OHCI suspend/resume, instead of new compatible.
> > > - Drop the compatible "atmel,sama5d2-ohci".
> > > - Drop [PATCH 2/2] ARM: at91/dt: sama5d2: Use new compatible for
> > > ohci node.
> > > - Drop include/soc/at91/at91_sfr.h, move the macro definitions to
> > > atmel-sfr.h which already exists.
> > > - Change the defines to align the exists.
> > >
> > > Changes in v3:
> > > - Change the compatible description for more precise.
> > >
> > > Changes in v2:
> > > - Add compatible to support forcibly suspend the ports.
> > > - Add soc/at91/at91_sfr.h to accommodate the defines.
> > > - Add error checking for .sfr_regmap.
> > > - Remove unnecessary regmap_read() statement.
> >
> >
> > > @@ -282,6 +301,28 @@ static int ohci_at91_hub_status_data(struct
> > > usb_hcd
> > *hcd, char *buf)
> > > return length;
> > > }
> > >
> > > +static int ohci_at91_port_ctrl(struct regmap *regmap, u16 port, u8
> > > +set) {
> > > + u32 regval;
> > > + int ret;
> > > +
> > > + if (!regmap)
> > > + return 0;
> > > +
> > > + ret = regmap_read(regmap, AT91_SFR_OHCIICR, &regval);
> > > + if (ret)
> > > + return ret;
> > > +
> > > + if (set)
> > > + regval |= AT91_OHCIICR_SUSPEND(port);
> > > + else
> > > + regval &= ~AT91_OHCIICR_SUSPEND(port);
> >
> > In the earlier versions of this patch, you did not use the port number.
> > Why has this changed?
>
> This function is called by ohci_at91_hub_control(), which is invoked on basis of
> port number.
>
> So, I think it is more reasonable of adding the port argument.
>
> >
> > How many ports does this controller have?
>
> This controller has three ports.
>
> >
> > > +
> > > + regmap_write(regmap, AT91_SFR_OHCIICR, regval);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > /*
> > > * Look at the control requests to the root hub and see if we need to override.
> > > */
> > > @@ -289,6 +330,7 @@ static int ohci_at91_hub_control(struct usb_hcd
> > > *hcd,
> > u16 typeReq, u16 wValue,
> > > u16 wIndex, char *buf, u16 wLength) {
> > > struct at91_usbh_data *pdata =
> > > dev_get_platdata(hcd->self.controller);
> > > + struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
> > > struct usb_hub_descriptor *desc;
> > > int ret = -EINVAL;
> > > u32 *data = (u32 *)buf;
> > > @@ -301,7 +343,8 @@ static int ohci_at91_hub_control(struct usb_hcd
> > > *hcd, u16 typeReq, u16 wValue,
> > >
> > > switch (typeReq) {
> > > case SetPortFeature:
> > > - if (wValue == USB_PORT_FEAT_POWER) {
> > > + switch (wValue) {
> > > + case USB_PORT_FEAT_POWER:
> > > dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n");
> > > if (valid_port(wIndex)) {
> > > ohci_at91_usb_set_power(pdata, wIndex, 1); @@
> > -309,6 +352,11 @@
> > > static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16
> wValue,
> > > }
> > >
> > > goto out;
> > > +
> > > + case USB_PORT_FEAT_SUSPEND:
> > > + dev_dbg(hcd->self.controller, "SetPortFeat: SUSPEND\n");
> > > + ohci_at91_port_ctrl(ohci_at91->sfr_regmap, wIndex, 1);
> > > + break;
> > > }
> > > break;
> > >
> > > @@ -342,6 +390,12 @@ static int ohci_at91_hub_control(struct usb_hcd
> > > *hcd,
> > u16 typeReq, u16 wValue,
> > > ohci_at91_usb_set_power(pdata, wIndex, 0);
> > > return 0;
> > > }
> > > + break;
> > > +
> > > + case USB_PORT_FEAT_SUSPEND:
> > > + dev_dbg(hcd->self.controller, "ClearPortFeature:
> > SUSPEND\n");
> > > + ohci_at91_port_ctrl(ohci_at91->sfr_regmap, wIndex, 0);
> > > + break;
> > > }
> > > break;
> > > }
> >
> > Note that after all this, the code goes ahead to call ohci_bub_control().
>
> Yes,
> The ohci_bub_control() will change the port_status[port] register after this
> operation.
>
> >
> > > @@ -587,7 +641,8 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
> > > struct usb_hcd *hcd = dev_get_drvdata(dev);
> > > struct ohci_hcd *ohci = hcd_to_ohci(hcd);
> > > struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
> > > - int ret;
> > > + u16 i;
> > > + int ret;
> > >
> > > /*
> > > * Disable wakeup if we are going to sleep with slow clock mode @@
> > > -599,6 +654,11 @@ ohci_hcd_at91_drv_suspend(struct device *dev)
> > > if (ohci_at91->wakeup)
> > > enable_irq_wake(hcd->irq);
> > >
> > > + for (i = 0; i < ohci->num_ports; i++) {
> > > + ohci_at91_hub_control(hcd, SetPortFeature,
> > > + USB_PORT_FEAT_SUSPEND, (i + 1), NULL,
> > 0);
> > > + }
> > > +
> > > ret = ohci_suspend(hcd, ohci_at91->wakeup);
> >
> > Do you really want to call ohci_hub_control() for ports that don't
> > have a device attached?
>
> Yes. I need to do this operation for ports that don't have a device attached.
>
> >
> > > if (ret) {
> > > if (ohci_at91->wakeup)
> > > @@ -630,7 +690,9 @@ static int __maybe_unused
> > > ohci_hcd_at91_drv_resume(struct device *dev) {
> > > struct usb_hcd *hcd = dev_get_drvdata(dev);
> > > + struct ohci_hcd *ohci = hcd_to_ohci(hcd);
> > > struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
> > > + u16 i;
> > >
> > > if (ohci_at91->wakeup)
> > > disable_irq_wake(hcd->irq);
> > > @@ -638,6 +700,12 @@ ohci_hcd_at91_drv_resume(struct device *dev)
> > > at91_start_clock(ohci_at91);
> > >
> > > ohci_resume(hcd, false);
> > > +
> > > + for (i = 0; i < ohci->num_ports; i++) {
> > > + ohci_at91_hub_control(hcd, ClearPortFeature,
> > > + USB_PORT_FEAT_SUSPEND, i + 1, NULL,
> > 0);
> > > + }
> >
> > Have you thought about how this will interact with runtime PM?
> >
> > If you intend to do this only for system suspend and not for runtime
> > suspend, why not set all the suspend bits for all the ports in the
> > OHCIICR register at once, in a single write, like you were doing before?
>
> Yes, this is only for system suspend.
>
> As I mentioned above, here calls ohci_at91_hub_control(), which is based on port
> number.
>
> >
> > Alan Stern
>
>
> Best Regards,
> Wenyou Yang