Re: Possible bug in xhci_resume()

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

 



On Fri, Dec 24, 2010 at 04:43:22PM +0800, Xu, Andiry wrote:
> > -----Original Message-----
> > From: Sarah Sharp [mailto:sarah.a.sharp@xxxxxxxxxxxxxxx]
> > Sent: Friday, December 24, 2010 7:14 AM
> > To: Xu, Andiry
> > Cc: linux-usb@xxxxxxxxxxxxxxx
> > Subject: Possible bug in xhci_resume()
> > 
> > Hi Andiry,
> > 
> > I'm seeing an unreachable code path in xhci_resume().  Can you please
> > explain what you meant to do here?
> > 
> > In xhci_resume, you save the host controller's state in the variable
> > old_state.  But then you only use it on an unreachable code path:
> > 
> > int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
> > {
> > 	u32			command, temp = 0;
> > 	struct usb_hcd		*hcd = xhci_to_hcd(xhci);
> > 	int	old_state, retval;
> > 
> > 	old_state = hcd->state;
> > 	...
> > 
> > 	if (!hibernated) {
> > 		/* restore registers */
> > 	}
> > 
> > 	if ((temp & STS_SRE) || hibernated) {
> > 		/* restart the host controller */
> > 
> > 		if (!retval)
> > 			set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
> > 		hcd->state = HC_STATE_SUSPENDED;
> > 		return retval;
> > 
> > 		/* Note the return here - this means if hibernated is
> > 		 * true, we will always return out of this function
> > 		 * here.
> > 		 */
> > 	}
> > 
> > 	...
> > 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
> > 	if (!hibernated)
> > 		hcd->state = old_state;
> > 	else
> > 		hcd->state = HC_STATE_SUSPENDED;
> > 	...
> > }
> > 
> > Did you mean to set the hcd->state back to the old value when the host
> > was resumed after a power loss?  If so, perhaps the if statement that
> > tests for hibernation or a power loss could be changed to:
> > 
> > 	if ((temp & STS_SRE) || hibernated) {
> > 		/* restart the host controller */
> > 		if (!retval)
> > 			set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
> > 		if (temp & STS_SRE)
> > 			hcd->state = old_state;
> > 		else
> > 			hcd->state = HC_STATE_SUSPENDED;
> > 		return retval;
> > 	}
> > 
> 
> Oh, thanks for catching this. I think it's another legacy design issue.
> 
> The right logic should be: set hcd->state = HC_STATE_SUSPENDED if there
> is a power loss in resume or the system is hibernated, otherwise leave
> it be. I referred to ehci_pci_resume().
> 
> So the old_state variable is redundant. The solution would be like this:
> 
> --- a/drivers/usb/host/xhci.c
> +++ b/drivers/usb/host/xhci.c
> @@ -705,9 +705,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool
> hibernated)
>  {
>  	u32			command, temp = 0;
>  	struct usb_hcd		*hcd = xhci_to_hcd(xhci);
> -	int	old_state, retval;
> +	int	retval;
>  
> -	old_state = hcd->state;
>  	if (time_before(jiffies, xhci->next_statechange))
>  		msleep(100);
>  
> @@ -791,10 +790,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool
> hibernated)
>  	 */
>  
>  	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
> -	if (!hibernated)
> -		hcd->state = old_state;
> -	else
> -		hcd->state = HC_STATE_SUSPENDED;
>  
>  	spin_unlock_irq(&xhci->lock);
>  	return 0;
> 
> If you are OK with this, I'll send a formal patch later. And Merry
> Christmas!

Yes, that looks fine, please send a formal patch.  Merry Christmas and a
happy new year!

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