]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Enable cache on ARM U-Boot port.
authorVladimir Serbinenko <phcoder@gmail.com>
Mon, 23 Dec 2013 04:01:58 +0000 (05:01 +0100)
committerVladimir Serbinenko <phcoder@gmail.com>
Mon, 23 Dec 2013 04:01:58 +0000 (05:01 +0100)
Without it the port is reidiculously slow.

ChangeLog
grub-core/Makefile.am
grub-core/kern/arm/cache.c
grub-core/kern/arm/cache_armv6.S
grub-core/kern/arm/efi/misc.c
grub-core/kern/uboot/init.c
grub-core/loader/arm/linux.c
include/grub/arm/system.h
include/grub/cache.h

index 02a225834cf3ea853217659d1718692c3457d63e..30a752b5ba7df04a3b91d388ef2c4c63aeedaafc 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2013-12-23  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Enable cache on ARM U-Boot port.
+
+       Without it the port is reidiculously slow.
+
 2013-12-23  Vladimir Serbinenko  <phcoder@gmail.com>
 
        Fix ARM cache maintainance.
index 51cdcdaa4c5aed32d8d5875a5eef6f0ac296be62..1b3142d2160737495d09f753aad642b1a4c7f778 100644 (file)
@@ -221,12 +221,14 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/uboot/uboot.h
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/uboot/disk.h
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/system.h
 endif
 
 if COND_arm_efi
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/efi/loader.h
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/system.h
 endif
 
 if COND_arm64_efi
index 0c0cb8816966ae58f4025e72fc3e8e09040bcd36..34154ccdb0e09d7d9fd91c4164fe8577ce449260 100644 (file)
@@ -1,6 +1,11 @@
 #include <grub/dl.h>
 #include <grub/cache.h>
 #include <grub/arm/system.h>
+#ifdef GRUB_MACHINE_UBOOT
+#include <grub/uboot/uboot.h>
+#include <grub/uboot/api_public.h>
+#include <grub/mm.h>
+#endif
 
 /* This is only about cache architecture. It doesn't imply
    the CPU architecture.  */
@@ -13,6 +18,8 @@ static enum
     ARCH_ARMV7
   } type = ARCH_UNKNOWN;
 
+static int is_v6_mmu;
+
 static grub_uint32_t grub_arch_cache_dlinesz;
 static grub_uint32_t grub_arch_cache_ilinesz;
 static grub_uint32_t grub_arch_cache_max_linesz;
@@ -45,8 +52,11 @@ probe_caches (void)
     case 0x4:
     case 0x5:
     case 0x6:
+      is_v6_mmu = 0;
+      break;
     case 0x7:
     case 0xf:
+      is_v6_mmu = 1;
       break;
     default:
       grub_fatal ("Unsupported ARM ID 0x%x", main_id);
@@ -95,6 +105,121 @@ probe_caches (void)
     grub_arch_cache_max_linesz = grub_arch_cache_ilinesz;
 }
 
