Re: [PATCH 4/6] usb: xhci-mtk: add support runtime PM

From: Chunfeng Yun
Date: Mon Apr 12 2021 - 23:36:07 EST


On Mon, 2021-04-12 at 13:14 +0800, Ikjoon Jang wrote:
> On Fri, Apr 9, 2021 at 4:54 PM Chunfeng Yun <chunfeng.yun@xxxxxxxxxxxx> wrote:
> >
> > On Fri, 2021-04-09 at 13:45 +0800, Ikjoon Jang wrote:
> > > On Thu, Apr 8, 2021 at 5:35 PM Chunfeng Yun <chunfeng.yun@xxxxxxxxxxxx> wrote:
> > > >
> > > > A dedicated wakeup irq will be used to handle runtime suspend/resume,
> > > > we use dev_pm_set_dedicated_wake_irq API to take care of requesting
> > > > and attaching wakeup irq, then the suspend/resume framework will help
> > > > to enable/disable wakeup irq.
> > > >
> > > > The runtime PM is default off since some platforms may not support it.
> > > > users can enable it via power/control (set "auto") in sysfs.
> > > >
> > > > Signed-off-by: Chunfeng Yun <chunfeng.yun@xxxxxxxxxxxx>
> > > > ---
> > > > drivers/usb/host/xhci-mtk.c | 140 +++++++++++++++++++++++++++++++-----
> > > > 1 file changed, 124 insertions(+), 16 deletions(-)
> > > >
> > > > diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
> > > > index a74764ab914a..30927f4064d4 100644
> > > > --- a/drivers/usb/host/xhci-mtk.c
> > > > +++ b/drivers/usb/host/xhci-mtk.c
[...]
> > > >
> > > > +static int check_rhub_status(struct xhci_hcd *xhci, struct xhci_hub *rhub)
> > > > +{
> > > > + u32 suspended_ports;
> > > > + u32 status;
> > > > + int num_ports;
> > > > + int i;
> > > > +
> > > > + num_ports = rhub->num_ports;
> > > > + suspended_ports = rhub->bus_state.suspended_ports;
> > > > + for (i = 0; i < num_ports; i++) {
> > > > + if (!(suspended_ports & BIT(i))) {
> > > > + status = readl(rhub->ports[i]->addr);
> > > > + if (status & PORT_CONNECT)
> > >
> > > So this pm_runtime support is activated only when there's no devices
> > > connected at all?
> > No, if the connected devices also support runtime suspend, it will enter
> > suspend mode when no data transfer, then the controller can enter
> > suspend too
> > > I think this will always return -EBUSY with my board having an on-board hub
> > > connected to both rhubs.
> > the on-board hub supports runtime suspend by default, so if no devices
> > connected, it will enter suspend
>
> Sorry, you're correct. I was confused that the condition was
> (suspended && connect)
> My on-board hub connected to rhub is always in a suspended state
> whenever it's called.
>
> However, I don't think this could return -EBUSY
> rpm_suspend() only be called when all the descendants are in sleep already.
You mean we can drop the bus check?
If PM already takes care of children count, I think no need check it
anymore.
> Did you see any cases of this function returning -EBUSY or any concerns on here?
No, I didn't see it before.

Thanks

>
>
> >
> > >
> > > > + return -EBUSY;
> > > > + }
> > > > + }
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +/*
> > > > + * check the bus whether it could suspend or not
> > > > + * the bus will suspend if the downstream ports are already suspended,
> > > > + * or no devices connected.
> > > > + */
> > > > +static int check_bus_status(struct xhci_hcd *xhci)
> > > > +{
> > > > + int ret;
> > > > +
> > > > + ret = check_rhub_status(xhci, &xhci->usb3_rhub);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + return check_rhub_status(xhci, &xhci->usb2_rhub);
> > > > +}
> > > > +
> > > > +static int __maybe_unused xhci_mtk_runtime_suspend(struct device *dev)
> > > > +{
> > > > + struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
> > > > + struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd);
> > > > + int ret = 0;
> > > > +
> > > > + if (xhci->xhc_state)
> > > > + return -ESHUTDOWN;
> > > > +
> > > > + if (device_may_wakeup(dev)) {
> > > > + ret = check_bus_status(xhci);
> > > > + if (!ret)
> > > > + ret = xhci_mtk_suspend(dev);
> > > > + }
> > > > +
> > > > + /* -EBUSY: let PM automatically reschedule another autosuspend */
> > > > + return ret ? -EBUSY : 0;
> > > > +}
> > > > +
> > > > +static int __maybe_unused xhci_mtk_runtime_resume(struct device *dev)
> > > > +{
> > > > + struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
> > > > + struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd);
> > > > + int ret = 0;
> > > > +
> > > > + if (xhci->xhc_state)
> > > > + return -ESHUTDOWN;
> > > > +
> > > > + if (device_may_wakeup(dev))
> > > > + ret = xhci_mtk_resume(dev);
> > > > +
> > > > + return ret;
> > > > +}
> > > > +
> > > > static const struct dev_pm_ops xhci_mtk_pm_ops = {
> > > > SET_SYSTEM_SLEEP_PM_OPS(xhci_mtk_suspend, xhci_mtk_resume)
> > > > + SET_RUNTIME_PM_OPS(xhci_mtk_runtime_suspend,
> > > > + xhci_mtk_runtime_resume, NULL)
> > > > };
> > > > -#define DEV_PM_OPS IS_ENABLED(CONFIG_PM) ? &xhci_mtk_pm_ops : NULL
> > > > +
> > > > +#define DEV_PM_OPS (IS_ENABLED(CONFIG_PM) ? &xhci_mtk_pm_ops : NULL)
> > > >
> > > > static const struct of_device_id mtk_xhci_of_match[] = {
> > > > { .compatible = "mediatek,mt8173-xhci"},
> > > > --
> > > > 2.18.0
> > > >
> >