diff options
Diffstat (limited to 'drivers/usb/host')
| -rw-r--r-- | drivers/usb/host/ehci-hcd.c | 7 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-hub.c | 2 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-q.c | 49 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-sched.c | 2 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-timer.c | 2 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-mem.c | 36 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-pci.c | 1 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-ring.c | 61 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.c | 25 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.h | 9 | 
10 files changed, 122 insertions, 72 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index b416a3fc995..416a6dce5e1 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -302,6 +302,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci)  static void end_unlink_async(struct ehci_hcd *ehci);  static void unlink_empty_async(struct ehci_hcd *ehci); +static void unlink_empty_async_suspended(struct ehci_hcd *ehci);  static void ehci_work(struct ehci_hcd *ehci);  static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh);  static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh); @@ -748,11 +749,9 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)  		/* guard against (alleged) silicon errata */  		if (cmd & CMD_IAAD)  			ehci_dbg(ehci, "IAA with IAAD still set?\n"); -		if (ehci->async_iaa) { +		if (ehci->async_iaa)  			COUNT(ehci->stats.iaa); -			end_unlink_async(ehci); -		} else -			ehci_dbg(ehci, "IAA with nothing unlinked?\n"); +		end_unlink_async(ehci);  	}  	/* remote wakeup [4.3.1] */ diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 4d3b294f203..7d06e77f6c4 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -328,7 +328,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)  	ehci->rh_state = EHCI_RH_SUSPENDED;  	end_unlink_async(ehci); -	unlink_empty_async(ehci); +	unlink_empty_async_suspended(ehci);  	ehci_handle_intr_unlinks(ehci);  	end_free_itds(ehci); diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index fd252f0cfb3..23d13690428 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -135,7 +135,7 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)  		 * qtd is updated in qh_completions(). Update the QH  		 * overlay here.  		 */ -		if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current) { +		if (qh->hw->hw_token & ACTIVE_BIT(ehci)) {  			qh->hw->hw_qtd_next = qtd->hw_next;  			qtd = NULL;  		} @@ -449,11 +449,19 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)  			else if (last_status == -EINPROGRESS && !urb->unlinked)  				continue; -			/* qh unlinked; token in overlay may be most current */ -			if (state == QH_STATE_IDLE -					&& cpu_to_hc32(ehci, qtd->qtd_dma) -						== hw->hw_current) { +			/* +			 * If this was the active qtd when the qh was unlinked +			 * and the overlay's token is active, then the overlay +			 * hasn't been written back to the qtd yet so use its +			 * token instead of the qtd's.  After the qtd is +			 * processed and removed, the overlay won't be valid +			 * any more. +			 */ +			if (state == QH_STATE_IDLE && +					qh->qtd_list.next == &qtd->qtd_list && +					(hw->hw_token & ACTIVE_BIT(ehci))) {  				token = hc32_to_cpu(ehci, hw->hw_token); +				hw->hw_token &= ~ACTIVE_BIT(ehci);  				/* An unlink may leave an incomplete  				 * async transaction in the TT buffer. @@ -1170,7 +1178,7 @@ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)  	struct ehci_qh		*prev;  	/* Add to the end of the list of QHs waiting for the next IAAD */ -	qh->qh_state = QH_STATE_UNLINK; +	qh->qh_state = QH_STATE_UNLINK_WAIT;  	if (ehci->async_unlink)  		ehci->async_unlink_last->unlink_next = qh;  	else @@ -1213,9 +1221,19 @@ static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested)  		/* Do only the first waiting QH (nVidia bug?) */  		qh = ehci->async_unlink; -		ehci->async_iaa = qh; -		ehci->async_unlink = qh->unlink_next; -		qh->unlink_next = NULL; + +		/* +		 * Intel (?) bug: The HC can write back the overlay region +		 * even after the IAA interrupt occurs.  In self-defense, +		 * always go through two IAA cycles for each QH. +		 */ +		if (qh->qh_state == QH_STATE_UNLINK_WAIT) { +			qh->qh_state = QH_STATE_UNLINK; +		} else { +			ehci->async_iaa = qh; +			ehci->async_unlink = qh->unlink_next; +			qh->unlink_next = NULL; +		}  		/* Make sure the unlinks are all visible to the hardware */  		wmb(); @@ -1298,6 +1316,19 @@ static void unlink_empty_async(struct ehci_hcd *ehci)  	}  } +/* The root hub is suspended; unlink all the async QHs */ +static void unlink_empty_async_suspended(struct ehci_hcd *ehci) +{ +	struct ehci_qh		*qh; + +	while (ehci->async->qh_next.qh) { +		qh = ehci->async->qh_next.qh; +		WARN_ON(!list_empty(&qh->qtd_list)); +		single_unlink_async(ehci, qh); +	} +	start_iaa_cycle(ehci, false); +} +  /* makes sure the async qh will become idle */  /* caller must own ehci->lock */ diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index b476daf49f6..010f686d888 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1214,6 +1214,7 @@ itd_urb_transaction (  		memset (itd, 0, sizeof *itd);  		itd->itd_dma = itd_dma; +		itd->frame = 9999;		/* an invalid value */  		list_add (&itd->itd_list, &sched->td_list);  	}  	spin_unlock_irqrestore (&ehci->lock, flags); @@ -1915,6 +1916,7 @@ sitd_urb_transaction (  		memset (sitd, 0, sizeof *sitd);  		sitd->sitd_dma = sitd_dma; +		sitd->frame = 9999;		/* an invalid value */  		list_add (&sitd->sitd_list, &iso_sched->td_list);  	} diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 20dbdcbe9b0..c3fa1305f83 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -304,7 +304,7 @@ static void ehci_iaa_watchdog(struct ehci_hcd *ehci)  	 * (a) SMP races against real IAA firing and retriggering, and  	 * (b) clean HC shutdown, when IAA watchdog was pending.  	 */ -	if (ehci->async_iaa) { +	if (1) {  		u32 cmd, status;  		/* If we get here, IAA is *REALLY* late.  It's barely diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 35616ffbe3a..6dc238c592b 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1022,44 +1022,24 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,   * is attached to (or the roothub port its ancestor hub is attached to).  All we   * know is the index of that port under either the USB 2.0 or the USB 3.0   * roothub, but that doesn't give us the real index into the HW port status - * registers.  Scan through the xHCI roothub port array, looking for the Nth - * entry of the correct port speed.  Return the port number of that entry. + * registers. Call xhci_find_raw_port_number() to get real index.   */  static u32 xhci_find_real_port_number(struct xhci_hcd *xhci,  		struct usb_device *udev)  {  	struct usb_device *top_dev; -	unsigned int num_similar_speed_ports; -	unsigned int faked_port_num; -	int i; +	struct usb_hcd *hcd; + +	if (udev->speed == USB_SPEED_SUPER) +		hcd = xhci->shared_hcd; +	else +		hcd = xhci->main_hcd;  	for (top_dev = udev; top_dev->parent && top_dev->parent->parent;  			top_dev = top_dev->parent)  		/* Found device below root hub */; -	faked_port_num = top_dev->portnum; -	for (i = 0, num_similar_speed_ports = 0; -			i < HCS_MAX_PORTS(xhci->hcs_params1); i++) { -		u8 port_speed = xhci->port_array[i]; - -		/* -		 * Skip ports that don't have known speeds, or have duplicate -		 * Extended Capabilities port speed entries. -		 */ -		if (port_speed == 0 || port_speed == DUPLICATE_ENTRY) -			continue; -		/* -		 * USB 3.0 ports are always under a USB 3.0 hub.  USB 2.0 and -		 * 1.1 ports are under the USB 2.0 hub.  If the port speed -		 * matches the device speed, it's a similar speed port. -		 */ -		if ((port_speed == 0x03) == (udev->speed == USB_SPEED_SUPER)) -			num_similar_speed_ports++; -		if (num_similar_speed_ports == faked_port_num) -			/* Roothub ports are numbered from 1 to N */ -			return i+1; -	} -	return 0; +	return	xhci_find_raw_port_number(hcd, top_dev->portnum);  }  /* Setup an xHCI virtual device for a Set Address command */ diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index af259e0ec17..1a30c380043 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -313,6 +313,7 @@ static const struct hc_driver xhci_pci_hc_driver = {  	.set_usb2_hw_lpm =	xhci_set_usb2_hardware_lpm,  	.enable_usb3_lpm_timeout =	xhci_enable_usb3_lpm_timeout,  	.disable_usb3_lpm_timeout =	xhci_disable_usb3_lpm_timeout, +	.find_raw_port_number =	xhci_find_raw_port_number,  };  /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 88287546530..1969c001b3f 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1599,14 +1599,20 @@ static void handle_port_status(struct xhci_hcd *xhci,  	max_ports = HCS_MAX_PORTS(xhci->hcs_params1);  	if ((port_id <= 0) || (port_id > max_ports)) {  		xhci_warn(xhci, "Invalid port id %d\n", port_id); -		bogus_port_status = true; -		goto cleanup; +		inc_deq(xhci, xhci->event_ring); +		return;  	}  	/* Figure out which usb_hcd this port is attached to:  	 * is it a USB 3.0 port or a USB 2.0/1.1 port?  	 */  	major_revision = xhci->port_array[port_id - 1]; + +	/* Find the right roothub. */ +	hcd = xhci_to_hcd(xhci); +	if ((major_revision == 0x03) != (hcd->speed == HCD_USB3)) +		hcd = xhci->shared_hcd; +  	if (major_revision == 0) {  		xhci_warn(xhci, "Event for port %u not in "  				"Extended Capabilities, ignoring.\n", @@ -1629,10 +1635,6 @@ static void handle_port_status(struct xhci_hcd *xhci,  	 * into the index into the ports on the correct split roothub, and the  	 * correct bus_state structure.  	 */ -	/* Find the right roothub. */ -	hcd = xhci_to_hcd(xhci); -	if ((major_revision == 0x03) != (hcd->speed == HCD_USB3)) -		hcd = xhci->shared_hcd;  	bus_state = &xhci->bus_state[hcd_index(hcd)];  	if (hcd->speed == HCD_USB3)  		port_array = xhci->usb3_ports; @@ -2027,8 +2029,8 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,  		if (event_trb != ep_ring->dequeue &&  				event_trb != td->last_trb)  			td->urb->actual_length = -				td->urb->transfer_buffer_length -				- TRB_LEN(le32_to_cpu(event->transfer_len)); +				td->urb->transfer_buffer_length - +				EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));  		else  			td->urb->actual_length = 0; @@ -2060,7 +2062,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,  		/* Maybe the event was for the data stage? */  			td->urb->actual_length =  				td->urb->transfer_buffer_length - -				TRB_LEN(le32_to_cpu(event->transfer_len)); +				EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));  			xhci_dbg(xhci, "Waiting for status "  					"stage event\n");  			return 0; @@ -2096,7 +2098,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,  	/* handle completion code */  	switch (trb_comp_code) {  	case COMP_SUCCESS: -		if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) { +		if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) {  			frame->status = 0;  			break;  		} @@ -2141,7 +2143,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,  				len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2]));  		}  		len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) - -			TRB_LEN(le32_to_cpu(event->transfer_len)); +			EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));  		if (trb_comp_code != COMP_STOP_INVAL) {  			frame->actual_length = len; @@ -2199,7 +2201,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,  	case COMP_SUCCESS:  		/* Double check that the HW transferred everything. */  		if (event_trb != td->last_trb || -				TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { +		    EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {  			xhci_warn(xhci, "WARN Successful completion "  					"on short TX\n");  			if (td->urb->transfer_flags & URB_SHORT_NOT_OK) @@ -2227,18 +2229,18 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,  				"%d bytes untransferred\n",  				td->urb->ep->desc.bEndpointAddress,  				td->urb->transfer_buffer_length, -				TRB_LEN(le32_to_cpu(event->transfer_len))); +				EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)));  	/* Fast path - was this the last TRB in the TD for this URB? */  	if (event_trb == td->last_trb) { -		if (TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { +		if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {  			td->urb->actual_length =  				td->urb->transfer_buffer_length - -				TRB_LEN(le32_to_cpu(event->transfer_len)); +				EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));  			if (td->urb->transfer_buffer_length <  					td->urb->actual_length) {  				xhci_warn(xhci, "HC gave bad length "  						"of %d bytes left\n", -					  TRB_LEN(le32_to_cpu(event->transfer_len))); +					  EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)));  				td->urb->actual_length = 0;  				if (td->urb->transfer_flags & URB_SHORT_NOT_OK)  					*status = -EREMOTEIO; @@ -2280,7 +2282,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,  		if (trb_comp_code != COMP_STOP_INVAL)  			td->urb->actual_length +=  				TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) - -				TRB_LEN(le32_to_cpu(event->transfer_len)); +				EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));  	}  	return finish_td(xhci, td, event_trb, event, ep, status, false); @@ -2368,7 +2370,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,  	 * transfer type  	 */  	case COMP_SUCCESS: -		if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) +		if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)  			break;  		if (xhci->quirks & XHCI_TRUST_TX_LENGTH)  			trb_comp_code = COMP_SHORT_TX; @@ -2461,14 +2463,21 @@ static int handle_tx_event(struct xhci_hcd *xhci,  		 * TD list.  		 */  		if (list_empty(&ep_ring->td_list)) { -			xhci_warn(xhci, "WARN Event TRB for slot %d ep %d " -					"with no TDs queued?\n", -				  TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), -				  ep_index); -			xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", -				 (le32_to_cpu(event->flags) & -				  TRB_TYPE_BITMASK)>>10); -			xhci_print_trb_offsets(xhci, (union xhci_trb *) event); +			/* +			 * A stopped endpoint may generate an extra completion +			 * event if the device was suspended.  Don't print +			 * warnings. +			 */ +			if (!(trb_comp_code == COMP_STOP || +						trb_comp_code == COMP_STOP_INVAL)) { +				xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", +						TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), +						ep_index); +				xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", +						(le32_to_cpu(event->flags) & +						 TRB_TYPE_BITMASK)>>10); +				xhci_print_trb_offsets(xhci, (union xhci_trb *) event); +			}  			if (ep->skip) {  				ep->skip = false;  				xhci_dbg(xhci, "td_list is empty while skip " diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f1f01a834ba..53b8f89a0b1 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -350,7 +350,7 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)  	 * generate interrupts.  Don't even try to enable MSI.  	 */  	if (xhci->quirks & XHCI_BROKEN_MSI) -		return 0; +		goto legacy_irq;  	/* unregister the legacy interrupt */  	if (hcd->irq) @@ -371,6 +371,7 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)  		return -EINVAL;  	} + legacy_irq:  	/* fall back to legacy interrupt*/  	ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,  			hcd->irq_descr, hcd); @@ -3778,6 +3779,28 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)  	return 0;  } +/* + * Transfer the port index into real index in the HW port status + * registers. Caculate offset between the port's PORTSC register + * and port status base. Divide the number of per port register + * to get the real index. The raw port number bases 1. + */ +int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1) +{ +	struct xhci_hcd *xhci = hcd_to_xhci(hcd); +	__le32 __iomem *base_addr = &xhci->op_regs->port_status_base; +	__le32 __iomem *addr; +	int raw_port; + +	if (hcd->speed != HCD_USB3) +		addr = xhci->usb2_ports[port1 - 1]; +	else +		addr = xhci->usb3_ports[port1 - 1]; + +	raw_port = (addr - base_addr)/NUM_PORT_REGS + 1; +	return raw_port; +} +  #ifdef CONFIG_USB_SUSPEND  /* BESL to HIRD Encoding array for USB2 LPM */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f791bd0aee6..63582719e0f 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -206,8 +206,8 @@ struct xhci_op_regs {  /* bits 12:31 are reserved (and should be preserved on writes). */  /* IMAN - Interrupt Management Register */ -#define IMAN_IP		(1 << 1) -#define IMAN_IE		(1 << 0) +#define IMAN_IE		(1 << 1) +#define IMAN_IP		(1 << 0)  /* USBSTS - USB status - status bitmasks */  /* HC not running - set to 1 when run/stop bit is cleared. */ @@ -972,6 +972,10 @@ struct xhci_transfer_event {  	__le32	flags;  }; +/* Transfer event TRB length bit mask */ +/* bits 0:23 */ +#define	EVENT_TRB_LEN(p)		((p) & 0xffffff) +  /** Transfer Event bit fields **/  #define	TRB_TO_EP_ID(p)	(((p) >> 16) & 0x1f) @@ -1829,6 +1833,7 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,  int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,  		char *buf, u16 wLength);  int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); +int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);  #ifdef CONFIG_PM  int xhci_bus_suspend(struct usb_hcd *hcd);  |