+#ifdef GRUB_MACHINE_UBOOT
+
+static void subdivide (grub_uint32_t *table, grub_uint32_t *subtable,
+                      grub_uint32_t addr)
+{
+  grub_uint32_t j;
+  addr = addr >> 20 << 20;
+  table[addr >> 20] = (grub_addr_t) subtable | 1;
+  for (j = 0; j < 256; j++)
+    subtable[j] = addr | (j << 12)
+      | (3 << 4) | (3 << 6) | (3 << 8) | (3 << 10)
+      | (0 << 3) | (1 << 2) | 2;
+}
+
+void
+grub_arm_enable_caches_mmu (void)
+{
+  grub_uint32_t *table;
+  grub_uint32_t i;
+  grub_uint32_t border_crossing = 0;
+  grub_uint32_t *subtable;
+  struct sys_info *si = grub_uboot_get_sys_info ();
+
+  if (!si || (si->mr_no == 0))
+    {
+      grub_printf ("couldn't get memory map, not enabling caches");
+      grub_errno = GRUB_ERR_NONE;
+      return;
+    }
+
+  if (type == ARCH_UNKNOWN)
+    probe_caches ();
+
+  for (i = 0; (signed) i < si->mr_no; i++)
+    {
+      if (si->mr[i].start & ((1 << 20) - 1))
+       border_crossing++;
+      if ((si->mr[i].start + si->mr[i].size) & ((1 << 20) - 1))
+       border_crossing++;
+    }
+
+  grub_printf ("%d crossers\n", border_crossing);
+
+  table = grub_memalign (1 << 14, (1 << 14) + (border_crossing << 10));
+  if (!table)
+    {
+      grub_printf ("couldn't allocate place for MMU table, not enabling caches");
+      grub_errno = GRUB_ERR_NONE;
+      return;
+    }
+
+  subtable = table + (1 << 12);
+  /* Map all unknown as device.  */
+  for (i = 0; i < (1 << 12); i++)
+    table[i] = (i << 20) | (3 << 10) | (0 << 3) | (1 << 2) | 2;
+  /*
+    Device: TEX= 0, C=0, B=1
+    normal: TEX= 0, C=1, B=1
+    AP = 3
+    IMP = 0
+    Domain = 0
+*/
+
+  for (i = 0; (signed) i < si->mr_no; i++)
+    {
+      if (si->mr[i].start & ((1 << 20) - 1))
+       {
+         subdivide (table, subtable, si->mr[i].start);
+         subtable += (1 << 8);
+       }
+      if ((si->mr[i].start + si->mr[i].size) & ((1 << 20) - 1))
+       {
+         subdivide (table, subtable, si->mr[i].start + si->mr[i].size);
+         subtable += (1 << 8);
+       }
+    }
+
+  for (i = 0; (signed) i < si->mr_no; i++)
+    if ((si->mr[i].flags & MR_ATTR_MASK) == MR_ATTR_DRAM
+       || (si->mr[i].flags & MR_ATTR_MASK) == MR_ATTR_SRAM
+       || (si->mr[i].flags & MR_ATTR_MASK) == MR_ATTR_FLASH)
+      {
+       grub_uint32_t cur, end;
+       cur = si->mr[i].start;
+       end = si->mr[i].start + si->mr[i].size;
+       while (cur < end)
+         {
+           grub_uint32_t *st;
+           if ((table[cur >> 20] & 3) == 2)
+             {
+               cur = cur >> 20 << 20;
+               table[cur >> 20] = cur | (3 << 10) | (1 << 3) | (1 << 2) | 2;
+               cur += (1 << 20);
+               continue;
+             }
+           cur = cur >> 12 << 12;
+           st = (grub_uint32_t *) (table[cur >> 20] & ~0x3ff);
+           st[(cur >> 12) & 0xff] = cur | (3 << 4) | (3 << 6)
+             | (3 << 8) | (3 << 10)
+             | (1 << 3) | (1 << 2) | 2;
+           cur += (1 << 12);
+         }
+      }
+
+  grub_printf ("MMU tables generated\n");
+  if (is_v6_mmu)
+    grub_arm_clear_mmu_v6 ();
+
+  grub_printf ("enabling MMU\n");
+  grub_arm_enable_mmu (table);
+  grub_printf ("MMU enabled\n");
+}
+
+#endif
+
 void
 grub_arch_sync_caches (void *address, grub_size_t len)
 {
index c8f94abcfdc5ba84686a1ea02c730091407a638c..39da1dfc60665803acf3cdde814d89e06dee0b55 100644 (file)
@@ -41,4 +41,33 @@ FUNCTION(grub_arm_main_id)
 
 FUNCTION(grub_arm_cache_type)
        mrc     p15, 0, r0, c0, c0, 1
-       bx lr
\ No newline at end of file
+       bx lr
+
+FUNCTION(grub_arm_clear_mmu_v6)
+       mov     r0, #0
+       mcr     p15, 0, r0, c2, c0, 2
+       bx      lr
+
+FUNCTION(grub_arm_enable_mmu)
+       mcr     p15, 0, r0, c2, c0, 0
+
+       mvn     r0, #0
+       mcr     p15, 0, r0, c3, c0, 0
+
+       mrc     p15, 0, r0, c1, c0, 0
+       bic     r0, r0, #(1 << 23)
+       mcr     p15, 0, r0, c1, c0, 0
+
+       mrc     p15, 0, r0, c1, c0, 0
+       orr     r0, r0, #(1 << 0)
+       mcr     p15, 0, r0, c1, c0, 0
+
+       mrc     p15, 0, r0, c1, c0, 0
+       orr     r0, r0, #(1 << 2)
+       mcr     p15, 0, r0, c1, c0, 0
+
+       mrc     p15, 0, r0, c1, c0, 0
+       orr     r0, r0, #(1 << 12)
+       mcr     p15, 0, r0, c1, c0, 0
+
+       bx      lr
index efec980615061e55511cc1f7c0e8a497b13b266a..7cd41842ae7662018c2ce5ff847aeb250572ec85 100644 (file)
@@ -198,6 +198,5 @@ grub_efi_prepare_platform (void)
   if (err != GRUB_ERR_NONE)
     return err;
 
-  grub_arm_disable_caches_mmu();
   return GRUB_ERR_NONE;
 }
