Re: [PATCH 1/2] EHCI: centralize controller suspend/resume

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Jun 28, 2012 at 8:49 PM, Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote:
> This patch (as1563) removes a lot of duplicated code by moving the
> EHCI controller suspend/resume routines into the core driver, where
> the various platform drivers can invoke them as needed.
>
> Not only does this simplify these platform drivers, this also makes it
> easier for other platform drivers to add suspend/resume support in the
> future.
>
> Note: The patch does not touch the ehci-fsl.c file, because its
> approach to suspend and resume is so different from all the others.
> It will have to be handled specially by its maintainer.
>
> Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
>
> ---
>
>  drivers/usb/host/ehci-au1xxx.c   |   73 +------------------------------
>  drivers/usb/host/ehci-hcd.c      |   89 +++++++++++++++++++++++++++++++++++++++
>  drivers/usb/host/ehci-hub.c      |    4 -
>  drivers/usb/host/ehci-msm.c      |   19 +-------
>  drivers/usb/host/ehci-pci.c      |   74 +-------------------------------
>  drivers/usb/host/ehci-platform.c |    7 +--
>  drivers/usb/host/ehci-s5p.c      |   61 +-------------------------
>  drivers/usb/host/ehci-sead3.c    |   74 +-------------------------------
>  drivers/usb/host/ehci-spear.c    |   61 +-------------------------
>  9 files changed, 114 insertions(+), 348 deletions(-)
>
> Index: usb-3.4/drivers/usb/host/ehci-hcd.c
> ===================================================================
> --- usb-3.4.orig/drivers/usb/host/ehci-hcd.c
> +++ usb-3.4/drivers/usb/host/ehci-hcd.c
> @@ -1242,6 +1242,95 @@ static int ehci_get_frame (struct usb_hc
>  }
>
>  /*-------------------------------------------------------------------------*/
> +
> +#ifdef CONFIG_PM
> +
> +/* suspend/resume, section 4.3 */
> +
> +/* These routines handle the generic parts of controller suspend/resume */
> +
> +static int __maybe_unused ehci_suspend(struct usb_hcd *hcd, bool do_wakeup)
> +{
> +       struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
> +
> +       if (time_before(jiffies, ehci->next_statechange))
> +               msleep(10);
> +
> +       /*
> +        * Root hub was already suspended.  Disable IRQ emission and
> +        * mark HW unaccessible.  The PM and USB cores make sure that
> +        * the root hub is either suspended or stopped.
> +        */
> +       ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup);
> +
> +       spin_lock_irq(&ehci->lock);
> +       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
> +       (void) ehci_readl(ehci, &ehci->regs->intr_enable);
> +
> +       clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
> +       spin_unlock_irq(&ehci->lock);
> +
> +       return 0;
> +}
> +
> +/* Returns 0 if power was preserved, 1 if power was lost */
> +static int __maybe_unused ehci_resume(struct usb_hcd *hcd, bool hibernated)
> +{
> +       struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
> +
> +       if (time_before(jiffies, ehci->next_statechange))
> +               msleep(100);
> +
> +       /* Mark hardware accessible again as we are back to full power by now */
> +       set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
> +
> +       /*
> +        * If CF is still set and we aren't resuming from hibernation
> +        * then we maintained suspend power.
> +        * Just undo the effect of ehci_suspend().
> +        */
> +       if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
> +                       !hibernated) {
> +               int     mask = INTR_MASK;
> +
> +               ehci_prepare_ports_for_controller_resume(ehci);
> +               if (!hcd->self.root_hub->do_remote_wakeup)
> +                       mask &= ~STS_PCD;
> +               ehci_writel(ehci, mask, &ehci->regs->intr_enable);
> +               ehci_readl(ehci, &ehci->regs->intr_enable);
> +               return 0;
> +       }
> +
> +       /*
> +        * Else reset, to cope with power loss or resume from hibernation
> +        * having let the firmware kick in during reboot.
> +        */
> +       usb_root_hub_lost_power(hcd->self.root_hub);
> +       (void) ehci_halt(ehci);
> +       (void) ehci_reset(ehci);
> +
> +       /* emptying the schedule aborts any urbs */
> +       spin_lock_irq(&ehci->lock);
> +       if (ehci->reclaim)
> +               end_unlink_async(ehci);
> +       ehci_work(ehci);
> +       spin_unlock_irq(&ehci->lock);
> +
> +       ehci_writel(ehci, ehci->command, &ehci->regs->command);
> +       ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
> +       ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
> +
> +       /* here we "know" root ports should always stay powered */
> +       ehci_port_power(ehci, 1);
> +
> +       ehci->rh_state = EHCI_RH_SUSPENDED;
> +       return 1;
> +}
> +
> +#endif
> +
> +/*-------------------------------------------------------------------------*/
> +
>  /*
>  * The EHCI in ChipIdea HDRC cannot be a separate module or device,
>  * because its registers (and irq) are shared between host/gadget/otg
> Index: usb-3.4/drivers/usb/host/ehci-hub.c
> ===================================================================
> --- usb-3.4.orig/drivers/usb/host/ehci-hub.c
> +++ usb-3.4/drivers/usb/host/ehci-hub.c
> @@ -107,7 +107,7 @@ static void ehci_handover_companion_port
>        ehci->owned_ports = 0;
>  }
>
> -static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci)
> +static int ehci_port_change(struct ehci_hcd *ehci)
>  {
>        int i = HCS_N_PORTS(ehci->hcs_params);
>
> @@ -128,7 +128,7 @@ static int __maybe_unused ehci_port_chan
>        return 0;
>  }
>
> -static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
> +static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
>                bool suspending, bool do_wakeup)
>  {
>        int             port;
> Index: usb-3.4/drivers/usb/host/ehci-au1xxx.c
> ===================================================================
> --- usb-3.4.orig/drivers/usb/host/ehci-au1xxx.c
> +++ usb-3.4/drivers/usb/host/ehci-au1xxx.c
> @@ -158,28 +158,10 @@ static int ehci_hcd_au1xxx_drv_remove(st
>  static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
>  {
>        struct usb_hcd *hcd = dev_get_drvdata(dev);
> -       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
> -       unsigned long flags;
> -       int rc = 0;
> -
> -       if (time_before(jiffies, ehci->next_statechange))
> -               msleep(10);
> -
> -       /* Root hub was already suspended. Disable irq emission and
> -        * mark HW unaccessible.  The PM and USB cores make sure that
> -        * the root hub is either suspended or stopped.
> -        */
> -       ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
> -       spin_lock_irqsave(&ehci->lock, flags);
> -       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
> -       (void)ehci_readl(ehci, &ehci->regs->intr_enable);
> -
> -       clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
> -       spin_unlock_irqrestore(&ehci->lock, flags);
> -
> -       // could save FLADJ in case of Vaux power loss
> -       // ... we'd only use it to handle clock skew
> +       bool do_wakeup = device_may_wakeup(dev);
> +       int rc;
>
> +       rc = ehci_suspend(hcd, do_wakeup);
>        alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
>
>        return rc;
> @@ -188,56 +170,9 @@ static int ehci_hcd_au1xxx_drv_suspend(s
>  static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
>  {
>        struct usb_hcd *hcd = dev_get_drvdata(dev);
> -       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
>
>        alchemy_usb_control(ALCHEMY_USB_EHCI0, 1);
> -
> -       // maybe restore FLADJ
> -
> -       if (time_before(jiffies, ehci->next_statechange))
> -               msleep(100);
> -
> -       /* Mark hardware accessible again as we are out of D3 state by now */
> -       set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
> -
> -       /* If CF is still set, we maintained PCI Vaux power.
> -        * Just undo the effect of ehci_pci_suspend().
> -        */
> -       if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
> -               int     mask = INTR_MASK;
> -
> -               ehci_prepare_ports_for_controller_resume(ehci);
> -               if (!hcd->self.root_hub->do_remote_wakeup)
> -                       mask &= ~STS_PCD;
> -               ehci_writel(ehci, mask, &ehci->regs->intr_enable);
> -               ehci_readl(ehci, &ehci->regs->intr_enable);
> -               return 0;
> -       }
> -
> -       ehci_dbg(ehci, "lost power, restarting\n");
> -       usb_root_hub_lost_power(hcd->self.root_hub);
> -
> -       /* Else reset, to cope with power loss or flush-to-storage
> -        * style "resume" having let BIOS kick in during reboot.
> -        */
> -       (void) ehci_halt(ehci);
> -       (void) ehci_reset(ehci);
> -
> -       /* emptying the schedule aborts any urbs */
> -       spin_lock_irq(&ehci->lock);
> -       if (ehci->reclaim)
> -               end_unlink_async(ehci);
> -       ehci_work(ehci);
> -       spin_unlock_irq(&ehci->lock);
> -
> -       ehci_writel(ehci, ehci->command, &ehci->regs->command);
> -       ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
> -       ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
> -
> -       /* here we "know" root ports should always stay powered */
> -       ehci_port_power(ehci, 1);
> -
> -       ehci->rh_state = EHCI_RH_SUSPENDED;
> +       ehci_resume(hcd, false);
>
>        return 0;
>  }
> Index: usb-3.4/drivers/usb/host/ehci-msm.c
> ===================================================================
> --- usb-3.4.orig/drivers/usb/host/ehci-msm.c
> +++ usb-3.4/drivers/usb/host/ehci-msm.c
> @@ -198,24 +198,11 @@ static int __devexit ehci_msm_remove(str
>  static int ehci_msm_pm_suspend(struct device *dev)
>  {
>        struct usb_hcd *hcd = dev_get_drvdata(dev);
> -       bool wakeup = device_may_wakeup(dev);
> +       bool do_wakeup = device_may_wakeup(dev);
>
>        dev_dbg(dev, "ehci-msm PM suspend\n");
>
> -       /*
> -        * EHCI helper function has also the same check before manipulating
> -        * port wakeup flags.  We do check here the same condition before
> -        * calling the same helper function to avoid bringing hardware
> -        * from Low power mode when there is no need for adjusting port
> -        * wakeup flags.
> -        */
> -       if (hcd->self.root_hub->do_remote_wakeup && !wakeup) {
> -               pm_runtime_resume(dev);
> -               ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
> -                               wakeup);
> -       }
> -
> -       return 0;
> +       return ehci_suspend(hcd, do_wakeup);
>  }
>
>  static int ehci_msm_pm_resume(struct device *dev)
> @@ -223,7 +210,7 @@ static int ehci_msm_pm_resume(struct dev
>        struct usb_hcd *hcd = dev_get_drvdata(dev);
>
>        dev_dbg(dev, "ehci-msm PM resume\n");
> -       ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
> +       ehci_resume(hcd, false);
>
>        return 0;
>  }
> Index: usb-3.4/drivers/usb/host/ehci-pci.c
> ===================================================================
> --- usb-3.4.orig/drivers/usb/host/ehci-pci.c
> +++ usb-3.4/drivers/usb/host/ehci-pci.c
> @@ -331,29 +331,7 @@ done:
>
>  static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
>  {
> -       struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
> -       unsigned long           flags;
> -       int                     rc = 0;
> -
> -       if (time_before(jiffies, ehci->next_statechange))
> -               msleep(10);
> -
> -       /* Root hub was already suspended. Disable irq emission and
> -        * mark HW unaccessible.  The PM and USB cores make sure that
> -        * the root hub is either suspended or stopped.
> -        */
> -       ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup);
> -       spin_lock_irqsave (&ehci->lock, flags);
> -       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
> -       (void)ehci_readl(ehci, &ehci->regs->intr_enable);
> -
> -       clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
> -       spin_unlock_irqrestore (&ehci->lock, flags);
> -
> -       // could save FLADJ in case of Vaux power loss
> -       // ... we'd only use it to handle clock skew
> -
> -       return rc;
> +       return ehci_suspend(hcd, do_wakeup);
>  }
>
>  static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
> @@ -402,54 +380,8 @@ static int ehci_pci_resume(struct usb_hc
>        if (usb_is_intel_switchable_ehci(pdev))
>                ehci_enable_xhci_companion();
>
> -       // maybe restore FLADJ
> -
> -       if (time_before(jiffies, ehci->next_statechange))
> -               msleep(100);
> -
> -       /* Mark hardware accessible again as we are out of D3 state by now */
> -       set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
> -
> -       /* If CF is still set and we aren't resuming from hibernation
> -        * then we maintained PCI Vaux power.
> -        * Just undo the effect of ehci_pci_suspend().
> -        */
> -       if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
> -                               !hibernated) {
> -               int     mask = INTR_MASK;
> -
> -               ehci_prepare_ports_for_controller_resume(ehci);
> -               if (!hcd->self.root_hub->do_remote_wakeup)
> -                       mask &= ~STS_PCD;
> -               ehci_writel(ehci, mask, &ehci->regs->intr_enable);
> -               ehci_readl(ehci, &ehci->regs->intr_enable);
> -               return 0;
> -       }
> -
> -       usb_root_hub_lost_power(hcd->self.root_hub);
> -
> -       /* Else reset, to cope with power loss or flush-to-storage
> -        * style "resume" having let BIOS kick in during reboot.
> -        */
> -       (void) ehci_halt(ehci);
> -       (void) ehci_reset(ehci);
> -       (void) ehci_pci_reinit(ehci, pdev);
> -
> -       /* emptying the schedule aborts any urbs */
> -       spin_lock_irq(&ehci->lock);
> -       if (ehci->reclaim)
> -               end_unlink_async(ehci);
> -       ehci_work(ehci);
> -       spin_unlock_irq(&ehci->lock);
> -
> -       ehci_writel(ehci, ehci->command, &ehci->regs->command);
> -       ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
> -       ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
> -
> -       /* here we "know" root ports should always stay powered */
> -       ehci_port_power(ehci, 1);
> -
> -       ehci->rh_state = EHCI_RH_SUSPENDED;
> +       if (ehci_resume(hcd, hibernated) != 0)
> +               (void) ehci_pci_reinit(ehci, pdev);
>        return 0;
>  }
>  #endif
> Index: usb-3.4/drivers/usb/host/ehci-platform.c
> ===================================================================
> --- usb-3.4.orig/drivers/usb/host/ehci-platform.c
> +++ usb-3.4/drivers/usb/host/ehci-platform.c
> @@ -153,17 +153,16 @@ static int __devexit ehci_platform_remov
>  static int ehci_platform_suspend(struct device *dev)
>  {
>        struct usb_hcd *hcd = dev_get_drvdata(dev);
> -       bool wakeup = device_may_wakeup(dev);
> +       bool do_wakeup = device_may_wakeup(dev);
>
> -       ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), wakeup);
> -       return 0;
> +       return ehci_suspend(hcd, do_wakeup);
>  }
>
>  static int ehci_platform_resume(struct device *dev)
>  {
>        struct usb_hcd *hcd = dev_get_drvdata(dev);
>
> -       ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
> +       ehci_resume(hcd, false);
>        return 0;
>  }
>

so, we can use omap drivers to hook into this ehci platform driver right?
then I think it requires call back functions for init, deinit, suspend, resume
as in /drivers/ata/ahci_platform.c , so that I will do the  hw
specific operations
in these hook functions not in the platform specific suspend/resume functions.

regards
keshava
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux