On Wed, 22 Feb 2006 15:28:02 -0500 (EST), Alan Stern <[EMAIL PROTECTED]> wrote:
> On Wed, 22 Feb 2006, Pete Zaitcev wrote:

> > Frankly, I cannot fathom Alan's resistance to it when he actually suggested
> > the main idea for the patch.
> 
> I'm not at all resistant to the idea.  It's just that the patch you wrote
> doesn't apply to the current USB development tree because of other,
> large-scale changes to the driver.  As far as I can see, it should work
> fine on earlier kernels, i.e., anything < 2.6.17-rc1.

I checked out your patches and it appears that they keep FSBR on as long as
there's an URB submitted. If that's the case, I am afraid there may be a
problem with that. I envision a scenario of a guy who has PCI bus hogged
by his UHCI executing FSBR whenever he has a USB serial device and something
like pilot-link, kermit, or getty opening the device. I remember someone
complaining that his I/O speed getting 5 times slower whenever he hooked
up his Pilot.

However, I tested the new driver at my laptops, and there was no such
effect on them (with Intel north- and southbridges). So, I think we best
proceed with what we have and fall back on my patch if a real-life problem
appears. I am attaching a version which works with the new UHCI, for
the archives.

> > So now it's up to you. If you get a performance
> > anomaly on stock upstream kernels and a loaded LAN, I can resubmit and
> > otherwise argue the point. But if not, bleah. I can bump the timeout
> > in RHEL-4 just as easily.
> 
> That should be a quick, easy fix for the problems people have been seeing.  
> Make the timeout something like 500 or 1000 ms.

I'll work with Chris on that.

-- Pete

