yep, that's the major problem with removing interrupt queueing...but it
should happen at some point...
removing "automagic resubmit", not "removing interrupt queuing" ... ;)


If noone's looked yet, I can look through the current drivers for any that
use interrupt URBs and try to create a patch fixing them all.  Of course
it also means that ohci and ehci need to remove their interrupt
resubmission too...
Here's a patch I sent by a while back, likely parts of it still apply.

But again, I'd really rather see that kind of patch be independent of
the rest of these UHCI-only changes.

- Dave

--- ./include/linux/usb.h-dist  Tue Aug 27 16:09:36 2002
+++ ./include/linux/usb.h       Tue Aug 27 16:27:40 2002
@@ -772,6 +772,5 @@
  *     request-specific driver context.
  * @complete: Completion handler. This URB is passed as the parameter to the
- *     completion function.  Except for interrupt or isochronous transfers
- *     that aren't being unlinked, the completion function may then do what
+ *     completion function.  The completion function may then do what
  *     it likes with the URB, including resubmitting or freeing it.
  * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to 
@@ -866,9 +865,4 @@
  * actual_length field tells how many bytes were transferred.
  *
- * For interrupt URBs, the URB provided to the callback
- * function is still "owned" by the USB core subsystem unless the status
- * indicates that the URB has been unlinked.  Completion handlers should
- * not modify such URBs until they have been unlinked.
- *
  * ISO transfer status is reported in the status and actual_length fields
  * of the iso_frame_desc array, and the number of errors is reported in
--- ./drivers/usb-dist/core/urb.c       Tue Aug 27 16:15:09 2002
+++ ./drivers/usb/core/urb.c    Tue Aug 27 16:27:40 2002
@@ -109,44 +109,44 @@
  * Successful submissions return 0; otherwise this routine returns a
  * negative error number.  If the submission is successful, the complete()
- * fuction of the urb will be called when the USB host driver is
- * finished with the urb (either a successful transmission, or some
- * error case.)
- *
- * Unreserved Bandwidth Transfers:
- *
- * Bulk or control requests complete only once.  When the completion
+ * callback from the urb will be called exactly once, when the USB
+ * controller is finished with the urb.  When the completion
  * function is called, control of the URB is returned to the device
  * driver which issued the request.  The completion handler may then
  * immediately free or reuse that URB.
  *
- * Bulk URBs may be queued by submitting an URB to an endpoint before
- * previous ones complete.  This can maximize bandwidth utilization by
- * letting the USB controller start work on the next URB without any
- * delay to report completion (scheduling and processing an interrupt)
- * and then submit that next request.
- *
  * For control endpoints, the synchronous usb_control_msg() call is
  * often used (in non-interrupt context) instead of this call.
+ * That is often used through convenience wrappers, for the requests
+ * that are standardized in the USB 2.0 specification.  For bulk
+ * endpoints, a synchronous usb_bulk_msg() call is available.
+ *
+ * Request Queuing:
+ *
+ * URBs may be submitted to endpoints before previous ones complete, to
+ * minimize the impact of interrupt latencies and system overhead on data
+ * throughput.  This is required for continuous isochronous data streams,
+ * and may also be required for some kinds of interrupt transfers. Such
+ * queueing also maximizes bandwidth utilization by letting USB controllers
+ * start work on later requests before driver software has finished the
+ * completion processing for earlier requests.
+ *
+ * Bulk and Isochronous URBs may always be queued.  At this writing, there
+ * are some controller drivers which do not support queueing control or
+ * interrupt transfer requests.
  *
  * Reserved Bandwidth Transfers:
  *
- * Periodic URBs (interrupt or isochronous) are performed repeatedly.
- *
- * For interrupt requests this is (currently) automagically done
- * until the original request is aborted.  When the completion callback
- * indicates the URB has been unlinked (with a special status code),
- * control of that URB returns to the device driver.  Otherwise, the
- * completion handler does not control the URB, and should not change
- * any of its fields.
- *
- * For isochronous requests, the completion handler is expected to
- * submit an urb, typically resubmitting its parameter, until drivers
- * stop wanting data transfers.  (For example, audio playback might have
- * finished, or a webcam turned off.)
- *
+ * Periodic transfers (interrupt or isochronous) are performed repeatedly,
+ * using bandwidth that is reserved for that purpose.
  * If the USB subsystem can't reserve sufficient bandwidth to perform
  * the periodic request, and bandwidth reservation is being done for
  * this controller, submitting such a periodic request will fail.
  *
+ * Device drivers must explicitly request that repetition.  It is normally
+ * done by having completion handlers update the URB returned to them, and
+ * then resubmitting it.  The resubmission is stopped when device access
+ * is no longer needed, such as when a webcam view is stopped or when audio
+ * playback completes.
+ *
  * Memory Flags:
  *
@@ -245,7 +245,8 @@
        }
 
-       /* periodic transfers limit size per frame/uframe */
-       switch (temp) {
-       case PIPE_ISOCHRONOUS: {
+       /* isochronous transfers limit size per frame/uframe,
+        * and aren't automatically packetized by HCDs
+        */
+       if (temp == PIPE_ISOCHRONOUS) {
                int     n, len;
 
@@ -258,9 +259,4 @@
                }
 
-               }
-               break;
-       case PIPE_INTERRUPT:
-               if (urb->transfer_buffer_length > max)
-                       return -EMSGSIZE;
        }
 
--- ./drivers/usb-dist/core/hcd.c       Tue Aug 27 16:15:08 2002
+++ ./drivers/usb/core/hcd.c    Tue Aug 27 16:27:40 2002
@@ -496,23 +496,15 @@
                                urb->actual_length = length;
                                urb->status = 0;
+                               urb->hcpriv = 0;
                                urb->complete (urb);
+                               return;
                        }
-                       spin_lock_irqsave (&hcd_data_lock, flags);
-                       urb->status = -EINPROGRESS;
-                       if (HCD_IS_RUNNING (hcd->state)
-                                       && rh_status_urb (hcd, urb) != 0) {
-                               /* another driver snuck in? */
-                               dbg ("%s, can't resubmit roothub status urb?",
-                                       hcd->self.bus_name);
-                               spin_unlock_irqrestore (&hcd_data_lock, flags);
-                               BUG ();
-                       }
-                       spin_unlock_irqrestore (&hcd_data_lock, flags);
-               } else {
+               } else
                        spin_unlock_irqrestore (&urb->lock, flags);
-                       spin_lock_irqsave (&hcd_data_lock, flags);
-                       rh_status_urb (hcd, urb);
-                       spin_unlock_irqrestore (&hcd_data_lock, flags);
-               }
+
+               /* retrigger timer until completion:  success or unlink */
+               spin_lock_irqsave (&hcd_data_lock, flags);
+               rh_status_urb (hcd, urb);
+               spin_unlock_irqrestore (&hcd_data_lock, flags);
        } else {
                /* this urb's been unlinked */
@@ -1155,5 +1147,8 @@
        }
 
-       /* maybe set up to block on completion notification */
+       /* maybe set up to block until the urb's completion fires.  the
+        * lower level hcd code is always async, locking on urb->status
+        * updates; an intercepted completion unblocks us.
+        */
        if ((urb->transfer_flags & USB_TIMEOUT_KILLED))
                urb->status = -ETIMEDOUT;
@@ -1287,9 +1282,4 @@
  * the device driver won't cause problems if it frees, modifies,
  * or resubmits this URB.
- * Bandwidth and other resources will be deallocated.
- *
- * HCDs must not use this for periodic URBs that are still scheduled
- * and will be reissued.  They should just call their completion handlers
- * until the urb is returned to the device driver by unlinking.
  */
 void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
--- ./drivers/usb-dist/core/hub.c       Tue Aug 27 16:15:08 2002
+++ ./drivers/usb/core/hub.c    Tue Aug 27 16:27:40 2002
@@ -120,4 +120,5 @@
        struct usb_hub *hub = (struct usb_hub *)urb->context;
        unsigned long flags;
+       int status;
 
        switch (urb->status) {
@@ -130,7 +131,7 @@
                /* Cause a hub reset after 10 consecutive errors */
                dbg("hub '%s' status %d for interrupt transfer",
-                       urb->dev->devpath, urb->status);
+                       hub->dev->devpath, urb->status);
                if ((++hub->nerrors < 10) || hub->error)
-                       return;
+                       goto resubmit;
                hub->error = urb->status;
                /* FALL THROUGH */
@@ -150,4 +151,11 @@
        }
        spin_unlock_irqrestore(&hub_event_lock, flags);
+
+resubmit:
+       urb->dev = hub->dev;
+       if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0)
+               err ("hub '%s-%s' status %d for interrupt resubmit",
+                       hub->dev->bus->bus_name, hub->dev->devpath,
+                       status);
 }
 
--- ./drivers/usb-dist/host/ehci-hcd.c  Tue Aug 27 16:15:10 2002
+++ ./drivers/usb/host/ehci-hcd.c       Tue Aug 27 16:27:40 2002
@@ -96,6 +96,4 @@
 // #define have_split_iso
 
-#define INTR_AUTOMAGIC         /* to be removed later in 2.5 */
-
 /* magic numbers that can affect system performance */
 #define        EHCI_TUNE_CERR          3       /* 0-3 qtd retries; 0 == don't stop */
--- ./drivers/usb-dist/host/ehci-q.c    Tue Aug 27 16:15:09 2002
+++ ./drivers/usb/host/ehci-q.c Tue Aug 27 16:27:40 2002
@@ -166,9 +166,4 @@
        struct urb              *urb
 ) {
-#ifdef INTR_AUTOMAGIC
-       struct urb              *resubmit = 0;
-       struct usb_device       *dev = 0;
-#endif
-
        if (likely (urb->hcpriv != 0)) {
                struct ehci_qh  *qh = (struct ehci_qh *) urb->hcpriv;
@@ -179,12 +174,4 @@
                        /* ... update hc-wide periodic stats (for usbfs) */
                        ehci->hcd.self.bandwidth_int_reqs--;
-
-#ifdef INTR_AUTOMAGIC
-                       if (!((urb->status == -ENOENT)
-                                       || (urb->status == -ECONNRESET))) {
-                               resubmit = usb_get_urb (urb);
-                               dev = urb->dev;
-                       }
-#endif
                }
                qh_put (ehci, qh);
@@ -201,23 +188,4 @@
 
        usb_hcd_giveback_urb (&ehci->hcd, urb);
-
-#ifdef INTR_AUTOMAGIC
-       if (resubmit && ((urb->status == -ENOENT)
-                               || (urb->status == -ECONNRESET))) {
-               usb_put_urb (resubmit);
-               resubmit = 0;
-       }
-       // device drivers will soon be doing something like this
-       if (resubmit) {
-               int     status;
-
-               resubmit->dev = dev;
-               status = usb_submit_urb (resubmit, SLAB_KERNEL);
-               if (status != 0)
-                       err ("can't resubmit interrupt urb %p: status %d",
-                                       resubmit, status);
-               usb_put_urb (resubmit);
-       }
-#endif
 }
 
--- ./drivers/usb-dist/host/ohci-q.c    Tue Aug 27 16:15:10 2002
+++ ./drivers/usb/host/ohci-q.c Tue Aug 27 16:27:40 2002
@@ -6,5 +6,4 @@
  * 
  * This file is licenced under the GPL.
- * $Id: ohci-q.c,v 1.8 2002/03/27 20:57:01 dbrownell Exp $
  */
 
@@ -59,45 +58,4 @@
 }
 
