From: Vladimir Serbinenko Date: Mon, 23 Dec 2013 04:01:58 +0000 (+0100) Subject: Enable cache on ARM U-Boot port. X-Git-Tag: grub-2.02-beta2~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bbc52c228ff3ef4e969bb6814adc1184162990cb;p=thirdparty%2Fgrub.git Enable cache on ARM U-Boot port. Without it the port is reidiculously slow. --- diff --git a/ChangeLog b/ChangeLog index 02a225834..30a752b5b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2013-12-23 Vladimir Serbinenko + + Enable cache on ARM U-Boot port. + + Without it the port is reidiculously slow. + 2013-12-23 Vladimir Serbinenko Fix ARM cache maintainance. diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 51cdcdaa4..1b3142d21 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -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 diff --git a/grub-core/kern/arm/cache.c b/grub-core/kern/arm/cache.c index 0c0cb8816..34154ccdb 100644 --- a/grub-core/kern/arm/cache.c +++ b/grub-core/kern/arm/cache.c @@ -1,6 +1,11 @@ #include #include #include +#ifdef GRUB_MACHINE_UBOOT +#include +#include +#include +#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) { diff --git a/grub-core/kern/arm/cache_armv6.S b/grub-core/kern/arm/cache_armv6.S index c8f94abcf..39da1dfc6 100644 --- a/grub-core/kern/arm/cache_armv6.S +++ b/grub-core/kern/arm/cache_armv6.S @@ -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 diff --git a/grub-core/kern/arm/efi/misc.c b/grub-core/kern/arm/efi/misc.c index efec98061..7cd41842a 100644 --- a/grub-core/kern/arm/efi/misc.c +++ b/grub-core/kern/arm/efi/misc.c @@ -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; } diff --git a/grub-core/kern/uboot/init.c b/grub-core/kern/uboot/init.c index c7ad73daf..5dcc106ed 100644 --- a/grub-core/kern/uboot/init.c +++ b/grub-core/kern/uboot/init.c @@ -31,6 +31,7 @@ #include #include #include +#include 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); diff --git a/grub-core/loader/arm/linux.c b/grub-core/loader/arm/linux.c index ee1c02b25..e6770d96d 100644 --- a/grub-core/loader/arm/linux.c +++ b/grub-core/loader/arm/linux.c @@ -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"); diff --git a/include/grub/arm/system.h b/include/grub/arm/system.h index aa43ed63f..f62c18c13 100644 --- a/include/grub/arm/system.h +++ b/include/grub/arm/system.h @@ -1,13 +1,18 @@ #ifndef GRUB_SYSTEM_CPU_HEADER #define GRUB_SYSTEM_CPU_HEADER +#include + 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 */ diff --git a/include/grub/cache.h b/include/grub/cache.h index c6a0b0ba4..a9b3f529c 100644 --- a/include/grub/cache.h +++ b/include/grub/cache.h @@ -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 */