diff -urp -X dontdiff linux-2.6.16-rc4-stern/drivers/usb/host/uhci-hcd.c 
linux-2.6.16-rc4-wlan/drivers/usb/host/uhci-hcd.c
--- linux-2.6.16-rc4-stern/drivers/usb/host/uhci-hcd.c  2006-03-01 
12:35:49.000000000 -0800
+++ linux-2.6.16-rc4-wlan/drivers/usb/host/uhci-hcd.c   2006-02-28 
23:17:55.000000000 -0800
@@ -88,8 +88,7 @@ static void wakeup_rh(struct uhci_hcd *u
 static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
 
 /* If a transfer is still active after this much time, turn off FSBR */
-#define IDLE_TIMEOUT   msecs_to_jiffies(50)
-#define FSBR_DELAY     msecs_to_jiffies(50)
+#define FSBR_TIMEOUT   msecs_to_jiffies(50)
 
 /* When we timeout an idle transfer for FSBR, we'll switch it over to */
 /* depth first traversal. We'll do it in groups of this number of TDs */
@@ -490,8 +489,10 @@ static int uhci_start(struct usb_hcd *hc
 
        hcd->uses_new_polling = 1;
 
-       uhci->fsbr = 0;
-       uhci->fsbrtimeout = 0;
+       uhci->fsbr_runs = 0;
+       init_timer(&uhci->fsbr_timer);
+       uhci->fsbr_timer.data = (unsigned long) uhci;
+       uhci->fsbr_timer.function = uhci_fsbr_timeout;
 
        spin_lock_init(&uhci->lock);
 
@@ -673,6 +674,8 @@ static void uhci_stop(struct usb_hcd *hc
        uhci_scan_schedule(uhci, NULL);
        spin_unlock_irq(&uhci->lock);
 
+       del_timer_sync(&uhci->fsbr_timer);
+
        release_uhci(uhci);
 }
 
diff -urp -X dontdiff linux-2.6.16-rc4-stern/drivers/usb/host/uhci-hcd.h 
linux-2.6.16-rc4-wlan/drivers/usb/host/uhci-hcd.h
--- linux-2.6.16-rc4-stern/drivers/usb/host/uhci-hcd.h  2006-03-01 
12:35:49.000000000 -0800
+++ linux-2.6.16-rc4-wlan/drivers/usb/host/uhci-hcd.h   2006-02-28 
23:16:17.000000000 -0800
@@ -396,8 +396,8 @@ struct uhci_hcd {
        __le32 *frame;
        void **frame_cpu;               /* CPU's frame list */
 
-       int fsbr;                       /* Full-speed bandwidth reclamation */
-       unsigned long fsbrtimeout;      /* FSBR delay */
+       int fsbr_runs;                  /* Full-speed bandwidth reclamation */
+       struct timer_list fsbr_timer;
 
        enum uhci_rh_state rh_state;
        unsigned long auto_stop_time;           /* When to AUTO_STOP */
@@ -453,9 +453,10 @@ struct urb_priv {
        struct urb *urb;
 
        struct uhci_qh *qh;             /* QH for this URB */
+       struct uhci_td *fsbr_td;
        struct list_head td_list;
 
-       unsigned fsbr : 1;              /* URB turned on FSBR */
+       unsigned fsbr : 1;              /* URB activates FSBR */
        unsigned short_transfer : 1;    /* URB got a short transfer, no
                                         * need to rescan */
 };
diff -urp -X dontdiff linux-2.6.16-rc4-stern/drivers/usb/host/uhci-hub.c 
linux-2.6.16-rc4-wlan/drivers/usb/host/uhci-hub.c
--- linux-2.6.16-rc4-stern/drivers/usb/host/uhci-hub.c  2005-11-21 
19:46:28.000000000 -0800
+++ linux-2.6.16-rc4-wlan/drivers/usb/host/uhci-hub.c   2006-02-28 
23:14:05.000000000 -0800
@@ -152,7 +152,6 @@ static int uhci_hub_status_data(struct u
        uhci_scan_schedule(uhci, NULL);
        if (uhci->hc_inaccessible)
                goto done;
-       check_fsbr(uhci);
        uhci_check_ports(uhci);
 
        status = get_hub_status_data(uhci, buf);
diff -urp -X dontdiff linux-2.6.16-rc4-stern/drivers/usb/host/uhci-q.c 
linux-2.6.16-rc4-wlan/drivers/usb/host/uhci-q.c
--- linux-2.6.16-rc4-stern/drivers/usb/host/uhci-q.c    2006-03-01 
12:35:49.000000000 -0800
+++ linux-2.6.16-rc4-wlan/drivers/usb/host/uhci-q.c     2006-02-28 
23:26:22.000000000 -0800
@@ -17,6 +17,9 @@
  */
 
 static void uhci_free_pending_tds(struct uhci_hcd *uhci);
+static void uhci_fsbr_check_td(struct uhci_hcd *uhci, struct urb *urb);
+static void uhci_fsbr_start_urb(struct uhci_hcd *uhci, struct urb *urb);
+static void uhci_fsbr_activate(struct uhci_hcd *uhci);
 
 /*
  * Technically, updating td->status here is a race, but it's not really a
@@ -439,28 +442,6 @@ static void uhci_free_urb_priv(struct uh
        kmem_cache_free(uhci_up_cachep, urbp);
 }
 
-static void uhci_inc_fsbr(struct uhci_hcd *uhci, struct urb *urb)
-{
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-       if ((!(urb->transfer_flags & URB_NO_FSBR)) && !urbp->fsbr) {
-               urbp->fsbr = 1;
-               if (!uhci->fsbr++ && !uhci->fsbrtimeout)
-                       uhci->skel_term_qh->link = 
cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
-       }
-}
-
-static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb)
-{
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-       if ((!(urb->transfer_flags & URB_NO_FSBR)) && urbp->fsbr) {
-               urbp->fsbr = 0;
-               if (!--uhci->fsbr)
-                       uhci->fsbrtimeout = jiffies + FSBR_DELAY;
-       }
-}
-
 /*
  * Map status to standard result codes
  *
@@ -497,6 +478,7 @@ static int uhci_map_status(int status, i
 static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
                struct uhci_qh *qh)
 {
+       struct urb_priv *urbp = urb->hcpriv;
        struct uhci_td *td;
        unsigned long destination, status;
        int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
@@ -551,6 +533,8 @@ static int uhci_submit_control(struct uh
                uhci_add_td_to_urb(urb, td);
                uhci_fill_td(td, status, destination | uhci_explen(pktsze),
                                data);
+               if (urbp->fsbr_td == NULL)
+                       urbp->fsbr_td = td;
                plink = &td->link;
 
                data += pktsze;
@@ -606,7 +590,7 @@ static int uhci_submit_control(struct uh
                qh->skel = uhci->skel_ls_control_qh;
        else {
                qh->skel = uhci->skel_fs_control_qh;
-               uhci_inc_fsbr(uhci, urb);
+               uhci_fsbr_start_urb(uhci, urb);
        }
        return 0;
 
@@ -750,6 +734,7 @@ err:
 static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
                struct uhci_qh *qh)
 {
+       struct urb_priv *urbp = urb->hcpriv;
        struct uhci_td *td;
        unsigned long destination, status;
        int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
@@ -798,6 +783,8 @@ static int uhci_submit_common(struct uhc
                                destination | uhci_explen(pktsze) |
                                        (toggle << TD_TOKEN_TOGGLE_SHIFT),
                                data);
+               if (urbp->fsbr_td == NULL)
+                       urbp->fsbr_td = td;
                plink = &td->link;
                status |= TD_CTRL_ACTIVE;
 
@@ -954,7 +941,7 @@ static inline int uhci_submit_bulk(struc
        qh->skel = uhci->skel_bulk_qh;
        ret = uhci_submit_common(uhci, urb, qh);
        if (ret == 0)
-               uhci_inc_fsbr(uhci, urb);
+               uhci_fsbr_start_urb(uhci, urb);
        return ret;
 }
 
@@ -1221,7 +1208,6 @@ __acquires(uhci->lock)
                qh->needs_fixup = 0;
        }
 
-       uhci_dec_fsbr(uhci, urb);       /* Safe since it checks */
        uhci_free_urb_priv(uhci, urbp);
 
        switch (usb_pipetype(urb->pipe)) {
@@ -1275,11 +1261,14 @@ static void uhci_scan_qh(struct uhci_hcd
 
                switch (usb_pipetype(urb->pipe)) {
                case PIPE_CONTROL:
+                       uhci_fsbr_check_td(uhci, urb);
                        status = uhci_result_control(uhci, urb);
                        break;
                case PIPE_ISOCHRONOUS:
                        status = uhci_result_isochronous(uhci, urb);
                        break;
+               case PIPE_BULK:
+                       uhci_fsbr_check_td(uhci, urb);
                default:        /* PIPE_BULK or PIPE_INTERRUPT */
                        status = uhci_result_common(uhci, urb);
                        break;
@@ -1348,6 +1337,62 @@ static void uhci_free_pending_tds(struct
 }
 
 /*
+ * FSBR management
+ */
+
+static void uhci_fsbr_check_td(struct uhci_hcd *uhci, struct urb *urb)
+{
+       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+       unsigned int status;
+ 
+       if (!urbp->fsbr)
+               return;
+       status = uhci_status_bits(td_status(urbp->fsbr_td));
+       if (status & TD_CTRL_ACTIVE)
+               return;
+ 
+       urbp->fsbr = 0;         /* The chance to extend timeout is used up. */
+       uhci_fsbr_activate(uhci);
+}
+
+static void uhci_fsbr_start_urb(struct uhci_hcd *uhci, struct urb *urb)
+{
+       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+       struct uhci_td *td;
+ 
+       if ((td = urbp->fsbr_td) == NULL)
+               return;
+       td->status |= cpu_to_le32(TD_CTRL_IOC);
+       urbp->fsbr = 1;
+       uhci_fsbr_activate(uhci);
+}
+
+static void uhci_fsbr_activate(struct uhci_hcd *uhci)
+{
+       __le32 dma_addr;
+
+       if (!uhci->fsbr_runs) {
+               uhci->fsbr_runs = 1;
+               dma_addr = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle);
+               uhci->skel_term_qh->link = dma_addr | UHCI_PTR_QH;
+       }
+       mod_timer(&uhci->fsbr_timer, jiffies + FSBR_TIMEOUT);
+}
+
+static void uhci_fsbr_timeout(unsigned long arg)
+{
+       struct uhci_hcd *uhci = (struct uhci_hcd *) arg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&uhci->lock, flags);
+       if (uhci->fsbr_runs) {
+               uhci->fsbr_runs = 0;
+               uhci->skel_term_qh->link = UHCI_PTR_TERM;
+       }
+       spin_unlock_irqrestore(&uhci->lock, flags);
+}
+
+/*
  * Process events in the schedule, but only in one thread at a time
  */
 static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
@@ -1395,15 +1440,3 @@ static void uhci_scan_schedule(struct uh
        else
                uhci_set_next_interrupt(uhci);
 }
-
-static void check_fsbr(struct uhci_hcd *uhci)
-{
-       /* For now, don't scan URBs for FSBR timeouts.
-        * Add it back in later... */
-
-       /* Really disable FSBR */
-       if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, 
uhci->fsbrtimeout)) {
-               uhci->fsbrtimeout = 0;
-               uhci->skel_term_qh->link = UHCI_PTR_TERM;
-       }
-}


-------------------------------------------------------
This SF.Net email is sponsored by xPML, a groundbreaking scripting language
that extends applications into web and mobile media. Attend the live webcast
and join the prime developer group breaking into this new coding territory!
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642
_______________________________________________
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