Re: [PATCH v3 1/1] USB: EHCI: wait more than 3ms until the device enters full-speed idle

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

 



On Mon, Feb 10, 2014 at 11:40:25AM -0500, Alan Stern wrote:
> On Fri, 7 Feb 2014, Peter Chen wrote:
> 
> > If the high-speed device does not enter full-speed idle after
> > wakeup on disconnect logic has effected, there will be an
> > unexpected disconnect wakeup interrupt due to the bus is still SE0.
> > 
> > Signed-off-by: Peter Chen <peter.chen@xxxxxxxxxxxxx>
> > 
> > Hi Alan,
> > 
> > If you can't met this issue, it may due to your hardware enables
> > WKDN after detecting full-speed idle or the time between stop
> > SoF and enable WKDN is more than 3ms (You need to know when
> > the WKDN has really taken effect).
> 
> Yes.  However, I don't like the way your patch can increase the total
> time if several ports have to be put into suspend.  Consider this patch 
> instead.
> 
> Alan Stern
> 
> 
> 
> Index: usb-3.14/drivers/usb/host/ehci-hub.c
> ===================================================================
> --- usb-3.14.orig/drivers/usb/host/ehci-hub.c
> +++ usb-3.14/drivers/usb/host/ehci-hub.c
> @@ -238,6 +238,7 @@ static int ehci_bus_suspend (struct usb_
>  	int			port;
>  	int			mask;
>  	int			changed;
> +	unsigned		want_WKDISC;

Not sure mixed uppercase letters and lowercase letters into a
single variable is a good idea.

>  
>  	ehci_dbg(ehci, "suspend root hub\n");
>  
> @@ -272,6 +273,7 @@ static int ehci_bus_suspend (struct usb_
>  	ehci->bus_suspended = 0;
>  	ehci->owned_ports = 0;
>  	changed = 0;
> +	want_WKDISC = 0;
>  	port = HCS_N_PORTS(ehci->hcs_params);
>  	while (port--) {
>  		u32 __iomem	*reg = &ehci->regs->port_status [port];
> @@ -300,16 +302,48 @@ static int ehci_bus_suspend (struct usb_
>  		}
>  
>  		if (t1 != t2) {
> +			/*
> +			 * Don't enable wake-on-disconnect until the bus has
> +			 * switched over to full-speed idle.
> +			 */
> +			if ((t2 & PORT_WKDISC_E) &&
> +					ehci_port_speed(ehci, t2) ==
> +						USB_PORT_STAT_HIGH_SPEED) {
> +				t2 &= ~PORT_WKDISC_E;
> +				want_WKDISC |= (1 << port);
> +			}
>  			ehci_writel(ehci, t2, reg);
>  			changed = 1;
>  		}
>  	}
> +	spin_unlock_irq(&ehci->lock);
>  
> -	if (changed && ehci->has_tdi_phy_lpm) {
> -		spin_unlock_irq(&ehci->lock);
> -		msleep(5);	/* 5 ms for HCD to enter low-power mode */
> +	if ((changed && ehci->has_tdi_phy_lpm) || want_WKDISC) {
> +		/*
> +		 * Wait for HCD to enter low-power mode or for the bus
> +		 * to switch to full-speed idle.
> +		 */
> +		usleep_range(5000, 5500);
> +	}
> +
> +	if (want_WKDISC) {
>  		spin_lock_irq(&ehci->lock);
> +		port = HCS_N_PORTS(ehci->hcs_params);
> +		while (port--) {
> +			u32 __iomem	*reg;
> +			u32		t2;
>  
> +			if (!(want_WKDISC & (1 << port)))
> +				continue;
> +			reg = &ehci->regs->port_status[port];
> +			t2 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;

Why it needs to re-do clear PORT_RWC_BITS?

> +			ehci_writel(ehci, t2 | PORT_WKDISC_E, reg);
> +		}
> +		spin_unlock_irq(&ehci->lock);
> +	}
> +
> +	if (changed && ehci->has_tdi_phy_lpm) {
> +		spin_lock_irq(&ehci->lock);
>  		port = HCS_N_PORTS(ehci->hcs_params);
>  		while (port--) {
>  			u32 __iomem	*hostpc_reg = &ehci->regs->hostpc[port];
> @@ -322,8 +356,8 @@ static int ehci_bus_suspend (struct usb_
>  					port, (t3 & HOSTPC_PHCD) ?
>  					"succeeded" : "failed");
>  		}
> +		spin_unlock_irq(&ehci->lock);
>  	}
> -	spin_unlock_irq(&ehci->lock);

How about adding spin_lock_irq and spin_unlock_irq only one time,
I mean not add them into the two if () conditional statement.
>  
>  	/* Apparently some devices need a >= 1-uframe delay here */
>  	if (ehci->bus_suspended)
> 
> 
> 

-- 

Best Regards,
Peter Chen

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