|
|
|
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

[Linux Media] [Video for Linux] [Linux Input] [Linux Audio Users] [Photo] [Yosemite News] [Yosemite Photos] [Free Online Dating] [Linux Kernel] [Linux SCSI] [Old Linux USB Devel Archive] [More Archives]
![]() |
![]() |