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

Reply via email to