summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sh/Kconfig1
-rw-r--r--arch/sh/Kconfig.cpu3
-rw-r--r--arch/sh/include/asm/cpu-features.h1
-rw-r--r--arch/sh/include/asm/mmu_context.h15
-rw-r--r--arch/sh/include/asm/mmu_context_32.h12
-rw-r--r--arch/sh/include/cpu-sh4/cpu/mmu_context.h35
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c2
-rw-r--r--arch/sh/kernel/setup.c2
-rw-r--r--arch/sh/mm/Makefile_326
-rw-r--r--arch/sh/mm/tlb-pteaex.c99
10 files changed, 148 insertions, 28 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index a0c879d17fd6..6c56495fd158 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -365,6 +365,7 @@ config CPU_SUBTYPE_SH7786
bool "Support SH7786 processor"
select CPU_SH4A
select CPU_SHX3
+ select CPU_HAS_PTEAEX
select ARCH_SPARSEMEM_ENABLE
select SYS_SUPPORTS_NUMA
diff --git a/arch/sh/Kconfig.cpu b/arch/sh/Kconfig.cpu
index 0e27fe3b182b..c7d704381a6d 100644
--- a/arch/sh/Kconfig.cpu
+++ b/arch/sh/Kconfig.cpu
@@ -104,6 +104,9 @@ config CPU_HAS_SR_RB
config CPU_HAS_PTEA
bool
+config CPU_HAS_PTEAEX
+ bool
+
config CPU_HAS_DSP
bool
diff --git a/arch/sh/include/asm/cpu-features.h b/arch/sh/include/asm/cpu-features.h
index 86308aa39731..694abe490edb 100644
--- a/arch/sh/include/asm/cpu-features.h
+++ b/arch/sh/include/asm/cpu-features.h
@@ -21,5 +21,6 @@
#define CPU_HAS_LLSC 0x0040 /* movli.l/movco.l */
#define CPU_HAS_L2_CACHE 0x0080 /* Secondary cache / URAM */
#define CPU_HAS_OP32 0x0100 /* 32-bit instruction support */
+#define CPU_HAS_PTEAEX 0x0200 /* PTE ASID Extension support */
#endif /* __ASM_SH_CPU_FEATURES_H */
diff --git a/arch/sh/include/asm/mmu_context.h b/arch/sh/include/asm/mmu_context.h
index 5d9157bd474d..2a9c55f1a83f 100644
--- a/arch/sh/include/asm/mmu_context.h
+++ b/arch/sh/include/asm/mmu_context.h
@@ -19,13 +19,18 @@
* (a) TLB cache version (or round, cycle whatever expression you like)
* (b) ASID (Address Space IDentifier)
*/
+#ifdef CONFIG_CPU_HAS_PTEAEX
+#define MMU_CONTEXT_ASID_MASK 0x0000ffff
+#else
#define MMU_CONTEXT_ASID_MASK 0x000000ff
-#define MMU_CONTEXT_VERSION_MASK 0xffffff00
-#define MMU_CONTEXT_FIRST_VERSION 0x00000100
-#define NO_CONTEXT 0UL
+#endif
-/* ASID is 8-bit value, so it can't be 0x100 */
-#define MMU_NO_ASID 0x100
+#define MMU_CONTEXT_VERSION_MASK (~0UL & ~MMU_CONTEXT_ASID_MASK)
+#define MMU_CONTEXT_FIRST_VERSION (MMU_CONTEXT_ASID_MASK + 1)
+
+/* Impossible ASID value, to differentiate from NO_CONTEXT. */
+#define MMU_NO_ASID MMU_CONTEXT_FIRST_VERSION
+#define NO_CONTEXT 0UL
#define asid_cache(cpu) (cpu_data[cpu].asid_cache)
diff --git a/arch/sh/include/asm/mmu_context_32.h b/arch/sh/include/asm/mmu_context_32.h
index f4f9aebd68b7..8ef800c549ab 100644
--- a/arch/sh/include/asm/mmu_context_32.h
+++ b/arch/sh/include/asm/mmu_context_32.h
@@ -10,6 +10,17 @@ static inline void destroy_context(struct mm_struct *mm)
/* Do nothing */
}
+#ifdef CONFIG_CPU_HAS_PTEAEX
+static inline void set_asid(unsigned long asid)
+{
+ __raw_writel(asid, MMU_PTEAEX);
+}
+
+static inline unsigned long get_asid(void)
+{
+ return __raw_readl(MMU_PTEAEX) & MMU_CONTEXT_ASID_MASK;
+}
+#else
static inline void set_asid(unsigned long asid)
{
unsigned long __dummy;
@@ -33,6 +44,7 @@ static inline unsigned long get_asid(void)
asid &= MMU_CONTEXT_ASID_MASK;
return asid;
}
+#endif /* CONFIG_CPU_HAS_PTEAEX */
/* MMU_TTB is used for optimizing the fault handling. */
static inline void set_TTB(pgd_t *pgd)
diff --git a/arch/sh/include/cpu-sh4/cpu/mmu_context.h b/arch/sh/include/cpu-sh4/cpu/mmu_context.h
index 9ea8eb27b18e..3ce7ef6c2978 100644
--- a/arch/sh/include/cpu-sh4/cpu/mmu_context.h
+++ b/arch/sh/include/cpu-sh4/cpu/mmu_context.h
@@ -14,28 +14,35 @@
#define MMU_PTEL 0xFF000004 /* Page table entry register LOW */
#define MMU_TTB 0xFF000008 /* Translation table base register */
#define MMU_TEA 0xFF00000C /* TLB Exception Address */
-#define MMU_PTEA 0xFF000034 /* Page table entry assistance register */
+#define MMU_PTEA 0xFF000034 /* PTE assistance register */
+#define MMU_PTEAEX 0xFF00007C /* PTE ASID extension register */
#define MMUCR 0xFF000010 /* MMU Control Register */
-#define MMU_ITLB_ADDRESS_ARRAY 0xF2000000
#define MMU_UTLB_ADDRESS_ARRAY 0xF6000000
+#define MMU_UTLB_ADDRESS_ARRAY2 0xF6800000
#define MMU_PAGE_ASSOC_BIT 0x80
#define MMUCR_TI (1<<2)
-#ifdef CONFIG_X2TLB
-#define MMUCR_ME (1 << 7)
-#else
-#define MMUCR_ME (0)
-#endif
-
#if defined(CONFIG_32BIT) && defined(CONFIG_CPU_SUBTYPE_ST40)
#define MMUCR_SE (1 << 4)
#else
#define MMUCR_SE (0)
#endif
+#ifdef CONFIG_CPU_HAS_PTEAEX
+#define MMUCR_AEX (1 << 6)
+#else
+#define MMUCR_AEX (0)
+#endif
+
+#ifdef CONFIG_X2TLB
+#define MMUCR_ME (1 << 7)
+#else
+#define MMUCR_ME (0)
+#endif
+
#ifdef CONFIG_SH_STORE_QUEUES
#define MMUCR_SQMD (1 << 9)
#else
@@ -43,17 +50,7 @@
#endif
#define MMU_NTLB_ENTRIES 64
-#define MMU_CONTROL_INIT (0x05|MMUCR_SQMD|MMUCR_ME|MMUCR_SE)
-
-#define MMU_ITLB_DATA_ARRAY 0xF3000000
-#define MMU_UTLB_DATA_ARRAY 0xF7000000
-
-#define MMU_UTLB_ENTRIES 64
-#define MMU_U_ENTRY_SHIFT 8
-#define MMU_UTLB_VALID 0x100
-#define MMU_ITLB_ENTRIES 4
-#define MMU_I_ENTRY_SHIFT 8
-#define MMU_ITLB_VALID 0x100
+#define MMU_CONTROL_INIT (0x05|MMUCR_SQMD|MMUCR_ME|MMUCR_SE|MMUCR_AEX)
#define TRA 0xff000020
#define EXPEVT 0xff000024
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index 2bd0ec962639..3d3a3c4425a9 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -134,7 +134,7 @@ int __init detect_cpu_and_cache_system(void)
boot_cpu_data.icache.ways = 4;
boot_cpu_data.dcache.ways = 4;
boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
- CPU_HAS_LLSC;
+ CPU_HAS_LLSC | CPU_HAS_PTEAEX;
break;
case 0x3008:
boot_cpu_data.icache.ways = 4;
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 61ab2a7f8647..24c60251f680 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -449,7 +449,7 @@ EXPORT_SYMBOL(get_cpu_subtype);
/* Symbolic CPU flags, keep in sync with asm/cpu-features.h */
static const char *cpu_flags[] = {
"none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr",
- "ptea", "llsc", "l2", "op32", NULL
+ "ptea", "llsc", "l2", "op32", "pteaex", NULL
};
static void show_cpuflags(struct seq_file *m, struct sh_cpuinfo *c)
diff --git a/arch/sh/mm/Makefile_32 b/arch/sh/mm/Makefile_32
index 469ff1672451..986a1e055834 100644
--- a/arch/sh/mm/Makefile_32
+++ b/arch/sh/mm/Makefile_32
@@ -25,8 +25,10 @@ obj-$(CONFIG_CPU_SH4) += cache-debugfs.o
endif
ifdef CONFIG_MMU
-obj-$(CONFIG_CPU_SH3) += tlb-sh3.o
-obj-$(CONFIG_CPU_SH4) += tlb-sh4.o
+tlb-$(CONFIG_CPU_SH3) := tlb-sh3.o
+tlb-$(CONFIG_CPU_SH4) := tlb-sh4.o
+tlb-$(CONFIG_CPU_HAS_PTEAEX) := tlb-pteaex.o
+obj-y += $(tlb-y)
ifndef CONFIG_CACHE_OFF
obj-$(CONFIG_CPU_SH4) += pg-sh4.o
obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o
diff --git a/arch/sh/mm/tlb-pteaex.c b/arch/sh/mm/tlb-pteaex.c
new file mode 100644
index 000000000000..5c9b2d781e08
--- /dev/null
+++ b/arch/sh/mm/tlb-pteaex.c
@@ -0,0 +1,99 @@
+/*
+ * arch/sh/mm/tlb-pteaex.c
+ *
+ * TLB operations for SH-X3 CPUs featuring PTE ASID Extensions.
+ *
+ * Copyright (C) 2009 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <asm/system.h>
+#include <asm/mmu_context.h>
+#include <asm/cacheflush.h>
+
+void update_mmu_cache(struct vm_area_struct * vma,
+ unsigned long address, pte_t pte)
+{
+ unsigned long flags;
+ unsigned long pteval;
+ unsigned long vpn;
+
+ /* Ptrace may call this routine. */
+ if (vma && current->active_mm != vma->vm_mm)
+ return;
+
+#ifndef CONFIG_CACHE_OFF
+ {
+ unsigned long pfn = pte_pfn(pte);
+
+ if (pfn_valid(pfn)) {
+ struct page *page = pfn_to_page(pfn);
+
+ if (!test_bit(PG_mapped, &page->flags)) {
+ unsigned long phys = pte_val(pte) & PTE_PHYS_MASK;
+ __flush_wback_region((void *)P1SEGADDR(phys),
+ PAGE_SIZE);
+ __set_bit(PG_mapped, &page->flags);
+ }
+ }
+ }
+#endif
+
+ local_irq_save(flags);
+
+ /* Set PTEH register */
+ vpn = address & MMU_VPN_MASK;
+ __raw_writel(vpn, MMU_PTEH);
+
+ /* Set PTEAEX */
+ __raw_writel(get_asid(), MMU_PTEAEX);
+
+ pteval = pte.pte_low;
+
+ /* Set PTEA register */
+#ifdef CONFIG_X2TLB
+ /*
+ * For the extended mode TLB this is trivial, only the ESZ and
+ * EPR bits need to be written out to PTEA, with the remainder of
+ * the protection bits (with the exception of the compat-mode SZ
+ * and PR bits, which are cleared) being written out in PTEL.
+ */
+ __raw_writel(pte.pte_high, MMU_PTEA);
+#else
+ /* TODO: make this look less hacky */
+ __raw_writel(((pteval >> 28) & 0xe) | (pteval & 0x1), MMU_PTEA);
+#endif
+
+ /* Set PTEL register */
+ pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
+#ifdef CONFIG_CACHE_WRITETHROUGH
+ pteval |= _PAGE_WT;
+#endif
+ /* conveniently, we want all the software flags to be 0 anyway */
+ __raw_writel(pteval, MMU_PTEL);
+
+ /* Load the TLB */
+ asm volatile("ldtlb": /* no output */ : /* no input */ : "memory");
+ local_irq_restore(flags);
+}
+
+/*
+ * While SH-X2 extended TLB mode splits out the memory-mapped I/UTLB
+ * data arrays, SH-X3 cores with PTEAEX split out the memory-mapped
+ * address arrays. In compat mode the second array is inaccessible, while
+ * in extended mode, the legacy 8-bit ASID field in address array 1 has
+ * undefined behaviour.
+ */
+void __uses_jump_to_uncached local_flush_tlb_one(unsigned long asid,
+ unsigned long page)
+{
+ jump_to_uncached();
+ __raw_writel(page, MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT);
+ __raw_writel(asid, MMU_UTLB_ADDRESS_ARRAY2 | MMU_PAGE_ASSOC_BIT);
+ back_to_cached();
+}