Commit 5541b427 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://bk.arm.linux.org.uk/linux-2.6-rmk

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 7ce42ae1 c2e26dd2
...@@ -210,6 +210,11 @@ config FORCE_MAX_ZONEORDER ...@@ -210,6 +210,11 @@ config FORCE_MAX_ZONEORDER
depends on SA1111 depends on SA1111
default "9" default "9"
config DMABOUNCE
bool
depends on SA1111
default y
source arch/arm/mm/Kconfig source arch/arm/mm/Kconfig
# bool 'Use XScale PMU as timer source' CONFIG_XSCALE_PMU_TIMER # bool 'Use XScale PMU as timer source' CONFIG_XSCALE_PMU_TIMER
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
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 obj-$(CONFIG_SA1111) += sa1111.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
obj-$(CONFIG_DMABOUNCE) += dmabounce.o
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/dma-mapping.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
...@@ -547,15 +548,6 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, ...@@ -547,15 +548,6 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
"%4.4lx", info->offset); "%4.4lx", info->offset);
/*
* If the parent device has a DMA mask associated with it,
* propagate it down to the children.
*/
if (sachip->dev->dma_mask) {
dev->dma_mask = *sachip->dev->dma_mask;
dev->dev.dma_mask = &dev->dma_mask;
}
dev->devid = info->devid; dev->devid = info->devid;
dev->dev.parent = sachip->dev; dev->dev.parent = sachip->dev;
dev->dev.bus = &sa1111_bus_type; dev->dev.bus = &sa1111_bus_type;
...@@ -573,15 +565,37 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, ...@@ -573,15 +565,37 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
if (ret) { if (ret) {
printk("SA1111: failed to allocate resource for %s\n", printk("SA1111: failed to allocate resource for %s\n",
dev->res.name); dev->res.name);
kfree(dev);
goto out; goto out;
} }
ret = device_register(&dev->dev); ret = device_register(&dev->dev);
if (ret) { if (ret) {
release_resource(&dev->res); release_resource(&dev->res);
out:
kfree(dev); kfree(dev);
goto out;
}
/*
* If the parent device has a DMA mask associated with it,
* propagate it down to the children.
*/
if (sachip->dev->dma_mask) {
dev->dma_mask = *sachip->dev->dma_mask;
dev->dev.dma_mask = &dev->dma_mask;
if (dev->dma_mask != 0xffffffffUL) {
ret = dmabounce_register_dev(&dev->dev, 1024, 4096);
if (ret) {
printk("SA1111: Failed to register %s with dmabounce", dev->dev.bus_id);
kfree(dev);
device_unregister(dev);
}
}
} }
out:
return ret; return ret;
} }
...@@ -742,61 +756,31 @@ static void __sa1111_remove(struct sa1111 *sachip) ...@@ -742,61 +756,31 @@ static void __sa1111_remove(struct sa1111 *sachip)
* *
* This routine only identifies whether or not a given DMA address * This routine only identifies whether or not a given DMA address
* is susceptible to the bug. * is susceptible to the bug.
*
* This should only get called for sa1111_device types due to the
* way we configure our device dma_masks.
*/ */
int sa1111_check_dma_bug(dma_addr_t addr) int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
{ {
struct sa1111 *sachip = g_sa1111;
unsigned int physaddr = SA1111_DMA_ADDR((unsigned int)addr); unsigned int physaddr = SA1111_DMA_ADDR((unsigned int)addr);
unsigned int smcr; u32 dma_mask = *dev->dma_mask;
/* Section 4.6 of the "Intel StrongARM SA-1111 Development Module /*
* Section 4.6 of the "Intel StrongARM SA-1111 Development Module
* User's Guide" mentions that jumpers R51 and R52 control the * User's Guide" mentions that jumpers R51 and R52 control the
* target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
* SDRAM bank 1 on Neponset). The default configuration selects * SDRAM bank 1 on Neponset). The default configuration selects
* Assabet, so any address in bank 1 is necessarily invalid. * Assabet, so any address in bank 1 is necessarily invalid.
*/ */
if ((machine_is_assabet() || machine_is_pfs168()) && addr >= 0xc8000000) if ((machine_is_assabet() || machine_is_pfs168()) &&
return -1; (addr >= 0xc8000000 || (addr + size) >= 0xc8000000))
return 1;
/* The bug only applies to buffers located more than one megabyte /*
* above the start of the target bank: * Check to see if either the start or end are illegal.
*/ */
if (physaddr<(1<<20)) return ((addr & ~(*dev->dma_mask))) ||
return 0; ((addr + size - 1) & ~(*dev->dma_mask));
smcr = sa1111_readl(sachip->base + SA1111_SMCR);
switch (FExtr(smcr, SMCR_DRAC)) {
case 01: /* 10 row + bank address bits, A<20> must not be set */
if (physaddr & (1<<20))
return -1;
break;
case 02: /* 11 row + bank address bits, A<23> must not be set */
if (physaddr & (1<<23))
return -1;
break;
case 03: /* 12 row + bank address bits, A<24> must not be set */
if (physaddr & (1<<24))
return -1;
break;
case 04: /* 13 row + bank address bits, A<25> must not be set */
if (physaddr & (1<<25))
return -1;
break;
case 05: /* 14 row + bank address bits, A<20> must not be set */
if (physaddr & (1<<20))
return -1;
break;
case 06: /* 15 row + bank address bits, A<20> must not be set */
if (physaddr & (1<<20))
return -1;
break;
default:
printk(KERN_ERR "%s(): invalid SMCR DRAC value 0%lo\n",
__FUNCTION__, FExtr(smcr, SMCR_DRAC));
return -1;
}
return 0;
} }
struct sa1111_save_data { struct sa1111_save_data {
...@@ -1293,7 +1277,6 @@ module_exit(sa1111_exit); ...@@ -1293,7 +1277,6 @@ module_exit(sa1111_exit);
MODULE_DESCRIPTION("Intel Corporation SA1111 core driver"); MODULE_DESCRIPTION("Intel Corporation SA1111 core driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
EXPORT_SYMBOL(sa1111_check_dma_bug);
EXPORT_SYMBOL(sa1111_select_audio_mode); EXPORT_SYMBOL(sa1111_select_audio_mode);
EXPORT_SYMBOL(sa1111_set_audio_rate); EXPORT_SYMBOL(sa1111_set_audio_rate);
EXPORT_SYMBOL(sa1111_get_audio_rate); EXPORT_SYMBOL(sa1111_get_audio_rate);
......
...@@ -44,7 +44,7 @@ static inline void atomic_set(atomic_t *v, int i) ...@@ -44,7 +44,7 @@ static inline void atomic_set(atomic_t *v, int i)
: "cc"); : "cc");
} }
static inline void atomic_add(int i, volatile atomic_t *v) static inline void atomic_add(int i, atomic_t *v)
{ {
unsigned long tmp, tmp2; unsigned long tmp, tmp2;
...@@ -59,7 +59,7 @@ static inline void atomic_add(int i, volatile atomic_t *v) ...@@ -59,7 +59,7 @@ static inline void atomic_add(int i, volatile atomic_t *v)
: "cc"); : "cc");
} }
static inline void atomic_sub(int i, volatile atomic_t *v) static inline void atomic_sub(int i, atomic_t *v)
{ {
unsigned long tmp, tmp2; unsigned long tmp, tmp2;
...@@ -77,7 +77,7 @@ static inline void atomic_sub(int i, volatile atomic_t *v) ...@@ -77,7 +77,7 @@ static inline void atomic_sub(int i, volatile atomic_t *v)
#define atomic_inc(v) atomic_add(1, v) #define atomic_inc(v) atomic_add(1, v)
#define atomic_dec(v) atomic_sub(1, v) #define atomic_dec(v) atomic_sub(1, v)
static inline int atomic_dec_and_test(volatile atomic_t *v) static inline int atomic_dec_and_test(atomic_t *v)
{ {
unsigned long tmp; unsigned long tmp;
int result; int result;
...@@ -95,7 +95,7 @@ static inline int atomic_dec_and_test(volatile atomic_t *v) ...@@ -95,7 +95,7 @@ static inline int atomic_dec_and_test(volatile atomic_t *v)
return result == 0; return result == 0;
} }
static inline int atomic_add_negative(int i, volatile atomic_t *v) static inline int atomic_add_negative(int i, atomic_t *v)
{ {
unsigned long tmp; unsigned long tmp;
int result; int result;
...@@ -138,7 +138,7 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) ...@@ -138,7 +138,7 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
#define atomic_set(v,i) (((v)->counter) = (i)) #define atomic_set(v,i) (((v)->counter) = (i))
static inline void atomic_add(int i, volatile atomic_t *v) static inline void atomic_add(int i, atomic_t *v)
{ {
unsigned long flags; unsigned long flags;
...@@ -147,7 +147,7 @@ static inline void atomic_add(int i, volatile atomic_t *v) ...@@ -147,7 +147,7 @@ static inline void atomic_add(int i, volatile atomic_t *v)
local_irq_restore(flags); local_irq_restore(flags);
} }
static inline void atomic_sub(int i, volatile atomic_t *v) static inline void atomic_sub(int i, atomic_t *v)
{ {
unsigned long flags; unsigned long flags;
...@@ -156,7 +156,7 @@ static inline void atomic_sub(int i, volatile atomic_t *v) ...@@ -156,7 +156,7 @@ static inline void atomic_sub(int i, volatile atomic_t *v)
local_irq_restore(flags); local_irq_restore(flags);
} }
static inline void atomic_inc(volatile atomic_t *v) static inline void atomic_inc(atomic_t *v)
{ {
unsigned long flags; unsigned long flags;
...@@ -165,7 +165,7 @@ static inline void atomic_inc(volatile atomic_t *v) ...@@ -165,7 +165,7 @@ static inline void atomic_inc(volatile atomic_t *v)
local_irq_restore(flags); local_irq_restore(flags);
} }
static inline void atomic_dec(volatile atomic_t *v) static inline void atomic_dec(atomic_t *v)
{ {
unsigned long flags; unsigned long flags;
...@@ -174,7 +174,7 @@ static inline void atomic_dec(volatile atomic_t *v) ...@@ -174,7 +174,7 @@ static inline void atomic_dec(volatile atomic_t *v)
local_irq_restore(flags); local_irq_restore(flags);
} }
static inline int atomic_dec_and_test(volatile atomic_t *v) static inline int atomic_dec_and_test(atomic_t *v)
{ {
unsigned long flags; unsigned long flags;
int val; int val;
...@@ -187,7 +187,7 @@ static inline int atomic_dec_and_test(volatile atomic_t *v) ...@@ -187,7 +187,7 @@ static inline int atomic_dec_and_test(volatile atomic_t *v)
return val == 0; return val == 0;
} }
static inline int atomic_add_negative(int i, volatile atomic_t *v) static inline int atomic_add_negative(int i, atomic_t *v)
{ {
unsigned long flags; unsigned long flags;
int val; int val;
......
#ifndef __ASM_ARM_DIV64 #ifndef __ASM_ARM_DIV64
#define __ASM_ARM_DIV64 #define __ASM_ARM_DIV64
#include <asm/system.h>
/* /*
* The semantics of do_div() are: * The semantics of do_div() are:
* *
...@@ -31,7 +33,11 @@ ...@@ -31,7 +33,11 @@
register unsigned long long __n asm("r0") = n; \ register unsigned long long __n asm("r0") = n; \
register unsigned long long __res asm("r2"); \ register unsigned long long __res asm("r2"); \
register unsigned int __rem asm(__xh); \ register unsigned int __rem asm(__xh); \
asm("bl __do_div64" \ asm( __asmeq("%0", __xh) \
__asmeq("%1", "r2") \
__asmeq("%2", "r0") \
__asmeq("%3", "r4") \
"bl __do_div64" \
: "=r" (__rem), "=r" (__res) \ : "=r" (__rem), "=r" (__res) \
: "r" (__n), "r" (__base) \ : "r" (__n), "r" (__base) \
: "ip", "lr", "cc"); \ : "ip", "lr", "cc"); \
......
...@@ -16,29 +16,6 @@ ...@@ -16,29 +16,6 @@
*/ */
extern void consistent_sync(void *kaddr, size_t size, int rw); extern void consistent_sync(void *kaddr, size_t size, int rw);
/*
* For SA-1111 these functions are "magic" and utilize bounce
* bufferes as needed to work around SA-1111 DMA bugs.
*/
dma_addr_t sa1111_map_single(struct device *dev, void *, size_t, enum dma_data_direction);
void sa1111_unmap_single(struct device *dev, dma_addr_t, size_t, enum dma_data_direction);
int sa1111_map_sg(struct device *dev, struct scatterlist *, int, enum dma_data_direction);
void sa1111_unmap_sg(struct device *dev, struct scatterlist *, int, enum dma_data_direction);
void sa1111_dma_sync_single_for_cpu(struct device *dev, dma_addr_t, size_t, enum dma_data_direction);
void sa1111_dma_sync_single_for_device(struct device *dev, dma_addr_t, size_t, enum dma_data_direction);
void sa1111_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *, int, enum dma_data_direction);
void sa1111_dma_sync_sg_for_device(struct device *dev, struct scatterlist *, int, enum dma_data_direction);
#ifdef CONFIG_SA1111
extern struct bus_type sa1111_bus_type;
#define dmadev_is_sa1111(dev) ((dev)->bus == &sa1111_bus_type)
#else
#define dmadev_is_sa1111(dev) (0)
#endif
/* /*
* Return whether the given device DMA address mask can be supported * Return whether the given device DMA address mask can be supported
* properly. For example, if your device can only drive the low 24-bits * properly. For example, if your device can only drive the low 24-bits
...@@ -70,6 +47,14 @@ static inline int dma_is_consistent(dma_addr_t handle) ...@@ -70,6 +47,14 @@ static inline int dma_is_consistent(dma_addr_t handle)
return 0; return 0;
} }
/*
* DMA errors are defined by all-bits-set in the DMA address.
*/
static inline int dma_mapping_error(dma_addr_t dma_addr)
{
return dma_addr == ~0;
}
/** /**
* dma_alloc_coherent - allocate consistent memory for DMA * dma_alloc_coherent - allocate consistent memory for DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
...@@ -118,6 +103,7 @@ dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int ...@@ -118,6 +103,7 @@ dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int
#define dma_free_writecombine(dev,size,cpu_addr,handle) \ #define dma_free_writecombine(dev,size,cpu_addr,handle) \
dma_free_coherent(dev,size,cpu_addr,handle) dma_free_coherent(dev,size,cpu_addr,handle)
/** /**
* dma_map_single - map a single buffer for streaming DMA * dma_map_single - map a single buffer for streaming DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
...@@ -132,16 +118,17 @@ dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int ...@@ -132,16 +118,17 @@ dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int
* can regain ownership by calling dma_unmap_single() or * can regain ownership by calling dma_unmap_single() or
* dma_sync_single_for_cpu(). * dma_sync_single_for_cpu().
*/ */
#ifndef CONFIG_DMABOUNCE
static inline dma_addr_t static inline dma_addr_t
dma_map_single(struct device *dev, void *cpu_addr, size_t size, 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))
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);
} }
#else
extern dma_addr_t dma_map_single(struct device *,void *, size_t, enum dma_data_direction);
#endif
/** /**
* dma_map_page - map a portion of a page for streaming DMA * dma_map_page - map a portion of a page for streaming DMA
...@@ -180,15 +167,16 @@ dma_map_page(struct device *dev, struct page *page, ...@@ -180,15 +167,16 @@ dma_map_page(struct device *dev, struct page *page,
* After this call, reads by the CPU to the buffer are guaranteed to see * After this call, reads by the CPU to the buffer are guaranteed to see
* whatever the device wrote there. * whatever the device wrote there.
*/ */
#ifndef CONFIG_DMABOUNCE
static inline void static inline void
dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size, 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))
sa1111_unmap_single(dev, handle, size, dir);
/* nothing to do */ /* nothing to do */
} }
#else
extern void dma_unmap_single(struct device *, dma_addr_t, size_t, enum dma_data_direction);
#endif
/** /**
* dma_unmap_page - unmap a buffer previously mapped through dma_map_page() * dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
...@@ -233,15 +221,13 @@ dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, ...@@ -233,15 +221,13 @@ dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size,
* Device ownership issues as mentioned above for dma_map_single are * Device ownership issues as mentioned above for dma_map_single are
* the same here. * the same here.
*/ */
#ifndef CONFIG_DMABOUNCE
static inline int static inline int
dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir) enum dma_data_direction dir)
{ {
int i; int i;
if (dmadev_is_sa1111(dev))
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;
...@@ -252,6 +238,9 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ...@@ -252,6 +238,9 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
return nents; return nents;
} }
#else
extern int dma_map_sg(struct device *, struct scatterlist *, int, enum dma_data_direction);
#endif
/** /**
* dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
...@@ -264,17 +253,18 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ...@@ -264,17 +253,18 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
* Again, CPU read rules concerning calls here are the same as for * Again, CPU read rules concerning calls here are the same as for
* dma_unmap_single() above. * dma_unmap_single() above.
*/ */
#ifndef CONFIG_DMABOUNCE
static inline void static inline void
dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, 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)) {
sa1111_unmap_sg(dev, sg, nents, dir);
return;
}
/* nothing to do */ /* nothing to do */
} }
#else
extern void dma_unmap_sg(struct device *, struct scatterlist *, int, enum dma_data_direction);
#endif
/** /**
* dma_sync_single_for_cpu * dma_sync_single_for_cpu
...@@ -293,15 +283,11 @@ dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, ...@@ -293,15 +283,11 @@ dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
* must first the perform a dma_sync_for_device, and then the * must first the perform a dma_sync_for_device, and then the
* device again owns the buffer. * device again owns the buffer.
*/ */
#ifndef CONFIG_DMABOUNCE
static inline void static inline void
dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, size_t size, dma_sync_single_for_cpu(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)) {
sa1111_dma_sync_single_for_cpu(dev, handle, size, dir);
return;
}
consistent_sync((void *)__bus_to_virt(handle), size, dir); consistent_sync((void *)__bus_to_virt(handle), size, dir);
} }
...@@ -309,13 +295,13 @@ static inline void ...@@ -309,13 +295,13 @@ static inline void
dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size, dma_sync_single_for_device(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)) {
sa1111_dma_sync_single_for_device(dev, handle, size, dir);
return;
}
consistent_sync((void *)__bus_to_virt(handle), size, dir); consistent_sync((void *)__bus_to_virt(handle), size, dir);
} }
#else
extern void dma_sync_single_for_cpu(struct device*, dma_addr_t, size_t, enum dma_data_direction);
extern void dma_sync_single_for_device(struct device*, dma_addr_t, size_t, enum dma_data_direction);
#endif
/** /**
* dma_sync_sg_for_cpu * dma_sync_sg_for_cpu
...@@ -330,17 +316,13 @@ dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size, ...@@ -330,17 +316,13 @@ dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size,
* The same as dma_sync_single_for_* but for a scatter-gather list, * The same as dma_sync_single_for_* but for a scatter-gather list,
* same rules and usage. * same rules and usage.
*/ */
#ifndef CONFIG_DMABOUNCE
static inline void static inline void
dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents, dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir) enum dma_data_direction dir)
{ {
int i; int i;
if (dmadev_is_sa1111(dev)) {
sa1111_dma_sync_sg_for_cpu(dev, sg, nents, dir);
return;
}
for (i = 0; i < nents; i++, sg++) { for (i = 0; i < nents; i++, sg++) {
char *virt = page_address(sg->page) + sg->offset; char *virt = page_address(sg->page) + sg->offset;
consistent_sync(virt, sg->length, dir); consistent_sync(virt, sg->length, dir);
...@@ -353,24 +335,73 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, ...@@ -353,24 +335,73 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
{ {
int i; int i;
if (dmadev_is_sa1111(dev)) {
sa1111_dma_sync_sg_for_device(dev, sg, nents, dir);
return;
}
for (i = 0; i < nents; i++, sg++) { for (i = 0; i < nents; i++, sg++) {
char *virt = page_address(sg->page) + sg->offset; char *virt = page_address(sg->page) + sg->offset;
consistent_sync(virt, sg->length, dir); consistent_sync(virt, sg->length, dir);
} }
} }
#else
extern void dma_sync_sg_for_cpu(struct device*, struct scatterlist*, int, enum dma_data_direction);
extern void dma_sync_sg_for_device(struct device*, struct scatterlist*, int, enum dma_data_direction);
#endif
#ifdef CONFIG_DMABOUNCE
/* /*
* DMA errors are defined by all-bits-set in the DMA address. * For SA-1111, IXP425, and ADI systems the dma-mapping functions are "magic"
* and utilize bounce buffers as needed to work around limited DMA windows.
*
* On the SA-1111, a bug limits DMA to only certain regions of RAM.
* On the IXP425, the PCI inbound window is 64MB (256MB total RAM)
* On some ADI engineering sytems, PCI inbound window is 32MB (12MB total RAM)
*
* The following are helper functions used by the dmabounce subystem
*
*/ */
static inline int dma_mapping_error(dma_addr_t dma_addr)
{ /**
return dma_addr == ~0; * dmabounce_register_dev
} *
* @dev: valid struct device pointer
* @small_buf_size: size of buffers to use with small buffer pool
* @large_buf_size: size of buffers to use with large buffer pool (can be 0)
*
* This function should be called by low-level platform code to register
* a device as requireing DMA buffer bouncing. The function will allocate
* appropriate DMA pools for the device.
*
*/
extern int dmabounce_register_dev(struct device *, unsigned long, unsigned long);
/**
* dmabounce_unregister_dev
*
* @dev: valid struct device pointer
*
* This function should be called by low-level platform code when device
* that was previously registered with dmabounce_register_dev is removed
* from the system.
*
*/
extern void dmabounce_unregister_dev(struct device *);
/**
* dma_needs_bounce
*
* @dev: valid struct device pointer
* @dma_handle: dma_handle of unbounced buffer
* @size: size of region being mapped
*
* Platforms that utilize the dmabounce mechanism must implement
* this function.
*
* The dmabounce routines call this function whenever a dma-mapping
* is requested to determine whether a given buffer needs to be bounced
* or not. The function must return 0 if the the buffer is OK for
* DMA access and 1 if the buffer needs to be bounced.
*
*/
extern int dma_needs_bounce(struct device*, dma_addr_t, size_t);
#endif /* CONFIG_DMABOUNCE */
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif #endif
...@@ -42,6 +42,15 @@ ...@@ -42,6 +42,15 @@
#define CR_XP (1 << 23) /* Extended page tables */ #define CR_XP (1 << 23) /* Extended page tables */
#define CR_VE (1 << 24) /* Vectored interrupts */ #define CR_VE (1 << 24) /* Vectored interrupts */
/*
* This is used to ensure the compiler did actually allocate the register we
* asked it for some inline assembly sequences. Apparently we can't trust
* the compiler from one version to another so a bit of paranoia won't hurt.
* This string is meant to be concatenated with the inline asm string and
* will cause compilation to stop on mismatch.
*/
#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <linux/kernel.h> #include <linux/kernel.h>
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <asm/errno.h> #include <asm/errno.h>
#include <asm/arch/memory.h> #include <asm/arch/memory.h>
#include <asm/domain.h> #include <asm/domain.h>
#include <asm/system.h>
#define VERIFY_READ 0 #define VERIFY_READ 0
#define VERIFY_WRITE 1 #define VERIFY_WRITE 1
...@@ -107,7 +108,9 @@ extern int __get_user_8(void *); ...@@ -107,7 +108,9 @@ extern int __get_user_8(void *);
extern int __get_user_bad(void); extern int __get_user_bad(void);
#define __get_user_x(__r1,__p,__e,__s,__i...) \ #define __get_user_x(__r1,__p,__e,__s,__i...) \
__asm__ __volatile__ ("bl __get_user_" #__s \ __asm__ __volatile__ ( \
__asmeq("%0", "r0") __asmeq("%1", "r1") \
"bl __get_user_" #__s \
: "=&r" (__e), "=r" (__r1) \ : "=&r" (__e), "=r" (__r1) \
: "0" (__p) \ : "0" (__p) \
: __i, "cc") : __i, "cc")
...@@ -223,7 +226,9 @@ extern int __put_user_8(void *, unsigned long long); ...@@ -223,7 +226,9 @@ extern int __put_user_8(void *, unsigned long long);
extern int __put_user_bad(void); extern int __put_user_bad(void);
#define __put_user_x(__r1,__p,__e,__s) \ #define __put_user_x(__r1,__p,__e,__s) \
__asm__ __volatile__ ("bl __put_user_" #__s \ __asm__ __volatile__ ( \
__asmeq("%0", "r0") __asmeq("%2", "r1") \
"bl __put_user_" #__s \
: "=&r" (__e) \ : "=&r" (__e) \
: "0" (__p), "r" (__r1) \ : "0" (__p), "r" (__r1) \
: "ip", "lr", "cc") : "ip", "lr", "cc")
......
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