diff options
| -rw-r--r-- | drivers/usb/host/xhci-hub.c | 22 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-ring.c | 1 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.c | 12 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.h | 2 | 
4 files changed, 25 insertions, 12 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 673ad120c43..89850a82d51 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -558,6 +558,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  				xhci_dbg(xhci, "Resume USB2 port %d\n",  					wIndex + 1);  				bus_state->resume_done[wIndex] = 0; +				clear_bit(wIndex, &bus_state->resuming_ports);  				xhci_set_link_state(xhci, port_array, wIndex,  							XDEV_U0);  				xhci_dbg(xhci, "set port %d resume\n", @@ -845,7 +846,12 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)  	/* Initial status is no changes */  	retval = (max_ports + 8) / 8;  	memset(buf, 0, retval); -	status = 0; + +	/* +	 * Inform the usbcore about resume-in-progress by returning +	 * a non-zero value even if there are no status changes. +	 */ +	status = bus_state->resuming_ports;  	mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC; @@ -885,15 +891,11 @@ int xhci_bus_suspend(struct usb_hcd *hcd)  	spin_lock_irqsave(&xhci->lock, flags);  	if (hcd->self.root_hub->do_remote_wakeup) { -		port_index = max_ports; -		while (port_index--) { -			if (bus_state->resume_done[port_index] != 0) { -				spin_unlock_irqrestore(&xhci->lock, flags); -				xhci_dbg(xhci, "suspend failed because " -						"port %d is resuming\n", -						port_index + 1); -				return -EBUSY; -			} +		if (bus_state->resuming_ports) { +			spin_unlock_irqrestore(&xhci->lock, flags); +			xhci_dbg(xhci, "suspend failed because " +						"a port is resuming\n"); +			return -EBUSY;  		}  	} diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 3d9422f16a2..cb1de111dae 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1377,6 +1377,7 @@ static void handle_port_status(struct xhci_hcd *xhci,  			xhci_dbg(xhci, "resume HS port %d\n", port_id);  			bus_state->resume_done[faked_port_index] = jiffies +  				msecs_to_jiffies(20); +			set_bit(faked_port_index, &bus_state->resuming_ports);  			mod_timer(&hcd->rh_timer,  				  bus_state->resume_done[faked_port_index]);  			/* Do the rest in GetPortStatus */ diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 36641a7f237..5910048b0a2 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -152,7 +152,7 @@ int xhci_reset(struct xhci_hcd *xhci)  {  	u32 command;  	u32 state; -	int ret; +	int ret, i;  	state = xhci_readl(xhci, &xhci->op_regs->status);  	if ((state & STS_HALT) == 0) { @@ -175,7 +175,15 @@ int xhci_reset(struct xhci_hcd *xhci)  	 * xHCI cannot write to any doorbells or operational registers other  	 * than status until the "Controller Not Ready" flag is cleared.  	 */ -	return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); +	ret = handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); + +	for (i = 0; i < 2; ++i) { +		xhci->bus_state[i].port_c_suspend = 0; +		xhci->bus_state[i].suspended_ports = 0; +		xhci->bus_state[i].resuming_ports = 0; +	} + +	return ret;  }  #ifdef CONFIG_PCI diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 3d69c4b2b54..ce1edd7246a 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1362,6 +1362,8 @@ struct xhci_bus_state {  	u32			suspended_ports;  	u32			port_remote_wakeup;  	unsigned long		resume_done[USB_MAXCHILDREN]; +	/* which ports have started to resume */ +	unsigned long		resuming_ports;  };  static inline unsigned int hcd_index(struct usb_hcd *hcd)  |