|
@@ -191,3 +191,175 @@ void adjust_cr(unsigned long mask, unsigned long set)
|
|
|
|
|
|
set_cr((get_cr() & ~mask) | set);
|
|
|
|
|
|
+ local_irq_restore(flags);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+#define PROT_PTE_DEVICE L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_XN
|
|
|
+#define PROT_SECT_DEVICE PMD_TYPE_SECT|PMD_SECT_AP_WRITE
|
|
|
+
|
|
|
+static struct mem_type mem_types[] = {
|
|
|
+ [MT_DEVICE] = { /* Strongly ordered / ARMv6 shared device */
|
|
|
+ .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED |
|
|
|
+ L_PTE_SHARED,
|
|
|
+ .prot_l1 = PMD_TYPE_TABLE,
|
|
|
+ .prot_sect = PROT_SECT_DEVICE | PMD_SECT_S,
|
|
|
+ .domain = DOMAIN_IO,
|
|
|
+ },
|
|
|
+ [MT_DEVICE_NONSHARED] = { /* ARMv6 non-shared device */
|
|
|
+ .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_NONSHARED,
|
|
|
+ .prot_l1 = PMD_TYPE_TABLE,
|
|
|
+ .prot_sect = PROT_SECT_DEVICE,
|
|
|
+ .domain = DOMAIN_IO,
|
|
|
+ },
|
|
|
+ [MT_DEVICE_CACHED] = { /* ioremap_cached */
|
|
|
+ .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_CACHED,
|
|
|
+ .prot_l1 = PMD_TYPE_TABLE,
|
|
|
+ .prot_sect = PROT_SECT_DEVICE | PMD_SECT_WB,
|
|
|
+ .domain = DOMAIN_IO,
|
|
|
+ },
|
|
|
+ [MT_DEVICE_WC] = { /* ioremap_wc */
|
|
|
+ .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_WC,
|
|
|
+ .prot_l1 = PMD_TYPE_TABLE,
|
|
|
+ .prot_sect = PROT_SECT_DEVICE,
|
|
|
+ .domain = DOMAIN_IO,
|
|
|
+ },
|
|
|
+ [MT_UNCACHED] = {
|
|
|
+ .prot_pte = PROT_PTE_DEVICE,
|
|
|
+ .prot_l1 = PMD_TYPE_TABLE,
|
|
|
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,
|
|
|
+ .domain = DOMAIN_IO,
|
|
|
+ },
|
|
|
+ [MT_CACHECLEAN] = {
|
|
|
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,
|
|
|
+ .domain = DOMAIN_KERNEL,
|
|
|
+ },
|
|
|
+#ifndef CONFIG_ARM_LPAE
|
|
|
+ [MT_MINICLEAN] = {
|
|
|
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN | PMD_SECT_MINICACHE,
|
|
|
+ .domain = DOMAIN_KERNEL,
|
|
|
+ },
|
|
|
+#endif
|
|
|
+ [MT_LOW_VECTORS] = {
|
|
|
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
|
|
|
+ L_PTE_RDONLY,
|
|
|
+ .prot_l1 = PMD_TYPE_TABLE,
|
|
|
+ .domain = DOMAIN_USER,
|
|
|
+ },
|
|
|
+ [MT_HIGH_VECTORS] = {
|
|
|
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
|
|
|
+ L_PTE_USER | L_PTE_RDONLY,
|
|
|
+ .prot_l1 = PMD_TYPE_TABLE,
|
|
|
+ .domain = DOMAIN_USER,
|
|
|
+ },
|
|
|
+ [MT_MEMORY] = {
|
|
|
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY,
|
|
|
+ .prot_l1 = PMD_TYPE_TABLE,
|
|
|
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
|
|
|
+ .domain = DOMAIN_KERNEL,
|
|
|
+ },
|
|
|
+ [MT_ROM] = {
|
|
|
+ .prot_sect = PMD_TYPE_SECT,
|
|
|
+ .domain = DOMAIN_KERNEL,
|
|
|
+ },
|
|
|
+ [MT_MEMORY_NONCACHED] = {
|
|
|
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
|
|
|
+ L_PTE_MT_BUFFERABLE,
|
|
|
+ .prot_l1 = PMD_TYPE_TABLE,
|
|
|
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
|
|
|
+ .domain = DOMAIN_KERNEL,
|
|
|
+ },
|
|
|
+ [MT_MEMORY_DTCM] = {
|
|
|
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
|
|
|
+ L_PTE_XN,
|
|
|
+ .prot_l1 = PMD_TYPE_TABLE,
|
|
|
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,
|
|
|
+ .domain = DOMAIN_KERNEL,
|
|
|
+ },
|
|
|
+ [MT_MEMORY_ITCM] = {
|
|
|
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY,
|
|
|
+ .prot_l1 = PMD_TYPE_TABLE,
|
|
|
+ .domain = DOMAIN_KERNEL,
|
|
|
+ },
|
|
|
+ [MT_MEMORY_SO] = {
|
|
|
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
|
|
|
+ L_PTE_MT_UNCACHED | L_PTE_XN,
|
|
|
+ .prot_l1 = PMD_TYPE_TABLE,
|
|
|
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_S |
|
|
|
+ PMD_SECT_UNCACHED | PMD_SECT_XN,
|
|
|
+ .domain = DOMAIN_KERNEL,
|
|
|
+ },
|
|
|
+ [MT_MEMORY_DMA_READY] = {
|
|
|
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY,
|
|
|
+ .prot_l1 = PMD_TYPE_TABLE,
|
|
|
+ .domain = DOMAIN_KERNEL,
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+const struct mem_type *get_mem_type(unsigned int type)
|
|
|
+{
|
|
|
+ return type < ARRAY_SIZE(mem_types) ? &mem_types[type] : NULL;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(get_mem_type);
|
|
|
+
|
|
|
+/*
|
|
|
+ * Adjust the PMD section entries according to the CPU in use.
|
|
|
+ */
|
|
|
+static void __init build_mem_type_table(void)
|
|
|
+{
|
|
|
+ struct cachepolicy *cp;
|
|
|
+ unsigned int cr = get_cr();
|
|
|
+ pteval_t user_pgprot, kern_pgprot, vecs_pgprot;
|
|
|
+ int cpu_arch = cpu_architecture();
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (cpu_arch < CPU_ARCH_ARMv6) {
|
|
|
+#if defined(CONFIG_CPU_DCACHE_DISABLE)
|
|
|
+ if (cachepolicy > CPOLICY_BUFFERED)
|
|
|
+ cachepolicy = CPOLICY_BUFFERED;
|
|
|
+#elif defined(CONFIG_CPU_DCACHE_WRITETHROUGH)
|
|
|
+ if (cachepolicy > CPOLICY_WRITETHROUGH)
|
|
|
+ cachepolicy = CPOLICY_WRITETHROUGH;
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ if (cpu_arch < CPU_ARCH_ARMv5) {
|
|
|
+ if (cachepolicy >= CPOLICY_WRITEALLOC)
|
|
|
+ cachepolicy = CPOLICY_WRITEBACK;
|
|
|
+ ecc_mask = 0;
|
|
|
+ }
|
|
|
+ if (is_smp())
|
|
|
+ cachepolicy = CPOLICY_WRITEALLOC;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Strip out features not present on earlier architectures.
|
|
|
+ * Pre-ARMv5 CPUs don't have TEX bits. Pre-ARMv6 CPUs or those
|
|
|
+ * without extended page tables don't have the 'Shared' bit.
|
|
|
+ */
|
|
|
+ if (cpu_arch < CPU_ARCH_ARMv5)
|
|
|
+ for (i = 0; i < ARRAY_SIZE(mem_types); i++)
|
|
|
+ mem_types[i].prot_sect &= ~PMD_SECT_TEX(7);
|
|
|
+ if ((cpu_arch < CPU_ARCH_ARMv6 || !(cr & CR_XP)) && !cpu_is_xsc3())
|
|
|
+ for (i = 0; i < ARRAY_SIZE(mem_types); i++)
|
|
|
+ mem_types[i].prot_sect &= ~PMD_SECT_S;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * ARMv5 and lower, bit 4 must be set for page tables (was: cache
|
|
|
+ * "update-able on write" bit on ARM610). However, Xscale and
|
|
|
+ * Xscale3 require this bit to be cleared.
|
|
|
+ */
|
|
|
+ if (cpu_is_xscale() || cpu_is_xsc3()) {
|
|
|
+ for (i = 0; i < ARRAY_SIZE(mem_types); i++) {
|
|
|
+ mem_types[i].prot_sect &= ~PMD_BIT4;
|
|
|
+ mem_types[i].prot_l1 &= ~PMD_BIT4;
|
|
|
+ }
|
|
|
+ } else if (cpu_arch < CPU_ARCH_ARMv6) {
|
|
|
+ for (i = 0; i < ARRAY_SIZE(mem_types); i++) {
|
|
|
+ if (mem_types[i].prot_l1)
|
|
|
+ mem_types[i].prot_l1 |= PMD_BIT4;
|
|
|
+ if (mem_types[i].prot_sect)
|
|
|
+ mem_types[i].prot_sect |= PMD_BIT4;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Mark the device areas according to the CPU/architecture.
|