Commit 6f221c06 authored by Russell King's avatar Russell King

[ARM] Update sa1111-pcibuf for dmapool changes.

- use dev_dbg for device-centric debugging messages
- use pr_debug for general debugging messages
- use dmapools instead of pcipools
- use NULL rather than 0 for NULL pointers
- use enum dma_data_direction rather than int
- use DMA_* direction definitions rather than PCI_DMA_*
- only check for sane DMA direction on mapping functions, but
  check that DMA direction matches when unmapping/syncing.
parent 9a13f8e3
...@@ -5,6 +5,6 @@ ...@@ -5,6 +5,6 @@
obj-y += platform.o obj-y += platform.o
obj-$(CONFIG_ARM_AMBA) += amba.o obj-$(CONFIG_ARM_AMBA) += amba.o
obj-$(CONFIG_ICST525) += icst525.o obj-$(CONFIG_ICST525) += icst525.o
obj-$(CONFIG_SA1111) += sa1111.o sa1111-pcibuf.o sa1111-pcipool.o obj-$(CONFIG_SA1111) += sa1111.o sa1111-pcibuf.o
obj-$(CONFIG_PCI_HOST_PLX90X0) += plx90x0.o obj-$(CONFIG_PCI_HOST_PLX90X0) += plx90x0.o
obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o
/* /*
* 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 * These functions utilize bouncer buffers to compensate for a bug in
* the SA-1111 hardware which don't allow DMA to/from addresses * the SA-1111 hardware which don't allow DMA to/from addresses
...@@ -17,20 +17,17 @@ ...@@ -17,20 +17,17 @@
* version 2 as published by the Free Software Foundation. * version 2 as published by the Free Software Foundation.
* */ * */
//#define DEBUG
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pci.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <asm/hardware/sa1111.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 //#define STATS
#ifdef STATS #ifdef STATS
#define DO_STATS(X) do { X ; } while (0) #define DO_STATS(X) do { X ; } while (0)
...@@ -46,12 +43,13 @@ struct safe_buffer { ...@@ -46,12 +43,13 @@ struct safe_buffer {
/* original request */ /* original request */
void *ptr; void *ptr;
size_t size; size_t size;
int direction; enum dma_data_direction direction;
/* safe buffer info */ /* safe buffer info */
struct pci_pool *pool; struct dma_pool *pool;
void *safe; void *safe;
dma_addr_t safe_dma_addr; dma_addr_t safe_dma_addr;
struct device *dev;
}; };
static LIST_HEAD(safe_buffers); static LIST_HEAD(safe_buffers);
...@@ -60,7 +58,7 @@ static LIST_HEAD(safe_buffers); ...@@ -60,7 +58,7 @@ static LIST_HEAD(safe_buffers);
#define SIZE_SMALL 1024 #define SIZE_SMALL 1024
#define SIZE_LARGE (4*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 #ifdef STATS
static unsigned long sbp_allocs __initdata = 0; static unsigned long sbp_allocs __initdata = 0;
...@@ -70,95 +68,90 @@ static unsigned long total_allocs __initdata= 0; ...@@ -70,95 +68,90 @@ static unsigned long total_allocs __initdata= 0;
static void print_alloc_stats(void) static void print_alloc_stats(void)
{ {
printk(KERN_INFO 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, sbp_allocs, lbp_allocs,
total_allocs - sbp_allocs - lbp_allocs, total_allocs); total_allocs - sbp_allocs - lbp_allocs, total_allocs);
} }
#endif #endif
static int __init static int __init create_safe_buffer_pools(void)
create_safe_buffer_pools(void)
{ {
small_buffer_pool = pci_pool_create("sa1111_small_dma_buffer", small_buffer_pool = dma_pool_create("sa1111_small_dma_buffer",
SA1111_FAKE_PCIDEV, NULL, SIZE_SMALL,
SIZE_SMALL,
0 /* byte alignment */, 0 /* byte alignment */,
0 /* no page-crossing issues */); 0 /* no page-crossing issues */);
if (0 == small_buffer_pool) { if (small_buffer_pool == NULL) {
printk(KERN_ERR printk(KERN_ERR
"sa1111_pcibuf: could not allocate small pci pool\n"); "sa1111_dmabuf: could not allocate small pci pool\n");
return -1; return -ENOMEM;
} }
large_buffer_pool = pci_pool_create("sa1111_large_dma_buffer", large_buffer_pool = dma_pool_create("sa1111_large_dma_buffer",
SA1111_FAKE_PCIDEV, NULL, SIZE_LARGE,
SIZE_LARGE,
0 /* byte alignment */, 0 /* byte alignment */,
0 /* no page-crossing issues */); 0 /* no page-crossing issues */);
if (0 == large_buffer_pool) { if (large_buffer_pool == NULL) {
printk(KERN_ERR printk(KERN_ERR
"sa1111_pcibuf: could not allocate large pci pool\n"); "sa1111_dmabuf: could not allocate large pci pool\n");
pci_pool_destroy(small_buffer_pool); dma_pool_destroy(small_buffer_pool);
small_buffer_pool = 0; small_buffer_pool = NULL;
return -1; return -ENOMEM;
} }
printk(KERN_INFO printk(KERN_INFO "SA1111: DMA buffer sizes: small=%u, large=%u\n",
"sa1111_pcibuf: buffer sizes: small=%u, large=%u\n",
SIZE_SMALL, SIZE_LARGE); SIZE_SMALL, SIZE_LARGE);
return 0; return 0;
} }
static void __exit static void __exit destroy_safe_buffer_pools(void)
destroy_safe_buffer_pools(void)
{ {
if (small_buffer_pool) if (small_buffer_pool)
pci_pool_destroy(small_buffer_pool); dma_pool_destroy(small_buffer_pool);
if (large_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 */ /* allocate a 'safe' buffer and keep track of it */
static struct safe_buffer * static struct safe_buffer *alloc_safe_buffer(struct device *dev, void *ptr,
alloc_safe_buffer(void *ptr, size_t size, int direction) size_t size,
enum dma_data_direction dir)
{ {
struct safe_buffer *buf; struct safe_buffer *buf;
struct pci_pool *pool; struct dma_pool *pool;
void *safe; void *safe;
dma_addr_t safe_dma_addr; dma_addr_t safe_dma_addr;
DPRINTK("%s(ptr=%p, size=%d, direction=%d)\n", dev_dbg(dev, "%s(ptr=%p, size=%d, direction=%d)\n",
__func__, ptr, size, direction); __func__, ptr, size, dir);
DO_STATS ( total_allocs++ ); DO_STATS ( total_allocs++ );
buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC); buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC);
if (buf == 0) { if (buf == NULL) {
printk(KERN_WARNING "%s: kmalloc failed\n", __func__); printk(KERN_WARNING "%s: kmalloc failed\n", __func__);
return 0; return 0;
} }
if (size <= SIZE_SMALL) { if (size <= SIZE_SMALL) {
pool = small_buffer_pool; 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++ ); DO_STATS ( sbp_allocs++ );
} else if (size <= SIZE_LARGE) { } else if (size <= SIZE_LARGE) {
pool = large_buffer_pool; 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++ ); DO_STATS ( lbp_allocs++ );
} else { } else {
pool = 0; pool = NULL;
safe = pci_alloc_consistent(SA1111_FAKE_PCIDEV, size, safe = dma_alloc_coherent(dev, size, &safe_dma_addr, GFP_ATOMIC);
&safe_dma_addr);
} }
if (safe == 0) { if (safe == NULL) {
printk(KERN_WARNING printk(KERN_WARNING
"%s: could not alloc dma memory (size=%d)\n", "%s: could not alloc dma memory (size=%d)\n",
__func__, size); __func__, size);
...@@ -175,20 +168,20 @@ alloc_safe_buffer(void *ptr, size_t size, int direction) ...@@ -175,20 +168,20 @@ alloc_safe_buffer(void *ptr, size_t size, int direction)
buf->ptr = ptr; buf->ptr = ptr;
buf->size = size; buf->size = size;
buf->direction = direction; buf->direction = dir;
buf->pool = pool; buf->pool = pool;
buf->safe = safe; buf->safe = safe;
buf->safe_dma_addr = safe_dma_addr; buf->safe_dma_addr = safe_dma_addr;
buf->dev = dev;
MOD_INC_USE_COUNT;
list_add(&buf->node, &safe_buffers); list_add(&buf->node, &safe_buffers);
return buf; return buf;
} }
/* determine if a buffer is from our "safe" pool */ /* determine if a buffer is from our "safe" pool */
static struct safe_buffer * static struct safe_buffer *find_safe_buffer(struct device *dev,
find_safe_buffer(dma_addr_t safe_dma_addr) dma_addr_t safe_dma_addr)
{ {
struct list_head *entry; struct list_head *entry;
...@@ -196,7 +189,8 @@ find_safe_buffer(dma_addr_t safe_dma_addr) ...@@ -196,7 +189,8 @@ find_safe_buffer(dma_addr_t safe_dma_addr)
struct safe_buffer *b = struct safe_buffer *b =
list_entry(entry, struct safe_buffer, node); 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 b;
} }
} }
...@@ -204,25 +198,22 @@ find_safe_buffer(dma_addr_t safe_dma_addr) ...@@ -204,25 +198,22 @@ find_safe_buffer(dma_addr_t safe_dma_addr)
return 0; return 0;
} }
static void static void free_safe_buffer(struct safe_buffer *buf)
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); list_del(&buf->node);
if (buf->pool) 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 else
pci_free_consistent(SA1111_FAKE_PCIDEV, buf->size, buf->safe, dma_free_coherent(buf->dev, buf->size, buf->safe,
buf->safe_dma_addr); buf->safe_dma_addr);
kfree(buf); kfree(buf);
MOD_DEC_USE_COUNT;
} }
static inline int static inline int dma_range_is_safe(struct device *dev, dma_addr_t addr,
dma_range_is_safe(dma_addr_t addr, size_t size) size_t size)
{ {
unsigned int physaddr = SA1111_DMA_ADDR((unsigned int) addr); unsigned int physaddr = SA1111_DMA_ADDR((unsigned int) addr);
...@@ -248,13 +239,13 @@ static unsigned long bounce_count __initdata = 0; ...@@ -248,13 +239,13 @@ static unsigned long bounce_count __initdata = 0;
static void print_map_stats(void) static void print_map_stats(void)
{ {
printk(KERN_INFO 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); map_op_count, bounce_count);
} }
#endif #endif
static dma_addr_t static dma_addr_t map_single(struct device *dev, void *ptr,
map_single(void *ptr, size_t size, int direction) size_t size, enum dma_data_direction dir)
{ {
dma_addr_t dma_addr; dma_addr_t dma_addr;
...@@ -262,37 +253,36 @@ map_single(void *ptr, size_t size, int direction) ...@@ -262,37 +253,36 @@ map_single(void *ptr, size_t size, int direction)
dma_addr = virt_to_bus(ptr); 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; struct safe_buffer *buf;
DO_STATS ( bounce_count++ ) ; DO_STATS ( bounce_count++ ) ;
buf = alloc_safe_buffer(ptr, size, direction); buf = alloc_safe_buffer(dev, ptr, size, dir);
if (buf == 0) { if (buf == NULL) {
printk(KERN_ERR printk(KERN_ERR
"%s: unable to map unsafe buffer %p!\n", "%s: unable to map unsafe buffer %p!\n",
__func__, ptr); __func__, ptr);
return 0; 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__, __func__,
buf->ptr, (void *) virt_to_bus(buf->ptr), buf->ptr, virt_to_bus(buf->ptr),
buf->safe, (void *) buf->safe_dma_addr); buf->safe, buf->safe_dma_addr);
if ((direction == PCI_DMA_TODEVICE) || if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) {
(direction == PCI_DMA_BIDIRECTIONAL)) { dev_dbg(dev, "%s: copy out from unsafe %p, to safe %p, size %d\n",
DPRINTK("%s: copy out from unsafe %p, to safe %p, size %d\n",
__func__, ptr, buf->safe, size); __func__, ptr, buf->safe, size);
memcpy(buf->safe, ptr, size); memcpy(buf->safe, ptr, size);
} }
consistent_sync(buf->safe, size, direction);
dma_addr = buf->safe_dma_addr; dma_addr = buf->safe_dma_addr;
} else { ptr = buf->safe;
consistent_sync(ptr, size, direction);
} }
consistent_sync(ptr, size, dir);
#ifdef STATS #ifdef STATS
if (map_op_count % 1000 == 0) if (map_op_count % 1000 == 0)
print_map_stats(); print_map_stats();
...@@ -301,28 +291,26 @@ map_single(void *ptr, size_t size, int direction) ...@@ -301,28 +291,26 @@ map_single(void *ptr, size_t size, int direction)
return dma_addr; return dma_addr;
} }
static void static void unmap_single(struct device *dev, dma_addr_t dma_addr,
unmap_single(dma_addr_t dma_addr, size_t size, int direction) size_t size, enum dma_data_direction dir)
{ {
struct safe_buffer *buf; struct safe_buffer *buf;
buf = find_safe_buffer(dma_addr); buf = find_safe_buffer(dev, dma_addr);
if (buf) { if (buf) {
BUG_ON(buf->size != size); 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__, __func__,
buf->ptr, (void *) virt_to_bus(buf->ptr), buf->ptr, virt_to_bus(buf->ptr),
buf->safe, (void *) buf->safe_dma_addr); buf->safe, buf->safe_dma_addr);
DO_STATS ( bounce_count++ ); DO_STATS ( bounce_count++ );
if ((direction == PCI_DMA_FROMDEVICE) || if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) {
(direction == PCI_DMA_BIDIRECTIONAL)) { dev_dbg(dev, "%s: copy back from safe %p, to unsafe %p size %d\n",
DPRINTK("%s: copy back from safe %p, to unsafe %p size %d\n",
__func__, buf->safe, buf->ptr, size); __func__, buf->safe, buf->ptr, size);
memcpy(buf->ptr, buf->safe, size); memcpy(buf->ptr, buf->safe, size);
} }
...@@ -330,44 +318,46 @@ unmap_single(dma_addr_t dma_addr, size_t size, int direction) ...@@ -330,44 +318,46 @@ unmap_single(dma_addr_t dma_addr, size_t size, int direction)
} }
} }
static void static void sync_single(struct device *dev, dma_addr_t dma_addr,
sync_single(dma_addr_t dma_addr, size_t size, int direction) size_t size, enum dma_data_direction dir)
{ {
struct safe_buffer *buf; struct safe_buffer *buf;
void *ptr;
buf = find_safe_buffer(dma_addr); buf = find_safe_buffer(dev, dma_addr);
if (buf) { if (buf) {
BUG_ON(buf->size != size); 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__, __func__,
buf->ptr, (void *) virt_to_bus(buf->ptr), buf->ptr, virt_to_bus(buf->ptr),
buf->safe, (void *) buf->safe_dma_addr); buf->safe, buf->safe_dma_addr);
DO_STATS ( bounce_count++ ); DO_STATS ( bounce_count++ );
switch (direction) { switch (dir) {
case PCI_DMA_FROMDEVICE: case DMA_FROM_DEVICE:
DPRINTK("%s: copy back from safe %p, to unsafe %p size %d\n", dev_dbg(dev, "%s: copy back from safe %p, to unsafe %p size %d\n",
__func__, buf->safe, buf->ptr, size); __func__, buf->safe, buf->ptr, size);
memcpy(buf->ptr, buf->safe, size); memcpy(buf->ptr, buf->safe, size);
break; break;
case PCI_DMA_TODEVICE: case DMA_TO_DEVICE:
DPRINTK("%s: copy out from unsafe %p, to safe %p, size %d\n", dev_dbg(dev, "%s: copy out from unsafe %p, to safe %p, size %d\n",
__func__,buf->ptr, buf->safe, size); __func__,buf->ptr, buf->safe, size);
memcpy(buf->safe, buf->ptr, size); memcpy(buf->safe, buf->ptr, size);
break; break;
case PCI_DMA_BIDIRECTIONAL: case DMA_BIDIRECTIONAL:
BUG(); /* is this allowed? what does it mean? */ BUG(); /* is this allowed? what does it mean? */
default: default:
BUG(); BUG();
} }
consistent_sync(buf->safe, size, direction); ptr = buf->safe;
} else { } else {
consistent_sync(bus_to_virt(dma_addr), size, direction); ptr = bus_to_virt(dma_addr);
} }
consistent_sync(ptr, size, dir);
} }
/* ************************************************** */ /* ************************************************** */
...@@ -378,20 +368,20 @@ sync_single(dma_addr_t dma_addr, size_t size, int direction) ...@@ -378,20 +368,20 @@ sync_single(dma_addr_t dma_addr, size_t size, int direction)
* substitute the safe buffer for the unsafe one. * substitute the safe buffer for the unsafe one.
* (basically move the buffer from an unsafe area to a safe one) * (basically move the buffer from an unsafe area to a safe one)
*/ */
dma_addr_t dma_addr_t sa1111_map_single(struct device *dev, void *ptr,
sa1111_map_single(void *ptr, size_t size, int direction) size_t size, enum dma_data_direction dir)
{ {
unsigned long flags; unsigned long flags;
dma_addr_t dma_addr; dma_addr_t dma_addr;
DPRINTK("%s(ptr=%p,size=%d,dir=%x)\n", dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n",
__func__, ptr, size, direction); __func__, ptr, size, dir);
BUG_ON(direction == PCI_DMA_NONE); BUG_ON(dir == DMA_NONE);
local_irq_save(flags); local_irq_save(flags);
dma_addr = map_single(ptr, size, direction); dma_addr = map_single(dev, ptr, size, dir);
local_irq_restore(flags); local_irq_restore(flags);
...@@ -404,34 +394,31 @@ sa1111_map_single(void *ptr, size_t size, int direction) ...@@ -404,34 +394,31 @@ sa1111_map_single(void *ptr, size_t size, int direction)
* the safe buffer. (basically return things back to the way they * the safe buffer. (basically return things back to the way they
* should be) * should be)
*/ */
void sa1111_unmap_single(struct device *dev, dma_addr_t dma_addr,
void size_t size, enum dma_data_direction dir)
sa1111_unmap_single(dma_addr_t dma_addr, size_t size, int direction)
{ {
unsigned long flags; unsigned long flags;
DPRINTK("%s(ptr=%p,size=%d,dir=%x)\n", dev_dbg(dev, "%s(ptr=%08lx,size=%d,dir=%x)\n",
__func__, (void *) dma_addr, size, direction); __func__, dma_addr, size, dir);
BUG_ON(direction == PCI_DMA_NONE);
local_irq_save(flags); local_irq_save(flags);
unmap_single(dma_addr, size, direction); unmap_single(dev, dma_addr, size, dir);
local_irq_restore(flags); local_irq_restore(flags);
} }
int int sa1111_map_sg(struct device *dev, struct scatterlist *sg,
sa1111_map_sg(struct scatterlist *sg, int nents, int direction) int nents, enum dma_data_direction dir)
{ {
unsigned long flags; unsigned long flags;
int i; int i;
DPRINTK("%s(sg=%p,nents=%d,dir=%x)\n", dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
__func__, sg, nents, direction); __func__, sg, nents, dir);
BUG_ON(direction == PCI_DMA_NONE); BUG_ON(dir == DMA_NONE);
local_irq_save(flags); local_irq_save(flags);
...@@ -441,8 +428,7 @@ sa1111_map_sg(struct scatterlist *sg, int nents, int direction) ...@@ -441,8 +428,7 @@ sa1111_map_sg(struct scatterlist *sg, int nents, int direction)
unsigned int length = sg->length; unsigned int length = sg->length;
void *ptr = page_address(page) + offset; void *ptr = page_address(page) + offset;
sg->dma_address = sg->dma_address = map_single(dev, ptr, length, dir);
map_single(ptr, length, direction);
} }
local_irq_restore(flags); local_irq_restore(flags);
...@@ -450,16 +436,14 @@ sa1111_map_sg(struct scatterlist *sg, int nents, int direction) ...@@ -450,16 +436,14 @@ sa1111_map_sg(struct scatterlist *sg, int nents, int direction)
return nents; return nents;
} }
void void sa1111_unmap_sg(struct device *dev, struct scatterlist *sg,
sa1111_unmap_sg(struct scatterlist *sg, int nents, int direction) int nents, enum dma_data_direction dir)
{ {
unsigned long flags; unsigned long flags;
int i; int i;
DPRINTK("%s(sg=%p,nents=%d,dir=%x)\n", dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
__func__, sg, nents, direction); __func__, sg, nents, dir);
BUG_ON(direction == PCI_DMA_NONE);
local_irq_save(flags); local_irq_save(flags);
...@@ -467,37 +451,35 @@ sa1111_unmap_sg(struct scatterlist *sg, int nents, int direction) ...@@ -467,37 +451,35 @@ sa1111_unmap_sg(struct scatterlist *sg, int nents, int direction)
dma_addr_t dma_addr = sg->dma_address; dma_addr_t dma_addr = sg->dma_address;
unsigned int length = sg->length; unsigned int length = sg->length;
unmap_single(dma_addr, length, direction); unmap_single(dev, dma_addr, length, dir);
} }
local_irq_restore(flags); local_irq_restore(flags);
} }
void void sa1111_dma_sync_single(struct device *dev, dma_addr_t dma_addr,
sa1111_dma_sync_single(dma_addr_t dma_addr, size_t size, int direction) size_t size, enum dma_data_direction dir)
{ {
unsigned long flags; unsigned long flags;
DPRINTK("%s(ptr=%p,size=%d,dir=%x)\n", dev_dbg(dev, "%s(ptr=%08lx,size=%d,dir=%x)\n",
__func__, (void *) dma_addr, size, direction); __func__, dma_addr, size, dir);
local_irq_save(flags); local_irq_save(flags);
sync_single(dma_addr, size, direction); sync_single(dev, dma_addr, size, dir);
local_irq_restore(flags); local_irq_restore(flags);
} }
void void sa1111_dma_sync_sg(struct device *dev, struct scatterlist *sg,
sa1111_dma_sync_sg(struct scatterlist *sg, int nents, int direction) int nents, enum dma_data_direction dir)
{ {
unsigned long flags; unsigned long flags;
int i; int i;
DPRINTK("%s(sg=%p,nents=%d,dir=%x)\n", dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n",
__func__, sg, nents, direction); __func__, sg, nents, dir);
BUG_ON(direction == PCI_DMA_NONE);
local_irq_save(flags); local_irq_save(flags);
...@@ -505,7 +487,7 @@ sa1111_dma_sync_sg(struct scatterlist *sg, int nents, int direction) ...@@ -505,7 +487,7 @@ sa1111_dma_sync_sg(struct scatterlist *sg, int nents, int direction)
dma_addr_t dma_addr = sg->dma_address; dma_addr_t dma_addr = sg->dma_address;
unsigned int length = sg->length; unsigned int length = sg->length;
sync_single(dma_addr, length, direction); sync_single(dev, dma_addr, length, dir);
} }
local_irq_restore(flags); local_irq_restore(flags);
...@@ -520,20 +502,15 @@ EXPORT_SYMBOL(sa1111_dma_sync_sg); ...@@ -520,20 +502,15 @@ EXPORT_SYMBOL(sa1111_dma_sync_sg);
/* **************************************** */ /* **************************************** */
static int __init sa1111_pcibuf_init(void) static int __init sa1111_dmabuf_init(void)
{ {
int ret; printk(KERN_DEBUG "sa1111_dmabuf: initializing SA-1111 DMA buffers\n");
printk(KERN_DEBUG
"sa1111_pcibuf: initializing SA-1111 DMA workaround\n");
ret = create_safe_buffer_pools();
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)); BUG_ON(!list_empty(&safe_buffers));
...@@ -544,8 +521,8 @@ static void __exit sa1111_pcibuf_exit(void) ...@@ -544,8 +521,8 @@ static void __exit sa1111_pcibuf_exit(void)
destroy_safe_buffer_pools(); destroy_safe_buffer_pools();
} }
module_exit(sa1111_pcibuf_exit); module_exit(sa1111_dmabuf_exit);
MODULE_AUTHOR("Christopher Hoover <ch@hpl.hp.com>"); 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"); MODULE_LICENSE("GPL");
/*
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");
...@@ -22,12 +22,12 @@ extern void consistent_sync(void *kaddr, size_t size, int rw); ...@@ -22,12 +22,12 @@ extern void consistent_sync(void *kaddr, size_t size, int rw);
* For SA-1111 these functions are "magic" and utilize bounce * For SA-1111 these functions are "magic" and utilize bounce
* bufferes as needed to work around SA-1111 DMA bugs. * bufferes as needed to work around SA-1111 DMA bugs.
*/ */
dma_addr_t sa1111_map_single(void *, size_t, int); dma_addr_t sa1111_map_single(struct device *dev, void *, size_t, enum dma_data_direction);
void sa1111_unmap_single(dma_addr_t, size_t, int); void sa1111_unmap_single(struct device *dev, dma_addr_t, size_t, enum dma_data_direction);
int sa1111_map_sg(struct scatterlist *, int, int); int sa1111_map_sg(struct device *dev, struct scatterlist *, int, enum dma_data_direction);
void sa1111_unmap_sg(struct scatterlist *, int, int); void sa1111_unmap_sg(struct device *dev, struct scatterlist *, int, enum dma_data_direction);
void sa1111_dma_sync_single(dma_addr_t, size_t, int); void sa1111_dma_sync_single(struct device *dev, dma_addr_t, size_t, enum dma_data_direction);
void sa1111_dma_sync_sg(struct scatterlist *, int, int); void sa1111_dma_sync_sg(struct device *dev, struct scatterlist *, int, enum dma_data_direction);
#ifdef CONFIG_SA1111 #ifdef CONFIG_SA1111
...@@ -122,7 +122,7 @@ dma_map_single(struct device *dev, void *cpu_addr, size_t size, ...@@ -122,7 +122,7 @@ dma_map_single(struct device *dev, void *cpu_addr, size_t size,
enum dma_data_direction dir) enum dma_data_direction dir)
{ {
if (dmadev_is_sa1111(dev)) if (dmadev_is_sa1111(dev))
return sa1111_map_single(cpu_addr, size, dir); return sa1111_map_single(dev, cpu_addr, size, dir);
consistent_sync(cpu_addr, size, dir); consistent_sync(cpu_addr, size, dir);
return __virt_to_bus((unsigned long)cpu_addr); return __virt_to_bus((unsigned long)cpu_addr);
...@@ -169,7 +169,7 @@ dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size, ...@@ -169,7 +169,7 @@ dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size,
enum dma_data_direction dir) enum dma_data_direction dir)
{ {
if (dmadev_is_sa1111(dev)) if (dmadev_is_sa1111(dev))
sa1111_unmap_single(handle, size, dir); sa1111_unmap_single(dev, handle, size, dir);
/* nothing to do */ /* nothing to do */
} }
...@@ -224,7 +224,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ...@@ -224,7 +224,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
int i; int i;
if (dmadev_is_sa1111(dev)) if (dmadev_is_sa1111(dev))
return sa1111_map_sg(sg, nents, dir); return sa1111_map_sg(dev, sg, nents, dir);
for (i = 0; i < nents; i++, sg++) { for (i = 0; i < nents; i++, sg++) {
char *virt; char *virt;
...@@ -253,7 +253,7 @@ dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, ...@@ -253,7 +253,7 @@ dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir) enum dma_data_direction dir)
{ {
if (dmadev_is_sa1111(dev)) { if (dmadev_is_sa1111(dev)) {
sa1111_unmap_sg(sg, nents, dir); sa1111_unmap_sg(dev, sg, nents, dir);
return; return;
} }
...@@ -281,7 +281,7 @@ dma_sync_single(struct device *dev, dma_addr_t handle, size_t size, ...@@ -281,7 +281,7 @@ dma_sync_single(struct device *dev, dma_addr_t handle, size_t size,
enum dma_data_direction dir) enum dma_data_direction dir)
{ {
if (dmadev_is_sa1111(dev)) { if (dmadev_is_sa1111(dev)) {
sa1111_dma_sync_single(handle, size, dir); sa1111_dma_sync_single(dev, handle, size, dir);
return; return;
} }
...@@ -308,7 +308,7 @@ dma_sync_sg(struct device *dev, struct scatterlist *sg, int nents, ...@@ -308,7 +308,7 @@ dma_sync_sg(struct device *dev, struct scatterlist *sg, int nents,
int i; int i;
if (dmadev_is_sa1111(dev)) { if (dmadev_is_sa1111(dev)) {
sa1111_dma_sync_sg(sg, nents, dir); sa1111_dma_sync_sg(dev, sg, nents, dir);
return; return;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment