/*
- * linux/arch/arm/mach-sa1100/pci-sa1111.c
+ * linux/arch/arm/mach-sa1100/sa1111-pcibuf.c
*
- * Special pci_{map/unmap/dma_sync}_* routines for SA-1111.
+ * Special dma_{map/unmap/dma_sync}_* routines for SA-1111.
*
* These functions utilize bouncer buffers to compensate for a bug in
* the SA-1111 hardware which don't allow DMA to/from addresses
* version 2 as published by the Free Software Foundation.
* */
+//#define DEBUG
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
#include <asm/hardware/sa1111.h>
-//#define DEBUG
-#ifdef DEBUG
-#define DPRINTK(...) do { printk(KERN_DEBUG __VA_ARGS__); } while (0)
-#else
-#define DPRINTK(...) do { } while (0)
-#endif
-
//#define STATS
#ifdef STATS
#define DO_STATS(X) do { X ; } while (0)
/* original request */
void *ptr;
size_t size;
- int direction;
+ enum dma_data_direction direction;
/* safe buffer info */
- struct pci_pool *pool;
+ struct dma_pool *pool;
void *safe;
dma_addr_t safe_dma_addr;
+ struct device *dev;
};
static LIST_HEAD(safe_buffers);
#define SIZE_SMALL 1024
#define SIZE_LARGE (4*1024)
-static struct pci_pool *small_buffer_pool, *large_buffer_pool;
+static struct dma_pool *small_buffer_pool, *large_buffer_pool;
#ifdef STATS
static unsigned long sbp_allocs __initdata = 0;
static void print_alloc_stats(void)
{
printk(KERN_INFO
- "sa1111_pcibuf: sbp: %lu, lbp: %lu, other: %lu, total: %lu\n",
+ "sa1111_dmabuf: sbp: %lu, lbp: %lu, other: %lu, total: %lu\n",
sbp_allocs, lbp_allocs,
total_allocs - sbp_allocs - lbp_allocs, total_allocs);
}
#endif
-static int __init
-create_safe_buffer_pools(void)
+static int __init create_safe_buffer_pools(void)
{
- small_buffer_pool = pci_pool_create("sa1111_small_dma_buffer",
- SA1111_FAKE_PCIDEV,
- SIZE_SMALL,
+ small_buffer_pool = dma_pool_create("sa1111_small_dma_buffer",
+ NULL, SIZE_SMALL,
0 /* byte alignment */,
0 /* no page-crossing issues */);
- if (0 == small_buffer_pool) {
+ if (small_buffer_pool == NULL) {
printk(KERN_ERR
- "sa1111_pcibuf: could not allocate small pci pool\n");
- return -1;
+ "sa1111_dmabuf: could not allocate small pci pool\n");
+ return -ENOMEM;
}
- large_buffer_pool = pci_pool_create("sa1111_large_dma_buffer",
- SA1111_FAKE_PCIDEV,
- SIZE_LARGE,
+ large_buffer_pool = dma_pool_create("sa1111_large_dma_buffer",
+ NULL, SIZE_LARGE,
0 /* byte alignment */,
0 /* no page-crossing issues */);
- if (0 == large_buffer_pool) {
+ if (large_buffer_pool == NULL) {
printk(KERN_ERR
- "sa1111_pcibuf: could not allocate large pci pool\n");
- pci_pool_destroy(small_buffer_pool);
- small_buffer_pool = 0;
- return -1;
+ "sa1111_dmabuf: could not allocate large pci pool\n");
+ dma_pool_destroy(small_buffer_pool);
+ small_buffer_pool = NULL;
+ return -ENOMEM;
}
- printk(KERN_INFO
- "sa1111_pcibuf: buffer sizes: small=%u, large=%u\n",
+ printk(KERN_INFO "SA1111: DMA buffer sizes: small=%u, large=%u\n",
SIZE_SMALL, SIZE_LARGE);
return 0;
}
-static void __exit
-destroy_safe_buffer_pools(void)
+static void __exit destroy_safe_buffer_pools(void)
{
if (small_buffer_pool)
- pci_pool_destroy(small_buffer_pool);
+ dma_pool_destroy(small_buffer_pool);
if (large_buffer_pool)
- pci_pool_destroy(large_buffer_pool);
+ dma_pool_destroy(large_buffer_pool);
- small_buffer_pool = large_buffer_pool = 0;
+ small_buffer_pool = large_buffer_pool = NULL;
}
/* allocate a 'safe' buffer and keep track of it */
-static struct safe_buffer *
-alloc_safe_buffer(void *ptr, size_t size, int direction)
+static struct safe_buffer *alloc_safe_buffer(struct device *dev, void *ptr,
+ size_t size,
+ enum dma_data_direction dir)
{
struct safe_buffer *buf;
- struct pci_pool *pool;
+ struct dma_pool *pool;
void *safe;
dma_addr_t safe_dma_addr;
- DPRINTK("%s(ptr=%p, size=%d, direction=%d)\n",
- __func__, ptr, size, direction);
+ dev_dbg(dev, "%s(ptr=%p, size=%d, direction=%d)\n",
+ __func__, ptr, size, dir);
DO_STATS ( total_allocs++ );
buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC);
- if (buf == 0) {
+ if (buf == NULL) {
printk(KERN_WARNING "%s: kmalloc failed\n", __func__);
return 0;
}
if (size <= SIZE_SMALL) {
pool = small_buffer_pool;
- safe = pci_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr);
+ safe = dma_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr);
DO_STATS ( sbp_allocs++ );
} else if (size <= SIZE_LARGE) {
pool = large_buffer_pool;
- safe = pci_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr);
+ safe = dma_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr);
DO_STATS ( lbp_allocs++ );
} else {
- pool = 0;
- safe = pci_alloc_consistent(SA1111_FAKE_PCIDEV, size,
- &safe_dma_addr);
+ pool = NULL;
+ safe = dma_alloc_coherent(dev, size, &safe_dma_addr, GFP_ATOMIC);
}
- if (safe == 0) {
+ if (safe == NULL) {
printk(KERN_WARNING
"%s: could not alloc dma memory (size=%d)\n",
__func__, size);
buf->ptr = ptr;
buf->size = size;
- buf->direction = direction;
+ buf->direction = dir;
buf->pool = pool;
buf->safe = safe;
buf->safe_dma_addr = safe_dma_addr;
+ buf->dev = dev;
- MOD_INC_USE_COUNT;
list_add(&buf->node, &safe_buffers);
return buf;
}
/* determine if a buffer is from our "safe" pool */
-static struct safe_buffer *
-find_safe_buffer(dma_addr_t safe_dma_addr)
+static struct safe_buffer *find_safe_buffer(struct device *dev,
+ dma_addr_t safe_dma_addr)
{
struct list_head *entry;
struct safe_buffer *b =
list_entry(entry, struct safe_buffer, node);
- if (b->safe_dma_addr == safe_dma_addr) {
+ if (b->safe_dma_addr == safe_dma_addr &&
+ b->dev == dev) {
return b;
}
}
return 0;
}
-static void
-free_safe_buffer(struct safe_buffer *buf)
+static void free_safe_buffer(struct safe_buffer *buf)
{
- DPRINTK("%s(buf=%p)\n", __func__, buf);
+ pr_debug("%s(buf=%p)\n", __func__, buf);
list_del(&buf->node);
if (buf->pool)
- pci_pool_free(buf->pool, buf->safe, buf->safe_dma_addr);
+ dma_pool_free(buf->pool, buf->safe, buf->safe_dma_addr);
else
- pci_free_consistent(SA1111_FAKE_PCIDEV, buf->size, buf->safe,
- buf->safe_dma_addr);
+ dma_free_coherent(buf->dev, buf->size, buf->safe,
+ buf->safe_dma_addr);
kfree(buf);
-
- MOD_DEC_USE_COUNT;
}
-static inline int
-dma_range_is_safe(dma_addr_t addr, size_t size)
+static inline int dma_range_is_safe(struct device *dev, dma_addr_t addr,
+ size_t size)
{
unsigned int physaddr = SA1111_DMA_ADDR((unsigned int) addr);
static void print_map_stats(void)
{
printk(KERN_INFO
- "sa1111_pcibuf: map_op_count=%lu, bounce_count=%lu\n",
+ "sa1111_dmabuf: map_op_count=%lu, bounce_count=%lu\n",
map_op_count, bounce_count);
}
#endif
-static dma_addr_t
-map_single(void *ptr, size_t size, int direction)
+static dma_addr_t map_single(struct device *dev, void *ptr,
+ size_t size, enum dma_data_direction dir)
{
dma_addr_t dma_addr;
dma_addr = virt_to_bus(ptr);
- if (!dma_range_is_safe(dma_addr, size)) {
+ if (!dma_range_is_safe(dev, dma_addr, size)) {
struct safe_buffer *buf;
DO_STATS ( bounce_count++ ) ;
- buf = alloc_safe_buffer(ptr, size, direction);
- if (buf == 0) {
+ buf = alloc_safe_buffer(dev, ptr, size, dir);
+ if (buf == NULL) {
printk(KERN_ERR
"%s: unable to map unsafe buffer %p!\n",
__func__, ptr);
return 0;
}
- DPRINTK("%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",
+ dev_dbg(dev, "%s: unsafe buffer %p (phy=%08lx) mapped to %p (phy=%08x)\n",
__func__,
- buf->ptr, (void *) virt_to_bus(buf->ptr),
- buf->safe, (void *) buf->safe_dma_addr);
+ buf->ptr, virt_to_bus(buf->ptr),
+ buf->safe, buf->safe_dma_addr);
- if ((direction == PCI_DMA_TODEVICE) ||
- (direction == PCI_DMA_BIDIRECTIONAL)) {
- DPRINTK("%s: copy out from unsafe %p, to safe %p, size %d\n",
+ if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) {
+ dev_dbg(dev, "%s: copy out from unsafe %p, to safe %p, size %d\n",
__func__, 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);
+ ptr = buf->safe;
}
+ consistent_sync(ptr, size, dir);
+
#ifdef STATS
if (map_op_count % 1000 == 0)
print_map_stats();
return dma_addr;
}
-static void
-unmap_single(dma_addr_t dma_addr, size_t size, int direction)
+static void unmap_single(struct device *dev, dma_addr_t dma_addr,
+ size_t size, enum dma_data_direction dir)
{
struct safe_buffer *buf;
- buf = find_safe_buffer(dma_addr);
+ buf = find_safe_buffer(dev, dma_addr);
if (buf) {
BUG_ON(buf->size != size);
- BUG_ON(buf->direction != direction);
+ BUG_ON(buf->direction != dir);
- DPRINTK("%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",
+ dev_dbg(dev, "%s: unsafe buffer %p (phy=%08lx) mapped to %p (phy=%08lx)\n",
__func__,
- buf->ptr, (void *) virt_to_bus(buf->ptr),
- buf->safe, (void *) buf->safe_dma_addr);
-
+ buf->ptr, virt_to_bus(buf->ptr),
+ buf->safe, buf->safe_dma_addr);
DO_STATS ( bounce_count++ );
- if ((direction == PCI_DMA_FROMDEVICE) ||
- (direction == PCI_DMA_BIDIRECTIONAL)) {
- DPRINTK("%s: copy back from safe %p, to unsafe %p size %d\n",
+ if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) {
+ dev_dbg(dev, "%s: copy back from safe %p, to unsafe %p size %d\n",
__func__, buf->safe, buf->ptr, size);
memcpy(buf->ptr, buf->safe, size);
}
}
}
-static void
-sync_single(dma_addr_t dma_addr, size_t size, int direction)
+static void sync_single(struct device *dev, dma_addr_t dma_addr,
+ size_t size, enum dma_data_direction dir)
{
struct safe_buffer *buf;
+ void *ptr;
- buf = find_safe_buffer(dma_addr);
+ buf = find_safe_buffer(dev, dma_addr);
if (buf) {
BUG_ON(buf->size != size);
- BUG_ON(buf->direction != direction);
+ BUG_ON(buf->direction != dir);
- DPRINTK("%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",
+ dev_dbg(dev, "%s: unsafe buffer %p (phy=%08lx) mapped to %p (phy=%08lx)\n",
__func__,
- buf->ptr, (void *) virt_to_bus(buf->ptr),
- buf->safe, (void *) buf->safe_dma_addr);
+ buf->ptr, virt_to_bus(buf->ptr),
+ buf->safe, buf->safe_dma_addr);
DO_STATS ( bounce_count++ );
- switch (direction) {
- case PCI_DMA_FROMDEVICE:
- DPRINTK("%s: copy back from safe %p, to unsafe %p size %d\n",
+ switch (dir) {
+ case DMA_FROM_DEVICE:
+ dev_dbg(dev, "%s: copy back from safe %p, to unsafe %p size %d\n",
__func__, buf->safe, buf->ptr, size);
memcpy(buf->ptr, buf->safe, size);
break;
- case PCI_DMA_TODEVICE:
- DPRINTK("%s: copy out from unsafe %p, to safe %p, size %d\n",
+ case DMA_TO_DEVICE:
+ dev_dbg(dev, "%s: copy out from unsafe %p, to safe %p, size %d\n",
__func__,buf->ptr, buf->safe, size);
memcpy(buf->safe, buf->ptr, size);
break;
- case PCI_DMA_BIDIRECTIONAL:
+ case DMA_BIDIRECTIONAL:
BUG(); /* is this allowed? what does it mean? */
default:
BUG();
}
- consistent_sync(buf->safe, size, direction);
+ ptr = buf->safe;
} else {
- consistent_sync(bus_to_virt(dma_addr), size, direction);
+ ptr = bus_to_virt(dma_addr);
}
+ consistent_sync(ptr, size, dir);
}
/* ************************************************** */
* substitute the safe buffer for the unsafe one.
* (basically move the buffer from an unsafe area to a safe one)
*/
-dma_addr_t
-sa1111_map_single(void *ptr, size_t size, int direction)
+dma_addr_t sa1111_map_single(struct device *dev, void *ptr,
+ size_t size, enum dma_data_direction dir)
{
unsigned long flags;
dma_addr_t dma_addr;
- DPRINTK("%s(ptr=%p,size=%d,dir=%x)\n",
- __func__, ptr, size, direction);
+ dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
+ __func__, ptr, size, dir);
- BUG_ON(direction == PCI_DMA_NONE);
+ BUG_ON(dir == DMA_NONE);
local_irq_save(flags);
- dma_addr = map_single(ptr, size, direction);
+ dma_addr = map_single(dev, ptr, size, dir);
local_irq_restore(flags);
* the safe buffer. (basically return things back to the way they
* should be)
*/
-
-void
-sa1111_unmap_single(dma_addr_t dma_addr, size_t size, int direction)
+void sa1111_unmap_single(struct device *dev, dma_addr_t dma_addr,
+ size_t size, enum dma_data_direction dir)
{
unsigned long flags;
- DPRINTK("%s(ptr=%p,size=%d,dir=%x)\n",
- __func__, (void *) dma_addr, size, direction);
-
- BUG_ON(direction == PCI_DMA_NONE);
+ dev_dbg(dev, "%s(ptr=%08lx,size=%d,dir=%x)\n",
+ __func__, dma_addr, size, dir);
local_irq_save(flags);
- unmap_single(dma_addr, size, direction);
+ unmap_single(dev, dma_addr, size, dir);
local_irq_restore(flags);
}
-int
-sa1111_map_sg(struct scatterlist *sg, int nents, int direction)
+int sa1111_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
{
unsigned long flags;
int i;
- DPRINTK("%s(sg=%p,nents=%d,dir=%x)\n",
- __func__, sg, nents, direction);
+ dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
+ __func__, sg, nents, dir);
- BUG_ON(direction == PCI_DMA_NONE);
+ BUG_ON(dir == DMA_NONE);
local_irq_save(flags);
unsigned int length = sg->length;
void *ptr = page_address(page) + offset;
- sg->dma_address =
- map_single(ptr, length, direction);
+ sg->dma_address = map_single(dev, ptr, length, dir);
}
local_irq_restore(flags);
return nents;
}
-void
-sa1111_unmap_sg(struct scatterlist *sg, int nents, int direction)
+void sa1111_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
{
unsigned long flags;
int i;
- DPRINTK("%s(sg=%p,nents=%d,dir=%x)\n",
- __func__, sg, nents, direction);
-
- BUG_ON(direction == PCI_DMA_NONE);
+ dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
+ __func__, sg, nents, dir);
local_irq_save(flags);
dma_addr_t dma_addr = sg->dma_address;
unsigned int length = sg->length;
- unmap_single(dma_addr, length, direction);
+ unmap_single(dev, dma_addr, length, dir);
}
local_irq_restore(flags);
}
-void
-sa1111_dma_sync_single(dma_addr_t dma_addr, size_t size, int direction)
+void sa1111_dma_sync_single(struct device *dev, dma_addr_t dma_addr,
+ size_t size, enum dma_data_direction dir)
{
unsigned long flags;
- DPRINTK("%s(ptr=%p,size=%d,dir=%x)\n",
- __func__, (void *) dma_addr, size, direction);
+ dev_dbg(dev, "%s(ptr=%08lx,size=%d,dir=%x)\n",
+ __func__, dma_addr, size, dir);
local_irq_save(flags);
- sync_single(dma_addr, size, direction);
+ sync_single(dev, dma_addr, size, dir);
local_irq_restore(flags);
}
-void
-sa1111_dma_sync_sg(struct scatterlist *sg, int nents, int direction)
+void sa1111_dma_sync_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
{
unsigned long flags;
int i;
- DPRINTK("%s(sg=%p,nents=%d,dir=%x)\n",
- __func__, sg, nents, direction);
-
- BUG_ON(direction == PCI_DMA_NONE);
+ dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
+ __func__, sg, nents, dir);
local_irq_save(flags);
dma_addr_t dma_addr = sg->dma_address;
unsigned int length = sg->length;
- sync_single(dma_addr, length, direction);
+ sync_single(dev, dma_addr, length, dir);
}
local_irq_restore(flags);
/* **************************************** */
-static int __init sa1111_pcibuf_init(void)
+static int __init sa1111_dmabuf_init(void)
{
- int ret;
-
- printk(KERN_DEBUG
- "sa1111_pcibuf: initializing SA-1111 DMA workaround\n");
-
- ret = create_safe_buffer_pools();
+ printk(KERN_DEBUG "sa1111_dmabuf: initializing SA-1111 DMA buffers\n");
- return ret;
+ return create_safe_buffer_pools();
}
-module_init(sa1111_pcibuf_init);
+module_init(sa1111_dmabuf_init);
-static void __exit sa1111_pcibuf_exit(void)
+static void __exit sa1111_dmabuf_exit(void)
{
BUG_ON(!list_empty(&safe_buffers));
destroy_safe_buffer_pools();
}
-module_exit(sa1111_pcibuf_exit);
+module_exit(sa1111_dmabuf_exit);
MODULE_AUTHOR("Christopher Hoover <ch@hpl.hp.com>");
-MODULE_DESCRIPTION("Special pci_{map/unmap/dma_sync}_* routines for SA-1111.");
+MODULE_DESCRIPTION("Special dma_{map/unmap/dma_sync}_* routines for SA-1111.");
MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- NOTE:
-
- this code was lifted straight out of drivers/pci/pci.c;
- when compiling for the Intel StrongARM SA-1110/SA-1111 the
- usb-ohci.c driver needs these routines even when the architecture
- has no pci bus...
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/bitops.h>
-
-#include <asm/page.h>
-
-/*
- * Pool allocator ... wraps the pci_alloc_consistent page allocator, so
- * small blocks are easily used by drivers for bus mastering controllers.
- * This should probably be sharing the guts of the slab allocator.
- */
-
-struct pci_pool { /* the pool */
- struct list_head page_list;
- spinlock_t lock;
- size_t blocks_per_page;
- size_t size;
- struct pci_dev *dev;
- size_t allocation;
- char name [32];
- wait_queue_head_t waitq;
-};
-
-struct pci_page { /* cacheable header for 'allocation' bytes */
- struct list_head page_list;
- void *vaddr;
- dma_addr_t dma;
- unsigned long bitmap [0];
-};
-
-#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)
-{
- struct pci_dev *pdev = (struct pci_dev *)pool->dev;
-
- if (pdev == 0)
- return "[0]";
-
- else if (pcidev_is_sa1111(pdev))
- return "[SA-1111]";
- else
- return pci_name(pdev);
-}
-
-
-/**
- * pci_pool_create - Creates a pool of pci consistent memory blocks, for dma.
- * @name: name of pool, for diagnostics
- * @pdev: pci device that will be doing the DMA
- * @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)
- * Context: !in_interrupt()
- *
- * 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()
- * may be used to allocate memory. Such memory will all have "consistent"
- * DMA mappings, accessible by the device and its driver without using
- * cache flushing primitives. The actual size of blocks allocated may be
- * larger than requested because of alignment.
- *
- * If allocation is nonzero, objects returned from pci_pool_alloc() won't
- * cross that size boundary. This is useful for devices which have
- * addressing restrictions on individual DMA transfers, such as not crossing
- * boundaries of 4KBytes.
- */
-struct pci_pool *
-pci_pool_create (const char *name, struct pci_dev *pdev,
- size_t size, size_t align, size_t allocation)
-{
- struct pci_pool *retval;
-
- if (align == 0)
- align = 1;
- if (size == 0)
- return 0;
- else if (size < align)
- size = align;
- else if ((size % align) != 0) {
- size += align + 1;
- size &= ~(align - 1);
- }
-
- if (allocation == 0) {
- if (PAGE_SIZE < size)
- allocation = size;
- else
- allocation = PAGE_SIZE;
- // FIXME: round up for less fragmentation
- } else if (allocation < size)
- return 0;
-
- if (!(retval = kmalloc (sizeof *retval, SLAB_KERNEL)))
- return retval;
-
- strlcpy (retval->name, name, sizeof retval->name);
-
- retval->dev = pdev;
- INIT_LIST_HEAD (&retval->page_list);
- spin_lock_init (&retval->lock);
- retval->size = size;
- 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",
- slot_name(retval), retval->name, size,
- retval->blocks_per_page, allocation);
-#endif
-
- return retval;
-}
-
-
-static struct pci_page *
-pool_alloc_page (struct pci_pool *pool, int mem_flags)
-{
- struct pci_page *page;
- int mapsize;
-
- mapsize = pool->blocks_per_page;
- mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG;
- mapsize *= sizeof (long);
-
- page = (struct pci_page *) kmalloc (mapsize + sizeof *page, mem_flags);
- if (!page)
- return 0;
- page->vaddr = pci_alloc_consistent (pool->dev,
- pool->allocation,
- &page->dma);
- if (page->vaddr) {
- memset (page->bitmap, 0xff, mapsize); // bit set == free
-#ifdef CONFIG_DEBUG_SLAB
- memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
-#endif
- list_add (&page->page_list, &pool->page_list);
- } else {
- kfree (page);
- page = 0;
- }
- return page;
-}
-
-
-static inline int
-is_page_busy (int blocks, unsigned long *bitmap)
-{
- while (blocks > 0) {
- if (*bitmap++ != ~0UL)
- return 1;
- blocks -= BITS_PER_LONG;
- }
- return 0;
-}
-
-static void
-pool_free_page (struct pci_pool *pool, struct pci_page *page)
-{
- dma_addr_t dma = page->dma;
-
-#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);
-}
-
-
-/**
- * pci_pool_destroy - destroys a pool of pci memory blocks.
- * @pool: pci pool that will be destroyed
- *
- * Caller guarantees that no more memory from the pool is in use,
- * and that nothing will try to use the pool after this call.
- */
-void
-pci_pool_destroy (struct pci_pool *pool)
-{
- unsigned long flags;
-
-#ifdef CONFIG_PCIPOOL_DEBUG
- printk (KERN_DEBUG "pcipool destroy %s/%s\n",
- slot_name(pool), pool->name);
-#endif
-
- spin_lock_irqsave (&pool->lock, flags);
- while (!list_empty (&pool->page_list)) {
- struct pci_page *page;
- page = list_entry (pool->page_list.next,
- 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",
- slot_name(pool), pool->name, page->vaddr);
- /* leak the still-in-use consistent memory */
- list_del (&page->page_list);
- kfree (page);
- } else
- pool_free_page (pool, page);
- }
- spin_unlock_irqrestore (&pool->lock, flags);
- kfree (pool);
-}
-
-
-/**
- * pci_pool_alloc - get a block of consistent memory
- * @pool: pci pool that will produce the block
- * @mem_flags: SLAB_KERNEL or SLAB_ATOMIC
- * @handle: pointer to dma address of block
- *
- * This returns the kernel virtual address of a currently unused block,
- * and reports its dma address through the handle.
- * If such a memory block can't be allocated, null is returned.
- */
-void *
-pci_pool_alloc (struct pci_pool *pool, int mem_flags, dma_addr_t *handle)
-{
- unsigned long flags;
- struct list_head *entry;
- struct pci_page *page;
- int map, block;
- size_t offset;
- void *retval;
-
-restart:
- spin_lock_irqsave (&pool->lock, flags);
- list_for_each (entry, &pool->page_list) {
- int i;
- page = list_entry (entry, struct pci_page, page_list);
- /* only cachable accesses here ... */
- for (map = 0, i = 0;
- i < pool->blocks_per_page;
- i += BITS_PER_LONG, map++) {
- if (page->bitmap [map] == 0)
- continue;
- block = ffz (~ page->bitmap [map]);
- if ((i + block) < pool->blocks_per_page) {
- clear_bit (block, &page->bitmap [map]);
- offset = (BITS_PER_LONG * map) + block;
- offset *= pool->size;
- goto ready;
- }
- }
- }
- if (!(page = pool_alloc_page (pool, mem_flags))) {
- if (mem_flags == SLAB_KERNEL) {
- DECLARE_WAITQUEUE (wait, current);
-
- current->state = TASK_INTERRUPTIBLE;
- add_wait_queue (&pool->waitq, &wait);
- spin_unlock_irqrestore (&pool->lock, flags);
-
- schedule_timeout (POOL_TIMEOUT_JIFFIES);
-
- remove_wait_queue (&pool->waitq, &wait);
- goto restart;
- }
- retval = 0;
- goto done;
- }
-
- clear_bit (0, &page->bitmap [0]);
- offset = 0;
-ready:
- retval = offset + page->vaddr;
- *handle = offset + page->dma;
-done:
- spin_unlock_irqrestore (&pool->lock, flags);
- return retval;
-}
-
-
-static struct pci_page *
-pool_find_page (struct pci_pool *pool, dma_addr_t dma)
-{
- unsigned long flags;
- struct list_head *entry;
- struct pci_page *page;
-
- spin_lock_irqsave (&pool->lock, flags);
- list_for_each (entry, &pool->page_list) {
- page = list_entry (entry, struct pci_page, page_list);
- if (dma < page->dma)
- continue;
- if (dma < (page->dma + pool->allocation))
- goto done;
- }
- page = 0;
-done:
- spin_unlock_irqrestore (&pool->lock, flags);
- return page;
-}
-
-
-/**
- * pci_pool_free - put block back into pci pool
- * @pool: the pci pool holding the block
- * @vaddr: virtual address of block
- * @dma: dma address of block
- *
- * Caller promises neither device nor driver will again touch this block
- * unless it is first re-allocated.
- */
-void
-pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t dma)
-{
- struct pci_page *page;
- unsigned long flags;
- int map, block;
-
- if ((page = pool_find_page (pool, dma)) == 0) {
- printk (KERN_ERR "pci_pool_free %s/%s, %p/%lx (bad dma)\n",
- pool->dev ? pci_name(pool->dev) : NULL,
- pool->name, vaddr, (unsigned long) dma);
- return;
- }
-
- block = dma - page->dma;
- block /= pool->size;
- map = block / BITS_PER_LONG;
- block %= BITS_PER_LONG;
-
-#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 ? pci_name(pool->dev) : 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 ? pci_name(pool->dev) : NULL,
- pool->name, dma);
- return;
- }
- memset (vaddr, POOL_POISON_BYTE, pool->size);
-#endif
-
- spin_lock_irqsave (&pool->lock, flags);
- set_bit (block, &page->bitmap [map]);
- if (waitqueue_active (&pool->waitq))
- wake_up (&pool->waitq);
- /*
- * Resist a temptation to do
- * if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page);
- * it is not interrupt safe. Better have empty pages hang around.
- */
- spin_unlock_irqrestore (&pool->lock, flags);
-}
-
-EXPORT_SYMBOL (pci_pool_create);
-EXPORT_SYMBOL (pci_pool_destroy);
-EXPORT_SYMBOL (pci_pool_alloc);
-EXPORT_SYMBOL (pci_pool_free);
-
-/* **************************************** */
-
-static int __init pcipool_init(void)
-{
- MOD_INC_USE_COUNT; /* never unload */
-
- return 0;
-}
-module_init(pcipool_init);
-
-MODULE_LICENSE("GPL");