[ARM] 3439/2: xsc3: add I/O coherency support

Patch from Lennert Buytenhek

This patch adds support for the I/O coherent cache available on the
xsc3.  The approach is to provide a simple API to determine whether the
chipset supports coherency by calling arch_is_coherent() and then
setting the appropriate system memory PTE and PMD bits.  In addition,
we call this API on dma_alloc_coherent() and dma_map_single() calls.
A generic version exists that will compile out all the coherency-related
code that is not needed on the majority of ARM systems.

Note that we do not check for coherency in the dma_alloc_writecombine()
function as that still requires a special PTE setting.  We also don't
touch dma_mmap_coherent() as that is a special ARM-only API that is by
definition only used on non-coherent system.

Signed-off-by: Deepak Saxena <[email protected]>
Signed-off-by: Lennert Buytenhek <[email protected]>
Signed-off-by: Russell King <[email protected]>
This commit is contained in:
Lennert Buytenhek 2006-04-02 00:07:39 +01:00 • committed by Russell King
commit 23759dc643
10 changed files with 80 additions and 8 deletions

View file

@ -28,6 +28,7 @@
* to an address that the kernel can use.
*/
#ifndef __ASSEMBLY__
#include <asm/mach-types.h>
#define __virt_to_bus(v) \
({ unsigned int ret; \
@ -40,6 +41,22 @@
data = *((volatile int *)IXP23XX_PCI_SDRAM_BAR); \
__phys_to_virt((((b - (data & 0xfffffff0)) + 0x00000000))); })
/*
* Coherency support. Only supported on A2 CPUs or on A1
* systems that have the cache coherency workaround.
*/
static inline int __ixp23xx_arch_is_coherent(void)
{
extern unsigned int processor_id;
if (((processor_id & 15) >= 2) || machine_is_roadrunner())
return 1;
return 0;
}
#define arch_is_coherent() __ixp23xx_arch_is_coherent()
#endif

View file

@ -47,7 +47,7 @@ static inline int dma_get_cache_alignment(void)
static inline int dma_is_consistent(dma_addr_t handle)
{
return 0;
return !!arch_is_coherent();
}
/*
@ -145,7 +145,9 @@ static inline dma_addr_t
dma_map_single(struct device *dev, void *cpu_addr, size_t size,
enum dma_data_direction dir)
{
consistent_sync(cpu_addr, size, dir);
if (!arch_is_coherent())
consistent_sync(cpu_addr, size, dir);
return virt_to_dma(dev, (unsigned long)cpu_addr);
}
#else
@ -255,7 +257,9 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
sg->dma_address = page_to_dma(dev, sg->page) + sg->offset;
virt = page_address(sg->page) + sg->offset;
consistent_sync(virt, sg->length, dir);
if (!arch_is_coherent())
consistent_sync(virt, sg->length, dir);
}
return nents;
@ -310,14 +314,16 @@ static inline void
dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, size_t size,
enum dma_data_direction dir)
{
consistent_sync((void *)dma_to_virt(dev, handle), size, dir);
if (!arch_is_coherent())
consistent_sync((void *)dma_to_virt(dev, handle), size, dir);
}
static inline void
dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size,
enum dma_data_direction dir)
{
consistent_sync((void *)dma_to_virt(dev, handle), size, dir);
if (!arch_is_coherent())
consistent_sync((void *)dma_to_virt(dev, handle), size, dir);
}
#else
extern void dma_sync_single_for_cpu(struct device*, dma_addr_t, size_t, enum dma_data_direction);
@ -347,7 +353,8 @@ dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents,
for (i = 0; i < nents; i++, sg++) {
char *virt = page_address(sg->page) + sg->offset;
consistent_sync(virt, sg->length, dir);
if (!arch_is_coherent())
consistent_sync(virt, sg->length, dir);
}
}
@ -359,7 +366,8 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
for (i = 0; i < nents; i++, sg++) {
char *virt = page_address(sg->page) + sg->offset;
consistent_sync(virt, sg->length, dir);
if (!arch_is_coherent())
consistent_sync(virt, sg->length, dir);
}
}
#else

View file

@ -234,6 +234,14 @@ static inline __deprecated void *bus_to_virt(unsigned long x)
#define virt_to_dma(dev, addr) (__arch_virt_to_dma(dev, addr))
#endif
/*
* Optional coherency support. Currently used only by selected
* Intel XSC3-based systems.
*/
#ifndef arch_is_coherent
#define arch_is_coherent() 0
#endif
#endif
#include <asm-generic/memory_model.h>

View file

@ -73,6 +73,7 @@
#define PTE_EXT_AP_URW_SRW (PTE_EXT_AP1|PTE_EXT_AP0)
#define PTE_EXT_TEX(x) ((x) << 6) /* v5 */
#define PTE_EXT_APX (1 << 9) /* v6 */
#define PTE_EXT_COHERENT (1 << 9) /* XScale3 */
#define PTE_EXT_SHARED (1 << 10) /* v6 */
#define PTE_EXT_NG (1 << 11) /* v6 */

View file

@ -156,6 +156,7 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
#define L_PTE_WRITE (1 << 5)
#define L_PTE_EXEC (1 << 6)
#define L_PTE_DIRTY (1 << 7)
#define L_PTE_COHERENT (1 << 9) /* I/O coherent (xsc3) */
#define L_PTE_SHARED (1 << 10) /* shared between CPUs (v6) */
#define L_PTE_ASID (1 << 11) /* non-global (use ASID, v6) */