This popped up when using USB storage on SMP, we ship it in RHEL & RHL.
Basically, copying anything from USB CD-ROM on a quad Xeon causes
interesting I/O errors. I consider it pretty safe, so I am sending
it separately from the rest just in case you get spooked by its
sheer size.

This is an old patch, but for a long time I wanted to backport
ohci-hcd from 2.6 instead. Now it seems I don't have strength
to make it happen, so let's just use what is known to work.

-- Pete

diff -urN -X dontdiff linux-2.4.26-rc2/drivers/usb/host/usb-ohci.c 
linux-2.4.26-rc2-nip/drivers/usb/host/usb-ohci.c
--- linux-2.4.26-rc2/drivers/usb/host/usb-ohci.c        2004-02-26 14:09:58.000000000 
-0800
+++ linux-2.4.26-rc2-nip/drivers/usb/host/usb-ohci.c    2004-04-09 17:31:44.000000000 
-0700
@@ -104,10 +104,6 @@
 
 #define OHCI_UNLINK_TIMEOUT    (HZ / 10)
 
-static LIST_HEAD (ohci_hcd_list);
-static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
-
-
 /*-------------------------------------------------------------------------*/
 
 /* AMD-756 (D2 rev) reports corrupt register contents in some cases.
@@ -134,6 +130,57 @@
 /*-------------------------------------------------------------------------*
  * URB support functions 
  *-------------------------------------------------------------------------*/ 
+
+static void ohci_complete_add(struct ohci *ohci, struct urb *urb)
+{
+
+       if (urb->hcpriv != NULL) {
+               printk("completing with non-null priv!\n");
+               return;
+       }
+
+       if (ohci->complete_tail == NULL) {
+               ohci->complete_head = urb;
+               ohci->complete_tail = urb;
+       } else {
+               ohci->complete_head->hcpriv = urb;
+               ohci->complete_tail = urb;
+       }
+}
+
+static inline struct urb *ohci_complete_get(struct ohci *ohci)
+{
+       struct urb *urb;
+
+       if ((urb = ohci->complete_head) == NULL)
+               return NULL;
+       if (urb == ohci->complete_tail) {
+               ohci->complete_tail = NULL;
+               ohci->complete_head = NULL;
+       } else {
+               ohci->complete_head = urb->hcpriv;
+       }
+       urb->hcpriv = NULL;
+       return urb;
+}
+
+static inline void ohci_complete(struct ohci *ohci)
+{
+       struct urb *urb;
+
+       spin_lock(&ohci->ohci_lock);
+       while ((urb = ohci_complete_get(ohci)) != NULL) {
+               spin_unlock(&ohci->ohci_lock);
+               if (urb->dev) {
+                       usb_dec_dev_use (urb->dev);
+                       urb->dev = NULL;
+               }
+               if (urb->complete)
+                       (*urb->complete)(urb);
+               spin_lock(&ohci->ohci_lock);
+       }
+       spin_unlock(&ohci->ohci_lock);
+}
  
 /* free HCD-private data associated with this URB */
 
@@ -209,20 +256,14 @@
                }
 
                urb_free_priv ((struct ohci *)urb->dev->bus->hcpriv, urb_priv);
-               usb_dec_dev_use (urb->dev);
-               urb->dev = NULL;
+       } else {
+               if (urb->dev != NULL) {
+                       err ("Non-null dev at rm_priv time");
+                       // urb->dev = NULL;
+               }
        }
 }
 
-static void urb_rm_priv (struct urb * urb)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave (&usb_ed_lock, flags);
-       urb_rm_priv_locked (urb);
-       spin_unlock_irqrestore (&usb_ed_lock, flags);
-}
-
 /*-------------------------------------------------------------------------*/
  
 #ifdef DEBUG
@@ -466,7 +507,6 @@
 {
        urb_priv_t * urb_priv = urb->hcpriv;
        struct urb * urbt;
-       unsigned long flags;
        int i;
        
        if (!urb_priv)
@@ -474,7 +514,8 @@
 
        /* just to be sure */
        if (!urb->complete) {
-               urb_rm_priv (urb);
+               urb_rm_priv_locked (urb);
+               ohci_complete_add(hc, urb);     /* Just usb_dec_dev_use */
                return -1;
        }
        
@@ -490,20 +531,18 @@
                                usb_pipeout (urb->pipe)
                                        ? PCI_DMA_TODEVICE
                                        : PCI_DMA_FROMDEVICE);
-
                        if (urb->interval) {
                                urb->complete (urb);
- 
+
                                /* implicitly requeued */
                                urb->actual_length = 0;
                                urb->status = -EINPROGRESS;
                                td_submit_urb (urb);
                        } else {
-                               urb_rm_priv(urb);
-                               urb->complete (urb);
+                               urb_rm_priv_locked (urb);
+                               ohci_complete_add(hc, urb);
                        }
-                       break;
-
+                       break;
                        
                case PIPE_ISOCHRONOUS:
                        for (urbt = urb->next; urbt && (urbt != urb); urbt = 
urbt->next);
@@ -515,7 +554,6 @@
                                                ? PCI_DMA_TODEVICE
                                                : PCI_DMA_FROMDEVICE);
                                urb->complete (urb);
-                               spin_lock_irqsave (&usb_ed_lock, flags);
                                urb->actual_length = 0;
                                urb->status = USB_ST_URB_PENDING;
                                urb->start_frame = urb_priv->ed->last_iso + 1;
@@ -526,18 +564,17 @@
                                        }
                                        td_submit_urb (urb);
                                }
-                               spin_unlock_irqrestore (&usb_ed_lock, flags);
-                               
+
                        } else { /* unlink URB, call complete */
-                               urb_rm_priv (urb);
-                               urb->complete (urb);    
+                               urb_rm_priv_locked (urb);
+                               ohci_complete_add(hc, urb);
                        }               
                        break;
                                
                case PIPE_BULK:
                case PIPE_CONTROL: /* unlink URB, call complete */
-                       urb_rm_priv (urb);
-                       urb->complete (urb);    
+                       urb_rm_priv_locked (urb);
+                       ohci_complete_add(hc, urb);
                        break;
        }
        return 0;
@@ -574,20 +611,24 @@
 #ifdef DEBUG
        urb_print (urb, "SUB", usb_pipein (pipe));
 #endif
-       
+
        /* handle a request to the virtual root hub */
        if (usb_pipedevice (pipe) == ohci->rh.devnum) 
                return rh_submit_urb (urb);
-       
+
+       spin_lock_irqsave(&ohci->ohci_lock, flags);
+
        /* when controller's hung, permit only roothub cleanup attempts
         * such as powering down ports */
        if (ohci->disabled) {
+               spin_unlock_irqrestore(&ohci->ohci_lock, flags);
                usb_dec_dev_use (urb->dev);     
                return -ESHUTDOWN;
        }
 
        /* every endpoint has a ed, locate and fill it */
        if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) {
+               spin_unlock_irqrestore(&ohci->ohci_lock, flags);
                usb_dec_dev_use (urb->dev);     
                return -ENOMEM;
        }
@@ -609,6 +650,7 @@
                case PIPE_ISOCHRONOUS: /* number of packets from URB */
                        size = urb->number_of_packets;
                        if (size <= 0) {
+                               spin_unlock_irqrestore(&ohci->ohci_lock, flags);
                                usb_dec_dev_use (urb->dev);     
                                return -EINVAL;
                        }
@@ -628,8 +670,9 @@
 
        /* allocate the private part of the URB */
        urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), 
-                                                       in_interrupt() ? GFP_ATOMIC : 
GFP_NOIO);
+                                                       GFP_ATOMIC);
        if (!urb_priv) {
+               spin_unlock_irqrestore(&ohci->ohci_lock, flags);
                usb_dec_dev_use (urb->dev);     
                return -ENOMEM;
        }
@@ -640,13 +683,12 @@
        urb_priv->ed = ed;      
 
        /* allocate the TDs (updating hash chains) */
-       spin_lock_irqsave (&usb_ed_lock, flags);
        for (i = 0; i < size; i++) { 
                urb_priv->td[i] = td_alloc (ohci, SLAB_ATOMIC);
                if (!urb_priv->td[i]) {
                        urb_priv->length = i;
                        urb_free_priv (ohci, urb_priv);
-                       spin_unlock_irqrestore (&usb_ed_lock, flags);
+                       spin_unlock_irqrestore(&ohci->ohci_lock, flags);
                        usb_dec_dev_use (urb->dev);     
                        return -ENOMEM;
                }
@@ -654,7 +696,7 @@
 
        if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
                urb_free_priv (ohci, urb_priv);
-               spin_unlock_irqrestore (&usb_ed_lock, flags);
+               spin_unlock_irqrestore(&ohci->ohci_lock, flags);
                usb_dec_dev_use (urb->dev);     
                return -EINVAL;
        }
@@ -676,7 +718,7 @@
                        }
                        if (bustime < 0) {
                                urb_free_priv (ohci, urb_priv);
-                               spin_unlock_irqrestore (&usb_ed_lock, flags);
+                               spin_unlock_irqrestore(&ohci->ohci_lock, flags);
                                usb_dec_dev_use (urb->dev);     
                                return bustime;
                        }
@@ -719,7 +761,7 @@
        }
 #endif
 
-       spin_unlock_irqrestore (&usb_ed_lock, flags);
+       spin_unlock_irqrestore(&ohci->ohci_lock, flags);
 
        return 0;       
 }
@@ -750,6 +792,7 @@
        if (usb_pipedevice (urb->pipe) == ohci->rh.devnum)
                return rh_unlink_urb (urb);
 
+       spin_lock_irqsave(&ohci->ohci_lock, flags);
        if (urb->hcpriv && (urb->status == USB_ST_URB_PENDING)) { 
                if (!ohci->disabled) {
                        urb_priv_t  * urb_priv;
@@ -759,6 +802,7 @@
                         */
                        if (!(urb->transfer_flags & USB_ASYNC_UNLINK)
                                        && in_interrupt ()) {
+                               spin_unlock_irqrestore(&ohci->ohci_lock, flags);
                                err ("bug in call from %p; use async!",
                                        __builtin_return_address(0));
                                return -EWOULDBLOCK;
@@ -767,11 +811,10 @@
                        /* flag the urb and its TDs for deletion in some
                         * upcoming SF interrupt delete list processing
                         */
-                       spin_lock_irqsave (&usb_ed_lock, flags);
                        urb_priv = urb->hcpriv;
 
                        if (!urb_priv || (urb_priv->state == URB_DEL)) {
-                               spin_unlock_irqrestore (&usb_ed_lock, flags);
+                               spin_unlock_irqrestore(&ohci->ohci_lock, flags);
                                return 0;
                        }
                                
@@ -786,7 +829,7 @@
 
                                add_wait_queue (&unlink_wakeup, &wait);
                                urb_priv->wait = &unlink_wakeup;
-                               spin_unlock_irqrestore (&usb_ed_lock, flags);
+                               spin_unlock_irqrestore(&ohci->ohci_lock, flags);
 
                                /* wait until all TDs are deleted */
                                set_current_state(TASK_UNINTERRUPTIBLE);
@@ -800,14 +843,22 @@
                                        err ("unlink URB timeout");
                                        return -ETIMEDOUT;
                                }
+
+                               usb_dec_dev_use (urb->dev);
+                               urb->dev = NULL;
+                               if (urb->complete)
+                                       urb->complete (urb); 
                        } else {
                                /* usb_dec_dev_use done in dl_del_list() */
                                urb->status = -EINPROGRESS;
-                               spin_unlock_irqrestore (&usb_ed_lock, flags);
+                               spin_unlock_irqrestore(&ohci->ohci_lock, flags);
                                return -EINPROGRESS;
                        }
                } else {
-                       urb_rm_priv (urb);
+                       urb_rm_priv_locked (urb);
+                       spin_unlock_irqrestore(&ohci->ohci_lock, flags);
+                       usb_dec_dev_use (urb->dev);
+                       urb->dev = NULL;
                        if (urb->transfer_flags & USB_ASYNC_UNLINK) {
                                urb->status = -ECONNRESET;
                                if (urb->complete)
@@ -815,6 +866,8 @@
                        } else 
                                urb->status = -ENOENT;
                }       
+       } else {
+               spin_unlock_irqrestore(&ohci->ohci_lock, flags);
        }       
        return 0;
 }
@@ -857,7 +910,7 @@
                 * (freeing all the TDs, unlinking EDs) but we need
                 * to defend against bugs that prevent that.
                 */
-               spin_lock_irqsave (&usb_ed_lock, flags);        
+               spin_lock_irqsave(&ohci->ohci_lock, flags);     
                for(i = 0; i < NUM_EDS; i++) {
                        ed = &(dev->ed[i]);
                        if (ed->state != ED_NEW) {
@@ -872,7 +925,7 @@
                                cnt++;
                        }
                }
-               spin_unlock_irqrestore (&usb_ed_lock, flags);
+               spin_unlock_irqrestore(&ohci->ohci_lock, flags);
                
                /* if the controller is running, tds for those unlinked
                 * urbs get freed by dl_del_list at the next SF interrupt
@@ -1206,17 +1259,12 @@
        td_t * td;
        ed_t * ed_ret;
        volatile ed_t * ed; 
-       unsigned long flags;
-       
-       
-       spin_lock_irqsave (&usb_ed_lock, flags);
 
        ed = ed_ret = &(usb_to_ohci (usb_dev)->ed[(usb_pipeendpoint (pipe) << 1) | 
                        (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]);
 
        if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
                /* pending delete request */
-               spin_unlock_irqrestore (&usb_ed_lock, flags);
                return NULL;
        }
        
@@ -1229,7 +1277,6 @@
                        /* out of memory */
                        if (td)
                            td_free(ohci, td);
-                       spin_unlock_irqrestore (&usb_ed_lock, flags);
                        return NULL;
                }
                ed->hwTailP = cpu_to_le32 (td->td_dma);
@@ -1252,8 +1299,7 @@
                ed->int_period = interval;
                ed->int_load = load;
        }
-       
-       spin_unlock_irqrestore (&usb_ed_lock, flags);
+
        return ed_ret; 
 }
 
@@ -1512,7 +1558,7 @@
 
 /* handle an urb that is being unlinked */
 
-static void dl_del_urb (struct urb * urb)
+static void dl_del_urb (ohci_t *ohci, struct urb * urb)
 {
        wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait;
 
@@ -1520,12 +1566,9 @@
 
        if (urb->transfer_flags & USB_ASYNC_UNLINK) {
                urb->status = -ECONNRESET;
-               if (urb->complete)
-                       urb->complete (urb);
+               ohci_complete_add(ohci, urb);
        } else {
                urb->status = -ENOENT;
-               if (urb->complete)
-                       urb->complete (urb);
 
                /* unblock sohci_unlink_urb */
                if (wait_head)
@@ -1544,10 +1587,7 @@
        td_t * td_rev = NULL;
        td_t * td_list = NULL;
        urb_priv_t * urb_priv = NULL;
-       unsigned long flags;
-       
-       spin_lock_irqsave (&usb_ed_lock, flags);
-       
+
        td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
        ohci->hcca->done_head = 0;
        
@@ -1573,7 +1613,6 @@
                td_rev = td_list;
                td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;    
        }       
-       spin_unlock_irqrestore (&usb_ed_lock, flags);
        return td_list;
 }
 
@@ -1585,7 +1624,6 @@
  
 static void dl_del_list (ohci_t  * ohci, unsigned int frame)
 {
-       unsigned long flags;
        ed_t * ed;
        __u32 edINFO;
        __u32 tdINFO;
@@ -1593,8 +1631,6 @@
        __u32 * td_p;
        int ctrl = 0, bulk = 0;
 
-       spin_lock_irqsave (&usb_ed_lock, flags);
-
        for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {
 
                tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
@@ -1615,7 +1651,7 @@
 
                                /* URB is done; clean up */
                                if (++(urb_priv->td_cnt) == urb_priv->length)
-                                       dl_del_urb (urb);
+                                       dl_del_urb (ohci, urb);
                        } else {
                                td_p = &td->hwNextTD;
                        }
@@ -1672,7 +1708,6 @@
        }
 
        ohci->ed_rm_list[frame] = NULL;
-       spin_unlock_irqrestore (&usb_ed_lock, flags);
 }
 
 
@@ -1689,9 +1724,7 @@
        struct urb * urb;
        urb_priv_t * urb_priv;
        __u32 tdINFO, edHeadP, edTailP;
-       
-       unsigned long flags;
-       
+ 
        while (td_list) {
                td_list_next = td_list->next_dl_td;
                
@@ -1720,13 +1753,10 @@
                                urb->status = cc_to_error[cc];
                                sohci_return_urb (ohci, urb);
                        } else {
-                               spin_lock_irqsave (&usb_ed_lock, flags);
-                               dl_del_urb (urb);
-                               spin_unlock_irqrestore (&usb_ed_lock, flags);
+                               dl_del_urb (ohci, urb);
                        }
                }
                
-               spin_lock_irqsave (&usb_ed_lock, flags);
                if (ed->state != ED_NEW) { 
                        edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
                        edTailP = le32_to_cpup (&ed->hwTailP);
@@ -1735,7 +1765,6 @@
                        if ((edHeadP == edTailP) && (ed->state == ED_OPER)) 
                                ep_unlink (ohci, ed);
                }       
-               spin_unlock_irqrestore (&usb_ed_lock, flags);
        
                td_list = td_list_next;
        }  
@@ -1926,7 +1955,8 @@
        int leni = urb->transfer_buffer_length;
        int len = 0;
        int status = TD_CC_NOERROR;
-       
+       unsigned long flags;
+
        __u32 datab[4];
        __u8  * data_buf = (__u8 *) datab;
        
@@ -1935,13 +1965,16 @@
        __u16 wIndex;
        __u16 wLength;
 
+       spin_lock_irqsave(&ohci->ohci_lock, flags);
+
        if (usb_pipeint(pipe)) {
                ohci->rh.urb =  urb;
                ohci->rh.send = 1;
                ohci->rh.interval = urb->interval;
                rh_init_int_timer(urb);
                urb->status = cc_to_error [TD_CC_NOERROR];
-               
+
+               spin_unlock_irqrestore(&ohci->ohci_lock, flags);
                return 0;
        }
 
@@ -2113,6 +2146,7 @@
 #endif
 
        urb->hcpriv = NULL;
+       spin_unlock_irqrestore(&ohci->ohci_lock, flags);
        usb_dec_dev_use (usb_dev);
        urb->dev = NULL;
        if (urb->complete)
@@ -2125,13 +2159,16 @@
 static int rh_unlink_urb (struct urb * urb)
 {
        ohci_t * ohci = urb->dev->bus->hcpriv;
+       unsigned int flags;
  
+       spin_lock_irqsave(&ohci->ohci_lock, flags);
        if (ohci->rh.urb == urb) {
                ohci->rh.send = 0;
                del_timer (&ohci->rh.rh_int_timer);
                ohci->rh.urb = NULL;
 
                urb->hcpriv = NULL;
+               spin_unlock_irqrestore(&ohci->ohci_lock, flags);
                usb_dec_dev_use(urb->dev);
                urb->dev = NULL;
                if (urb->transfer_flags & USB_ASYNC_UNLINK) {
@@ -2140,6 +2177,8 @@
                                urb->complete (urb);
                } else
                        urb->status = -ENOENT;
+       } else {
+               spin_unlock_irqrestore(&ohci->ohci_lock, flags);
        }
        return 0;
 }
@@ -2283,7 +2322,7 @@
 
 static void check_timeouts (struct ohci *ohci)
 {
-       spin_lock (&usb_ed_lock);
+       spin_lock (&ohci->ohci_lock);
        while (!list_empty (&ohci->timeout_list)) {
                struct urb      *urb;
 
@@ -2296,15 +2335,15 @@
                        continue;
 
                urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
-               spin_unlock (&usb_ed_lock);
+               spin_unlock (&ohci->ohci_lock);
 
                // outside the interrupt handler (in a timer...)
                // this reference would race interrupts
                sohci_unlink_urb (urb);
 
-               spin_lock (&usb_ed_lock);
+               spin_lock (&ohci->ohci_lock);
        }
-       spin_unlock (&usb_ed_lock);
+       spin_unlock (&ohci->ohci_lock);
 }
 
 
@@ -2318,6 +2357,8 @@
        struct ohci_regs * regs = ohci->regs;
        int ints; 
 
+       spin_lock (&ohci->ohci_lock);
+
        /* avoid (slow) readl if only WDH happened */
        if ((ohci->hcca->done_head != 0)
                        && !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
@@ -2326,11 +2367,13 @@
        /* cardbus/... hardware gone before remove() */
        } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
                ohci->disabled++;
+               spin_unlock (&ohci->ohci_lock);
                err ("%s device removed!", ohci->ohci_dev->slot_name);
                return;
 
        /* interrupt for some other device? */
        } else if ((ints &= readl (&regs->intrenable)) == 0) {
+               spin_unlock (&ohci->ohci_lock);
                return;
        } 
 
@@ -2381,6 +2424,13 @@
                }
        }
 
