Commit c1fdb68e authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

USB: EHCI: changes related to qh_refresh()

This patch (as1638) makes several changes to the ehci-hcd driver, all
related to the qh_refresh() function.  This function must be called
whenever an idle QH gets linked back into either the async or the
periodic schedule.

	Change a BUG_ON() in the qh_update routine to a WARN_ON().
	Since this code runs in atomic context, a BUG_ON() would
	immediately freeze the whole system.

	Remove two unneeded calls to qh_refresh(), one when a QH is
	initialized and one when a QH becomes idle.  Adjust the
	adjacent comments accordingly.

	Move the qh_refresh() and qh_link_periodic() calls for new
	interrupt URBs to after the new TDs have been added.

	As a result of the previous two changes, qh_refresh() is never
	called when the qtd_list is empty.  The corresponding check in
	qh_refresh() can be removed, along with an indentation level.

These changes should not cause any alteration of behavior.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c79041a4
...@@ -90,7 +90,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) ...@@ -90,7 +90,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
struct ehci_qh_hw *hw = qh->hw; struct ehci_qh_hw *hw = qh->hw;
/* writes to an active overlay are unsafe */ /* writes to an active overlay are unsafe */
BUG_ON(qh->qh_state != QH_STATE_IDLE); WARN_ON(qh->qh_state != QH_STATE_IDLE);
hw->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma); hw->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
hw->hw_alt_next = EHCI_LIST_END(ehci); hw->hw_alt_next = EHCI_LIST_END(ehci);
...@@ -123,26 +123,19 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -123,26 +123,19 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
{ {
struct ehci_qtd *qtd; struct ehci_qtd *qtd;
if (list_empty (&qh->qtd_list)) qtd = list_entry(qh->qtd_list.next, struct ehci_qtd, qtd_list);
qtd = qh->dummy;
else {
qtd = list_entry (qh->qtd_list.next,
struct ehci_qtd, qtd_list);
/*
* first qtd may already be partially processed.
* If we come here during unlink, the QH overlay region
* might have reference to the just unlinked qtd. The
* qtd is updated in qh_completions(). Update the QH
* overlay here.
*/
if (qh->hw->hw_token & ACTIVE_BIT(ehci)) {
qh->hw->hw_qtd_next = qtd->hw_next;
qtd = NULL;
}
}
if (qtd) /*
qh_update (ehci, qh, qtd); * first qtd may already be partially processed.
* If we come here during unlink, the QH overlay region
* might have reference to the just unlinked qtd. The
* qtd is updated in qh_completions(). Update the QH
* overlay here.
*/
if (qh->hw->hw_token & ACTIVE_BIT(ehci))
qh->hw->hw_qtd_next = qtd->hw_next;
else
qh_update(ehci, qh, qtd);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -553,12 +546,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -553,12 +546,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
* overlaying the dummy qtd (which reduces DMA chatter). * overlaying the dummy qtd (which reduces DMA chatter).
*/ */
if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) { if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) {
switch (state) { if (state == QH_STATE_LINKED) {
case QH_STATE_IDLE: /*
qh_refresh(ehci, qh); * We won't refresh a QH that's linked (after the HC
break;
case QH_STATE_LINKED:
/* We won't refresh a QH that's linked (after the HC
* stopped the queue). That avoids a race: * stopped the queue). That avoids a race:
* - HC reads first part of QH; * - HC reads first part of QH;
* - CPU updates that first part and the token; * - CPU updates that first part and the token;
...@@ -568,13 +558,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -568,13 +558,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
* *
* That should be rare for interrupt transfers, * That should be rare for interrupt transfers,
* except maybe high bandwidth ... * except maybe high bandwidth ...
*
* Therefore tell the caller to start an unlink.
*/ */
/* Tell the caller to start an unlink */
qh->needs_rescan = 1; qh->needs_rescan = 1;
break;
/* otherwise, unlink already started */
} }
/* otherwise, unlink already started */
} }
return count; return count;
...@@ -957,14 +946,13 @@ qh_make ( ...@@ -957,14 +946,13 @@ qh_make (
/* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */ /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */
/* init as live, toggle clear, advance to dummy */ /* init as live, toggle clear */
qh->qh_state = QH_STATE_IDLE; qh->qh_state = QH_STATE_IDLE;
hw = qh->hw; hw = qh->hw;
hw->hw_info1 = cpu_to_hc32(ehci, info1); hw->hw_info1 = cpu_to_hc32(ehci, info1);
hw->hw_info2 = cpu_to_hc32(ehci, info2); hw->hw_info2 = cpu_to_hc32(ehci, info2);
qh->is_out = !is_input; qh->is_out = !is_input;
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
qh_refresh (ehci, qh);
return qh; return qh;
} }
......
...@@ -792,7 +792,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -792,7 +792,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
struct ehci_qh_hw *hw = qh->hw; struct ehci_qh_hw *hw = qh->hw;
qh_refresh(ehci, qh);
hw->hw_next = EHCI_LIST_END(ehci); hw->hw_next = EHCI_LIST_END(ehci);
frame = qh->start; frame = qh->start;
...@@ -844,8 +843,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -844,8 +843,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
} else } else
ehci_dbg (ehci, "reused qh %p schedule\n", qh); ehci_dbg (ehci, "reused qh %p schedule\n", qh);
/* stuff into the periodic schedule */
qh_link_periodic(ehci, qh);
done: done:
return status; return status;
} }
...@@ -891,6 +888,12 @@ static int intr_submit ( ...@@ -891,6 +888,12 @@ static int intr_submit (
qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv); qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
BUG_ON (qh == NULL); 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 */ /* ... update usbfs periodic stats */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs++; ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment