ChangeSet 1.2181.4.46, 2005/03/21 22:36:17-08:00, [EMAIL PROTECTED]

        [PATCH] UHCI updates
        
        This is the fourth of five updates to the uhci-hcd driver:
        
                Reimplement the get_current_frame routines so that when the
                controller isn't running they return a cached value.  Also add
                a flag to track whether the controller is running and allow
                critical data structure updates to occur immediately if the
                controller is stopped.
        
        Signed-off-by: Alan Stern <[EMAIL PROTECTED]>
        Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>



 uhci-hcd.c |   51 +++++++++++++++++++++++++++++++++++----------------
 uhci-hcd.h |    4 +++-
 uhci-q.c   |   31 ++++++++++++++-----------------
 3 files changed, 52 insertions(+), 34 deletions(-)


diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c       2005-03-30 15:13:54 -08:00
+++ b/drivers/usb/host/uhci-hcd.c       2005-03-30 15:13:54 -08:00
@@ -89,7 +89,7 @@
 
 static kmem_cache_t *uhci_up_cachep;   /* urb_priv */
 
-static unsigned int uhci_get_current_frame_number(struct uhci_hcd *uhci);
+static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
 static void hc_state_transitions(struct uhci_hcd *uhci);
 
 /* If a transfer is still active after this much time, turn off FSBR */
@@ -116,8 +116,11 @@
        int called_uhci_finish_completion = 0;
 
        spin_lock_irqsave(&uhci->lock, flags);
+       uhci_get_current_frame_number(uhci);
+
        if (!list_empty(&uhci->urb_remove_list) &&
-           uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) {
+                       uhci->frame_number + uhci->is_stopped !=
+                               uhci->urb_remove_age) {
                uhci_remove_pending_urbps(uhci);
                uhci_finish_completion(uhci, NULL);
                called_uhci_finish_completion = 1;
@@ -173,7 +176,6 @@
        unsigned long io_addr = uhci->io_addr;
        unsigned short status;
        struct urb_priv *urbp, *tmp;
-       unsigned int age;
 
        /*
         * Read the interrupt status, and write it back to clear the
@@ -203,13 +205,13 @@
                uhci->resume_detect = 1;
 
        spin_lock(&uhci->lock);
+       uhci_get_current_frame_number(uhci);
 
-       age = uhci_get_current_frame_number(uhci);
-       if (age != uhci->qh_remove_age)
+       if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age)
                uhci_free_pending_qhs(uhci);
-       if (age != uhci->td_remove_age)
+       if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age)
                uhci_free_pending_tds(uhci);
-       if (age != uhci->urb_remove_age)
+       if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age)
                uhci_remove_pending_urbps(uhci);
 
        if (list_empty(&uhci->urb_remove_list) &&
@@ -256,6 +258,7 @@
        /* Another 10ms delay */
        msleep(10);
        uhci->resume_detect = 0;
+       uhci->is_stopped = UHCI_IS_STOPPED;
 }
 
 static void suspend_hc(struct uhci_hcd *uhci)
@@ -266,6 +269,10 @@
        uhci->state = UHCI_SUSPENDED;
        uhci->resume_detect = 0;
        outw(USBCMD_EGSM, io_addr + USBCMD);
+
+       /* FIXME: Wait for the controller to actually stop */
+       uhci_get_current_frame_number(uhci);
+       uhci->is_stopped = UHCI_IS_STOPPED;
 }
 
 static void wakeup_hc(struct uhci_hcd *uhci)
@@ -280,6 +287,7 @@
                        outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD);
                        uhci->state = UHCI_RESUMING_1;
                        uhci->state_end = jiffies + msecs_to_jiffies(20);
+                       uhci->is_stopped = 0;
                        break;
 
                case UHCI_RESUMING_1:           /* End global resume */
@@ -386,11 +394,13 @@
 }
 
 /*
- * returns the current frame number for a USB bus/controller.
+ * Store the current frame number in uhci->frame_number if the controller
+ * is runnning
  */
-static unsigned int uhci_get_current_frame_number(struct uhci_hcd *uhci)
+static void uhci_get_current_frame_number(struct uhci_hcd *uhci)
 {
-       return inw(uhci->io_addr + USBFRNUM);
+       if (!uhci->is_stopped)
+               uhci->frame_number = inw(uhci->io_addr + USBFRNUM);
 }
 
 static int start_hc(struct uhci_hcd *uhci)
@@ -430,6 +440,7 @@
        uhci->state = UHCI_RUNNING_GRACE;
        uhci->state_end = jiffies + HZ;
        outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
+       uhci->is_stopped = 0;
 
        return 0;
 }
@@ -767,11 +778,9 @@
        spin_lock_irq(&uhci->lock);
 
        /* Don't try to suspend broken motherboards, reset instead */
-       if (suspend_allowed(uhci)) {
+       if (suspend_allowed(uhci))
                suspend_hc(uhci);
-               uhci->saved_framenumber =
-                               inw(uhci->io_addr + USBFRNUM) & 0x3ff;
-       } else {
+       else {
                spin_unlock_irq(&uhci->lock);
                reset_hc(uhci);
                spin_lock_irq(&uhci->lock);
@@ -800,7 +809,7 @@
                 */
                pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
                                0);
-               outw(uhci->saved_framenumber, uhci->io_addr + USBFRNUM);
+               outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
                outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
                outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC |
                                USBINTR_SP, uhci->io_addr + USBINTR);
@@ -832,7 +841,17 @@
 
 static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
 {
-       return uhci_get_current_frame_number(hcd_to_uhci(hcd));
+       struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+       int frame_number;
+       unsigned long flags;
+
+       /* Minimize latency by avoiding the spinlock */
+       local_irq_save(flags);
+       rmb();
+       frame_number = (uhci->is_stopped ? uhci->frame_number :
+                       inw(uhci->io_addr + USBFRNUM));
+       local_irq_restore(flags);
+       return frame_number;
 }
 
 static const char hcd_name[] = "uhci_hcd";
diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
--- a/drivers/usb/host/uhci-hcd.h       2005-03-30 15:13:54 -08:00
+++ b/drivers/usb/host/uhci-hcd.h       2005-03-30 15:13:54 -08:00
@@ -366,7 +366,9 @@
        enum uhci_state state;                  /* FIXME: needs a spinlock */
        unsigned long state_end;                /* Time of next transition */
        int resume_detect;                      /* Need a Global Resume */
-       unsigned int saved_framenumber;         /* Save during PM suspend */
+       unsigned int frame_number;              /* As of last check */
+       unsigned int is_stopped;
+#define UHCI_IS_STOPPED                9999            /* Larger than a frame 
# */
 
        /* Support for port suspend/resume/reset */
        unsigned long port_c_suspend;           /* Bit-arrays of ports */
diff -Nru a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
--- a/drivers/usb/host/uhci-q.c 2005-03-30 15:13:54 -08:00
+++ b/drivers/usb/host/uhci-q.c 2005-03-30 15:13:54 -08:00
@@ -264,7 +264,6 @@
 {
        struct uhci_qh *pqh;
        __le32 newlink;
-       unsigned int age;
 
        if (!qh)
                return;
@@ -310,10 +309,10 @@
        list_del_init(&qh->urbp->queue_list);
        qh->urbp = NULL;
 
-       age = uhci_get_current_frame_number(uhci);
-       if (age != uhci->qh_remove_age) {
+       uhci_get_current_frame_number(uhci);
+       if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age) {
                uhci_free_pending_qhs(uhci);
-               uhci->qh_remove_age = age;
+               uhci->qh_remove_age = uhci->frame_number;
        }
 
        /* Check to see if the remove list is empty. Set the IOC bit */
@@ -492,7 +491,6 @@
 {
        struct uhci_td *td, *tmp;
        struct urb_priv *urbp;
-       unsigned int age;
 
        urbp = (struct urb_priv *)urb->hcpriv;
        if (!urbp)
@@ -502,10 +500,10 @@
                dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list "
                                "or uhci->remove_list!\n", urb);
 
-       age = uhci_get_current_frame_number(uhci);
-       if (age != uhci->td_remove_age) {
+       uhci_get_current_frame_number(uhci);
+       if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) {
                uhci_free_pending_tds(uhci);
-               uhci->td_remove_age = age;
+               uhci->td_remove_age = uhci->frame_number;
        }
 
        /* Check to see if the remove list is empty. Set the IOC bit */
@@ -1063,11 +1061,11 @@
        limits = isochronous_find_limits(uhci, urb, &start, &end);
 
        if (urb->transfer_flags & URB_ISO_ASAP) {
-               if (limits)
-                       urb->start_frame =
-                                       (uhci_get_current_frame_number(uhci) +
-                                               10) & (UHCI_NUMFRAMES - 1);
-               else
+               if (limits) {
+                       uhci_get_current_frame_number(uhci);
+                       urb->start_frame = (uhci->frame_number + 10)
+                                       & (UHCI_NUMFRAMES - 1);
+               } else
                        urb->start_frame = end;
        } else {
                urb->start_frame &= (UHCI_NUMFRAMES - 1);
@@ -1371,7 +1369,6 @@
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
        unsigned long flags;
        struct urb_priv *urbp;
-       unsigned int age;
 
        spin_lock_irqsave(&uhci->lock, flags);
        urbp = urb->hcpriv;
@@ -1381,10 +1378,10 @@
 
        uhci_unlink_generic(uhci, urb);
 
-       age = uhci_get_current_frame_number(uhci);
-       if (age != uhci->urb_remove_age) {
+       uhci_get_current_frame_number(uhci);
+       if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age) {
                uhci_remove_pending_urbps(uhci);
-               uhci->urb_remove_age = age;
+               uhci->urb_remove_age = uhci->frame_number;
        }
 
        /* If we're the first, set the next interrupt bit */
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to