From: "Du, Alek" <alek.du@intel.com>
To: Alan Stern <stern@rowland.harvard.edu>
Cc: Ondrej Zary <linux@rainbow-software.org>,
Linux-pm mailing list <linux-pm@lists.linux-foundation.org>,
USB list <linux-usb@vger.kernel.org>,
Kernel development list <linux-kernel@vger.kernel.org>
Subject: Re: [linux-pm] [PATCH v2] [RFC] ehci: Disable wake on overcurrent (WKOC_E) and disconnect (WKDISC_E)
Date: Tue, 11 May 2010 11:31:20 +0800 [thread overview]
Message-ID: <20100511113120.02787f96@dxy2> (raw)
In-Reply-To: <Pine.LNX.4.44L0.1005101616540.1626-100000@iolanthe.rowland.org>
On Tue, 11 May 2010 05:05:34 +0800
Alan Stern <stern@rowland.harvard.edu> wrote:
> On Mon, 10 May 2010, Du, Alek wrote:
>
> > Alan,
> >
> > The following patch (based on your previous two patches) works for me, could you
> > help to review and test on your machine? Basically, this will only affect those
> > "has_hostpc" HCDs.
>
> Based on your suggestion, I completely redid both of my patches. They
> are now combined into a single patch, which is meant to go on top of
> the patch you submitted this morning. It adds the stuff we talked
> about, and it cleans up some of the changes you made.
>
> Does it look good to you?
>
> Alan Stern
>
Alan,
It looks good and works for my hardware. Thanks a lot!
Will you submit it soon?
Alek
>
>
> Index: usb-2.6/drivers/usb/host/ehci-hub.c
> ===================================================================
> --- usb-2.6.orig/drivers/usb/host/ehci-hub.c
> +++ usb-2.6/drivers/usb/host/ehci-hub.c
> @@ -106,12 +106,72 @@ static void ehci_handover_companion_port
> ehci->owned_ports = 0;
> }
>
> +static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, bool resuming)
> +{
> + int port;
> + u32 temp;
> +
> + /* If remote wakeup is enabled for the root hub but disabled
> + * for the controller, we must adjust all the port wakeup flags.
> + */
> + if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup ||
> + device_may_wakeup(ehci_to_hcd(ehci)->self.controller))
> + return;
> +
> + /* clear phy low-power mode before changing wakeup flags */
> + if (ehci->has_hostpc) {
> + port = HCS_N_PORTS(ehci->hcs_params);
> + while (port--) {
> + u32 __iomem *hostpc_reg;
> +
> + hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
> + + HOSTPC0 + 4 * port);
> + temp = ehci_readl(ehci, hostpc_reg);
> + ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg);
> + }
> + msleep(5);
> + }
> +
> + port = HCS_N_PORTS(ehci->hcs_params);
> + while (port--) {
> + u32 __iomem *reg = &ehci->regs->port_status[port];
> + u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
> + u32 t2 = t1 & ~PORT_WAKE_BITS;
> +
> + /* If we are suspending the controller, clear the flags.
> + * If we are resuming the controller, set the wakeup flags.
> + */
> + if (resuming) {
> + if (t1 & PORT_CONNECT)
> + t2 |= PORT_WKOC_E | PORT_WKDISC_E;
> + else
> + t2 |= PORT_WKOC_E | PORT_WKCONN_E;
> + }
> + ehci_vdbg(ehci, "port %d, %08x -> %08x\n",
> + port + 1, t1, t2);
> + ehci_writel(ehci, t2, reg);
> + }
> +
> + /* enter phy low-power mode again */
> + if (ehci->has_hostpc) {
> + port = HCS_N_PORTS(ehci->hcs_params);
> + while (port--) {
> + u32 __iomem *hostpc_reg;
> +
> + hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
> + + HOSTPC0 + 4 * port);
> + temp = ehci_readl(ehci, hostpc_reg);
> + ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg);
> + }
> + }
> +}
> +
> static int ehci_bus_suspend (struct usb_hcd *hcd)
> {
> struct ehci_hcd *ehci = hcd_to_ehci (hcd);
> int port;
> int mask;
> - u32 __iomem *hostpc_reg = NULL;
> + int changed;
>
> ehci_dbg(ehci, "suspend root hub\n");
>
> @@ -155,15 +215,13 @@ static int ehci_bus_suspend (struct usb_
> */
> ehci->bus_suspended = 0;
> ehci->owned_ports = 0;
> + changed = 0;
> port = HCS_N_PORTS(ehci->hcs_params);
> while (port--) {
> u32 __iomem *reg = &ehci->regs->port_status [port];
> u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
> - u32 t2 = t1;
> + u32 t2 = t1 & ~PORT_WAKE_BITS;
>
> - if (ehci->has_hostpc)
> - hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
> - + HOSTPC0 + 4 * (port & 0xff));
> /* keep track of which ports we suspend */
> if (t1 & PORT_OWNER)
> set_bit(port, &ehci->owned_ports);
> @@ -172,40 +230,45 @@ static int ehci_bus_suspend (struct usb_
> set_bit(port, &ehci->bus_suspended);
> }
>
> - /* enable remote wakeup on all ports */
> + /* enable remote wakeup on all ports, if told to do so */
> if (hcd->self.root_hub->do_remote_wakeup) {
> /* only enable appropriate wake bits, otherwise the
> * hardware can not go phy low power mode. If a race
> * condition happens here(connection change during bits
> * set), the port change detection will finally fix it.
> */
> - if (t1 & PORT_CONNECT) {
> + if (t1 & PORT_CONNECT)
> t2 |= PORT_WKOC_E | PORT_WKDISC_E;
> - t2 &= ~PORT_WKCONN_E;
> - } else {
> + else
> t2 |= PORT_WKOC_E | PORT_WKCONN_E;
> - t2 &= ~PORT_WKDISC_E;
> - }
> - } else
> - t2 &= ~PORT_WAKE_BITS;
> + }
>
> if (t1 != t2) {
> ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
> port + 1, t1, t2);
> ehci_writel(ehci, t2, reg);
> - if (hostpc_reg) {
> - u32 t3;
> + changed = 1;
> + }
> + }
>
> - spin_unlock_irq(&ehci->lock);
> - msleep(5);/* 5ms for HCD enter low pwr mode */
> - spin_lock_irq(&ehci->lock);
> - t3 = ehci_readl(ehci, hostpc_reg);
> - ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
> - t3 = ehci_readl(ehci, hostpc_reg);
> - ehci_dbg(ehci, "Port%d phy low pwr mode %s\n",
> + if (changed && ehci->has_hostpc) {
> + spin_unlock_irq(&ehci->lock);
> + msleep(5); /* 5 ms for HCD to enter low-power mode */
> + spin_lock_irq(&ehci->lock);
> +
> + port = HCS_N_PORTS(ehci->hcs_params);
> + while (port--) {
> + u32 __iomem *hostpc_reg;
> + u32 t3;
> +
> + hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
> + + HOSTPC0 + 4 * port);
> + t3 = ehci_readl(ehci, hostpc_reg);
> + ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
> + t3 = ehci_readl(ehci, hostpc_reg);
> + ehci_dbg(ehci, "Port %d phy low-power mode %s\n",
> port, (t3 & HOSTPC_PHCD) ?
> "succeeded" : "failed");
> - }
> }
> }
>
> @@ -291,19 +354,28 @@ static int ehci_bus_resume (struct usb_h
> msleep(8);
> spin_lock_irq(&ehci->lock);
>
> + /* clear phy low-power mode before resume */
> + if (ehci->bus_suspended && ehci->has_hostpc) {
> + i = HCS_N_PORTS (ehci->hcs_params);
> + while (i--) {
> + if (test_bit(i, &ehci->bus_suspended)) {
> + u32 __iomem *hostpc_reg;
> +
> + hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
> + + HOSTPC0 + 4 * i);
> + temp = ehci_readl(ehci, hostpc_reg);
> + ehci_writel(ehci, temp & ~HOSTPC_PHCD,
> + hostpc_reg);
> + }
> + }
> + spin_unlock_irq(&ehci->lock);
> + msleep(5);
> + spin_lock_irq(&ehci->lock);
> + }
> +
> /* manually resume the ports we suspended during bus_suspend() */
> i = HCS_N_PORTS (ehci->hcs_params);
> while (i--) {
> - /* clear phy low power mode before resume */
> - if (ehci->has_hostpc) {
> - u32 __iomem *hostpc_reg =
> - (u32 __iomem *)((u8 *)ehci->regs
> - + HOSTPC0 + 4 * (i & 0xff));
> - temp = ehci_readl(ehci, hostpc_reg);
> - ehci_writel(ehci, temp & ~HOSTPC_PHCD,
> - hostpc_reg);
> - mdelay(5);
> - }
> temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
> temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
> if (test_bit(i, &ehci->bus_suspended) &&
> @@ -685,23 +757,25 @@ static int ehci_hub_control (
> goto error;
> if (ehci->no_selective_suspend)
> break;
> - if (temp & PORT_SUSPEND) {
> - if ((temp & PORT_PE) == 0)
> - goto error;
> - /* clear phy low power mode before resume */
> - if (hostpc_reg) {
> - temp1 = ehci_readl(ehci, hostpc_reg);
> - ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
> - hostpc_reg);
> - mdelay(5);
> - }
> - /* resume signaling for 20 msec */
> - temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
> - ehci_writel(ehci, temp | PORT_RESUME,
> - status_reg);
> - ehci->reset_done [wIndex] = jiffies
> - + msecs_to_jiffies (20);
> + if (!(temp & PORT_SUSPEND))
> + break;
> + if ((temp & PORT_PE) == 0)
> + goto error;
> +
> + /* clear phy low-power mode before resume */
> + if (hostpc_reg) {
> + temp1 = ehci_readl(ehci, hostpc_reg);
> + ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
> + hostpc_reg);
> + spin_unlock_irqrestore(&ehci->lock, flags);
> + msleep(5);/* wait to leave low-power mode */
> + spin_lock_irqsave(&ehci->lock, flags);
> }
> + /* resume signaling for 20 msec */
> + temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
> + ehci_writel(ehci, temp | PORT_RESUME, status_reg);
> + ehci->reset_done[wIndex] = jiffies
> + + msecs_to_jiffies(20);
> break;
> case USB_PORT_FEAT_C_SUSPEND:
> clear_bit(wIndex, &ehci->port_c_suspend);
> Index: usb-2.6/drivers/usb/host/ehci-pci.c
> ===================================================================
> --- usb-2.6.orig/drivers/usb/host/ehci-pci.c
> +++ usb-2.6/drivers/usb/host/ehci-pci.c
> @@ -287,23 +287,15 @@ static int ehci_pci_suspend(struct usb_h
> msleep(10);
>
> /* Root hub was already suspended. Disable irq emission and
> - * mark HW unaccessible, bail out if RH has been resumed. Use
> - * the spinlock to properly synchronize with possible pending
> - * RH suspend or resume activity.
> - *
> - * This is still racy as hcd->state is manipulated outside of
> - * any locks =P But that will be a different fix.
> + * mark HW unaccessible. The PM and USB cores make sure that
> + * the root hub is either suspended or stopped.
> */
> spin_lock_irqsave (&ehci->lock, flags);
> - if (hcd->state != HC_STATE_SUSPENDED) {
> - rc = -EINVAL;
> - goto bail;
> - }
> + ehci_adjust_port_wakeup_flags(ehci, false);
> ehci_writel(ehci, 0, &ehci->regs->intr_enable);
> (void)ehci_readl(ehci, &ehci->regs->intr_enable);
>
> clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
> - bail:
> spin_unlock_irqrestore (&ehci->lock, flags);
>
> // could save FLADJ in case of Vaux power loss
> @@ -333,6 +325,7 @@ static int ehci_pci_resume(struct usb_hc
> !hibernated) {
> int mask = INTR_MASK;
>
> + ehci_adjust_port_wakeup_flags(ehci, true);
> if (!hcd->self.root_hub->do_remote_wakeup)
> mask &= ~STS_PCD;
> ehci_writel(ehci, mask, &ehci->regs->intr_enable);
> Index: usb-2.6/drivers/usb/host/ehci-au1xxx.c
> ===================================================================
> --- usb-2.6.orig/drivers/usb/host/ehci-au1xxx.c
> +++ usb-2.6/drivers/usb/host/ehci-au1xxx.c
> @@ -224,26 +224,17 @@ static int ehci_hcd_au1xxx_drv_suspend(s
> msleep(10);
>
> /* Root hub was already suspended. Disable irq emission and
> - * mark HW unaccessible, bail out if RH has been resumed. Use
> - * the spinlock to properly synchronize with possible pending
> - * RH suspend or resume activity.
> - *
> - * This is still racy as hcd->state is manipulated outside of
> - * any locks =P But that will be a different fix.
> + * mark HW unaccessible. The PM and USB cores make sure that
> + * the root hub is either suspended or stopped.
> */
> spin_lock_irqsave(&ehci->lock, flags);
> - if (hcd->state != HC_STATE_SUSPENDED) {
> - rc = -EINVAL;
> - goto bail;
> - }
> + ehci_adjust_port_wakeup_flags(ehci, false);
> ehci_writel(ehci, 0, &ehci->regs->intr_enable);
> (void)ehci_readl(ehci, &ehci->regs->intr_enable);
>
> clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
>
> au1xxx_stop_ehc();
> -
> -bail:
> spin_unlock_irqrestore(&ehci->lock, flags);
>
> // could save FLADJ in case of Vaux power loss
> @@ -273,6 +264,7 @@ static int ehci_hcd_au1xxx_drv_resume(st
> if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
> int mask = INTR_MASK;
>
> + ehci_adjust_port_wakeup_flags(ehci, true);
> if (!hcd->self.root_hub->do_remote_wakeup)
> mask &= ~STS_PCD;
> ehci_writel(ehci, mask, &ehci->regs->intr_enable);
> Index: usb-2.6/drivers/usb/host/ehci-fsl.c
> ===================================================================
> --- usb-2.6.orig/drivers/usb/host/ehci-fsl.c
> +++ usb-2.6/drivers/usb/host/ehci-fsl.c
> @@ -313,6 +313,7 @@ static int ehci_fsl_drv_suspend(struct d
> struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
> void __iomem *non_ehci = hcd->regs;
>
> + ehci_adjust_port_wakeup_flags(ehci, false);
> if (!fsl_deep_sleep())
> return 0;
>
> @@ -327,6 +328,7 @@ static int ehci_fsl_drv_resume(struct de
> struct ehci_hcd *ehci = hcd_to_ehci(hcd);
> void __iomem *non_ehci = hcd->regs;
>
> + ehci_adjust_port_wakeup_flags(ehci, true);
> if (!fsl_deep_sleep())
> return 0;
>
>
next prev parent reply other threads:[~2010-05-11 3:35 UTC|newest]
Thread overview: 54+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-04-27 13:23 ehci_hcd causes immediate wakeup from suspend to RAM or disk on Asus P4P800-VM Ondrej Zary
2010-04-27 14:22 ` [PATCH] ehci: Disable wake on overcurrent (WKOC_E) Ondrej Zary
2010-04-27 14:22 ` Ondrej Zary
2010-04-27 16:25 ` [PATCH v2] [RFC] ehci: Disable wake on overcurrent (WKOC_E) and disconnect (WKDISC_E) Ondrej Zary
2010-04-27 19:21 ` Alan Stern
2010-04-27 20:46 ` Ondrej Zary
2010-04-27 21:33 ` Greg KH
2010-04-27 21:33 ` Greg KH
2010-04-28 15:41 ` Alan Stern
2010-04-28 15:41 ` Alan Stern
2010-04-28 17:30 ` Ondrej Zary
2010-04-29 16:16 ` Alan Stern
2010-04-29 17:45 ` Alan Stern
2010-04-29 17:45 ` [linux-pm] " Alan Stern
2010-04-29 21:14 ` Ondrej Zary
2010-04-29 21:14 ` [linux-pm] " Ondrej Zary
2010-05-04 5:37 ` Du, Alek
2010-05-04 5:37 ` [linux-pm] " Du, Alek
2010-05-05 3:12 ` Du, Alek
2010-05-05 3:12 ` [linux-pm] " Du, Alek
2010-05-05 15:55 ` Alan Stern
2010-05-06 0:11 ` Du, Alek
2010-05-06 0:11 ` Du, Alek
2010-05-06 8:23 ` [linux-pm] " Du, Alek
2010-05-06 14:46 ` Alan Stern
2010-05-06 14:46 ` [linux-pm] " Alan Stern
2010-05-06 15:20 ` Du, Alek
2010-05-06 15:20 ` [linux-pm] " Du, Alek
2010-05-06 16:06 ` Alan Stern
2010-05-07 1:32 ` Du, Alek
2010-05-07 1:32 ` [linux-pm] " Du, Alek
2010-05-07 15:20 ` Alan Stern
2010-05-08 2:00 ` Du, Alek
2010-05-08 2:00 ` [linux-pm] " Du, Alek
[not found] ` <6C44CD31806DCD4BB88546DAB7AFC9A201EB5A39FA@shsmsx502.ccr.corp.intel.com>
2010-05-10 2:25 ` Du, Alek
2010-05-10 2:25 ` [linux-pm] " Du, Alek
2010-05-10 21:05 ` Alan Stern
2010-05-10 21:05 ` [linux-pm] " Alan Stern
2010-05-11 3:31 ` Du, Alek [this message]
2010-05-11 14:01 ` Alan Stern
2010-05-11 14:01 ` [linux-pm] " Alan Stern
2010-05-11 15:58 ` Alan Stern
2010-05-11 15:58 ` [linux-pm] " Alan Stern
2010-05-11 16:10 ` Du, Alek
2010-05-11 16:10 ` [linux-pm] " Du, Alek
2010-05-11 3:31 ` Du, Alek
2010-05-07 15:20 ` Alan Stern
2010-05-06 16:06 ` Alan Stern
2010-05-06 8:23 ` Du, Alek
2010-05-05 15:55 ` Alan Stern
2010-04-28 17:30 ` Ondrej Zary
2010-04-27 20:46 ` Ondrej Zary
2010-04-27 19:21 ` Alan Stern
2010-04-27 16:25 ` Ondrej Zary
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100511113120.02787f96@dxy2 \
--to=alek.du@intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@lists.linux-foundation.org \
--cc=linux-usb@vger.kernel.org \
--cc=linux@rainbow-software.org \
--cc=stern@rowland.harvard.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.