Commit 26a26d32 authored by Russell King's avatar Russell King

ARM: dma-mapping: switch ARMv7 DMA mappings to retain 'memory' attribute

On ARMv7, it is invalid to map the same physical address multiple times
with different memory types.  Since system RAM is already mapped as
'memory', subsequent remapping of it must retain this attribute.

However, DMA memory maps it as "strongly ordered".  Fix this by introducing
'pgprot_dmacoherent()' which provides the necessary page table bits for
DMA mappings.
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
Acked-by: default avatarGreg Ungerer <gerg@uclinux.org>
Reviewed-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent acaac256
...@@ -304,13 +304,23 @@ PTE_BIT_FUNC(mkyoung, |= L_PTE_YOUNG); ...@@ -304,13 +304,23 @@ PTE_BIT_FUNC(mkyoung, |= L_PTE_YOUNG);
static inline pte_t pte_mkspecial(pte_t pte) { return pte; } static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
#define __pgprot_modify(prot,mask,bits) \
__pgprot((pgprot_val(prot) & ~(mask)) | (bits))
/* /*
* Mark the prot value as uncacheable and unbufferable. * Mark the prot value as uncacheable and unbufferable.
*/ */
#define pgprot_noncached(prot) \ #define pgprot_noncached(prot) \
__pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_UNCACHED) __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
#define pgprot_writecombine(prot) \ #define pgprot_writecombine(prot) \
__pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_BUFFERABLE) __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE)
#if __LINUX_ARM_ARCH__ >= 7
#define pgprot_dmacoherent(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK|L_PTE_EXEC, L_PTE_MT_BUFFERABLE)
#else
#define pgprot_dmacoherent(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK|L_PTE_EXEC, L_PTE_MT_UNCACHED)
#endif
#define pmd_none(pmd) (!pmd_val(pmd)) #define pmd_none(pmd) (!pmd_val(pmd))
#define pmd_present(pmd) (pmd_val(pmd)) #define pmd_present(pmd) (pmd_val(pmd))
......
...@@ -138,21 +138,26 @@ extern unsigned int user_debug; ...@@ -138,21 +138,26 @@ extern unsigned int user_debug;
#define dmb() __asm__ __volatile__ ("" : : : "memory") #define dmb() __asm__ __volatile__ ("" : : : "memory")
#endif #endif
#ifndef CONFIG_SMP #if __LINUX_ARM_ARCH__ >= 7 || defined(CONFIG_SMP)
#define mb() dmb()
#define rmb() dmb()
#define wmb() dmb()
#else
#define mb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0) #define mb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
#define rmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0) #define rmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
#define wmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0) #define wmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
#endif
#ifndef CONFIG_SMP
#define smp_mb() barrier() #define smp_mb() barrier()
#define smp_rmb() barrier() #define smp_rmb() barrier()
#define smp_wmb() barrier() #define smp_wmb() barrier()
#else #else
#define mb() dmb() #define smp_mb() mb()
#define rmb() dmb() #define smp_rmb() rmb()
#define wmb() dmb() #define smp_wmb() wmb()
#define smp_mb() dmb()
#define smp_rmb() dmb()
#define smp_wmb() dmb()
#endif #endif
#define read_barrier_depends() do { } while(0) #define read_barrier_depends() do { } while(0)
#define smp_read_barrier_depends() do { } while(0) #define smp_read_barrier_depends() do { } while(0)
......
...@@ -317,7 +317,7 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gf ...@@ -317,7 +317,7 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gf
return memory; return memory;
return __dma_alloc(dev, size, handle, gfp, return __dma_alloc(dev, size, handle, gfp,
pgprot_noncached(pgprot_kernel)); pgprot_dmacoherent(pgprot_kernel));
} }
EXPORT_SYMBOL(dma_alloc_coherent); EXPORT_SYMBOL(dma_alloc_coherent);
...@@ -365,7 +365,7 @@ static int dma_mmap(struct device *dev, struct vm_area_struct *vma, ...@@ -365,7 +365,7 @@ static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma, int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
void *cpu_addr, dma_addr_t dma_addr, size_t size) void *cpu_addr, dma_addr_t dma_addr, size_t size)
{ {
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_page_prot = pgprot_dmacoherent(vma->vm_page_prot);
return dma_mmap(dev, vma, cpu_addr, dma_addr, size); return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
} }
EXPORT_SYMBOL(dma_mmap_coherent); EXPORT_SYMBOL(dma_mmap_coherent);
......
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