diff options
Diffstat (limited to 'drivers/usb/host/xhci.c')
| -rw-r--r-- | drivers/usb/host/xhci.c | 196 | 
1 files changed, 36 insertions, 160 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 1e36dbb48366..4265b48856f6 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -730,6 +730,9 @@ void xhci_shutdown(struct usb_hcd *hcd)  	spin_lock_irq(&xhci->lock);  	xhci_halt(xhci); +	/* Workaround for spurious wakeups at shutdown with HSW */ +	if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) +		xhci_reset(xhci);  	spin_unlock_irq(&xhci->lock);  	xhci_cleanup_msix(xhci); @@ -737,6 +740,10 @@ void xhci_shutdown(struct usb_hcd *hcd)  	xhci_dbg_trace(xhci, trace_xhci_dbg_init,  			"xhci_shutdown completed - status = %x",  			xhci_readl(xhci, &xhci->op_regs->status)); + +	/* Yet another workaround for spurious wakeups at shutdown with HSW */ +	if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) +		pci_set_power_state(to_pci_dev(hcd->self.controller), PCI_D3hot);  }  #ifdef CONFIG_PM @@ -839,6 +846,7 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)  int xhci_suspend(struct xhci_hcd *xhci)  {  	int			rc = 0; +	unsigned int		delay = XHCI_MAX_HALT_USEC;  	struct usb_hcd		*hcd = xhci_to_hcd(xhci);  	u32			command; @@ -861,8 +869,12 @@ int xhci_suspend(struct xhci_hcd *xhci)  	command = xhci_readl(xhci, &xhci->op_regs->command);  	command &= ~CMD_RUN;  	xhci_writel(xhci, command, &xhci->op_regs->command); + +	/* Some chips from Fresco Logic need an extraordinary delay */ +	delay *= (xhci->quirks & XHCI_SLOW_SUSPEND) ? 10 : 1; +  	if (xhci_handshake(xhci, &xhci->op_regs->status, -		      STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC)) { +		      STS_HALT, STS_HALT, delay)) {  		xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n");  		spin_unlock_irq(&xhci->lock);  		return -ETIMEDOUT; @@ -3447,7 +3459,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)  	/* Wait for the Reset Device command to finish */  	timeleft = wait_for_completion_interruptible_timeout(  			reset_device_cmd->completion, -			USB_CTRL_SET_TIMEOUT); +			XHCI_CMD_DEFAULT_TIMEOUT);  	if (timeleft <= 0) {  		xhci_warn(xhci, "%s while waiting for reset device command\n",  				timeleft == 0 ? "Timeout" : "Signal"); @@ -3571,11 +3583,6 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)  		del_timer_sync(&virt_dev->eps[i].stop_cmd_timer);  	} -	if (udev->usb2_hw_lpm_enabled) { -		xhci_set_usb2_hardware_lpm(hcd, udev, 0); -		udev->usb2_hw_lpm_enabled = 0; -	} -  	spin_lock_irqsave(&xhci->lock, flags);  	/* Don't disable the slot if the host controller is dead. */  	state = xhci_readl(xhci, &xhci->op_regs->status); @@ -3709,9 +3716,6 @@ disable_slot:   * the device).   * We should be protected by the usb_address0_mutex in khubd's hub_port_init, so   * we should only issue and wait on one address command at the same time. - * - * We add one to the device address issued by the hardware because the USB core - * uses address 1 for the root hubs (even though they're not really devices).   */  int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)  { @@ -3856,16 +3860,13 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)  	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);  	trace_xhci_address_ctx(xhci, virt_dev->out_ctx,  				slot_ctx->dev_info >> 27); -	/* Use kernel assigned address for devices; store xHC assigned -	 * address locally. */ -	virt_dev->address = (le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK) -		+ 1;  	/* Zero the input context control for later use */  	ctrl_ctx->add_flags = 0;  	ctrl_ctx->drop_flags = 0;  	xhci_dbg_trace(xhci, trace_xhci_dbg_address, -			"Internal device address = %d", virt_dev->address); +		       "Internal device address = %d", +		       le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK);  	return 0;  } @@ -4013,133 +4014,6 @@ static int xhci_calculate_usb2_hw_lpm_params(struct usb_device *udev)  	return PORT_BESLD(besld) | PORT_L1_TIMEOUT(l1) | PORT_HIRDM(hirdm);  } -static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd, -					struct usb_device *udev) -{ -	struct xhci_hcd	*xhci = hcd_to_xhci(hcd); -	struct dev_info	*dev_info; -	__le32 __iomem	**port_array; -	__le32 __iomem	*addr, *pm_addr; -	u32		temp, dev_id; -	unsigned int	port_num; -	unsigned long	flags; -	int		hird; -	int		ret; - -	if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support || -			!udev->lpm_capable) -		return -EINVAL; - -	/* we only support lpm for non-hub device connected to root hub yet */ -	if (!udev->parent || udev->parent->parent || -			udev->descriptor.bDeviceClass == USB_CLASS_HUB) -		return -EINVAL; - -	spin_lock_irqsave(&xhci->lock, flags); - -	/* Look for devices in lpm_failed_devs list */ -	dev_id = le16_to_cpu(udev->descriptor.idVendor) << 16 | -			le16_to_cpu(udev->descriptor.idProduct); -	list_for_each_entry(dev_info, &xhci->lpm_failed_devs, list) { -		if (dev_info->dev_id == dev_id) { -			ret = -EINVAL; -			goto finish; -		} -	} - -	port_array = xhci->usb2_ports; -	port_num = udev->portnum - 1; - -	if (port_num > HCS_MAX_PORTS(xhci->hcs_params1)) { -		xhci_dbg(xhci, "invalid port number %d\n", udev->portnum); -		ret = -EINVAL; -		goto finish; -	} - -	/* -	 * Test USB 2.0 software LPM. -	 * FIXME: some xHCI 1.0 hosts may implement a new register to set up -	 * hardware-controlled USB 2.0 LPM. See section 5.4.11 and 4.23.5.1.1.1 -	 * in the June 2011 errata release. -	 */ -	xhci_dbg(xhci, "test port %d software LPM\n", port_num); -	/* -	 * Set L1 Device Slot and HIRD/BESL. -	 * Check device's USB 2.0 extension descriptor to determine whether -	 * HIRD or BESL shoule be used. See USB2.0 LPM errata. -	 */ -	pm_addr = port_array[port_num] + PORTPMSC; -	hird = xhci_calculate_hird_besl(xhci, udev); -	temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird); -	xhci_writel(xhci, temp, pm_addr); - -	/* Set port link state to U2(L1) */ -	addr = port_array[port_num]; -	xhci_set_link_state(xhci, port_array, port_num, XDEV_U2); - -	/* wait for ACK */ -	spin_unlock_irqrestore(&xhci->lock, flags); -	msleep(10); -	spin_lock_irqsave(&xhci->lock, flags); - -	/* Check L1 Status */ -	ret = xhci_handshake(xhci, pm_addr, -			PORT_L1S_MASK, PORT_L1S_SUCCESS, 125); -	if (ret != -ETIMEDOUT) { -		/* enter L1 successfully */ -		temp = xhci_readl(xhci, addr); -		xhci_dbg(xhci, "port %d entered L1 state, port status 0x%x\n", -				port_num, temp); -		ret = 0; -	} else { -		temp = xhci_readl(xhci, pm_addr); -		xhci_dbg(xhci, "port %d software lpm failed, L1 status %d\n", -				port_num, temp & PORT_L1S_MASK); -		ret = -EINVAL; -	} - -	/* Resume the port */ -	xhci_set_link_state(xhci, port_array, port_num, XDEV_U0); - -	spin_unlock_irqrestore(&xhci->lock, flags); -	msleep(10); -	spin_lock_irqsave(&xhci->lock, flags); - -	/* Clear PLC */ -	xhci_test_and_clear_bit(xhci, port_array, port_num, PORT_PLC); - -	/* Check PORTSC to make sure the device is in the right state */ -	if (!ret) { -		temp = xhci_readl(xhci, addr); -		xhci_dbg(xhci, "resumed port %d status 0x%x\n",	port_num, temp); -		if (!(temp & PORT_CONNECT) || !(temp & PORT_PE) || -				(temp & PORT_PLS_MASK) != XDEV_U0) { -			xhci_dbg(xhci, "port L1 resume fail\n"); -			ret = -EINVAL; -		} -	} - -	if (ret) { -		/* Insert dev to lpm_failed_devs list */ -		xhci_warn(xhci, "device LPM test failed, may disconnect and " -				"re-enumerate\n"); -		dev_info = kzalloc(sizeof(struct dev_info), GFP_ATOMIC); -		if (!dev_info) { -			ret = -ENOMEM; -			goto finish; -		} -		dev_info->dev_id = dev_id; -		INIT_LIST_HEAD(&dev_info->list); -		list_add(&dev_info->list, &xhci->lpm_failed_devs); -	} else { -		xhci_ring_device(xhci, udev->slot_id); -	} - -finish: -	spin_unlock_irqrestore(&xhci->lock, flags); -	return ret; -} -  int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,  			struct usb_device *udev, int enable)  { @@ -4216,7 +4090,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,  		}  		pm_val &= ~PORT_HIRD_MASK; -		pm_val |= PORT_HIRD(hird) | PORT_RWE; +		pm_val |= PORT_HIRD(hird) | PORT_RWE | PORT_L1DS(udev->slot_id);  		xhci_writel(xhci, pm_val, pm_addr);  		pm_val = xhci_readl(xhci, pm_addr);  		pm_val |= PORT_HLE; @@ -4224,7 +4098,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,  		/* flush write */  		xhci_readl(xhci, pm_addr);  	} else { -		pm_val &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK); +		pm_val &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK | PORT_L1DS_MASK);  		xhci_writel(xhci, pm_val, pm_addr);  		/* flush write */  		xhci_readl(xhci, pm_addr); @@ -4267,24 +4141,26 @@ static int xhci_check_usb2_port_capability(struct xhci_hcd *xhci, int port,  int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)  {  	struct xhci_hcd	*xhci = hcd_to_xhci(hcd); -	int		ret;  	int		portnum = udev->portnum - 1; -	ret = xhci_usb2_software_lpm_test(hcd, udev); -	if (!ret) { -		xhci_dbg(xhci, "software LPM test succeed\n"); -		if (xhci->hw_lpm_support == 1 && -		    xhci_check_usb2_port_capability(xhci, portnum, XHCI_HLC)) { -			udev->usb2_hw_lpm_capable = 1; -			udev->l1_params.timeout = XHCI_L1_TIMEOUT; -			udev->l1_params.besl = XHCI_DEFAULT_BESL; -			if (xhci_check_usb2_port_capability(xhci, portnum, -							    XHCI_BLC)) -				udev->usb2_hw_lpm_besl_capable = 1; -			ret = xhci_set_usb2_hardware_lpm(hcd, udev, 1); -			if (!ret) -				udev->usb2_hw_lpm_enabled = 1; -		} +	if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support || +			!udev->lpm_capable) +		return 0; + +	/* we only support lpm for non-hub device connected to root hub yet */ +	if (!udev->parent || udev->parent->parent || +			udev->descriptor.bDeviceClass == USB_CLASS_HUB) +		return 0; + +	if (xhci->hw_lpm_support == 1 && +			xhci_check_usb2_port_capability( +				xhci, portnum, XHCI_HLC)) { +		udev->usb2_hw_lpm_capable = 1; +		udev->l1_params.timeout = XHCI_L1_TIMEOUT; +		udev->l1_params.besl = XHCI_DEFAULT_BESL; +		if (xhci_check_usb2_port_capability(xhci, portnum, +					XHCI_BLC)) +			udev->usb2_hw_lpm_besl_capable = 1;  	}  	return 0;  | 
