aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mm')
-rw-r--r--arch/arm/mm/Kconfig7
-rw-r--r--arch/arm/mm/Makefile2
-rw-r--r--arch/arm/mm/cache-l2x0.c104
-rw-r--r--arch/arm/mm/consistent.c17
-rw-r--r--arch/arm/mm/context.c12
-rw-r--r--arch/arm/mm/proc-v6.S14
-rw-r--r--arch/arm/mm/tlb-v6.S4
7 files changed, 146 insertions, 14 deletions
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index aade2f72c920..af3fa9d622ff 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -609,3 +609,10 @@ config NEEDS_SYSCALL_FOR_CMPXCHG
Forget about fast user space cmpxchg support.
It is just not possible.
+config OUTER_CACHE
+ bool
+ default n
+
+config CACHE_L2X0
+ bool
+ select OUTER_CACHE
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index d2f5672ecf62..2f8b95947774 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -66,3 +66,5 @@ obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o
obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o
obj-$(CONFIG_CPU_XSC3) += proc-xsc3.o
obj-$(CONFIG_CPU_V6) += proc-v6.o
+
+obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
new file mode 100644
index 000000000000..08a36f1b35d2
--- /dev/null
+++ b/arch/arm/mm/cache-l2x0.c
@@ -0,0 +1,104 @@
+/*
+ * arch/arm/mm/cache-l2x0.c - L210/L220 cache controller support
+ *
+ * Copyright (C) 2007 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/init.h>
+
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#define CACHE_LINE_SIZE 32
+
+static void __iomem *l2x0_base;
+
+static inline void sync_writel(unsigned long val, unsigned long reg,
+ unsigned long complete_mask)
+{
+ writel(val, l2x0_base + reg);
+ /* wait for the operation to complete */
+ while (readl(l2x0_base + reg) & complete_mask)
+ ;
+}
+
+static inline void cache_sync(void)
+{
+ sync_writel(0, L2X0_CACHE_SYNC, 1);
+}
+
+static inline void l2x0_inv_all(void)
+{
+ /* invalidate all ways */
+ sync_writel(0xff, L2X0_INV_WAY, 0xff);
+ cache_sync();
+}
+
+static void l2x0_inv_range(unsigned long start, unsigned long end)
+{
+ unsigned long addr;
+
+ start &= ~(CACHE_LINE_SIZE - 1);
+ for (addr = start; addr < end; addr += CACHE_LINE_SIZE)
+ sync_writel(addr, L2X0_INV_LINE_PA, 1);
+ cache_sync();
+}
+
+static void l2x0_clean_range(unsigned long start, unsigned long end)
+{
+ unsigned long addr;
+
+ start &= ~(CACHE_LINE_SIZE - 1);
+ for (addr = start; addr < end; addr += CACHE_LINE_SIZE)
+ sync_writel(addr, L2X0_CLEAN_LINE_PA, 1);
+ cache_sync();
+}
+
+static void l2x0_flush_range(unsigned long start, unsigned long end)
+{
+ unsigned long addr;
+
+ start &= ~(CACHE_LINE_SIZE - 1);
+ for (addr = start; addr < end; addr += CACHE_LINE_SIZE)
+ sync_writel(addr, L2X0_CLEAN_INV_LINE_PA, 1);
+ cache_sync();
+}
+
+void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
+{
+ __u32 aux;
+
+ l2x0_base = base;
+
+ /* disable L2X0 */
+ writel(0, l2x0_base + L2X0_CTRL);
+
+ aux = readl(l2x0_base + L2X0_AUX_CTRL);
+ aux &= aux_mask;
+ aux |= aux_val;
+ writel(aux, l2x0_base + L2X0_AUX_CTRL);
+
+ l2x0_inv_all();
+
+ /* enable L2X0 */
+ writel(1, l2x0_base + L2X0_CTRL);
+
+ outer_cache.inv_range = l2x0_inv_range;
+ outer_cache.clean_range = l2x0_clean_range;
+ outer_cache.flush_range = l2x0_flush_range;
+
+ printk(KERN_INFO "L2X0 cache controller enabled\n");
+}
diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
index 6a9c362fef5e..1f9f94f9af4b 100644
--- a/arch/arm/mm/consistent.c
+++ b/arch/arm/mm/consistent.c
@@ -205,9 +205,10 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
* kernel direct-mapped region for device DMA.
*/
{
- unsigned long kaddr = (unsigned long)page_address(page);
- memset(page_address(page), 0, size);
- dmac_flush_range(kaddr, kaddr + size);
+ void *ptr = page_address(page);
+ memset(ptr, 0, size);
+ dmac_flush_range(ptr, ptr + size);
+ outer_flush_range(__pa(ptr), __pa(ptr) + size);
}
/*
@@ -480,20 +481,24 @@ core_initcall(consistent_init);
* platforms with CONFIG_DMABOUNCE.
* Use the driver DMA support - see dma-mapping.h (dma_sync_*)
*/
-void consistent_sync(void *vaddr, size_t size, int direction)
+void consistent_sync(const void *start, size_t size, int direction)
{
- unsigned long start = (unsigned long)vaddr;
- unsigned long end = start + size;
+ const void *end = start + size;
+
+ BUG_ON(!virt_addr_valid(start) || !virt_addr_valid(end - 1));
switch (direction) {
case DMA_FROM_DEVICE: /* invalidate only */
dmac_inv_range(start, end);
+ outer_inv_range(__pa(start), __pa(end));
break;
case DMA_TO_DEVICE: /* writeback only */
dmac_clean_range(start, end);
+ outer_clean_range(__pa(start), __pa(end));
break;
case DMA_BIDIRECTIONAL: /* writeback and invalidate */
dmac_flush_range(start, end);
+ outer_flush_range(__pa(start), __pa(end));
break;
default:
BUG();
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index 79e800202424..9da43a0fdcdf 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -19,7 +19,8 @@ unsigned int cpu_last_asid = { 1 << ASID_BITS };
/*
* We fork()ed a process, and we need a new context for the child
* to run in. We reserve version 0 for initial tasks so we will
- * always allocate an ASID.
+ * always allocate an ASID. The ASID 0 is reserved for the TTBR
+ * register changing sequence.
*/
void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
@@ -38,8 +39,15 @@ void __new_context(struct mm_struct *mm)
* If we've used up all our ASIDs, we need
* to start a new version and flush the TLB.
*/
- if ((asid & ~ASID_MASK) == 0)
+ if ((asid & ~ASID_MASK) == 0) {
+ asid = ++cpu_last_asid;
+ /* set the reserved ASID before flushing the TLB */
+ asm("mcr p15, 0, %0, c13, c0, 1 @ set reserved context ID\n"
+ :
+ : "r" (0));
+ isb();
flush_tlb_all();
+ }
mm->context.id = asid;
}
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index f27d9eb64803..eb42e5b94863 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -33,6 +33,12 @@
#define TTB_RGN_WT (2 << 3)
#define TTB_RGN_WB (3 << 3)
+#ifndef CONFIG_SMP
+#define TTB_FLAGS TTB_RGN_WBWA
+#else
+#define TTB_FLAGS TTB_RGN_WBWA|TTB_S
+#endif
+
ENTRY(cpu_v6_proc_init)
mov pc, lr
@@ -95,9 +101,7 @@ ENTRY(cpu_v6_switch_mm)
#ifdef CONFIG_MMU
mov r2, #0
ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id
-#ifdef CONFIG_SMP
- orr r0, r0, #TTB_RGN_WBWA|TTB_S @ mark PTWs shared, outer cacheable
-#endif
+ orr r0, r0, #TTB_FLAGS
mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB
mcr p15, 0, r2, c7, c10, 4 @ drain write buffer
mcr p15, 0, r0, c2, c0, 0 @ set TTB 0
@@ -206,9 +210,7 @@ __v6_setup:
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs
mcr p15, 0, r0, c2, c0, 2 @ TTB control register
-#ifdef CONFIG_SMP
- orr r4, r4, #TTB_RGN_WBWA|TTB_S @ mark PTWs shared, outer cacheable
-#endif
+ orr r4, r4, #TTB_FLAGS
mcr p15, 0, r4, c2, c0, 1 @ load TTB1
#endif /* CONFIG_MMU */
adr r5, v6_crval
diff --git a/arch/arm/mm/tlb-v6.S b/arch/arm/mm/tlb-v6.S
index fd6adde39091..20f84bbaa9bb 100644
--- a/arch/arm/mm/tlb-v6.S
+++ b/arch/arm/mm/tlb-v6.S
@@ -53,6 +53,8 @@ ENTRY(v6wbi_flush_user_tlb_range)
add r0, r0, #PAGE_SZ
cmp r0, r1
blo 1b
+ mcr p15, 0, ip, c7, c5, 6 @ flush BTAC/BTB
+ mcr p15, 0, ip, c7, c10, 4 @ data synchronization barrier
mov pc, lr
/*
@@ -80,7 +82,9 @@ ENTRY(v6wbi_flush_kern_tlb_range)
add r0, r0, #PAGE_SZ
cmp r0, r1
blo 1b
+ mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB
mcr p15, 0, r2, c7, c10, 4 @ data synchronization barrier
+ mcr p15, 0, r2, c7, c5, 4 @ prefetch flush
mov pc, lr
.section ".text.init", #alloc, #execinstr