diff options
Diffstat (limited to 'drivers/usb/host')
| -rw-r--r-- | drivers/usb/host/ehci-hub.c | 7 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-s5p.c | 1 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-hub.c | 19 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-ring.c | 109 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.c | 28 | 
5 files changed, 124 insertions, 40 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index e051b30c184..4c32cb19b40 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -343,7 +343,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)  	u32			temp;  	u32			power_okay;  	int			i; -	u8			resume_needed = 0; +	unsigned long		resume_needed = 0;  	if (time_before (jiffies, ehci->next_statechange))  		msleep(5); @@ -416,7 +416,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)  		if (test_bit(i, &ehci->bus_suspended) &&  				(temp & PORT_SUSPEND)) {  			temp |= PORT_RESUME; -			resume_needed = 1; +			set_bit(i, &resume_needed);  		}  		ehci_writel(ehci, temp, &ehci->regs->port_status [i]);  	} @@ -431,8 +431,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)  	i = HCS_N_PORTS (ehci->hcs_params);  	while (i--) {  		temp = ehci_readl(ehci, &ehci->regs->port_status [i]); -		if (test_bit(i, &ehci->bus_suspended) && -				(temp & PORT_SUSPEND)) { +		if (test_bit(i, &resume_needed)) {  			temp &= ~(PORT_RWC_BITS | PORT_RESUME);  			ehci_writel(ehci, temp, &ehci->regs->port_status [i]);  			ehci_vdbg (ehci, "resumed port %d\n", i + 1); diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index b3958b3d316..9e77f1c8bdb 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c @@ -86,6 +86,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)  		goto fail_hcd;  	} +	s5p_ehci->hcd = hcd;  	s5p_ehci->clk = clk_get(&pdev->dev, "usbhost");  	if (IS_ERR(s5p_ehci->clk)) { diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 0be788cc2fd..723f8231193 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -463,11 +463,12 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  					&& (temp & PORT_POWER))  				status |= USB_PORT_STAT_SUSPEND;  		} -		if ((temp & PORT_PLS_MASK) == XDEV_RESUME) { +		if ((temp & PORT_PLS_MASK) == XDEV_RESUME && +				!DEV_SUPERSPEED(temp)) {  			if ((temp & PORT_RESET) || !(temp & PORT_PE))  				goto error; -			if (!DEV_SUPERSPEED(temp) && time_after_eq(jiffies, -						bus_state->resume_done[wIndex])) { +			if (time_after_eq(jiffies, +					bus_state->resume_done[wIndex])) {  				xhci_dbg(xhci, "Resume USB2 port %d\n",  					wIndex + 1);  				bus_state->resume_done[wIndex] = 0; @@ -487,6 +488,14 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  				xhci_ring_device(xhci, slot_id);  				bus_state->port_c_suspend |= 1 << wIndex;  				bus_state->suspended_ports &= ~(1 << wIndex); +			} else { +				/* +				 * The resume has been signaling for less than +				 * 20ms. Report the port status as SUSPEND, +				 * let the usbcore check port status again +				 * and clear resume signaling later. +				 */ +				status |= USB_PORT_STAT_SUSPEND;  			}  		}  		if ((temp & PORT_PLS_MASK) == XDEV_U0 @@ -664,7 +673,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  			xhci_dbg(xhci, "PORTSC %04x\n", temp);  			if (temp & PORT_RESET)  				goto error; -			if (temp & XDEV_U3) { +			if ((temp & PORT_PLS_MASK) == XDEV_U3) {  				if ((temp & PORT_PE) == 0)  					goto error; @@ -752,7 +761,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)  	memset(buf, 0, retval);  	status = 0; -	mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC; +	mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC;  	spin_lock_irqsave(&xhci->lock, flags);  	/* For each port, did anything change?  If so, set that bit in buf. */ diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 7113d16e2d3..952e2ded61a 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -514,8 +514,12 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,  			(unsigned long long) addr);  } +/* flip_cycle means flip the cycle bit of all but the first and last TRB. + * (The last TRB actually points to the ring enqueue pointer, which is not part + * of this TD.)  This is used to remove partially enqueued isoc TDs from a ring. + */  static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, -		struct xhci_td *cur_td) +		struct xhci_td *cur_td, bool flip_cycle)  {  	struct xhci_segment *cur_seg;  	union xhci_trb *cur_trb; @@ -528,6 +532,12 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,  			 * leave the pointers intact.  			 */  			cur_trb->generic.field[3] &= cpu_to_le32(~TRB_CHAIN); +			/* Flip the cycle bit (link TRBs can't be the first +			 * or last TRB). +			 */ +			if (flip_cycle) +				cur_trb->generic.field[3] ^= +					cpu_to_le32(TRB_CYCLE);  			xhci_dbg(xhci, "Cancel (unchain) link TRB\n");  			xhci_dbg(xhci, "Address = %p (0x%llx dma); "  					"in seg %p (0x%llx dma)\n", @@ -541,6 +551,11 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,  			cur_trb->generic.field[2] = 0;  			/* Preserve only the cycle bit of this TRB */  			cur_trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE); +			/* Flip the cycle bit except on the first or last TRB */ +			if (flip_cycle && cur_trb != cur_td->first_trb && +					cur_trb != cur_td->last_trb) +				cur_trb->generic.field[3] ^= +					cpu_to_le32(TRB_CYCLE);  			cur_trb->generic.field[3] |= cpu_to_le32(  				TRB_TYPE(TRB_TR_NOOP));  			xhci_dbg(xhci, "Cancel TRB %p (0x%llx dma) " @@ -719,14 +734,14 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,  					cur_td->urb->stream_id,  					cur_td, &deq_state);  		else -			td_to_noop(xhci, ep_ring, cur_td); +			td_to_noop(xhci, ep_ring, cur_td, false);  remove_finished_td:  		/*  		 * The event handler won't see a completion for this TD anymore,  		 * so remove it from the endpoint ring's TD list.  Keep it in  		 * the cancelled TD list for URB completion later.  		 */ -		list_del(&cur_td->td_list); +		list_del_init(&cur_td->td_list);  	}  	last_unlinked_td = cur_td;  	xhci_stop_watchdog_timer_in_irq(xhci, ep); @@ -754,7 +769,7 @@ remove_finished_td:  	do {  		cur_td = list_entry(ep->cancelled_td_list.next,  				struct xhci_td, cancelled_td_list); -		list_del(&cur_td->cancelled_td_list); +		list_del_init(&cur_td->cancelled_td_list);  		/* Clean up the cancelled URB */  		/* Doesn't matter what we pass for status, since the core will @@ -862,9 +877,9 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)  				cur_td = list_first_entry(&ring->td_list,  						struct xhci_td,  						td_list); -				list_del(&cur_td->td_list); +				list_del_init(&cur_td->td_list);  				if (!list_empty(&cur_td->cancelled_td_list)) -					list_del(&cur_td->cancelled_td_list); +					list_del_init(&cur_td->cancelled_td_list);  				xhci_giveback_urb_in_irq(xhci, cur_td,  						-ESHUTDOWN, "killed");  			} @@ -873,7 +888,7 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)  						&temp_ep->cancelled_td_list,  						struct xhci_td,  						cancelled_td_list); -				list_del(&cur_td->cancelled_td_list); +				list_del_init(&cur_td->cancelled_td_list);  				xhci_giveback_urb_in_irq(xhci, cur_td,  						-ESHUTDOWN, "killed");  			} @@ -1565,10 +1580,10 @@ td_cleanup:  			else  				*status = 0;  		} -		list_del(&td->td_list); +		list_del_init(&td->td_list);  		/* Was this TD slated to be cancelled but completed anyway? */  		if (!list_empty(&td->cancelled_td_list)) -			list_del(&td->cancelled_td_list); +			list_del_init(&td->cancelled_td_list);  		urb_priv->td_cnt++;  		/* Giveback the urb when all the tds are completed */ @@ -1919,8 +1934,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,  	int status = -EINPROGRESS;  	struct urb_priv *urb_priv;  	struct xhci_ep_ctx *ep_ctx; +	struct list_head *tmp;  	u32 trb_comp_code;  	int ret = 0; +	int td_num = 0;  	slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));  	xdev = xhci->devs[slot_id]; @@ -1942,6 +1959,12 @@ static int handle_tx_event(struct xhci_hcd *xhci,  		return -ENODEV;  	} +	/* Count current td numbers if ep->skip is set */ +	if (ep->skip) { +		list_for_each(tmp, &ep_ring->td_list) +			td_num++; +	} +  	event_dma = le64_to_cpu(event->buffer);  	trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));  	/* Look for common error cases */ @@ -2053,7 +2076,18 @@ static int handle_tx_event(struct xhci_hcd *xhci,  			goto cleanup;  		} +		/* We've skipped all the TDs on the ep ring when ep->skip set */ +		if (ep->skip && td_num == 0) { +			ep->skip = false; +			xhci_dbg(xhci, "All tds on the ep_ring skipped. " +						"Clear skip flag.\n"); +			ret = 0; +			goto cleanup; +		} +  		td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list); +		if (ep->skip) +			td_num--;  		/* Is this a TRB in the currently executing TD? */  		event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, @@ -2500,11 +2534,8 @@ static int prepare_transfer(struct xhci_hcd *xhci,  	if (td_index == 0) {  		ret = usb_hcd_link_urb_to_ep(bus_to_hcd(urb->dev->bus), urb); -		if (unlikely(ret)) { -			xhci_urb_free_priv(xhci, urb_priv); -			urb->hcpriv = NULL; +		if (unlikely(ret))  			return ret; -		}  	}  	td->urb = urb; @@ -2672,6 +2703,10 @@ static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len,  {  	int packets_transferred; +	/* One TRB with a zero-length data packet. */ +	if (running_total == 0 && trb_buff_len == 0) +		return 0; +  	/* All the TRB queueing functions don't count the current TRB in  	 * running_total.  	 */ @@ -3113,21 +3148,16 @@ static int count_isoc_trbs_needed(struct xhci_hcd *xhci,  		struct urb *urb, int i)  {  	int num_trbs = 0; -	u64 addr, td_len, running_total; +	u64 addr, td_len;  	addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset);  	td_len = urb->iso_frame_desc[i].length; -	running_total = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1)); -	running_total &= TRB_MAX_BUFF_SIZE - 1; -	if (running_total != 0) +	num_trbs = DIV_ROUND_UP(td_len + (addr & (TRB_MAX_BUFF_SIZE - 1)), +			TRB_MAX_BUFF_SIZE); +	if (num_trbs == 0)  		num_trbs++; -	while (running_total < td_len) { -		num_trbs++; -		running_total += TRB_MAX_BUFF_SIZE; -	} -  	return num_trbs;  } @@ -3226,6 +3256,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  	start_trb = &ep_ring->enqueue->generic;  	start_cycle = ep_ring->cycle_state; +	urb_priv = urb->hcpriv;  	/* Queue the first TRB, even if it's zero-length */  	for (i = 0; i < num_tds; i++) {  		unsigned int total_packet_count; @@ -3237,9 +3268,11 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  		addr = start_addr + urb->iso_frame_desc[i].offset;  		td_len = urb->iso_frame_desc[i].length;  		td_remain_len = td_len; -		/* FIXME: Ignoring zero-length packets, can those happen? */  		total_packet_count = roundup(td_len,  				le16_to_cpu(urb->ep->desc.wMaxPacketSize)); +		/* A zero-length transfer still involves at least one packet. */ +		if (total_packet_count == 0) +			total_packet_count++;  		burst_count = xhci_get_burst_count(xhci, urb->dev, urb,  				total_packet_count);  		residue = xhci_get_last_burst_packet_count(xhci, @@ -3249,12 +3282,13 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  		ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index,  				urb->stream_id, trbs_per_td, urb, i, mem_flags); -		if (ret < 0) -			return ret; +		if (ret < 0) { +			if (i == 0) +				return ret; +			goto cleanup; +		} -		urb_priv = urb->hcpriv;  		td = urb_priv->td[i]; -  		for (j = 0; j < trbs_per_td; j++) {  			u32 remainder = 0;  			field = TRB_TBC(burst_count) | TRB_TLBPC(residue); @@ -3344,6 +3378,27 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,  	giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,  			start_cycle, start_trb);  	return 0; +cleanup: +	/* Clean up a partially enqueued isoc transfer. */ + +	for (i--; i >= 0; i--) +		list_del_init(&urb_priv->td[i]->td_list); + +	/* Use the first TD as a temporary variable to turn the TDs we've queued +	 * into No-ops with a software-owned cycle bit. That way the hardware +	 * won't accidentally start executing bogus TDs when we partially +	 * overwrite them.  td->first_trb and td->start_seg are already set. +	 */ +	urb_priv->td[0]->last_trb = ep_ring->enqueue; +	/* Every TRB except the first & last will have its cycle bit flipped. */ +	td_to_noop(xhci, ep_ring, urb_priv->td[0], true); + +	/* Reset the ring enqueue back to the first TRB and its cycle bit. */ +	ep_ring->enqueue = urb_priv->td[0]->first_trb; +	ep_ring->enq_seg = urb_priv->td[0]->start_seg; +	ep_ring->cycle_state = start_cycle; +	usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb); +	return ret;  }  /* diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 1c4432d8fc1..3a0f695138f 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1085,8 +1085,11 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)  		if (urb->dev->speed == USB_SPEED_FULL) {  			ret = xhci_check_maxpacket(xhci, slot_id,  					ep_index, urb); -			if (ret < 0) +			if (ret < 0) { +				xhci_urb_free_priv(xhci, urb_priv); +				urb->hcpriv = NULL;  				return ret; +			}  		}  		/* We have a spinlock and interrupts disabled, so we must pass @@ -1097,6 +1100,8 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)  			goto dying;  		ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb,  				slot_id, ep_index); +		if (ret) +			goto free_priv;  		spin_unlock_irqrestore(&xhci->lock, flags);  	} else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) {  		spin_lock_irqsave(&xhci->lock, flags); @@ -1117,6 +1122,8 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)  			ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,  					slot_id, ep_index);  		} +		if (ret) +			goto free_priv;  		spin_unlock_irqrestore(&xhci->lock, flags);  	} else if (usb_endpoint_xfer_int(&urb->ep->desc)) {  		spin_lock_irqsave(&xhci->lock, flags); @@ -1124,6 +1131,8 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)  			goto dying;  		ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb,  				slot_id, ep_index); +		if (ret) +			goto free_priv;  		spin_unlock_irqrestore(&xhci->lock, flags);  	} else {  		spin_lock_irqsave(&xhci->lock, flags); @@ -1131,18 +1140,22 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)  			goto dying;  		ret = xhci_queue_isoc_tx_prepare(xhci, GFP_ATOMIC, urb,  				slot_id, ep_index); +		if (ret) +			goto free_priv;  		spin_unlock_irqrestore(&xhci->lock, flags);  	}  exit:  	return ret;  dying: -	xhci_urb_free_priv(xhci, urb_priv); -	urb->hcpriv = NULL;  	xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for "  			"non-responsive xHCI host.\n",  			urb->ep->desc.bEndpointAddress, urb); +	ret = -ESHUTDOWN; +free_priv: +	xhci_urb_free_priv(xhci, urb_priv); +	urb->hcpriv = NULL;  	spin_unlock_irqrestore(&xhci->lock, flags); -	return -ESHUTDOWN; +	return ret;  }  /* Get the right ring for the given URB. @@ -1239,6 +1252,13 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)  	if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) {  		xhci_dbg(xhci, "HW died, freeing TD.\n");  		urb_priv = urb->hcpriv; +		for (i = urb_priv->td_cnt; i < urb_priv->length; i++) { +			td = urb_priv->td[i]; +			if (!list_empty(&td->td_list)) +				list_del_init(&td->td_list); +			if (!list_empty(&td->cancelled_td_list)) +				list_del_init(&td->cancelled_td_list); +		}  		usb_hcd_unlink_urb_from_ep(hcd, urb);  		spin_unlock_irqrestore(&xhci->lock, flags);  |