Patch is against kernels 2.6.18 through at least 2.6.18-git7 patch 1: This patch slightly refactors isoch stream cleanup such that stream state is more persistent; it is instantiated at first transfer and not released until endpoint shutdown. This is to isoch transfers something persistent to associate with bandwidth budget reservations later.
Signed-off-by: Christopher "Monty" Montgomery <[EMAIL PROTECTED]> --- diff -X b/Documentation/dontdiff -upr a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h --- a/drivers/usb/host/ehci.h 2006-08-07 00:18:54.000000000 -0400 +++ b/drivers/usb/host/ehci.h 2006-09-26 22:06:01.000000000 -0400 @@ -604,6 +604,14 @@ struct ehci_fstn { /*-------------------------------------------------------------------------*/ +#define EHCI_EP_QH(x) (((x)->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) \ + != USB_ENDPOINT_XFER_ISOC ? (x)->hcpriv : NULL) +#define EHCI_EP_STREAM(x) (((x)->desc.bmAttributes & \ + USB_ENDPOINT_XFERTYPE_MASK) == \ + USB_ENDPOINT_XFER_ISOC ? (x)->hcpriv : NULL) + +/*-------------------------------------------------------------------------*/ + #ifdef CONFIG_USB_EHCI_ROOT_HUB_TT /* diff -X b/Documentation/dontdiff -upr a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c 2006-08-09 22:12:43.000000000 -0400 +++ b/drivers/usb/host/ehci-hcd.c 2006-09-26 22:06:01.000000000 -0400 @@ -815,62 +815,79 @@ ehci_endpoint_disable (struct usb_hcd *h struct ehci_hcd *ehci = hcd_to_ehci (hcd); unsigned long flags; struct ehci_qh *qh, *tmp; + struct ehci_iso_stream *iso; /* ASSERT: any requests/urbs are being unlinked */ /* ASSERT: nobody can be submitting urbs for this any more */ -rescan: spin_lock_irqsave (&ehci->lock, flags); - qh = ep->hcpriv; - if (!qh) - goto done; + iso = EHCI_EP_STREAM(ep); - /* endpoints can be iso streams. for now, we don't - * accelerate iso completions ... so spin a while. - */ - if (qh->hw_info1 == 0) { - ehci_vdbg (ehci, "iso delay\n"); - goto idle_timeout; - } + if (iso){ + /* for now, we don't accelerate iso completions ... so spin + a while. */ + + while(iso->refcount>1){ + spin_unlock_irqrestore (&ehci->lock, flags); + schedule_timeout_uninterruptible(1); + spin_lock_irqsave (&ehci->lock, flags); + } - if (!HC_IS_RUNNING (hcd->state)) - qh->qh_state = QH_STATE_IDLE; - switch (qh->qh_state) { - case QH_STATE_LINKED: - for (tmp = ehci->async->qh_next.qh; - tmp && tmp != qh; - tmp = tmp->qh_next.qh) - continue; - /* periodic qh self-unlinks on empty */ - if (!tmp) - goto nogood; - unlink_async (ehci, qh); - /* FALL THROUGH */ - case QH_STATE_UNLINK: /* wait for hw to finish? */ -idle_timeout: + /* we want to be sure completions deref the stream to 1, + then we finally pull the plug here */ + iso_stream_put(ehci,iso); + ep->hcpriv = NULL; spin_unlock_irqrestore (&ehci->lock, flags); - schedule_timeout_uninterruptible(1); - goto rescan; - case QH_STATE_IDLE: /* fully unlinked */ - if (list_empty (&qh->qtd_list)) { - qh_put (qh); + return; + } + + while ( (qh = EHCI_EP_QH(ep)) ){ + + if (!HC_IS_RUNNING (hcd->state)) + qh->qh_state = QH_STATE_IDLE; + switch (qh->qh_state) { + case QH_STATE_LINKED: + for (tmp = ehci->async->qh_next.qh; + tmp && tmp != qh; + tmp = tmp->qh_next.qh) + continue; + + /* periodic qh self-unlinks on empty */ + if (!tmp) goto error; + unlink_async (ehci, qh); + /* FALL THROUGH */ + + case QH_STATE_UNLINK: /* wait for hw to finish? */ + + spin_unlock_irqrestore (&ehci->lock, flags); + schedule_timeout_uninterruptible(1); + spin_lock_irqsave (&ehci->lock, flags); break; + + case QH_STATE_IDLE: /* fully unlinked */ + + if (list_empty (&qh->qtd_list)) { + qh_put (qh); + ep->hcpriv = NULL; + break; + } + /* else FALL THROUGH */ + default: + goto error; } - /* else FALL THROUGH */ - default: -nogood: - /* caller was supposed to have unlinked any requests; - * that's not our job. just leak this memory. - */ - ehci_err (ehci, "qh %p (#%02x) state %d%s\n", - qh, ep->desc.bEndpointAddress, qh->qh_state, - list_empty (&qh->qtd_list) ? "" : "(has tds)"); - break; } - ep->hcpriv = NULL; -done: + spin_unlock_irqrestore (&ehci->lock, flags); return; + +error: + /* caller was supposed to have unlinked any requests; + * that's not our job. just leak this memory. + */ + ehci_err (ehci, "qh %p (#%02x) state %d%s\n", + qh, ep->desc.bEndpointAddress, qh->qh_state, + list_empty (&qh->qtd_list) ? "" : "(has tds)"); + ep->hcpriv = NULL; } static int ehci_get_frame (struct usb_hcd *hcd) diff -X b/Documentation/dontdiff -upr a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c --- a/drivers/usb/host/ehci-sched.c 2006-08-09 22:12:43.000000000 -0400 +++ b/drivers/usb/host/ehci-sched.c 2006-09-26 22:06:01.000000000 -0400 @@ -959,10 +959,14 @@ iso_stream_put(struct ehci_hcd *ehci, st { stream->refcount--; - /* free whenever just a dev->ep reference remains. - * not like a QH -- no persistent state (toggle, halt) - */ - if (stream->refcount == 1) { + /* don't free on last descriptor; free when endpoint disable + finally releases last refcount. Although it is technically + broken for an endpoint driver to submit its streaming + descriptors such that a new one appears after the old one + ends, it is only punishing the users to insist on breaking + these drivers when it's not necessary to do so. This saves + substantial overhead in that case.*/ + if (stream->refcount == 0) { int is_in; // BUG_ON (!list_empty(&stream->td_list)); ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys -- and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel