diff options
Diffstat (limited to 'drivers/usb/host/ehci-sched.c')
| -rw-r--r-- | drivers/usb/host/ehci-sched.c | 42 | 
1 files changed, 18 insertions, 24 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index b476daf49f6..acff5b8f6e8 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -539,6 +539,7 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)  	}  	qh->qh_state = QH_STATE_LINKED;  	qh->xacterrs = 0; +	qh->exception = 0;  	/* update per-qh bandwidth for usbfs */  	ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period @@ -602,15 +603,9 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)  static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)  { -	/* If the QH isn't linked then there's nothing we can do -	 * unless we were called during a giveback, in which case -	 * qh_completions() has to deal with it. -	 */ -	if (qh->qh_state != QH_STATE_LINKED) { -		if (qh->qh_state == QH_STATE_COMPLETING) -			qh->needs_rescan = 1; +	/* If the QH isn't linked then there's nothing we can do. */ +	if (qh->qh_state != QH_STATE_LINKED)  		return; -	}  	qh_unlink_periodic (ehci, qh); @@ -625,17 +620,13 @@ static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)  	qh->unlink_cycle = ehci->intr_unlink_cycle;  	/* New entries go at the end of the intr_unlink list */ -	if (ehci->intr_unlink) -		ehci->intr_unlink_last->unlink_next = qh; -	else -		ehci->intr_unlink = qh; -	ehci->intr_unlink_last = qh; +	list_add_tail(&qh->unlink_node, &ehci->intr_unlink);  	if (ehci->intr_unlinking)  		;	/* Avoid recursive calls */  	else if (ehci->rh_state < EHCI_RH_RUNNING)  		ehci_handle_intr_unlinks(ehci); -	else if (ehci->intr_unlink == qh) { +	else if (ehci->intr_unlink.next == &qh->unlink_node) {  		ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);  		++ehci->intr_unlink_cycle;  	} @@ -649,7 +640,8 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)  	qh->qh_state = QH_STATE_IDLE;  	hw->hw_next = EHCI_LIST_END(ehci); -	qh_completions(ehci, qh); +	if (!list_empty(&qh->qtd_list)) +		qh_completions(ehci, qh);  	/* reschedule QH iff another request is queued */  	if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) { @@ -792,7 +784,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)  	unsigned	frame;		/* 0..(qh->period - 1), or NO_FRAME */  	struct ehci_qh_hw	*hw = qh->hw; -	qh_refresh(ehci, qh);  	hw->hw_next = EHCI_LIST_END(ehci);  	frame = qh->start; @@ -844,8 +835,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)  	} else  		ehci_dbg (ehci, "reused qh %p schedule\n", qh); -	/* stuff into the periodic schedule */ -	qh_link_periodic(ehci, qh);  done:  	return status;  } @@ -891,6 +880,12 @@ static int intr_submit (  	qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);  	BUG_ON (qh == NULL); +	/* stuff into the periodic schedule */ +	if (qh->qh_state == QH_STATE_IDLE) { +		qh_refresh(ehci, qh); +		qh_link_periodic(ehci, qh); +	} +  	/* ... update usbfs periodic stats */  	ehci_to_hcd(ehci)->self.bandwidth_int_reqs++; @@ -911,7 +906,7 @@ static void scan_intr(struct ehci_hcd *ehci)  	list_for_each_entry_safe(qh, ehci->qh_scan_next, &ehci->intr_qh_list,  			intr_node) { - rescan: +  		/* clean any finished work for this qh */  		if (!list_empty(&qh->qtd_list)) {  			int temp; @@ -924,12 +919,9 @@ static void scan_intr(struct ehci_hcd *ehci)  			 * in qh_unlink_periodic().  			 */  			temp = qh_completions(ehci, qh); -			if (unlikely(qh->needs_rescan || -					(list_empty(&qh->qtd_list) && -						qh->qh_state == QH_STATE_LINKED))) +			if (unlikely(temp || (list_empty(&qh->qtd_list) && +					qh->qh_state == QH_STATE_LINKED)))  				start_unlink_intr(ehci, qh); -			else if (temp != 0) -				goto rescan;  		}  	}  } @@ -1214,6 +1206,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 +1908,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);  	}  |