+       /*
+        * Finally, we are done with trashing about our hardware lists
+        * and other CPUs are allowed in. The festive flipping of the lock
+        * ensues as we struggle with the check_timeouts disaster.
+        */
+       spin_unlock (&ohci->ohci_lock);
+
        if (!list_empty (&ohci->timeout_list)) {
                check_timeouts (ohci);
 // FIXME:  enable SF as needed in a timer;
@@ -2393,6 +2443,8 @@
        writel (ints, &regs->intrstatus);
        writel (OHCI_INTR_MIE, &regs->intrenable);      
        (void)readl (&regs->intrdisable); /* PCI posting flush */
+
+       ohci_complete(ohci);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -2425,10 +2477,8 @@
        ohci->ohci_dev = dev;
        pci_set_drvdata(dev, ohci);
  
-       INIT_LIST_HEAD (&ohci->ohci_hcd_list);
-       list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
-
        INIT_LIST_HEAD (&ohci->timeout_list);
+       spin_lock_init(&ohci->ohci_lock);
 
        ohci->bus = usb_alloc_bus (&sohci_device_operations);
        if (!ohci->bus) {
@@ -2472,9 +2522,6 @@
                usb_free_bus (ohci->bus);
        }
 
-       list_del (&ohci->ohci_hcd_list);
-       INIT_LIST_HEAD (&ohci->ohci_hcd_list);
-
        ohci_mem_cleanup (ohci);
     
        /* unmap the IO address space */
@@ -2720,12 +2767,12 @@
        ohci->sleeping = 1;
 
        /* First stop processing */
-       spin_lock_irqsave (&usb_ed_lock, flags);
+       spin_lock_irqsave (&ohci->ohci_lock, flags);
        ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
        writel (ohci->hc_control, &ohci->regs->control);
        writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
        (void) readl (&ohci->regs->intrstatus);
-       spin_unlock_irqrestore (&usb_ed_lock, flags);
+       spin_unlock_irqrestore (&ohci->ohci_lock, flags);
 
        /* Wait a frame or two */
        mdelay(1);
@@ -2851,7 +2898,7 @@
                mdelay (3);
 
                /* Then re-enable operations */
-               spin_lock_irqsave (&usb_ed_lock, flags);
+               spin_lock_irqsave (&ohci->ohci_lock, flags);
                ohci->disabled = 0;
                ohci->sleeping = 0;
                ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
@@ -2867,7 +2914,6 @@
                /* Check for a pending done list */
                writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);       
                (void) readl (&ohci->regs->intrdisable);
-               spin_unlock_irqrestore (&usb_ed_lock, flags);
 #ifdef CONFIG_PMAC_PBOOK
                if (_machine == _MACH_Pmac)
                        enable_irq (ohci->irq);
@@ -2877,6 +2923,7 @@
                writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
                writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
                writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+               spin_unlock_irqrestore (&ohci->ohci_lock, flags);
                break;
 
        default:
diff -urN -X dontdiff linux-2.4.26-rc2/drivers/usb/host/usb-ohci.h 
linux-2.4.26-rc2-nip/drivers/usb/host/usb-ohci.h
--- linux-2.4.26-rc2/drivers/usb/host/usb-ohci.h        2004-03-09 19:19:51.000000000 
-0800
+++ linux-2.4.26-rc2-nip/drivers/usb/host/usb-ohci.h    2004-04-09 17:51:20.000000000 
-0700
@@ -384,12 +384,12 @@
 #define OHCI_QUIRK_SUCKYIO     0x02            /* NSC superio */
 
        struct ohci_regs * regs;        /* OHCI controller's memory */
-       struct list_head ohci_hcd_list; /* list of all ohci_hcd */
 
        struct list_head timeout_list;
        // struct list_head urb_list;   // list of all pending urbs
-       // spinlock_t urb_list_lock;    // lock to keep consistency 
-  
+       spinlock_t ohci_lock;           /* Covers all fields up & down */
+       struct urb *complete_head, *complete_tail;
+
        int ohci_int_load[32];          /* load of the 32 Interrupt Chains (for load 
balancing)*/
        ed_t * ed_rm_list[2];     /* lists of all endpoints to be removed */
        ed_t * ed_bulktail;       /* last endpoint of bulk list */


-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials
Free Linux tutorial presented by Daniel Robbins, President and CEO of
GenToo technologies. Learn everything from fundamentals to system
administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to