This patch changes usb-ohci.[ch] to use pci_alloc_consistent to allocate
the HCCA, ED's and TD's and to call pci_dma_map_single in td_fill to ensure
that the data in DRAM is viewed consistently by the CPU and the OHCI
controller on processors such as StrongARM that do not have cache-coherent
DMA.  All coherence issues are handled in this driver so none of the USB
device drivers need to be modified.

I posted this yesterday with a note that it had not been tested yet.  I
tested it today under pre6 with no errors.

-Jamey Hicks


PATCH FOLLOWS

Index: drivers/usb/usb-ohci.c
===================================================================
RCS file: /cvs/linux/kernel/drivers/usb/usb-ohci.c,v
retrieving revision 1.1.1.3
retrieving revision 1.4
diff -u -w -r1.1.1.3 -r1.4
--- drivers/usb/usb-ohci.c      2000/05/03 22:37:02     1.1.1.3
+++ drivers/usb/usb-ohci.c      2000/05/04 15:51:38     1.4
@@ -70,8 +70,126 @@
 static DECLARE_WAIT_QUEUE_HEAD (op_wakeup); 
 static LIST_HEAD (ohci_hcd_list);
 static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t usb_td_lock = SPIN_LOCK_UNLOCKED;
 
 /*-------------------------------------------------------------------------*
+ * Code to check addresses are in range
+ *-------------------------------------------------------------------------*/ 
+
+static int __verify_virt(volatile void *virt, int line)
+{
+  unsigned long addr = (unsigned long)virt;
+  int ok = ((addr & 0xF0000000) == 0xC0000000);
+  if (!ok)
+    printk(KERN_CRIT __FILE__ ":%d: Expected virtual address, got %p\n", line, virt);
+  return ok;
+}
+static int __verify_dma(dma_addr_t dma, int line)
+{
+  unsigned long addr = (unsigned long)dma;
+  int ok = ((addr & 0xF0000000) == 0xE0000000);
+  if (!ok)
+    printk(KERN_CRIT __FILE__ ":%d: Expected DMA address, got %#08x\n", line, dma);
+  return ok;
+}
+#define verify_virt(virt) __verify_virt((virt), __LINE__)
+#define verify_dma(dma) __verify_dma((dma), __LINE__)
+
+/*-------------------------------------------------------------------------*
+ * Consistent allocation functions 
+ *-------------------------------------------------------------------------*/ 
+
+static int ohci_consistent_storage_create(struct pci_dev *pdev, struct 
+ohci_consistent_storage *ocsp)
+{
+   int num_eds = NUM_EDS * 256;
+   int num_tds = 2048;
+   int i;
+   char *storage = NULL;
+   if (ocsp == NULL)
+      return -EINVAL;
+   storage = ocsp->virt = pci_alloc_consistent(pdev, 
+                                               sizeof(ed_t) * num_eds + sizeof(td_t) 
+* num_tds,
+                                               &ocsp->dma_addr);
+   if (storage == NULL)
+      return -ENOMEM;
+   ocsp->edlist = NULL;
+   for (i = 0; i < num_eds; i++) {
+      ed_t *ed = (ed_t *)(storage + i * sizeof(ed_t));
+      *(ed_t **)ed = ocsp->edlist;
+      ocsp->edlist = ed;
+   }
+   ocsp->tdlist = NULL;
+   for (i = 0; i < num_tds; i++) {
+      td_t *td = (td_t *)(storage + i * sizeof(td_t));
+      *(td_t **)td = ocsp->tdlist;
+      ocsp->tdlist = td;
+   }
+
+   ocsp->virt_to_dma = (long)ocsp->dma_addr - (long)ocsp->virt;
+   return 0;
+}
+
+static ed_t *ohci_alloc_consistent_ed(struct ohci *ohci) 
+{
+   int flags = 0;
+   ed_t *ed;
+   if (!in_interrupt()) spin_lock_irqsave (&usb_ed_lock, flags);       
+   ed = ohci->consistent_storage.edlist;
+   ohci->consistent_storage.edlist = *(ed_t **)ed;
+   if (!in_interrupt()) spin_unlock_irqrestore (&usb_ed_lock, flags);
+   if (0) printk(KERN_CRIT "alloc_consistent_ed: ed=%p\n", ed);
+   return ed;
+}
+
+static void ohci_free_consistent_ed(struct ohci *ohci, ed_t *ed) 
+{
+   int flags = 0;
+   if (!in_interrupt()) spin_lock_irqsave (&usb_ed_lock, flags);       
+   *(ed_t **)ed = ohci->consistent_storage.edlist;
+   ohci->consistent_storage.edlist = ed;
+   if (!in_interrupt()) spin_unlock_irqrestore (&usb_ed_lock, flags);
+}
+
+static td_t *ohci_alloc_consistent_td(struct ohci *ohci)
+{
+   int flags = 0;
+   td_t *td;
+   if (!in_interrupt()) spin_lock_irqsave (&usb_td_lock, flags);       
+   td = ohci->consistent_storage.tdlist;
+   ohci->consistent_storage.tdlist = *(td_t **)td;
+   if (!in_interrupt()) spin_unlock_irqrestore (&usb_td_lock, flags);
+   verify_virt(td);
+   if (0) printk(KERN_CRIT "alloc_consistent_td: td=%p\n", td);
+   return td;
+}
+
+static void ohci_free_consistent_td(struct ohci *ohci, td_t *td)
+{
+   int flags = 0;
+   verify_virt(td);
+   if (!in_interrupt()) spin_lock_irqsave (&usb_td_lock, flags);       
+   *(td_t **)td = ohci->consistent_storage.tdlist;
+   ohci->consistent_storage.tdlist = td;
+   if (!in_interrupt()) spin_unlock_irqrestore (&usb_td_lock, flags);
+}
+
+static dma_addr_t ohci_virt_to_bus(struct ohci *ohci, volatile void *obp)
+{
+   dma_addr_t dma = (long)(obp + ohci->consistent_storage.virt_to_dma);
+   verify_virt(obp);
+   verify_dma(dma);
+   return dma;
+}
+
+static void *ohci_bus_to_virt(struct ohci *ohci, dma_addr_t dma_addr)
+{
+   void *virt = (void *)(dma_addr - ohci->consistent_storage.virt_to_dma);
+   verify_virt(virt);
+   verify_dma(dma_addr);
+   return virt;
+}
+
+/*-------------------------------------------------------------------------*
  * URB support functions 
  *-------------------------------------------------------------------------*/ 
  
@@ -79,6 +197,7 @@
  
 static void urb_rm_priv (urb_t * urb) 
 {
+       struct ohci *ohci = (ohci_t *) urb->dev->bus->hcpriv;
        urb_priv_t * urb_priv = urb->hcpriv;
        int i;
        void * wait;
@@ -89,7 +208,7 @@
        
        for (i = 0; i < urb_priv->length; i++) {
                if (urb_priv->td [i]) {
-                       OHCI_FREE (urb_priv->td [i]);
+                       OHCI_FREE_TD (ohci, urb_priv->td [i]);
                }
        }
        kfree (urb->hcpriv);
@@ -157,12 +276,12 @@
         __u32 * ed_p;
        for (i= 0; i < 32; i++) {
                j = 5;
-               ed_p = &(ohci->hcca.int_table [i]);
+               ed_p = &(ohci->hcca->int_table [i]);
                if (*ed_p == 0)
                    continue;
                printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):", str, i, i);
                while (*ed_p != 0 && j--) {
-                       ed_t *ed = (ed_t *) bus_to_virt(le32_to_cpup(ed_p));
+                       ed_t *ed = (ed_t *) ohci_bus_to_virt(ohci, le32_to_cpup(ed_p));
                        printk (" ed: %4x;", ed->hwINFO);
                        ed_p = &ed->hwNextED;
                }
@@ -320,7 +439,7 @@
        ohci_dump_status (controller);
        if (verbose)
                ep_print_int_eds (controller, "hcca");
-       dbg ("hcca frame #%04x", controller->hcca.frame_no);
+       dbg ("hcca frame #%04x", controller->hcca->frame_no);
        ohci_dump_roothub (controller, 1);
 }
 
@@ -480,7 +599,7 @@
        
        /* allocate the TDs */
        for (i = 0; i < size; i++) { 
-               OHCI_ALLOC (urb_priv->td[i], sizeof (td_t));
+               OHCI_ALLOC_TD (ohci, urb_priv->td[i]);
                if (!urb_priv->td[i]) {
                        usb_dec_dev_use (urb->dev);     
                        urb_rm_priv (urb);
@@ -498,7 +617,7 @@
        /* for ISOC transfers calculate start frame index */
        if (urb->transfer_flags & USB_ISO_ASAP) { 
                urb->start_frame = ((ed->state == ED_OPER)? (ed->last_iso + 1): 
-                                                               (le16_to_cpu 
(ohci->hcca.frame_no) + 10)) & 0xffff;
+                                                               (le16_to_cpu 
+(ohci->hcca->frame_no) + 10)) & 0xffff;
        }       
        
        if (ed->state != ED_OPER)  /* link the ed into a chain if is not already */
@@ -567,6 +686,8 @@
 
 static int sohci_alloc_dev (struct usb_device *usb_dev)
 {
+        int i;
+        struct ohci *ohci = usb_dev->bus->hcpriv;
        struct ohci_device * dev;
 
        dev = kmalloc (sizeof (*dev), GFP_KERNEL);
@@ -575,6 +696,12 @@
                
        memset (dev, 0, sizeof (*dev));
 
+        for (i = 0; i < NUM_EDS; i++) {
+           dev->ed[i] = ohci_alloc_consistent_ed(ohci);
+           if (dev->ed[i] == NULL)
+              return -ENOMEM;
+        }
+
        usb_dev->hcpriv = dev;
 
        return 0;
@@ -600,13 +727,14 @@
                /* delete all TDs of all EDs */
                spin_lock_irqsave (&usb_ed_lock, flags);        
                for(i = 0; i < NUM_EDS; i++) {
-                       ed = &(dev->ed[i]);
+                       ed = dev->ed[i];
                        if (ed->state != ED_NEW) {
                                if (ed->state == ED_OPER) ep_unlink (ohci, ed);
                                ep_rm_ed (usb_dev, ed);
                                ed->state = ED_DEL;
                                cnt++;
                        }
+                        ohci_free_consistent_ed(ohci, ed);
                }
                spin_unlock_irqrestore (&usb_ed_lock, flags);
                
@@ -630,7 +758,7 @@
 {
        ohci_t * ohci = usb_dev->bus->hcpriv;
        
-       return le16_to_cpu (ohci->hcca.frame_no);
+       return le16_to_cpu (ohci->hcca->frame_no);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -711,9 +839,9 @@
        case CTRL:
                ed->hwNextED = 0;
                if (ohci->ed_controltail == NULL) {
-                       writel (virt_to_bus (ed), &ohci->regs->ed_controlhead);
+                       writel (ohci_virt_to_bus (ohci, ed), 
+&ohci->regs->ed_controlhead);
                } else {
-                       ohci->ed_controltail->hwNextED = cpu_to_le32 (virt_to_bus 
(ed));
+                       ohci->ed_controltail->hwNextED = cpu_to_le32 (ohci_virt_to_bus 
+(ohci, ed));
                }
                ed->ed_prev = ohci->ed_controltail;
                ohci->ed_controltail = edi;       
@@ -722,9 +850,9 @@
        case BULK:  
                ed->hwNextED = 0;
                if (ohci->ed_bulktail == NULL) {
-                       writel (virt_to_bus (ed), &ohci->regs->ed_bulkhead);
+                       writel (ohci_virt_to_bus (ohci, ed), &ohci->regs->ed_bulkhead);
                } else {
-                       ohci->ed_bulktail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
+                       ohci->ed_bulktail->hwNextED = cpu_to_le32 (ohci_virt_to_bus 
+(ohci, ed));
                }
                ed->ed_prev = ohci->ed_bulktail;
                ohci->ed_bulktail = edi;          
@@ -739,12 +867,12 @@
                
                for (i = 0; i < ep_rev (6, interval); i += inter) {
                        inter = 1;
-                       for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + 
int_branch]); 
-                               (*ed_p != 0) && (((ed_t *) bus_to_virt (le32_to_cpup 
(ed_p)))->int_interval >= interval); 
-                               ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup 
(ed_p)))->hwNextED)) 
-                                       inter = ep_rev (6, ((ed_t *) bus_to_virt 
(le32_to_cpup (ed_p)))->int_interval);
+                       for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + 
+int_branch]); 
+                               (*ed_p != 0) && (((ed_t *) ohci_bus_to_virt (ohci, 
+le32_to_cpup (ed_p)))->int_interval >= interval); 
+                               ed_p = &(((ed_t *) ohci_bus_to_virt (ohci, 
+le32_to_cpup (ed_p)))->hwNextED)) 
+                                       inter = ep_rev (6, ((ed_t *) ohci_bus_to_virt 
+(ohci, le32_to_cpup (ed_p)))->int_interval);
                        ed->hwNextED = *ed_p; 
-                       *ed_p = cpu_to_le32 (virt_to_bus (ed));
+                       *ed_p = cpu_to_le32 (ohci_virt_to_bus (ohci, ed));
                }
 #ifdef DEBUG
                ep_print_int_eds (ohci, "LINK_INT");
@@ -755,16 +883,16 @@
                ed->hwNextED = 0;
                ed->int_interval = 1;
                if (ohci->ed_isotail != NULL) {
-                       ohci->ed_isotail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
+                       ohci->ed_isotail->hwNextED = cpu_to_le32 (ohci_virt_to_bus 
+(ohci, ed));
                        ed->ed_prev = ohci->ed_isotail;
                } else {
                        for ( i = 0; i < 32; i += inter) {
                                inter = 1;
-                               for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); 
+                               for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i)]); 
                                        *ed_p != 0; 
-                                       ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup 
(ed_p)))->hwNextED)) 
-                                               inter = ep_rev (6, ((ed_t *) 
bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
-                               *ed_p = cpu_to_le32 (virt_to_bus (ed)); 
+                                       ed_p = &(((ed_t *) ohci_bus_to_virt (ohci, 
+le32_to_cpup (ed_p)))->hwNextED)) 
+                                               inter = ep_rev (6, ((ed_t *) 
+ohci_bus_to_virt (ohci, le32_to_cpup (ed_p)))->int_interval);
+                               *ed_p = cpu_to_le32 (ohci_virt_to_bus (ohci, ed));     
+ 
                        }       
                        ed->ed_prev = NULL;
                }       
@@ -803,7 +931,7 @@
                if(ohci->ed_controltail == ed) {
                        ohci->ed_controltail = ed->ed_prev;
                } else {
-                       ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev 
= ed->ed_prev;
+                       ((ed_t *) ohci_bus_to_virt (ohci, le32_to_cpup 
+(&ed->hwNextED)))->ed_prev = ed->ed_prev;
                }
                break;
       
@@ -816,7 +944,7 @@
                if (ohci->ed_bulktail == ed) {
                        ohci->ed_bulktail = ed->ed_prev;
                } else {
-                       ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev 
= ed->ed_prev;
+                       ((ed_t *) ohci_bus_to_virt (ohci, le32_to_cpup 
+(&ed->hwNextED)))->ed_prev = ed->ed_prev;
                }
                break;
       
@@ -825,11 +953,11 @@
                interval = ed->int_interval;
 
                for (i = 0; i < ep_rev (6, interval); i += inter) {
-                       for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + 
int_branch]), inter = 1; 
+                       for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + 
+int_branch]), inter = 1; 
                                (*ed_p != 0) && (*ed_p != ed->hwNextED); 
-                               ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup 
(ed_p)))->hwNextED), 
-                               inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup 
(ed_p)))->int_interval)) {                               
-                                       if(((ed_t *) bus_to_virt (le32_to_cpup 
(ed_p))) == ed) {
+                               ed_p = &(((ed_t *) ohci_bus_to_virt (ohci, 
+le32_to_cpup (ed_p)))->hwNextED), 
+                               inter = ep_rev (6, ((ed_t *) ohci_bus_to_virt (ohci, 
+le32_to_cpup (ed_p)))->int_interval)) {                            
+                                       if(((ed_t *) ohci_bus_to_virt (ohci, 
+le32_to_cpup (ed_p))) == ed) {
                                                *ed_p = ed->hwNextED;           
                                                break;
                                        }
@@ -846,18 +974,18 @@
        if (ohci->ed_isotail == ed)
                                ohci->ed_isotail = ed->ed_prev;
                if (ed->hwNextED != 0) 
-                               ((ed_t *) bus_to_virt (le32_to_cpup 
(&ed->hwNextED)))->ed_prev = ed->ed_prev;
+                               ((ed_t *) ohci_bus_to_virt (ohci, le32_to_cpup 
+(&ed->hwNextED)))->ed_prev = ed->ed_prev;
                                
                if (ed->ed_prev != NULL) {
                        ed->ed_prev->hwNextED = ed->hwNextED;
                } else {
                        for (i = 0; i < 32; i += inter) {
                                inter = 1;
-                               for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); 
+                               for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i)]); 
                                        *ed_p != 0; 
-                                       ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup 
(ed_p)))->hwNextED)) {
-                                               inter = ep_rev (6, ((ed_t *) 
bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
-                                               if(((ed_t *) bus_to_virt (le32_to_cpup 
(ed_p))) == ed) {
+                                       ed_p = &(((ed_t *) ohci_bus_to_virt (ohci, 
+le32_to_cpup (ed_p)))->hwNextED)) {
+                                               inter = ep_rev (6, ((ed_t *) 
+ohci_bus_to_virt (ohci, le32_to_cpup (ed_p)))->int_interval);
+                                               if(((ed_t *) ohci_bus_to_virt (ohci, 
+le32_to_cpup (ed_p))) == ed) {
                                                        *ed_p = ed->hwNextED;          
 
                                                        break;
                                                }
@@ -892,17 +1020,16 @@
        
        spin_lock (&usb_ed_lock);
 
-       ed = ed_ret = &(usb_to_ohci (usb_dev)->ed[(usb_pipeendpoint (pipe) << 1) | 
-                       (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]);
+       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)) 
                return NULL; /* pending delete request */
        
        if (ed->state == ED_NEW) {
                ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
-               OHCI_ALLOC (td, sizeof (*td)); /* dummy td; end of td list for ed */
+               OHCI_ALLOC_TD (ohci, td); /* dummy td; end of td list for ed */
                if(!td) return NULL; /* out of memory */
-               ed->hwTailP = cpu_to_le32 (virt_to_bus (td));
+               ed->hwTailP = cpu_to_le32 (ohci_virt_to_bus (ohci, td));
                ed->hwHeadP = ed->hwTailP;      
                ed->state = ED_UNLINK;
                ed->type = usb_pipetype (pipe);
@@ -945,7 +1072,7 @@
        writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
        writel (OHCI_INTR_SF, &ohci->regs->intrenable); /* enable sof interrupt */
 
-       frame = le16_to_cpu (ohci->hcca.frame_no) & 0x1;
+       frame = le16_to_cpu (ohci->hcca->frame_no) & 0x1;
        ed->ed_rm_list = ohci->ed_rm_list[frame];
        ohci->ed_rm_list[frame] = ed;
 
@@ -965,34 +1092,45 @@
 
 /* prepare a TD */
 
-static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int type, 
int index)
+static void td_fill (struct ohci *ohci, unsigned int info, dma_addr_t data, int len, 
+urb_t * urb, int type, int index)
 {
        volatile td_t  * td, * td_pt;
        urb_priv_t * urb_priv = urb->hcpriv;
 
+        if (urb_priv == NULL) return;
+
        if (index >= urb_priv->length) {
                err("internal OHCI error: TD index > length");
                return;
        }
        
        td_pt = urb_priv->td [index];
+        if (td_pt == NULL) return;
+
+
        /* fill the old dummy TD */
-       td = urb_priv->td [index] = (td_t *) bus_to_virt (le32_to_cpup 
(&urb_priv->ed->hwTailP) & 0xfffffff0);
+       td = urb_priv->td [index] = (td_t *) ohci_bus_to_virt (ohci, le32_to_cpup 
+(&urb_priv->ed->hwTailP) & 0xfffffff0);
+        if (td == NULL) return;
+
        td->ed = urb_priv->ed;
+
+        if (td->ed == NULL) return;
+
        td->index = index;
        td->urb = urb; 
        td->hwINFO = cpu_to_le32 (info);
        td->type = type;
        if ((td->ed->type & 3) == PIPE_ISOCHRONOUS) {
                td->hwCBP = cpu_to_le32 (((!data || !len)? 
-                                                               0 : virt_to_bus 
(data)) & 0xFFFFF000);
+                                          0 : data) & 0xFFFFF000);
                td->ed->last_iso = info & 0xffff;
        } else {
-               td->hwCBP = cpu_to_le32 (((!data || !len)? 0 : virt_to_bus (data))); 
+               td->hwCBP = cpu_to_le32 (((!data || !len)? 0 : data)); 
        }                       
-       td->hwBE = cpu_to_le32 ((!data || !len )? 0: virt_to_bus (data + len - 1));
-       td->hwNextTD = cpu_to_le32 (virt_to_bus (td_pt));
-       td->hwPSW [0] = cpu_to_le16 ((virt_to_bus (data) & 0x0FFF) | 0xE000);
+       td->hwBE = cpu_to_le32 ((!data || !len )? 0: (data + len - 1));
+       td->hwNextTD = cpu_to_le32 (ohci_virt_to_bus (ohci, td_pt));
+       td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
+
        td_pt->hwNextTD = 0;
        td->ed->hwTailP = td->hwNextTD;
    
@@ -1010,10 +1148,15 @@
        void * ctrl = urb->setup_packet;
        void * data = urb->transfer_buffer;
        int data_len = urb->transfer_buffer_length;
+        dma_addr_t dma_data = 
+           pci_map_single(ohci->consistent_storage.pci_dev,
+                          data, data_len, usb_pipeout (urb->pipe) ? PCI_DMA_TODEVICE 
+: PCI_DMA_FROMDEVICE);
        int cnt = 0; 
        __u32 info = 0;
        unsigned int toggle = 0;
 
+        urb_priv->transfer_buffer_dma_addr = dma_data;
+
        /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for 
reseting */
        if(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), 
usb_pipeout(urb->pipe))) {
                toggle = TD_T_TOGGLE;
@@ -1029,12 +1172,12 @@
                        info = usb_pipeout (urb->pipe)? 
                                TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
                        while(data_len > 4096) {                
-                               td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, 4096, 
urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
-                               data += 4096; data_len -= 4096; cnt++;
+                               td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), 
+dma_data, 4096, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
+                               dma_data += 4096; data_len -= 4096; cnt++;
                        }
                        info = usb_pipeout (urb->pipe)?
                                TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
-                       td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, data_len, 
urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
+                       td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), dma_data, 
+data_len, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
                        cnt++;
                        writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list 
*/
                        break;
@@ -1042,27 +1185,29 @@
                case PIPE_INTERRUPT:
                        info = usb_pipeout (urb->pipe)? 
                                TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | 
toggle;
-                       td_fill (info, data, data_len, urb, ST_ADDR | ADD_LEN, cnt++);
+                       td_fill (ohci, info, dma_data, data_len, urb, ST_ADDR | 
+ADD_LEN, cnt++);
                        break;
 
                case PIPE_CONTROL:
                        info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
-                       td_fill (info, ctrl, 8, urb, ST_ADDR, cnt++); 
+                       td_fill (ohci, info, 
+pci_map_single(ohci->consistent_storage.pci_dev, ctrl, 8, PCI_DMA_TODEVICE), 
+                                 8, urb, ST_ADDR, cnt++); 
                        if (data_len > 0) {  
                                info = usb_pipeout (urb->pipe)? 
                                        TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC 
| TD_R | TD_DP_IN | TD_T_DATA1;
-                               td_fill (info, data, data_len, urb, ADD_LEN, cnt++);  
+                               td_fill (ohci, info, dma_data, data_len, urb, ADD_LEN, 
+cnt++);  
                        } 
                        info = usb_pipeout (urb->pipe)? 
                                TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | 
TD_T_DATA1;
-                       td_fill (info, NULL, 0, urb, 0, cnt++);
+                       td_fill (ohci, info, (dma_addr_t)NULL, 0, urb, 0, cnt++);
                        writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control 
list */
                        break;
 
                case PIPE_ISOCHRONOUS:
                        for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
-                               td_fill (TD_CC|TD_ISO | ((urb->start_frame + cnt) & 
0xffff), 
-                                       (__u8 *) data + 
urb->iso_frame_desc[cnt].offset, 
+                               td_fill (ohci,
+                                         TD_CC|TD_ISO | ((urb->start_frame + cnt) & 
+0xffff), 
+                                        dma_data + urb->iso_frame_desc[cnt].offset, 
                                        urb->iso_frame_desc[cnt].length, urb, (cnt? 0: 
ST_ADDR) | ADD_LEN, cnt); 
                        }
                        break;
@@ -1088,11 +1233,11 @@
        
        spin_lock_irqsave (&usb_ed_lock, flags);
        
-       td_list_hc = le32_to_cpup (&ohci->hcca.done_head) & 0xfffffff0;
-       ohci->hcca.done_head = 0;
+       td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
+       ohci->hcca->done_head = 0;
        
        while (td_list_hc) {            
-               td_list = (td_t *) bus_to_virt (td_list_hc);
+               td_list = (td_t *) ohci_bus_to_virt (ohci, td_list_hc);
 
                if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
                        urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
@@ -1135,8 +1280,8 @@
        spin_lock_irqsave (&usb_ed_lock, flags);
        for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {
 
-               tdTailP = bus_to_virt (le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
-               tdHeadP = bus_to_virt (le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+               tdTailP = ohci_bus_to_virt (ohci, le32_to_cpup (&ed->hwTailP) & 
+0xfffffff0);
+               tdHeadP = ohci_bus_to_virt (ohci, le32_to_cpup (&ed->hwHeadP) & 
+0xfffffff0);
                edINFO = le32_to_cpup (&ed->hwINFO);
                td_p = &ed->hwHeadP;
                        
@@ -1144,7 +1289,7 @@
                        urb_t * urb = td->urb;
                        urb_priv_t * urb_priv = td->urb->hcpriv;
                        
-                       td_next = bus_to_virt (le32_to_cpup (&td->hwNextTD) & 
0xfffffff0);
+                       td_next = ohci_bus_to_virt (ohci, le32_to_cpup (&td->hwNextTD) 
+& 0xfffffff0);
                        if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
                                *td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
                                if(++ (urb_priv->td_cnt) == urb_priv->length) 
@@ -1156,7 +1301,7 @@
                }
                if (ed->state & ED_DEL) { /* set by sohci_free_dev */
                        struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 
0x7F]);
-                       OHCI_FREE (tdTailP); /* free dummy td */
+                       OHCI_FREE_TD (ohci, tdTailP); /* free dummy td */
                        ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); 
                        ed->state = ED_NEW; 
                        /* if all eds are removed wake up sohci_free_dev */
@@ -1235,9 +1380,9 @@
                        } else {
                                if (tdBE != 0) {
                                        if (td_list->hwCBP == 0)
-                                               urb->actual_length = bus_to_virt 
(tdBE) - urb->transfer_buffer + 1;
+                                                urb->actual_length = tdBE - 
+urb_priv->transfer_buffer_dma_addr + 1;
                                        else
-                                               urb->actual_length = bus_to_virt 
(tdCBP) - urb->transfer_buffer;
+                                                urb->actual_length = tdCBP - 
+urb_priv->transfer_buffer_dma_addr;
                            }
                        }
                }
@@ -1699,7 +1844,7 @@
        writel (0, &ohci->regs->ed_controlhead);
        writel (0, &ohci->regs->ed_bulkhead);
        
-       writel (virt_to_bus (&ohci->hcca), &ohci->regs->hcca); /* a reset clears this 
*/
+       writel (ohci->hcca_dma_addr, &ohci->regs->hcca); /* a reset clears this */
    
        fminterval = 0x2edf;
        writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
@@ -1751,14 +1896,14 @@
        struct ohci_regs * regs = ohci->regs;
        int ints; 
 
-       if ((ohci->hcca.done_head != 0) && !(le32_to_cpup (&ohci->hcca.done_head) & 
0x01)) {
+       if ((ohci->hcca->done_head != 0) && !(le32_to_cpup (&ohci->hcca->done_head) & 
+0x01)) {
                ints =  OHCI_INTR_WDH;
        } else { 
                if ((ints = (readl (&regs->intrstatus) & readl (&regs->intrenable))) 
== 0)
                        return;
        } 
 
-       // dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
+       // dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no));
 
        if (ints & OHCI_INTR_UE) {
                ohci->disabled++;
@@ -1778,7 +1923,7 @@
        }
 
        if (ints & OHCI_INTR_SF) { 
-               unsigned int frame = le16_to_cpu (ohci->hcca.frame_no) & 1;
+               unsigned int frame = le16_to_cpu (ohci->hcca->frame_no) & 1;
                writel (OHCI_INTR_SF, &regs->intrdisable);      
                if (ohci->ed_rm_list[!frame] != NULL) {
                        dl_del_list (ohci, !frame);
@@ -1793,30 +1938,39 @@
 
 /* allocate OHCI */
 
-static ohci_t * hc_alloc_ohci (void * mem_base)
+static ohci_t * hc_alloc_ohci (struct pci_dev *pdev, void * mem_base)
 {
        int i;
        ohci_t * ohci;
        struct usb_bus * bus;
+        int err;
 
        ohci = (ohci_t *) __get_free_pages (GFP_KERNEL, 1);
        if (!ohci)
                return NULL;
                
        memset (ohci, 0, sizeof (ohci_t));
+       ohci->hcca = (struct ohci_hcca *)pci_alloc_consistent(pdev, sizeof(struct 
+ohci_hcca), &ohci->hcca_dma_addr);
+        if (!ohci->hcca)
+                return NULL;
        
        ohci->irq = -1;
        ohci->regs = mem_base;   
 
        /* for load ballancing of the interrupt branches */
        for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
-       for (i = 0; i < NUM_INTS; i++) ohci->hcca.int_table[i] = 0;
+       for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table[i] = 0;
        
        /* end of control and bulk lists */      
        ohci->ed_isotail     = NULL;
        ohci->ed_controltail = NULL;
        ohci->ed_bulktail    = NULL;
 
+        if ((err = ohci_consistent_storage_create(pdev, &ohci->consistent_storage))) {
+           printk(KERN_ERR "hc_alloc_ohci: failed to allocate consistent storage: 
+err=%d\n", err);
+           return NULL;
+        }
+
        bus = usb_alloc_bus (&sohci_device_operations);
        if (!bus) {
                free_pages ((unsigned long) ohci, 1);
@@ -1878,7 +2032,7 @@
                (unsigned long) mem_base, bufp);
        printk(KERN_INFO __FILE__ ": %s\n", dev->name);
     
-       ohci = hc_alloc_ohci (mem_base);
+       ohci = hc_alloc_ohci (dev, mem_base);
        if (!ohci) {
                return -ENOMEM;
        }
Index: drivers/usb/usb-ohci.h
===================================================================
RCS file: /cvs/linux/kernel/drivers/usb/usb-ohci.h,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -w -r1.1.1.1 -r1.3
--- drivers/usb/usb-ohci.h      2000/05/03 22:12:55     1.1.1.1
+++ drivers/usb/usb-ohci.h      2000/05/04 15:51:38     1.3
@@ -374,21 +374,39 @@
        __u16 td_cnt;   // number of tds already serviced
        int   state;
        void * wait;
+        dma_addr_t transfer_buffer_dma_addr;
        td_t * td[0];   // list pointer to all corresponding TDs associated with this 
request
 
 } urb_priv_t;
 #define URB_DEL 1
 
+
 /*
+ * In order to use the pci_alloc_consistent interface to allocate ED's and
+ * TD's, we need to keep a mapping between the virtual addresses and the
+ * dma addresses.  We do this using a kmem_cache, allowing it a single slab
+ * only.
+ */
+
+struct ohci_consistent_storage {
+        char *virt;
+        dma_addr_t dma_addr;
+        long virt_to_dma;
+        ed_t *edlist; /* freelist of eds */
+        td_t *tdlist; /* freelist of tds */
+        struct pci_dev *pci_dev;
+};
+
+/*
  * This is the full ohci controller description
  *
  * Note how the "proper" USB information is just
  * a subset of what the full implementation needs. (Linus)
  */
 
-
 typedef struct ohci {
-       struct ohci_hcca hcca;          /* hcca */
+       struct ohci_hcca *hcca;         /* hcca */
+        dma_addr_t  hcca_dma_addr;
 
        int irq;
        int disabled;                   /* e.g. got a UE, we're hung */
@@ -410,6 +428,7 @@
        struct usb_bus * bus;    
        struct usb_device * dev[128];
        struct virt_root_hub rh;
+        struct ohci_consistent_storage consistent_storage;
 } ohci_t;
 
 
@@ -417,7 +436,7 @@
 #define NUM_EDS 32             /* num of preallocated endpoint descriptors */
 
 struct ohci_device {
-       ed_t    ed[NUM_EDS];
+       ed_t    *ed[NUM_EDS];
        int ed_cnt;
        void  * wait;
 };
@@ -432,7 +451,7 @@
 static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, 
int load);
 static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed);
 /* td */
-static void td_fill(unsigned int info, void * data, int len, urb_t * urb, int type, 
int index);
+static void td_fill(struct ohci *, unsigned int info, dma_addr_t data, int len, urb_t 
+* urb, int type, int index);
 static void td_submit_urb(urb_t * urb);
 /* root hub */
 static int rh_submit_urb(urb_t * urb);
@@ -440,11 +459,11 @@
 static int rh_init_int_timer(urb_t * urb);
 
 #ifdef DEBUG
-#define OHCI_FREE(x) kfree(x); printk("OHCI FREE: %d: %4x\n", -- __ohci_free_cnt, 
(unsigned int) x)
-#define OHCI_ALLOC(x,size) (x) = kmalloc(size, in_interrupt() ? GFP_ATOMIC : 
GFP_KERNEL); printk("OHCI ALLO: %d: %4x\n", ++ __ohci_free_cnt,(unsigned int) x)
+#define OHCI_FREE_TD(ohci,x) ohci_free_consistent_td(ohci, x); printk("OHCI FREE: %d: 
+%4x\n", -- __ohci_free_cnt, (unsigned int) x)
+#define OHCI_ALLOC_TD(ohci,x) (x) = ohci_alloc_consistent_td(ohci); printk("OHCI 
+ALLO: %d: %4x\n", ++ __ohci_free_cnt,(unsigned int) x)
 static int __ohci_free_cnt = 0;
 #else
-#define OHCI_FREE(x) kfree(x) 
-#define OHCI_ALLOC(x,size) (x) = kmalloc(size, in_interrupt() ? GFP_ATOMIC : 
GFP_KERNEL) 
+#define OHCI_FREE_TD(ohci, x) ohci_free_consistent_td(ohci, x) 
+#define OHCI_ALLOC_TD(ohci, x) (x) = ohci_alloc_consistent_td(ohci) 
 #endif
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to