index c7ad73dafe37d932ebf0abd44525f6d3c80972ce..5dcc106ed9bcc1fa2cdbe2ba6cbb9e709420ceb3 100644 (file)
@@ -31,6 +31,7 @@
 #include <grub/uboot/uboot.h>
 #include <grub/uboot/api_public.h>
 #include <grub/cpu/system.h>
+#include <grub/cache.h>
 
 extern char __bss_start[];
 extern char _end[];
@@ -107,6 +108,11 @@ grub_machine_init (void)
   /* Enumerate memory and initialize the memory management system. */
   grub_uboot_mm_init ();
 
+  /* Should be earlier but it needs memalign.  */
+#ifdef __arm__
+  grub_arm_enable_caches_mmu ();
+#endif
+
   grub_dprintf ("init", "__bss_start: %p\n", __bss_start);
   grub_dprintf ("init", "_end: %p\n", _end);
   grub_dprintf ("init", "grub_modbase: %p\n", (void *) grub_modbase);
index ee1c02b25cf26ea490bd935b71adc6ae305ceb01..e6770d96d292189356be046fb36399f313ec74f4 100644 (file)
@@ -283,6 +283,8 @@ linux_boot (void)
   }
 #endif
 
+  grub_arm_disable_caches_mmu ();
+
   linuxmain (0, machine_type, fdt_addr);
 
   return grub_error (GRUB_ERR_BAD_OS, "Linux call returned");
index aa43ed63f5ba773227efb21a2d60423d166ec8cd..f62c18c13a870a767c89b33b246989d739811714 100644 (file)
@@ -1,13 +1,18 @@
 #ifndef GRUB_SYSTEM_CPU_HEADER
 #define GRUB_SYSTEM_CPU_HEADER
 
+#include <grub/types.h>
+
 enum
   {
     GRUB_ARM_MACHINE_TYPE_RASPBERRY_PI = 3138,
     GRUB_ARM_MACHINE_TYPE_FDT = 0xFFFFFFFF
   };
 
-void grub_arm_disable_caches_mmu (void);
+void EXPORT_FUNC(grub_arm_disable_caches_mmu) (void);
+void grub_arm_enable_caches_mmu (void);
+void grub_arm_enable_mmu (grub_uint32_t *mmu_tables);
+void grub_arm_clear_mmu_v6 (void);
 
 #endif /* ! GRUB_SYSTEM_CPU_HEADER */
 
index c6a0b0ba447fb3746eb7c7decadf448e3dac6db9..a9b3f529cc7907080f532362a6110a1eaa85a20c 100644 (file)
@@ -45,4 +45,9 @@ grub_arch_sync_dma_caches (void *address __attribute__ ((unused)),
 #endif
 #endif
 
+#ifdef __arm__
+void
+grub_arm_cache_enable (void);
+#endif
+
 #endif /* ! GRUB_CACHE_HEADER */