This patch replaces the "exception" bitflag in the ehci_qh structure with a more explicit "unlink_reason" bitmask. This is for use in the following patch, where we will need to have a good idea of the reason for unlinking a QH, not just "something exceptional happened".
Signed-off-by: Alan Stern <st...@rowland.harvard.edu> Tested-by: Michael Reutman <mreut...@epiqsolutions.com> --- v2: No changes [as1792b] drivers/usb/host/ehci-hcd.c | 11 +++++++---- drivers/usb/host/ehci-q.c | 13 +++++++++---- drivers/usb/host/ehci-sched.c | 2 +- drivers/usb/host/ehci-timer.c | 1 + drivers/usb/host/ehci.h | 10 ++++++++-- 5 files changed, 26 insertions(+), 11 deletions(-) Index: usb-4.3/drivers/usb/host/ehci.h =================================================================== --- usb-4.3.orig/drivers/usb/host/ehci.h +++ usb-4.3/drivers/usb/host/ehci.h @@ -432,13 +432,19 @@ struct ehci_qh { u8 xacterrs; /* XactErr retry counter */ #define QH_XACTERR_MAX 32 /* XactErr retry limit */ + u8 unlink_reason; +#define QH_UNLINK_HALTED 0x01 /* Halt flag is set */ +#define QH_UNLINK_SHORT_READ 0x02 /* Recover from a short read */ +#define QH_UNLINK_DUMMY_OVERLAY 0x04 /* QH overlayed the dummy TD */ +#define QH_UNLINK_SHUTDOWN 0x08 /* The HC isn't running */ +#define QH_UNLINK_QUEUE_EMPTY 0x10 /* Reached end of the queue */ +#define QH_UNLINK_REQUESTED 0x20 /* Disable, reset, or dequeue */ + u8 gap_uf; /* uframes split/csplit gap */ unsigned is_out:1; /* bulk or intr OUT */ unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ unsigned dequeue_during_giveback:1; - unsigned exception:1; /* got a fault, or an unlink - was requested */ unsigned should_be_inactive:1; }; Index: usb-4.3/drivers/usb/host/ehci-hcd.c =================================================================== --- usb-4.3.orig/drivers/usb/host/ehci-hcd.c +++ usb-4.3/drivers/usb/host/ehci-hcd.c @@ -911,7 +911,7 @@ static int ehci_urb_dequeue(struct usb_h */ } else { qh = (struct ehci_qh *) urb->hcpriv; - qh->exception = 1; + qh->unlink_reason |= QH_UNLINK_REQUESTED; switch (qh->qh_state) { case QH_STATE_LINKED: if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) @@ -972,10 +972,13 @@ rescan: goto done; } - qh->exception = 1; + qh->unlink_reason |= QH_UNLINK_REQUESTED; switch (qh->qh_state) { case QH_STATE_LINKED: - WARN_ON(!list_empty(&qh->qtd_list)); + if (list_empty(&qh->qtd_list)) + qh->unlink_reason |= QH_UNLINK_QUEUE_EMPTY; + else + WARN_ON(1); if (usb_endpoint_type(&ep->desc) != USB_ENDPOINT_XFER_INT) start_unlink_async(ehci, qh); else @@ -1042,7 +1045,7 @@ ehci_endpoint_reset(struct usb_hcd *hcd, * re-linking will call qh_refresh(). */ usb_settoggle(qh->ps.udev, epnum, is_out, 0); - qh->exception = 1; + qh->unlink_reason |= QH_UNLINK_REQUESTED; if (eptype == USB_ENDPOINT_XFER_BULK) start_unlink_async(ehci, qh); else Index: usb-4.3/drivers/usb/host/ehci-q.c =================================================================== --- usb-4.3.orig/drivers/usb/host/ehci-q.c +++ usb-4.3/drivers/usb/host/ehci-q.c @@ -394,6 +394,7 @@ qh_completions (struct ehci_hcd *ehci, s goto retry_xacterr; } stopped = 1; + qh->unlink_reason |= QH_UNLINK_HALTED; /* magic dummy for some short reads; qh won't advance. * that silicon quirk can kick in with this dummy too. @@ -408,6 +409,7 @@ qh_completions (struct ehci_hcd *ehci, s && !(qtd->hw_alt_next & EHCI_LIST_END(ehci))) { stopped = 1; + qh->unlink_reason |= QH_UNLINK_SHORT_READ; } /* stop scanning when we reach qtds the hc is using */ @@ -420,8 +422,10 @@ qh_completions (struct ehci_hcd *ehci, s stopped = 1; /* cancel everything if we halt, suspend, etc */ - if (ehci->rh_state < EHCI_RH_RUNNING) + if (ehci->rh_state < EHCI_RH_RUNNING) { last_status = -ESHUTDOWN; + qh->unlink_reason |= QH_UNLINK_SHUTDOWN; + } /* this qtd is active; skip it unless a previous qtd * for its urb faulted, or its urb was canceled. @@ -538,10 +542,10 @@ qh_completions (struct ehci_hcd *ehci, s * except maybe high bandwidth ... */ if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) - qh->exception = 1; + qh->unlink_reason |= QH_UNLINK_DUMMY_OVERLAY; /* Let the caller know if the QH needs to be unlinked. */ - return qh->exception; + return qh->unlink_reason; } /*-------------------------------------------------------------------------*/ @@ -1003,7 +1007,7 @@ static void qh_link_async (struct ehci_h qh->qh_state = QH_STATE_LINKED; qh->xacterrs = 0; - qh->exception = 0; + qh->unlink_reason = 0; /* qtd completions reported later by interrupt */ enable_async(ehci); @@ -1395,6 +1399,7 @@ static void unlink_empty_async(struct eh /* If nothing else is being unlinked, unlink the last empty QH */ if (list_empty(&ehci->async_unlink) && qh_to_unlink) { + qh_to_unlink->unlink_reason |= QH_UNLINK_QUEUE_EMPTY; start_unlink_async(ehci, qh_to_unlink); --count; } Index: usb-4.3/drivers/usb/host/ehci-sched.c =================================================================== --- usb-4.3.orig/drivers/usb/host/ehci-sched.c +++ usb-4.3/drivers/usb/host/ehci-sched.c @@ -595,7 +595,7 @@ static void qh_link_periodic(struct ehci } qh->qh_state = QH_STATE_LINKED; qh->xacterrs = 0; - qh->exception = 0; + qh->unlink_reason = 0; /* update per-qh bandwidth for debugfs */ ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->ps.bw_period Index: usb-4.3/drivers/usb/host/ehci-timer.c =================================================================== --- usb-4.3.orig/drivers/usb/host/ehci-timer.c +++ usb-4.3/drivers/usb/host/ehci-timer.c @@ -237,6 +237,7 @@ static void ehci_handle_start_intr_unlin ehci->intr_unlink_wait_cycle)) break; list_del_init(&qh->unlink_node); + qh->unlink_reason |= QH_UNLINK_QUEUE_EMPTY; start_unlink_intr(ehci, qh); } -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html