-static void td_submit_urb (struct ohci_hcd *ohci, struct urb *urb);
-
-/* Report interrupt transfer completion, maybe reissue */
-static inline void intr_resub (struct ohci_hcd *hc, struct urb *urb)
-{
-       struct urb_priv *urb_priv = urb->hcpriv;
-       unsigned long   flags;
-
-// FIXME going away along with the rest of interrrupt automagic...
-
-       /* FIXME: MP race.  If another CPU partially unlinks
-        * this URB (urb->status was updated, hasn't yet told
-        * us to dequeue) before we call complete() here, an
-        * extra "unlinked" completion will be reported...
-        */
-
-       spin_lock_irqsave (&urb->lock, flags);
-       if (likely (urb->status == -EINPROGRESS))
-               urb->status = 0;
-       spin_unlock_irqrestore (&urb->lock, flags);
-
-#ifdef OHCI_VERBOSE_DEBUG
-       urb_print (urb, "INTR", usb_pipeout (urb->pipe));
-#endif
-       urb->complete (urb);
-
-       /* always requeued, but ED_SKIP if complete() unlinks.
-        * EDs are removed from periodic table only at SOF intr.
-        */
-       urb->actual_length = 0;
-       spin_lock_irqsave (&urb->lock, flags);
-       if (urb_priv->state != URB_DEL)
-               urb->status = -EINPROGRESS;
-       spin_unlock (&urb->lock);
-
-       spin_lock (&hc->lock);
-       td_submit_urb (hc, urb);
-       spin_unlock_irqrestore (&hc->lock, flags);
-}
-
-
 /*-------------------------------------------------------------------------*
  * ED handling functions
@@ -982,14 +940,6 @@
                 */
                if (urb_priv->td_cnt == urb_priv->length) {
-                       int     resubmit;
-
-                       resubmit = usb_pipeint (urb->pipe)
-                                       && (urb_priv->state != URB_DEL);
-
                        spin_unlock_irqrestore (&ohci->lock, flags);
-                       if (resubmit)
-                               intr_resub (ohci, urb);
-                       else
-                               finish_urb (ohci, urb);
+                       finish_urb (ohci, urb);
                        spin_lock_irqsave (&ohci->lock, flags);
                }
--- ./drivers/usb-dist/input/hid-core.c Tue Aug 27 16:15:02 2002
+++ ./drivers/usb/input/hid-core.c      Tue Aug 27 16:27:40 2002
@@ -916,10 +916,24 @@
 static void hid_irq_in(struct urb *urb)
 {
-       if (urb->status) {
-               dbg("nonzero status in input irq %d", urb->status);
+       struct hid_device       *hid = urb->context;
+       int                     status;
+
+       switch (urb->status) {
+       case 0:                 /* success */
+               hid_input_report(HID_INPUT_REPORT, urb);
+               break;
+       case -ECONNRESET:       /* unlink completed */
+       case -ENOENT:
                return;
+       default:                /* error */
+               dbg("nonzero status in input irq %d", urb->status);
        }
-
-       hid_input_report(HID_INPUT_REPORT, urb);
+       
+       urb->dev = hid->dev;
+       status = usb_submit_urb (urb, SLAB_ATOMIC);
+       if (status)
+               err ("can't resubmit intr, %s-%s/input%d, status %d",
+                               hid->dev->bus->bus_name, hid->dev->devpath,
+                               hid->ifnum, status);
 }
 
--- ./drivers/usb-dist/input/usbkbd.c   Tue Aug 27 16:15:02 2002
+++ ./drivers/usb/input/usbkbd.c        Tue Aug 27 16:27:40 2002
@@ -83,5 +83,13 @@
        int i;
 
-       if (urb->status) return;
+       switch (urb->status) {
+       case 0:                 /* success */
+               break;
+       case -ENOENT:           /* unlink */
+       case -ECONNRESET:
+               return;
+       default:                /* error */
+               goto resubmit;
+       }
 
        for (i = 0; i < 8; i++)
@@ -108,4 +116,11 @@
 
        memcpy(kbd->old, kbd->new, 8);
+
+resubmit:
+       urb->dev = kbd->usbdev;
+       i = usb_submit_urb (urb, SLAB_ATOMIC);
+       if (i)
+               err ("can't resubmit intr, %s-%s/input0, status %d",
+                               kbd->usbdev->bus->bus_name, kbd->usbdev->devpath, i);
 }
 
--- ./drivers/usb-dist/net/pegasus.c    Tue Aug 27 16:15:03 2002
+++ ./drivers/usb/net/pegasus.c Tue Aug 27 16:27:40 2002
@@ -671,4 +671,5 @@
        struct net_device *net;
        __u8 *d;
+       int status;
 
        if (!pegasus)
@@ -701,4 +702,10 @@
                }
        }
+
+       urb->dev = pegasus->usb;
+       status = usb_submit_urb (urb, SLAB_ATOMIC);
+       if (status)
+               err ("%s: can't resubmit interrupt urb, %d",
+                               net->name, status);
 }
 

Reply via email to