The state of ohci-hcd on SA-111 is looking good.

The current set of sources in the usb-2.5 bk respository (which are
2.5.21++) combined with the following arm-specific patch (an updated
patch #1167) work better than any previous set of sources in my
experience.

There are still a few glitches here and there.  I am investigating
each to see if it is SA-1111 specific or not.

The bad news: usb-ohci-sa1111 is broken.  I've decide I am not going
to bother fixing it since that code is getting stale and it has been
abandoned on i386.  (It is probably something simple, if anyone cares,
because both drivers were working as recently as yesterday.)

-- 
-ch
mailto:[EMAIL PROTECTED]
mailto:[EMAIL PROTECTED]

p.s. I tried to update the patch #1167 in the patch system with the
following, but the mailer on *.arm.linux.org.uk flamed out on me.


------------------------------------------------------------------------

[PATCH] SA-1111 "fake" PCI support for USB (Patch #1167)

Comprehensive patch superseding 1167/1:

   -- fix several oopsen in the SA-1111 "fake" PCI support

   -- re-write of the SA-1111 DMA bug "bounce buffer" workaround

   -- merge latest drivers/pci/pool.c into mach-sa1100/pcipool.c (pool
      allocation debugging follows CONFIG_DEBUG_SLAB a la pci/pool.c)


$TOP/arch/arm/mach-sa1100/pcipool.h can be deleted
(unrelated: $TOP/arch/arm/mach-sa1100/sa1111-ohci.c can be deleted)

Applies to 2.5.18-rmk1.  Need to back port to 2.4.x.

(This patch is required for SA-1111 OHCI code that is part of 2.5.21.)



--- linux-2.5.18-rmk1/include/asm-arm/pci.h     Fri May 24 18:55:23 2002
+++ linux-2.5.18-rmk1-ch3/include/asm-arm/pci.h Tue Jun 11 14:15:05 2002
@@ -12,6 +12,8 @@
 
 struct pci_dev;
 
+#define SA1111_FAKE_PCIDEV ((struct pci_dev *) 1)
+
 static inline void pcibios_set_master(struct pci_dev *dev)
 {
        /* No special bus mastering setup handling */
@@ -65,11 +67,10 @@ pci_map_single(struct pci_dev *hwdev, vo
        extern dma_addr_t sa1111_map_single(struct pci_dev *, void *, size_t, int);
 
        /*
-        * for SA1111 these functions are "magic" and relocate buffers.  We
-        * only need to do these if hwdev is non-null; otherwise we expect
-        * the buffer to already be suitable for DMA.
+        * For SA-1111 these functions are "magic" and utilize bounce
+        * buffers as need to workaround SA-1111 DMA bugs.
         */
-       if (hwdev != NULL)
+       if (hwdev == SA1111_FAKE_PCIDEV)
                return sa1111_map_single(hwdev, ptr, size, direction);
 #endif
        consistent_sync(ptr, size, direction);
@@ -89,7 +90,11 @@ pci_unmap_single(struct pci_dev *hwdev, 
 #ifdef CONFIG_SA1111
        extern void sa1111_unmap_single(struct pci_dev *, dma_addr_t, size_t, int);
 
-       if (hwdev != NULL)
+       /*
+        * For SA-1111 these functions are "magic" and utilize bounce
+        * buffers as need to workaround SA-1111 DMA bugs.
+        */
+       if (hwdev == SA1111_FAKE_PCIDEV)
                sa1111_unmap_single(hwdev, dma_addr, size, direction);
 #endif
        /* nothing to do */
@@ -99,7 +104,7 @@ pci_unmap_single(struct pci_dev *hwdev, 
  * Whether pci_unmap_{single,page} is a nop depends upon the
  * configuration.
  */
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) || defined(CONFIG_SA1111)
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)      dma_addr_t ADDR_NAME;
 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)                __u32 LEN_NAME;
 #define pci_unmap_addr(PTR, ADDR_NAME)         ((PTR)->ADDR_NAME)
@@ -135,6 +140,11 @@ pci_map_sg(struct pci_dev *hwdev, struct
 {
        int i;
 
+#ifdef CONFIG_SA1111
+       /* we haven't made this work yet. */
+       BUG_ON(hwdev == SA1111_FAKE_PCIDEV);
+#endif
+
        for (i = 0; i < nents; i++, sg++) {
                char *virt;
 
@@ -168,6 +178,18 @@ pci_unmap_sg(struct pci_dev *hwdev, stru
 static inline void
 pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int 
direction)
 {
+#ifdef CONFIG_SA1111
+       extern dma_addr_t sa1111_map_sync_single(struct pci_dev *, dma_addr_t, int, 
+int);
+
+       /*
+        * For SA-1111 these functions are "magic" and utilize bounce
+        * buffers as need to workaround SA-1111 DMA bugs.
+        */
+       if (hwdev == SA1111_FAKE_PCIDEV) {
+               sa1111_map_sync_single(hwdev, dma_handle, size, direction);
+               return;
+       }
+#endif
        consistent_sync(bus_to_virt(dma_handle), size, direction);
 }
 
@@ -203,6 +225,18 @@ static inline int pci_dma_supported(stru
 
 /* Return the index of the PCI controller for device PDEV. */
 #define pci_controller_num(PDEV)       (0)
+
+#if defined(CONFIG_SA1111) && !defined(CONFIG_PCI)
+/* SA-1111 needs these prototypes even when !defined(CONFIG_PCI) */
+
+/* kmem_cache style wrapper around pci_alloc_consistent() */
+struct pci_pool *pci_pool_create (const char *name, struct pci_dev *dev,
+               size_t size, size_t align, size_t allocation, int flags);
+void pci_pool_destroy (struct pci_pool *pool);
+
+void *pci_pool_alloc (struct pci_pool *pool, int flags, dma_addr_t *handle);
+void pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t addr);
+#endif
 
 #endif /* __KERNEL__ */
  
diff -x *led* -x sa1111.c -x vmlinux.lds -X ../dontdiff.txt -Naurp 
linux-2.5.18-rmk1/arch/arm/mach-sa1100/Makefile 
linux-2.5.18-rmk1-ch3/arch/arm/mach-sa1100/Makefile
--- linux-2.5.18-rmk1/arch/arm/mach-sa1100/Makefile     Fri May 24 18:55:31 2002
+++ linux-2.5.18-rmk1-ch3/arch/arm/mach-sa1100/Makefile Tue Jun 11 12:27:16 2002
@@ -26,8 +26,7 @@ obj-$(CONFIG_SA1100_PT_SYSTEM3)               += cpu-
 endif
 
 # Next, the SA1111 stuff.
-obj-$(CONFIG_SA1111)           += sa1111.o
-obj-$(CONFIG_USB_OHCI_SA1111)  += sa1111-pcibuf.o pcipool.o
+obj-$(CONFIG_SA1111)           += sa1111.o sa1111-pcibuf.o pcipool.o
 
 # Specific board support
 obj-$(CONFIG_SA1100_ADSBITSY)          += adsbitsy.o
diff -x *led* -x sa1111.c -x vmlinux.lds -X ../dontdiff.txt -Naurp 
linux-2.5.18-rmk1/arch/arm/mach-sa1100/pcipool.c 
linux-2.5.18-rmk1-ch3/arch/arm/mach-sa1100/pcipool.c
--- linux-2.5.18-rmk1/arch/arm/mach-sa1100/pcipool.c    Fri May 24 18:55:20 2002
+++ linux-2.5.18-rmk1-ch3/arch/arm/mach-sa1100/pcipool.c        Tue Jun 11 12:22:26 
+2002
@@ -20,7 +20,8 @@
 
 #include <asm/page.h>
 
-#include "pcipool.h"
+#define CONFIG_PCIPOOL_DEBUG
+
 
 /*
  * Pool allocator ... wraps the pci_alloc_consistent page allocator, so
@@ -33,7 +34,6 @@ struct pci_pool {     /* the pool */
        spinlock_t              lock;
        size_t                  blocks_per_page;
        size_t                  size;
-       int                     flags;
        struct pci_dev          *dev;
        size_t                  allocation;
        char                    name [32];
@@ -50,7 +50,17 @@ struct pci_page {    /* cacheable header fo
 #define        POOL_TIMEOUT_JIFFIES    ((100 /* msec */ * HZ) / 1000)
 #define        POOL_POISON_BYTE        0xa7
 
-// #define CONFIG_PCIPOOL_DEBUG
+static inline const char *slot_name(const struct pci_pool *pool)
+{
+       const struct pci_dev *pdev = pool->dev;
+
+       if (pdev == 0)
+               return "[?]";
+       else if (pdev == SA1111_FAKE_PCIDEV)
+               return "[SA-1111]";
+       else
+               return pdev->slot_name;
+}
 
 
 /**
@@ -60,7 +70,7 @@ struct pci_page {     /* cacheable header fo
  * @size: size of the blocks in this pool.
  * @align: alignment requirement for blocks; must be a power of two
  * @allocation: returned blocks won't cross this boundary (or zero)
- * @flags: SLAB_* flags (not all are supported).
+ * @mem_flags: SLAB_* flags.
  *
  * Returns a pci allocation pool with the requested characteristics, or
  * null if one can't be created.  Given one of these pools, pci_pool_alloc()
@@ -76,7 +86,7 @@ struct pci_page {     /* cacheable header fo
  */
 struct pci_pool *
 pci_pool_create (const char *name, struct pci_dev *pdev,
-       size_t size, size_t align, size_t allocation, int flags)
+       size_t size, size_t align, size_t allocation, int mem_flags)
 {
        struct pci_pool         *retval;
 
@@ -100,13 +110,9 @@ pci_pool_create (const char *name, struc
        } else if (allocation < size)
                return 0;
 
-       if (!(retval = kmalloc (sizeof *retval, flags)))
+       if (!(retval = kmalloc (sizeof *retval, mem_flags)))
                return retval;
 
-#ifdef CONFIG_PCIPOOL_DEBUG
-       flags |= SLAB_POISON;
-#endif
-
        strncpy (retval->name, name, sizeof retval->name);
        retval->name [sizeof retval->name - 1] = 0;
 
@@ -114,14 +120,13 @@ pci_pool_create (const char *name, struc
        INIT_LIST_HEAD (&retval->page_list);
        spin_lock_init (&retval->lock);
        retval->size = size;
-       retval->flags = flags;
        retval->allocation = allocation;
        retval->blocks_per_page = allocation / size;
        init_waitqueue_head (&retval->waitq);
 
 #ifdef CONFIG_PCIPOOL_DEBUG
        printk (KERN_DEBUG "pcipool create %s/%s size %d, %d/page (%d alloc)\n",
-               pdev ? pdev->slot_name : NULL, retval->name, size,
+               slot_name(retval), retval->name, size,
                retval->blocks_per_page, allocation);
 #endif
 
@@ -143,11 +148,13 @@ pool_alloc_page (struct pci_pool *pool, 
        if (!page)
                return 0;
        page->vaddr = pci_alloc_consistent (pool->dev,
-                               pool->allocation, &page->dma);
+                                           pool->allocation,
+                                           &page->dma);
        if (page->vaddr) {
                memset (page->bitmap, 0xff, mapsize);   // bit set == free
-               if (pool->flags & SLAB_POISON)
-                       memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+#ifdef CONFIG_DEBUG_SLAB
+               memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+#endif
                list_add (&page->page_list, &pool->page_list);
        } else {
                kfree (page);
@@ -173,8 +180,9 @@ pool_free_page (struct pci_pool *pool, s
 {
        dma_addr_t      dma = page->dma;
 
-       if (pool->flags & SLAB_POISON)
-               memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+#ifdef CONFIG_DEBUG_SLAB
+       memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+#endif
        pci_free_consistent (pool->dev, pool->allocation, page->vaddr, dma);
        list_del (&page->page_list);
        kfree (page);
@@ -195,8 +203,7 @@ pci_pool_destroy (struct pci_pool *pool)
 
 #ifdef CONFIG_PCIPOOL_DEBUG
        printk (KERN_DEBUG "pcipool destroy %s/%s\n",
-               pool->dev ? pool->dev->slot_name : NULL,
-               pool->name);
+               slot_name(pool), pool->name);
 #endif
 
        spin_lock_irqsave (&pool->lock, flags);
@@ -206,8 +213,7 @@ pci_pool_destroy (struct pci_pool *pool)
                                struct pci_page, page_list);
                if (is_page_busy (pool->blocks_per_page, page->bitmap)) {
                        printk (KERN_ERR "pci_pool_destroy %s/%s, %p busy\n",
-                               pool->dev ? pool->dev->slot_name : NULL,
-                               pool->name, page->vaddr);
+                               slot_name(pool), pool->name, page->vaddr);
                        /* leak the still-in-use consistent memory */
                        list_del (&page->page_list);
                        kfree (page);
@@ -327,35 +333,32 @@ pci_pool_free (struct pci_pool *pool, vo
        int                     map, block;
 
        if ((page = pool_find_page (pool, dma)) == 0) {
-               printk (KERN_ERR "pci_pool_free %s/%s, %p/%x (bad dma)\n",
+               printk (KERN_ERR "pci_pool_free %s/%s, %p/%lx (bad dma)\n",
                        pool->dev ? pool->dev->slot_name : NULL,
-                       pool->name, vaddr, dma);
+                       pool->name, vaddr, (unsigned long) dma);
                return;
        }
-#ifdef CONFIG_PCIPOOL_DEBUG
-       if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
-               printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%x\n",
-                       pool->dev ? pool->dev->slot_name : NULL,
-                       pool->name, vaddr, dma);
-               return;
-       }
-#endif
 
        block = dma - page->dma;
        block /= pool->size;
        map = block / BITS_PER_LONG;
        block %= BITS_PER_LONG;
 
-#ifdef CONFIG_PCIPOOL_DEBUG
+#ifdef CONFIG_DEBUG_SLAB
+       if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
+               printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%lx\n",
+                       pool->dev ? pool->dev->slot_name : NULL,
+                       pool->name, vaddr, (unsigned long) dma);
+               return;
+       }
        if (page->bitmap [map] & (1UL << block)) {
                printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n",
                        pool->dev ? pool->dev->slot_name : NULL,
                        pool->name, dma);
                return;
        }
+       memset (vaddr, POOL_POISON_BYTE, pool->size);
 #endif
-       if (pool->flags & SLAB_POISON)
-               memset (vaddr, POOL_POISON_BYTE, pool->size);
 
        spin_lock_irqsave (&pool->lock, flags);
        set_bit (block, &page->bitmap [map]);
@@ -374,4 +377,3 @@ EXPORT_SYMBOL (pci_pool_create);
 EXPORT_SYMBOL (pci_pool_destroy);
 EXPORT_SYMBOL (pci_pool_alloc);
 EXPORT_SYMBOL (pci_pool_free);
-
diff -x *led* -x sa1111.c -x vmlinux.lds -X ../dontdiff.txt -Naurp 
linux-2.5.18-rmk1/arch/arm/mach-sa1100/pcipool.h 
linux-2.5.18-rmk1-ch3/arch/arm/mach-sa1100/pcipool.h
--- linux-2.5.18-rmk1/arch/arm/mach-sa1100/pcipool.h    Fri May 24 18:55:17 2002
+++ linux-2.5.18-rmk1-ch3/arch/arm/mach-sa1100/pcipool.h        Wed Dec 31 16:00:00 
+1969
@@ -1,8 +0,0 @@
-
-struct pci_pool *pci_pool_create (const char *name, struct pci_dev *dev,
-               size_t size, size_t align, size_t allocation, int flags);
-void pci_pool_destroy (struct pci_pool *pool);
-
-void *pci_pool_alloc (struct pci_pool *pool, int flags, dma_addr_t *handle);
-void pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t addr);
-
diff -x *led* -x sa1111.c -x vmlinux.lds -X ../dontdiff.txt -Naurp 
linux-2.5.18-rmk1/arch/arm/mach-sa1100/sa1111-pcibuf.c 
linux-2.5.18-rmk1-ch3/arch/arm/mach-sa1100/sa1111-pcibuf.c
--- linux-2.5.18-rmk1/arch/arm/mach-sa1100/sa1111-pcibuf.c      Fri May 24 18:55:17 
2002
+++ linux-2.5.18-rmk1-ch3/arch/arm/mach-sa1100/sa1111-pcibuf.c  Tue Jun 11 14:26:07 
+2002
@@ -1,272 +1,332 @@
 /*
  *  linux/arch/arm/mach-sa1100/pci-sa1111.c
  *
- *  Special pci_map/unmap_single routines for SA-1111.   These functions
- *  compensate for a bug in the SA-1111 hardware which don't allow DMA
- *  to/from addresses above 1MB.
+ *  Special pci_map/unmap_single routines for SA-1111.  
  *
- *  Brad Parker ([EMAIL PROTECTED])
+ *  These functions utilize bouncer buffers to compensate for a bug in
+ *  the SA-1111 hardware which don't allow DMA to/from addresses
+ *  certain addresses above 1MB. (See sa1111.c:sa1111_check_dma_bug()
+ *  for details.)
  *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
+ *  Re-written by Christopher Hoover <[EMAIL PROTECTED]>
+ *  Original version by Brad Parker ([EMAIL PROTECTED])
  *
- *  06/13/2001 - created.
- */
+ *  Copyright (C) 2002 Hewlett Packard Company.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  version 2 as published by the Free Software Foundation.
+ * */
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/list.h>
 
-#include "pcipool.h"
+struct safe_buffer {
+       struct list_head node;
 
-/*
- * simple buffer allocator for copying of unsafe to safe buffers
- * uses __alloc/__free for actual buffers
- * keeps track of safe buffers we've allocated so we can recover the
- * unsafe buffers.
- */
+       /* original request */
+       void            *ptr;
+       size_t          size;
+       int             direction;
+
+       /* safe buffer info */
+       struct pci_pool *pool;
+       void            *safe;
+       dma_addr_t      safe_dma_addr;
+};
+
+extern int sa1111_check_dma_bug(dma_addr_t addr);
+
+//#define DEBUG
+#ifdef DEBUG
+#define DPRINTK(...) do { printk(KERN_DEBUG __VA_ARGS__); } while (0)
+#else
+#define DPRINTK(...) do { } while (0)
+#endif
 
-#define MAX_SAFE       32
-#define SIZE_SMALL     1024
-#define SIZE_LARGE     (16*1024)
 
-static long mapped_alloc_size;
-static char *safe_buffers[MAX_SAFE][2];
 
+#define SIZE_SMALL     1024
+#define SIZE_LARGE     (16*1024)
 
 static struct pci_pool *small_buffer_cache, *large_buffer_cache;
+LIST_HEAD(safe_buffers);
 
-static int
-init_safe_buffers(struct pci_dev *dev)
+static int __init
+init_safe_buffers(void)
 {
-       small_buffer_cache = pci_pool_create("pci_small_buffer",
-                                           dev,
-                                           SIZE_SMALL,
-                                           0 /* byte alignment */,
-                                           0 /* no page-crossing issues */,
-                                           GFP_KERNEL | GFP_DMA);
-
-       if (small_buffer_cache == 0)
+       small_buffer_cache = pci_pool_create("sa1111_small_dma_buffer",
+                                            0,
+                                            SIZE_SMALL,
+                                            0 /* byte alignment */,
+                                            0 /* no page-crossing issues */,
+                                            GFP_KERNEL | GFP_DMA);
+
+       if (0 == small_buffer_cache) {
+               printk(KERN_ERR __FUNCTION__ 
+                      ": could not allocate small pci pool\n");
                return -1;
+       }
 
-       large_buffer_cache = pci_pool_create("pci_large_buffer",
-                                           dev,
-                                           SIZE_LARGE,
-                                           0 /* byte alignment */,
-                                           0 /* no page-crossing issues */,
-                                           GFP_KERNEL | GFP_DMA);
-       if (large_buffer_cache == 0)
+       large_buffer_cache = pci_pool_create("sa111_large_dma_buffer",
+                                            0,
+                                            SIZE_LARGE,
+                                            0 /* byte alignment */,
+                                            0 /* no page-crossing issues */,
+                                            GFP_KERNEL | GFP_DMA);
+       if (0 == large_buffer_cache) {
+               printk(KERN_ERR __FUNCTION__ 
+                      ": could not allocate large pci pool\n");
                return -1;
+       }
 
        return 0;
 }
 
 /* allocate a 'safe' buffer and keep track of it */
-static char *
-alloc_safe_buffer(char *unsafe, int size, dma_addr_t *pbus)
+static struct safe_buffer *
+alloc_safe_buffer(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
 {
-       char *safe;
-       dma_addr_t busptr;
+       void *safe;
+       dma_addr_t safe_dma_addr;
        struct pci_pool *pool;
-       int i;
+       struct safe_buffer *buf;
 
-       if (0) printk("alloc_safe_buffer(size=%d)\n", size);
+       DPRINTK(__FUNCTION__ "(ptr=%p, size=%d, direction=%d)\n", 
+               ptr, size, direction);
 
        if (size <= SIZE_SMALL)
                pool = small_buffer_cache;
-       else
-               if (size < SIZE_LARGE)
-                       pool = large_buffer_cache;
-                               else
-                                       return 0;
-
-       safe = pci_pool_alloc(pool, SLAB_ATOMIC, &busptr);
-       if (safe == 0)
+       else if (size < SIZE_LARGE)
+               pool = large_buffer_cache;
+       else {
+               BUG();                  // eventually use pci_alloc_consistent
                return 0;
-
-       for (i = 0; i < MAX_SAFE; i++)
-               if (safe_buffers[i][0] == 0) {
-                       break;
-               }
-
-       if (i == MAX_SAFE) {
-               panic(__FILE__ ": exceeded MAX_SAFE buffers");
        }
 
-       /* place the size index and the old buffer ptr in the first 8 bytes
-        * and return a ptr + 12 to caller
-        */
-       ((int *)safe)[0] = i;
-       ((char **)safe)[1] = (char *)pool;
-       ((char **)safe)[2] = unsafe;
-
-       busptr += sizeof(int) + sizeof(char *) + sizeof(char *);
-
-       safe_buffers[i][0] = (void *)busptr;
-       safe_buffers[i][1] = (void *)safe;
+       safe = pci_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr);
+       if (safe == 0) {
+               return 0;
+       }               
+       
+       //BUG_ON(sa1111_check_dma_bug(safe_dma_addr));  // paranoia
+
+       buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC);
+       buf->ptr = ptr;
+       buf->size = size;
+       buf->direction = direction;
+       buf->pool = pool;
+       buf->safe = safe;
+       buf->safe_dma_addr = safe_dma_addr;
 
-       safe += sizeof(int) + sizeof(char *) + sizeof(char *);
+       list_add(&buf->node, &safe_buffers);
 
-       *pbus = busptr;
-       return safe;
+       return buf;
 }
 
 /* determine if a buffer is from our "safe" pool */
-static char *
-find_safe_buffer(char *busptr, char **unsafe)
+static struct safe_buffer *
+find_safe_buffer(dma_addr_t safe_dma_addr)
 {
-       int i;
-       char *buf;
+       struct list_head *entry;
 
-       for (i = 0; i < MAX_SAFE; i++) {
-               if (safe_buffers[i][0] == busptr) {
-                       if (0) printk("find_safe_buffer(%p) found @ %d\n", busptr, i);
-                       buf = safe_buffers[i][1];
-                       *unsafe = ((char **)buf)[2];
-                       return buf + sizeof(int) + sizeof(char *) + sizeof(char *);
+       list_for_each(entry, &safe_buffers) {
+               struct safe_buffer *b = 
+                       list_entry(entry, struct safe_buffer, node);
+
+               if (b->safe_dma_addr == safe_dma_addr) {
+                       return b;
                }
        }
 
-       return (char *)0;
+       return 0;
 }
 
 static void
-free_safe_buffer(char *buf)
+free_safe_buffer(struct safe_buffer *buf)
 {
-       int index;
-       struct pci_pool *pool;
-       char *dma;
+       DPRINTK(__FUNCTION__ "(buf=%p)\n", buf);
 
-       if (0) printk("free_safe_buffer(buf=%p)\n", buf);
-
-       /* retrieve the buffer size index */
-       buf -= sizeof(int) + sizeof(char*) + sizeof(char*);
-       index = ((int *)buf)[0];
-       pool = (struct pci_pool *)((char **)buf)[1];
-
-       if (0) printk("free_safe_buffer(%p) index %d\n",
-                     buf, index);
-
-       if (index < 0 || index >= MAX_SAFE) {
-               printk(__FILE__ ": free_safe_buffer() corrupt buffer\n");
-               return;
-       }
-
-       dma = safe_buffers[index][0];
-       safe_buffers[index][0] = 0;
-
-       pci_pool_free(pool, buf, (u32)dma);
+       list_del(&buf->node);
+       pci_pool_free(buf->pool, buf->safe, buf->safe_dma_addr);
+       kfree(buf);
 }
 
 /*
-  NOTE:
-  replace pci_map/unmap_single with local routines which will
-  do buffer copies if buffer is above 1mb...
-*/
-
-/*
  * see if a buffer address is in an 'unsafe' range.  if it is
  * allocate a 'safe' buffer and copy the unsafe buffer into it.
  * substitute the safe buffer for the unsafe one.
  * (basically move the buffer from an unsafe area to a safe one)
- *
- * we assume calls to map_single are symmetric with calls to unmap_single...
  */
 dma_addr_t
-sa1111_map_single(struct pci_dev *hwdev, void *virtptr,
-              size_t size, int direction)
+sa1111_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
 {
-       dma_addr_t busptr;
-
-       mapped_alloc_size += size;
-
-       if (0) printk("pci_map_single(hwdev=%p,ptr=%p,size=%d,dir=%x) "
-                     "alloced=%ld\n",
-                     hwdev, virtptr, size, direction, mapped_alloc_size);
+       unsigned long flags;
+       dma_addr_t dma_addr;
 
-       busptr = virt_to_bus(virtptr);
+       DPRINTK(__FUNCTION__ "(hwdev=%p,ptr=%p,size=%d,dir=%x)\n",
+              hwdev, ptr, size, direction);
 
-       /* we assume here that a buffer will never be >=64k */
-       if ( (((unsigned long)busptr) & 0x100000) ||
-            ((((unsigned long)busptr)+size) & 0x100000) )
-       {
-               char *safe;
-
-               safe = alloc_safe_buffer(virtptr, size, &busptr);
-               if (safe == 0) {
-                       printk("unable to map unsafe buffer %p!\n", virtptr);
+       BUG_ON(hwdev != SA1111_FAKE_PCIDEV);
+       BUG_ON(direction == PCI_DMA_NONE);
+       
+       local_irq_save(flags);
+
+       dma_addr = virt_to_bus(ptr);
+
+       if (sa1111_check_dma_bug(dma_addr)) {
+               struct safe_buffer *buf;
+
+               buf = alloc_safe_buffer(hwdev, ptr, size, direction);
+               if (buf == 0) {
+                       printk(KERN_ERR __FUNCTION__ 
+                              ": unable to map unsafe buffer %p!\n", ptr);
+                       local_irq_restore(flags);
                        return 0;
                }
 
-               if (0) printk("unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",
-                             virtptr, (void *)virt_to_bus(virtptr),
-                             safe, (void *)busptr);
-
-               memcpy(safe, virtptr, size);
-               consistent_sync(safe, size, direction);
-
-               return busptr;
+               DPRINTK(__FUNCTION__
+                      ": unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",
+                      buf->ptr, (void *) virt_to_bus(buf->ptr),
+                      buf->safe, (void *) buf->safe_dma_addr);
+
+               if ((direction == PCI_DMA_TODEVICE) || 
+                   (direction == PCI_DMA_BIDIRECTIONAL)) {
+                       DPRINTK(__FUNCTION__ 
+                              ": copy out from unsafe %p, to safe %p, size %d\n",
+                              ptr, buf->safe, size);
+                       memcpy(buf->safe, ptr, size);
+               }
+               consistent_sync(buf->safe, size, direction);
+               
+               dma_addr = buf->safe_dma_addr;
+       } else {
+               consistent_sync(ptr, size, direction);
        }
 
-       consistent_sync(virtptr, size, direction);
-       return busptr;
+       local_irq_restore(flags);
+       return dma_addr;
 }
 
 /*
- * see if a mapped address was really a "safe" buffer and if so,
- * copy the data from the safe buffer back to the unsafe buffer
- * and free up the safe buffer.
- * (basically return things back to the way they should be)
+ * see if a mapped address was really a "safe" buffer and if so, copy
+ * the data from the safe buffer back to the unsafe buffer and free up
+ * the safe buffer.  (basically return things back to the way they
+ * should be) 
  */
+
 void
 sa1111_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
-                size_t size, int direction)
+                   size_t size, int direction)
 {
-       char *safe, *unsafe;
-       void *buf;
+       unsigned long flags;
+       struct safe_buffer *buf;
+
+       DPRINTK(__FUNCTION__ "(hwdev=%p,ptr=%p,size=%d,dir=%x)\n",
+              hwdev, (void *) dma_addr, size, direction);
 
-       /* hack; usb-ohci.c never sends hwdev==NULL, all others do */
-       if (hwdev == NULL) {
-               return;
+       BUG_ON(hwdev != SA1111_FAKE_PCIDEV);
+       BUG_ON(direction == PCI_DMA_NONE);
+
+       local_irq_save(flags);
+
+       buf = find_safe_buffer(dma_addr);
+       if (buf) {
+               BUG_ON(buf->size != size);
+               BUG_ON(buf->direction != direction);
+
+               DPRINTK(__FUNCTION__
+                      ": unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",
+                      buf->ptr, (void *) virt_to_bus(buf->ptr),
+                      buf->safe, (void *) buf->safe_dma_addr);
+
+               if ((direction == PCI_DMA_FROMDEVICE) ||
+                   (direction == PCI_DMA_BIDIRECTIONAL)) {
+                       DPRINTK(__FUNCTION__ 
+                              ": copy back from safe %p, to unsafe %p size %d\n",
+                              buf->safe, buf->ptr, size);
+                       memcpy(buf->ptr, buf->safe, size);
+               }
+               free_safe_buffer(buf);
        }
 
-       mapped_alloc_size -= size;
+       local_irq_restore(flags);
+}
+
+void
+sa1111_map_sync_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+                      size_t size, int direction)
+{
+       unsigned long flags;
+       struct safe_buffer *buf;
+
+       DPRINTK(__FUNCTION__ "(hwdev=%p,ptr=%p,size=%d,dir=%x)\n",
+              hwdev, (void *) dma_addr, size, direction);
 
-       if (0) printk("pci_unmap_single(hwdev=%p,ptr=%p,size=%d,dir=%x) "
-                     "alloced=%ld\n",
-                     hwdev, (void *)dma_addr, size, direction,
-                     mapped_alloc_size);
-
-       if ((safe = find_safe_buffer((void *)dma_addr, &unsafe))) {
-               if (0) printk("copyback unsafe %p, safe %p, size %d\n",
-                             unsafe, safe, size);
-
-               consistent_sync(safe, size, PCI_DMA_FROMDEVICE);
-               memcpy(unsafe, safe, size);
-               free_safe_buffer(safe);
+       BUG_ON(hwdev != SA1111_FAKE_PCIDEV);
+
+       local_irq_save(flags);
+
+       buf = find_safe_buffer(dma_addr);
+       if (buf) {
+               BUG_ON(buf->size != size);
+               BUG_ON(buf->direction != direction);
+
+               DPRINTK(__FUNCTION__
+                      ": unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",
+                      buf->ptr, (void *) virt_to_bus(buf->ptr),
+                      buf->safe, (void *) buf->safe_dma_addr);
+
+               switch (direction) {
+               case PCI_DMA_FROMDEVICE:
+                       DPRINTK(__FUNCTION__ 
+                              ": copy back from safe %p, to unsafe %p size %d\n",
+                              buf->safe, buf->ptr, size);
+                       memcpy(buf->ptr, buf->safe, size);
+                       break;
+               case PCI_DMA_TODEVICE:
+                       DPRINTK(__FUNCTION__ 
+                              ": copy out from unsafe %p, to safe %p, size %d\n",
+                               buf->ptr, buf->safe, size);
+                       memcpy(buf->safe, buf->ptr, size);
+                       break;
+               case PCI_DMA_BIDIRECTIONAL:
+                       BUG();  /* is this allowed?  what does it mean? */
+               default:
+                       BUG();
+               }
+               consistent_sync(buf->safe, size, direction);
        } else {
-               /* assume this is normal memory */
-               buf = bus_to_virt(dma_addr);
-               consistent_sync(buf, size, PCI_DMA_FROMDEVICE);
+               consistent_sync(bus_to_virt(dma_addr), size, direction);
        }
+
+       local_irq_restore(flags);
 }
 
 EXPORT_SYMBOL(sa1111_map_single);
 EXPORT_SYMBOL(sa1111_unmap_single);
+EXPORT_SYMBOL(sa1111_map_sync_single);
 
-static int __init sa1111_init_safe_buffers(void)
+
+static void __init sa1111_pcibuf_init(void)
 {
-       printk("Initializing SA1111 buffer pool for DMA workaround\n");
-       init_safe_buffers(NULL);
-       return 0;
+       MOD_INC_USE_COUNT;      /* don't unload; not safe yet */
+
+       printk(KERN_INFO "Initializing SA1111 buffer pool for DMA workaround\n");
+
+       init_safe_buffers();
 }
+module_init(sa1111_pcibuf_init);
 
-static void free_safe_buffers(void)
+static void sa1111_pcibuf_exit(void)
 {
-       pci_pool_destroy(small_buffer_cache);
-       pci_pool_destroy(large_buffer_cache);
+       if (list_empty(&safe_buffers)) {
+               pci_pool_destroy(small_buffer_cache);
+               pci_pool_destroy(large_buffer_cache);
+       } else
+               printk(KERN_DEBUG __FUNCTION__ ": outstanding safe buffers\n");
 }
-
-module_init(sa1111_init_safe_buffers);
-module_exit(free_safe_buffers);
+module_exit(sa1111_pcibuf_exit);
diff -x *led* -x sa1111.c -x vmlinux.lds -X ../dontdiff.txt -Naurp 
linux-2.5.18-rmk1/arch/arm/mm/consistent.c 
linux-2.5.18-rmk1-ch3/arch/arm/mm/consistent.c
--- linux-2.5.18-rmk1/arch/arm/mm/consistent.c  Fri May 24 18:55:21 2002
+++ linux-2.5.18-rmk1-ch3/arch/arm/mm/consistent.c      Tue Jun 11 12:22:26 2002
@@ -98,7 +98,8 @@ void *pci_alloc_consistent(struct pci_de
 {
        int gfp = GFP_KERNEL;
 
-       if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
+       if (hwdev == NULL || hwdev == SA1111_FAKE_PCIDEV ||
+           hwdev->dma_mask != 0xffffffff)
                gfp |= GFP_DMA;
 
        return consistent_alloc(gfp, size, handle);


_______________________________________________________________

Multimillion Dollar Computer Inventory
Live Webcast Auctions Thru Aug. 2002 - http://www.cowanalexander.com/calendar



_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to