diff options
Diffstat (limited to 'drivers/usb/host/xhci.c')
| -rw-r--r-- | drivers/usb/host/xhci.c | 49 | 
1 files changed, 31 insertions, 18 deletions
| diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index a9bb796794e3..3f79f35d0b19 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -9,6 +9,7 @@   */  #include <linux/pci.h> +#include <linux/iopoll.h>  #include <linux/irq.h>  #include <linux/log2.h>  #include <linux/module.h> @@ -52,7 +53,6 @@ static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring)  	return false;  } -/* TODO: copied from ehci-hcd.c - can this be refactored? */  /*   * xhci_handshake - spin reading hc until handshake completes or fails   * @ptr: address of hc register to be read @@ -69,18 +69,16 @@ static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring)  int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec)  {  	u32	result; +	int	ret; -	do { -		result = readl(ptr); -		if (result == ~(u32)0)		/* card removed */ -			return -ENODEV; -		result &= mask; -		if (result == done) -			return 0; -		udelay(1); -		usec--; -	} while (usec > 0); -	return -ETIMEDOUT; +	ret = readl_poll_timeout_atomic(ptr, result, +					(result & mask) == done || +					result == U32_MAX, +					1, usec); +	if (result == U32_MAX)		/* card removed */ +		return -ENODEV; + +	return ret;  }  /* @@ -1468,6 +1466,10 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag  			xhci_dbg(xhci, "urb submitted during PCI suspend\n");  		return -ESHUTDOWN;  	} +	if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) { +		xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n"); +		return -ENODEV; +	}  	if (usb_endpoint_xfer_isoc(&urb->ep->desc))  		num_tds = urb->number_of_packets; @@ -3756,6 +3758,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,  	}  	/* If necessary, update the number of active TTs on this root port */  	xhci_update_tt_active_eps(xhci, virt_dev, old_active_eps); +	virt_dev->flags = 0;  	ret = 0;  command_cleanup: @@ -4320,7 +4323,6 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,  	pm_addr = ports[port_num]->addr + PORTPMSC;  	pm_val = readl(pm_addr);  	hlpm_addr = ports[port_num]->addr + PORTHLPMC; -	field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);  	xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",  			enable ? "enable" : "disable", port_num + 1); @@ -4332,6 +4334,7 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,  			 * default one which works with mixed HIRD and BESL  			 * systems. See XHCI_DEFAULT_BESL definition in xhci.h  			 */ +			field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);  			if ((field & USB_BESL_SUPPORT) &&  			    (field & USB_BESL_BASELINE_VALID))  				hird = USB_GET_BESL_BASELINE(field); @@ -5062,16 +5065,26 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)  	} else {  		/*  		 * Some 3.1 hosts return sbrn 0x30, use xhci supported protocol -		 * minor revision instead of sbrn +		 * minor revision instead of sbrn. Minor revision is a two digit +		 * BCD containing minor and sub-minor numbers, only show minor.  		 */ -		minor_rev = xhci->usb3_rhub.min_rev; -		if (minor_rev) { +		minor_rev = xhci->usb3_rhub.min_rev / 0x10; + +		switch (minor_rev) { +		case 2: +			hcd->speed = HCD_USB32; +			hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS; +			hcd->self.root_hub->rx_lanes = 2; +			hcd->self.root_hub->tx_lanes = 2; +			break; +		case 1:  			hcd->speed = HCD_USB31;  			hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS; +			break;  		} -		xhci_info(xhci, "Host supports USB 3.%x %s SuperSpeed\n", +		xhci_info(xhci, "Host supports USB 3.%x %sSuperSpeed\n",  			  minor_rev, -			  minor_rev ? "Enhanced" : ""); +			  minor_rev ? "Enhanced " : "");  		xhci->usb3_rhub.hcd = hcd;  		/* xHCI private pointer was set in xhci_pci_probe for the second | 
