diff options
Diffstat (limited to 'arch/arm/mm')
| -rw-r--r-- | arch/arm/mm/Kconfig | 51 | ||||
| -rw-r--r-- | arch/arm/mm/Makefile | 6 | ||||
| -rw-r--r-- | arch/arm/mm/cache-fa.S | 220 | ||||
| -rw-r--r-- | arch/arm/mm/cache-feroceon-l2.c | 54 | ||||
| -rw-r--r-- | arch/arm/mm/cache-xsc3l2.c | 107 | ||||
| -rw-r--r-- | arch/arm/mm/copypage-fa.c | 86 | ||||
| -rw-r--r-- | arch/arm/mm/dma-mapping.c | 72 | ||||
| -rw-r--r-- | arch/arm/mm/flush.c | 2 | ||||
| -rw-r--r-- | arch/arm/mm/highmem.c | 116 | ||||
| -rw-r--r-- | arch/arm/mm/init.c | 21 | ||||
| -rw-r--r-- | arch/arm/mm/mm.h | 3 | ||||
| -rw-r--r-- | arch/arm/mm/mmu.c | 43 | ||||
| -rw-r--r-- | arch/arm/mm/proc-fa526.S | 248 | ||||
| -rw-r--r-- | arch/arm/mm/proc-mohawk.S | 416 | ||||
| -rw-r--r-- | arch/arm/mm/tlb-fa.S | 75 |
15 files changed, 1464 insertions, 56 deletions
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index d490f3773c01..20979564e7ee 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig | |||
| @@ -186,6 +186,24 @@ config CPU_ARM926T | |||
| 186 | Say Y if you want support for the ARM926T processor. | 186 | Say Y if you want support for the ARM926T processor. |
| 187 | Otherwise, say N. | 187 | Otherwise, say N. |
| 188 | 188 | ||
| 189 | # FA526 | ||
| 190 | config CPU_FA526 | ||
| 191 | bool | ||
| 192 | select CPU_32v4 | ||
| 193 | select CPU_ABRT_EV4 | ||
| 194 | select CPU_PABRT_NOIFAR | ||
| 195 | select CPU_CACHE_VIVT | ||
| 196 | select CPU_CP15_MMU | ||
| 197 | select CPU_CACHE_FA | ||
| 198 | select CPU_COPY_FA if MMU | ||
| 199 | select CPU_TLB_FA if MMU | ||
| 200 | help | ||
| 201 | The FA526 is a version of the ARMv4 compatible processor with | ||
| 202 | Branch Target Buffer, Unified TLB and cache line size 16. | ||
| 203 | |||
| 204 | Say Y if you want support for the FA526 processor. | ||
| 205 | Otherwise, say N. | ||
| 206 | |||
| 189 | # ARM940T | 207 | # ARM940T |
| 190 | config CPU_ARM940T | 208 | config CPU_ARM940T |
| 191 | bool "Support ARM940T processor" if ARCH_INTEGRATOR | 209 | bool "Support ARM940T processor" if ARCH_INTEGRATOR |
| @@ -340,6 +358,17 @@ config CPU_XSC3 | |||
| 340 | select CPU_TLB_V4WBI if MMU | 358 | select CPU_TLB_V4WBI if MMU |
| 341 | select IO_36 | 359 | select IO_36 |
| 342 | 360 | ||
| 361 | # Marvell PJ1 (Mohawk) | ||
| 362 | config CPU_MOHAWK | ||
| 363 | bool | ||
| 364 | select CPU_32v5 | ||
| 365 | select CPU_ABRT_EV5T | ||
| 366 | select CPU_PABRT_NOIFAR | ||
| 367 | select CPU_CACHE_VIVT | ||
| 368 | select CPU_CP15_MMU | ||
| 369 | select CPU_TLB_V4WBI if MMU | ||
| 370 | select CPU_COPY_V4WB if MMU | ||
| 371 | |||
| 343 | # Feroceon | 372 | # Feroceon |
| 344 | config CPU_FEROCEON | 373 | config CPU_FEROCEON |
| 345 | bool | 374 | bool |
| @@ -484,6 +513,9 @@ config CPU_CACHE_VIVT | |||
| 484 | config CPU_CACHE_VIPT | 513 | config CPU_CACHE_VIPT |
| 485 | bool | 514 | bool |
| 486 | 515 | ||
| 516 | config CPU_CACHE_FA | ||
| 517 | bool | ||
| 518 | |||
| 487 | if MMU | 519 | if MMU |
| 488 | # The copy-page model | 520 | # The copy-page model |
| 489 | config CPU_COPY_V3 | 521 | config CPU_COPY_V3 |
| @@ -498,6 +530,9 @@ config CPU_COPY_V4WB | |||
| 498 | config CPU_COPY_FEROCEON | 530 | config CPU_COPY_FEROCEON |
| 499 | bool | 531 | bool |
| 500 | 532 | ||
| 533 | config CPU_COPY_FA | ||
| 534 | bool | ||
| 535 | |||
| 501 | config CPU_COPY_V6 | 536 | config CPU_COPY_V6 |
| 502 | bool | 537 | bool |
| 503 | 538 | ||
| @@ -528,6 +563,13 @@ config CPU_TLB_FEROCEON | |||
| 528 | help | 563 | help |
| 529 | Feroceon TLB (v4wbi with non-outer-cachable page table walks). | 564 | Feroceon TLB (v4wbi with non-outer-cachable page table walks). |
| 530 | 565 | ||
| 566 | config CPU_TLB_FA | ||
| 567 | bool | ||
| 568 | help | ||
| 569 | Faraday ARM FA526 architecture, unified TLB with writeback cache | ||
| 570 | and invalidate instruction cache entry. Branch target buffer is | ||
| 571 | also supported. | ||
| 572 | |||
| 531 | config CPU_TLB_V6 | 573 | config CPU_TLB_V6 |
| 532 | bool | 574 | bool |
| 533 | 575 | ||
| @@ -569,7 +611,7 @@ comment "Processor Features" | |||
| 569 | 611 | ||
| 570 | config ARM_THUMB | 612 | config ARM_THUMB |
| 571 | bool "Support Thumb user binaries" | 613 | bool "Support Thumb user binaries" |
| 572 | depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6 || CPU_V7 || CPU_FEROCEON | 614 | depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_V6 || CPU_V7 || CPU_FEROCEON |
| 573 | default y | 615 | default y |
| 574 | help | 616 | help |
| 575 | Say Y if you want to include kernel support for running user space | 617 | Say Y if you want to include kernel support for running user space |
| @@ -638,7 +680,7 @@ config CPU_DCACHE_SIZE | |||
| 638 | 680 | ||
| 639 | config CPU_DCACHE_WRITETHROUGH | 681 | config CPU_DCACHE_WRITETHROUGH |
| 640 | bool "Force write through D-cache" | 682 | bool "Force write through D-cache" |
| 641 | depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020) && !CPU_DCACHE_DISABLE | 683 | depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_FA526) && !CPU_DCACHE_DISABLE |
| 642 | default y if CPU_ARM925T | 684 | default y if CPU_ARM925T |
| 643 | help | 685 | help |
| 644 | Say Y here to use the data cache in writethrough mode. Unless you | 686 | Say Y here to use the data cache in writethrough mode. Unless you |
| @@ -653,7 +695,7 @@ config CPU_CACHE_ROUND_ROBIN | |||
| 653 | 695 | ||
| 654 | config CPU_BPREDICT_DISABLE | 696 | config CPU_BPREDICT_DISABLE |
| 655 | bool "Disable branch prediction" | 697 | bool "Disable branch prediction" |
| 656 | depends on CPU_ARM1020 || CPU_V6 || CPU_XSC3 || CPU_V7 | 698 | depends on CPU_ARM1020 || CPU_V6 || CPU_MOHAWK || CPU_XSC3 || CPU_V7 || CPU_FA526 |
| 657 | help | 699 | help |
| 658 | Say Y here to disable branch prediction. If unsure, say N. | 700 | Say Y here to disable branch prediction. If unsure, say N. |
| 659 | 701 | ||
| @@ -704,7 +746,8 @@ config CACHE_FEROCEON_L2_WRITETHROUGH | |||
| 704 | 746 | ||
| 705 | config CACHE_L2X0 | 747 | config CACHE_L2X0 |
| 706 | bool "Enable the L2x0 outer cache controller" | 748 | bool "Enable the L2x0 outer cache controller" |
| 707 | depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || REALVIEW_EB_A9MP | 749 | depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \ |
| 750 | REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31 | ||
| 708 | default y | 751 | default y |
| 709 | select OUTER_CACHE | 752 | select OUTER_CACHE |
| 710 | help | 753 | help |
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index 480f78a3611a..63e3f6dd0e21 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile | |||
| @@ -16,6 +16,7 @@ obj-$(CONFIG_MODULES) += proc-syms.o | |||
| 16 | 16 | ||
| 17 | obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o | 17 | obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o |
| 18 | obj-$(CONFIG_DISCONTIGMEM) += discontig.o | 18 | obj-$(CONFIG_DISCONTIGMEM) += discontig.o |
| 19 | obj-$(CONFIG_HIGHMEM) += highmem.o | ||
| 19 | 20 | ||
| 20 | obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o | 21 | obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o |
| 21 | obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o | 22 | obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o |
| @@ -32,6 +33,7 @@ obj-$(CONFIG_CPU_CACHE_V4WT) += cache-v4wt.o | |||
| 32 | obj-$(CONFIG_CPU_CACHE_V4WB) += cache-v4wb.o | 33 | obj-$(CONFIG_CPU_CACHE_V4WB) += cache-v4wb.o |
| 33 | obj-$(CONFIG_CPU_CACHE_V6) += cache-v6.o | 34 | obj-$(CONFIG_CPU_CACHE_V6) += cache-v6.o |
| 34 | obj-$(CONFIG_CPU_CACHE_V7) += cache-v7.o | 35 | obj-$(CONFIG_CPU_CACHE_V7) += cache-v7.o |
| 36 | obj-$(CONFIG_CPU_CACHE_FA) += cache-fa.o | ||
| 35 | 37 | ||
| 36 | obj-$(CONFIG_CPU_COPY_V3) += copypage-v3.o | 38 | obj-$(CONFIG_CPU_COPY_V3) += copypage-v3.o |
| 37 | obj-$(CONFIG_CPU_COPY_V4WT) += copypage-v4wt.o | 39 | obj-$(CONFIG_CPU_COPY_V4WT) += copypage-v4wt.o |
| @@ -41,6 +43,7 @@ obj-$(CONFIG_CPU_COPY_V6) += copypage-v6.o context.o | |||
| 41 | obj-$(CONFIG_CPU_SA1100) += copypage-v4mc.o | 43 | obj-$(CONFIG_CPU_SA1100) += copypage-v4mc.o |
| 42 | obj-$(CONFIG_CPU_XSCALE) += copypage-xscale.o | 44 | obj-$(CONFIG_CPU_XSCALE) += copypage-xscale.o |
| 43 | obj-$(CONFIG_CPU_XSC3) += copypage-xsc3.o | 45 | obj-$(CONFIG_CPU_XSC3) += copypage-xsc3.o |
| 46 | obj-$(CONFIG_CPU_COPY_FA) += copypage-fa.o | ||
| 44 | 47 | ||
| 45 | obj-$(CONFIG_CPU_TLB_V3) += tlb-v3.o | 48 | obj-$(CONFIG_CPU_TLB_V3) += tlb-v3.o |
| 46 | obj-$(CONFIG_CPU_TLB_V4WT) += tlb-v4.o | 49 | obj-$(CONFIG_CPU_TLB_V4WT) += tlb-v4.o |
| @@ -49,6 +52,7 @@ obj-$(CONFIG_CPU_TLB_V4WBI) += tlb-v4wbi.o | |||
| 49 | obj-$(CONFIG_CPU_TLB_FEROCEON) += tlb-v4wbi.o # reuse v4wbi TLB functions | 52 | obj-$(CONFIG_CPU_TLB_FEROCEON) += tlb-v4wbi.o # reuse v4wbi TLB functions |
| 50 | obj-$(CONFIG_CPU_TLB_V6) += tlb-v6.o | 53 | obj-$(CONFIG_CPU_TLB_V6) += tlb-v6.o |
| 51 | obj-$(CONFIG_CPU_TLB_V7) += tlb-v7.o | 54 | obj-$(CONFIG_CPU_TLB_V7) += tlb-v7.o |
| 55 | obj-$(CONFIG_CPU_TLB_FA) += tlb-fa.o | ||
| 52 | 56 | ||
| 53 | obj-$(CONFIG_CPU_ARM610) += proc-arm6_7.o | 57 | obj-$(CONFIG_CPU_ARM610) += proc-arm6_7.o |
| 54 | obj-$(CONFIG_CPU_ARM710) += proc-arm6_7.o | 58 | obj-$(CONFIG_CPU_ARM710) += proc-arm6_7.o |
| @@ -62,6 +66,7 @@ obj-$(CONFIG_CPU_ARM925T) += proc-arm925.o | |||
| 62 | obj-$(CONFIG_CPU_ARM926T) += proc-arm926.o | 66 | obj-$(CONFIG_CPU_ARM926T) += proc-arm926.o |
| 63 | obj-$(CONFIG_CPU_ARM940T) += proc-arm940.o | 67 | obj-$(CONFIG_CPU_ARM940T) += proc-arm940.o |
| 64 | obj-$(CONFIG_CPU_ARM946E) += proc-arm946.o | 68 | obj-$(CONFIG_CPU_ARM946E) += proc-arm946.o |
| 69 | obj-$(CONFIG_CPU_FA526) += proc-fa526.o | ||
| 65 | obj-$(CONFIG_CPU_ARM1020) += proc-arm1020.o | 70 | obj-$(CONFIG_CPU_ARM1020) += proc-arm1020.o |
| 66 | obj-$(CONFIG_CPU_ARM1020E) += proc-arm1020e.o | 71 | obj-$(CONFIG_CPU_ARM1020E) += proc-arm1020e.o |
| 67 | obj-$(CONFIG_CPU_ARM1022) += proc-arm1022.o | 72 | obj-$(CONFIG_CPU_ARM1022) += proc-arm1022.o |
| @@ -70,6 +75,7 @@ obj-$(CONFIG_CPU_SA110) += proc-sa110.o | |||
| 70 | obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o | 75 | obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o |
| 71 | obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o | 76 | obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o |
| 72 | obj-$(CONFIG_CPU_XSC3) += proc-xsc3.o | 77 | obj-$(CONFIG_CPU_XSC3) += proc-xsc3.o |
| 78 | obj-$(CONFIG_CPU_MOHAWK) += proc-mohawk.o | ||
| 73 | obj-$(CONFIG_CPU_FEROCEON) += proc-feroceon.o | 79 | obj-$(CONFIG_CPU_FEROCEON) += proc-feroceon.o |
| 74 | obj-$(CONFIG_CPU_V6) += proc-v6.o | 80 | obj-$(CONFIG_CPU_V6) += proc-v6.o |
| 75 | obj-$(CONFIG_CPU_V7) += proc-v7.o | 81 | obj-$(CONFIG_CPU_V7) += proc-v7.o |
diff --git a/arch/arm/mm/cache-fa.S b/arch/arm/mm/cache-fa.S new file mode 100644 index 000000000000..b63a8f7b95cf --- /dev/null +++ b/arch/arm/mm/cache-fa.S | |||
| @@ -0,0 +1,220 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mm/cache-fa.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 2005 Faraday Corp. | ||
| 5 | * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> | ||
| 6 | * | ||
| 7 | * Based on cache-v4wb.S: | ||
| 8 | * Copyright (C) 1997-2002 Russell king | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | * | ||
| 14 | * Processors: FA520 FA526 FA626 | ||
| 15 | */ | ||
| 16 | #include <linux/linkage.h> | ||
| 17 | #include <linux/init.h> | ||
| 18 | #include <asm/memory.h> | ||
| 19 | #include <asm/page.h> | ||
| 20 | |||
| 21 | #include "proc-macros.S" | ||
| 22 | |||
| 23 | /* | ||
| 24 | * The size of one data cache line. | ||
| 25 | */ | ||
| 26 | #define CACHE_DLINESIZE 16 | ||
| 27 | |||
| 28 | /* | ||
| 29 | * The total size of the data cache. | ||
| 30 | */ | ||
| 31 | #ifdef CONFIG_ARCH_GEMINI | ||
| 32 | #define CACHE_DSIZE 8192 | ||
| 33 | #else | ||
| 34 | #define CACHE_DSIZE 16384 | ||
| 35 | #endif | ||
| 36 | |||
| 37 | /* FIXME: put optimal value here. Current one is just estimation */ | ||
| 38 | #define CACHE_DLIMIT (CACHE_DSIZE * 2) | ||
| 39 | |||
| 40 | /* | ||
| 41 | * flush_user_cache_all() | ||
| 42 | * | ||
| 43 | * Clean and invalidate all cache entries in a particular address | ||
| 44 | * space. | ||
| 45 | */ | ||
| 46 | ENTRY(fa_flush_user_cache_all) | ||
| 47 | /* FALLTHROUGH */ | ||
| 48 | /* | ||
| 49 | * flush_kern_cache_all() | ||
| 50 | * | ||
| 51 | * Clean and invalidate the entire cache. | ||
| 52 | */ | ||
| 53 | ENTRY(fa_flush_kern_cache_all) | ||
| 54 | mov ip, #0 | ||
| 55 | mov r2, #VM_EXEC | ||
| 56 | __flush_whole_cache: | ||
| 57 | mcr p15, 0, ip, c7, c14, 0 @ clean/invalidate D cache | ||
| 58 | tst r2, #VM_EXEC | ||
| 59 | mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache | ||
| 60 | mcrne p15, 0, ip, c7, c5, 6 @ invalidate BTB | ||
| 61 | mcrne p15, 0, ip, c7, c10, 4 @ drain write buffer | ||
| 62 | mcrne p15, 0, ip, c7, c5, 4 @ prefetch flush | ||
| 63 | mov pc, lr | ||
| 64 | |||
| 65 | /* | ||
| 66 | * flush_user_cache_range(start, end, flags) | ||
| 67 | * | ||
| 68 | * Invalidate a range of cache entries in the specified | ||
| 69 | * address space. | ||
| 70 | * | ||
| 71 | * - start - start address (inclusive, page aligned) | ||
| 72 | * - end - end address (exclusive, page aligned) | ||
| 73 | * - flags - vma_area_struct flags describing address space | ||
| 74 | */ | ||
| 75 | ENTRY(fa_flush_user_cache_range) | ||
| 76 | mov ip, #0 | ||
| 77 | sub r3, r1, r0 @ calculate total size | ||
| 78 | cmp r3, #CACHE_DLIMIT @ total size >= limit? | ||
| 79 | bhs __flush_whole_cache @ flush whole D cache | ||
| 80 | |||
| 81 | 1: tst r2, #VM_EXEC | ||
| 82 | mcrne p15, 0, r0, c7, c5, 1 @ invalidate I line | ||
| 83 | mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry | ||
| 84 | add r0, r0, #CACHE_DLINESIZE | ||
| 85 | cmp r0, r1 | ||
| 86 | blo 1b | ||
| 87 | tst r2, #VM_EXEC | ||
| 88 | mcrne p15, 0, ip, c7, c5, 6 @ invalidate BTB | ||
| 89 | mcrne p15, 0, ip, c7, c10, 4 @ data write barrier | ||
| 90 | mcrne p15, 0, ip, c7, c5, 4 @ prefetch flush | ||
| 91 | mov pc, lr | ||
| 92 | |||
| 93 | /* | ||
| 94 | * coherent_kern_range(start, end) | ||
| 95 | * | ||
| 96 | * Ensure coherency between the Icache and the Dcache in the | ||
| 97 | * region described by start. If you have non-snooping | ||
| 98 | * Harvard caches, you need to implement this function. | ||
| 99 | * | ||
| 100 | * - start - virtual start address | ||
| 101 | * - end - virtual end address | ||
| 102 | */ | ||
| 103 | ENTRY(fa_coherent_kern_range) | ||
| 104 | /* fall through */ | ||
| 105 | |||
| 106 | /* | ||
| 107 | * coherent_user_range(start, end) | ||
| 108 | * | ||
| 109 | * Ensure coherency between the Icache and the Dcache in the | ||
| 110 | * region described by start. If you have non-snooping | ||
| 111 | * Harvard caches, you need to implement this function. | ||
| 112 | * | ||
| 113 | * - start - virtual start address | ||
| 114 | * - end - virtual end address | ||
| 115 | */ | ||
| 116 | ENTRY(fa_coherent_user_range) | ||
| 117 | bic r0, r0, #CACHE_DLINESIZE - 1 | ||
| 118 | 1: mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry | ||
| 119 | mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry | ||
| 120 | add r0, r0, #CACHE_DLINESIZE | ||
| 121 | cmp r0, r1 | ||
| 122 | blo 1b | ||
| 123 | mov r0, #0 | ||
| 124 | mcr p15, 0, r0, c7, c5, 6 @ invalidate BTB | ||
| 125 | mcr p15, 0, r0, c7, c10, 4 @ drain write buffer | ||
| 126 | mcr p15, 0, r0, c7, c5, 4 @ prefetch flush | ||
| 127 | mov pc, lr | ||
| 128 | |||
| 129 | /* | ||
| 130 | * flush_kern_dcache_page(kaddr) | ||
| 131 | * | ||
| 132 | * Ensure that the data held in the page kaddr is written back | ||
| 133 | * to the page in question. | ||
| 134 | * | ||
| 135 | * - kaddr - kernel address (guaranteed to be page aligned) | ||
| 136 | */ | ||
| 137 | ENTRY(fa_flush_kern_dcache_page) | ||
| 138 | add r1, r0, #PAGE_SZ | ||
| 139 | 1: mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line | ||
| 140 | add r0, r0, #CACHE_DLINESIZE | ||
| 141 | cmp r0, r1 | ||
| 142 | blo 1b | ||
| 143 | mov r0, #0 | ||
| 144 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 145 | mcr p15, 0, r0, c7, c10, 4 @ drain write buffer | ||
| 146 | mov pc, lr | ||
| 147 | |||
| 148 | /* | ||
| 149 | * dma_inv_range(start, end) | ||
| 150 | * | ||
| 151 | * Invalidate (discard) the specified virtual address range. | ||
| 152 | * May not write back any entries. If 'start' or 'end' | ||
| 153 | * are not cache line aligned, those lines must be written | ||
| 154 | * back. | ||
| 155 | * | ||
| 156 | * - start - virtual start address | ||
| 157 | * - end - virtual end address | ||
| 158 | */ | ||
| 159 | ENTRY(fa_dma_inv_range) | ||
| 160 | tst r0, #CACHE_DLINESIZE - 1 | ||
| 161 | bic r0, r0, #CACHE_DLINESIZE - 1 | ||
| 162 | mcrne p15, 0, r0, c7, c14, 1 @ clean & invalidate D entry | ||
| 163 | tst r1, #CACHE_DLINESIZE - 1 | ||
| 164 | bic r1, r1, #CACHE_DLINESIZE - 1 | ||
| 165 | mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate D entry | ||
| 166 | 1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry | ||
| 167 | add r0, r0, #CACHE_DLINESIZE | ||
| 168 | cmp r0, r1 | ||
| 169 | blo 1b | ||
| 170 | mov r0, #0 | ||
| 171 | mcr p15, 0, r0, c7, c10, 4 @ drain write buffer | ||
| 172 | mov pc, lr | ||
| 173 | |||
| 174 | /* | ||
| 175 | * dma_clean_range(start, end) | ||
| 176 | * | ||
| 177 | * Clean (write back) the specified virtual address range. | ||
| 178 | * | ||
| 179 | * - start - virtual start address | ||
| 180 | * - end - virtual end address | ||
| 181 | */ | ||
| 182 | ENTRY(fa_dma_clean_range) | ||
| 183 | bic r0, r0, #CACHE_DLINESIZE - 1 | ||
| 184 | 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry | ||
| 185 | add r0, r0, #CACHE_DLINESIZE | ||
| 186 | cmp r0, r1 | ||
| 187 | blo 1b | ||
| 188 | mov r0, #0 | ||
| 189 | mcr p15, 0, r0, c7, c10, 4 @ drain write buffer | ||
| 190 | mov pc, lr | ||
| 191 | |||
| 192 | /* | ||
| 193 | * dma_flush_range(start,end) | ||
| 194 | * - start - virtual start address of region | ||
| 195 | * - end - virtual end address of region | ||
| 196 | */ | ||
| 197 | ENTRY(fa_dma_flush_range) | ||
| 198 | bic r0, r0, #CACHE_DLINESIZE - 1 | ||
| 199 | 1: mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D entry | ||
| 200 | add r0, r0, #CACHE_DLINESIZE | ||
| 201 | cmp r0, r1 | ||
| 202 | blo 1b | ||
| 203 | mov r0, #0 | ||
| 204 | mcr p15, 0, r0, c7, c10, 4 @ drain write buffer | ||
| 205 | mov pc, lr | ||
| 206 | |||
| 207 | __INITDATA | ||
| 208 | |||
| 209 | .type fa_cache_fns, #object | ||
| 210 | ENTRY(fa_cache_fns) | ||
| 211 | .long fa_flush_kern_cache_all | ||
| 212 | .long fa_flush_user_cache_all | ||
| 213 | .long fa_flush_user_cache_range | ||
| 214 | .long fa_coherent_kern_range | ||
| 215 | .long fa_coherent_user_range | ||
| 216 | .long fa_flush_kern_dcache_page | ||
| 217 | .long fa_dma_inv_range | ||
| 218 | .long fa_dma_clean_range | ||
| 219 | .long fa_dma_flush_range | ||
| 220 | .size fa_cache_fns, . - fa_cache_fns | ||
diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c index 80cd207cbaea..d6dd83826f8a 100644 --- a/arch/arm/mm/cache-feroceon-l2.c +++ b/arch/arm/mm/cache-feroceon-l2.c | |||
| @@ -14,8 +14,12 @@ | |||
| 14 | 14 | ||
| 15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 16 | #include <asm/cacheflush.h> | 16 | #include <asm/cacheflush.h> |
| 17 | #include <asm/kmap_types.h> | ||
| 18 | #include <asm/fixmap.h> | ||
| 19 | #include <asm/pgtable.h> | ||
| 20 | #include <asm/tlbflush.h> | ||
| 17 | #include <plat/cache-feroceon-l2.h> | 21 | #include <plat/cache-feroceon-l2.h> |
| 18 | 22 | #include "mm.h" | |
| 19 | 23 | ||
| 20 | /* | 24 | /* |
| 21 | * Low-level cache maintenance operations. | 25 | * Low-level cache maintenance operations. |
| @@ -34,14 +38,36 @@ | |||
| 34 | * The range operations require two successive cp15 writes, in | 38 | * The range operations require two successive cp15 writes, in |
| 35 | * between which we don't want to be preempted. | 39 | * between which we don't want to be preempted. |
| 36 | */ | 40 | */ |
| 41 | |||
| 42 | static inline unsigned long l2_start_va(unsigned long paddr) | ||
| 43 | { | ||
| 44 | #ifdef CONFIG_HIGHMEM | ||
| 45 | /* | ||
| 46 | * Let's do our own fixmap stuff in a minimal way here. | ||
| 47 | * Because range ops can't be done on physical addresses, | ||
| 48 | * we simply install a virtual mapping for it only for the | ||
| 49 | * TLB lookup to occur, hence no need to flush the untouched | ||
| 50 | * memory mapping. This is protected with the disabling of | ||
| 51 | * interrupts by the caller. | ||
| 52 | */ | ||
| 53 | unsigned long idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id(); | ||
| 54 | unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); | ||
| 55 | set_pte_ext(TOP_PTE(vaddr), pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL), 0); | ||
| 56 | local_flush_tlb_kernel_page(vaddr); | ||
| 57 | return vaddr + (paddr & ~PAGE_MASK); | ||
| 58 | #else | ||
| 59 | return __phys_to_virt(paddr); | ||
| 60 | #endif | ||
| 61 | } | ||
| 62 | |||
| 37 | static inline void l2_clean_pa(unsigned long addr) | 63 | static inline void l2_clean_pa(unsigned long addr) |
| 38 | { | 64 | { |
| 39 | __asm__("mcr p15, 1, %0, c15, c9, 3" : : "r" (addr)); | 65 | __asm__("mcr p15, 1, %0, c15, c9, 3" : : "r" (addr)); |
| 40 | } | 66 | } |
| 41 | 67 | ||
| 42 | static inline void l2_clean_mva_range(unsigned long start, unsigned long end) | 68 | static inline void l2_clean_pa_range(unsigned long start, unsigned long end) |
| 43 | { | 69 | { |
| 44 | unsigned long flags; | 70 | unsigned long va_start, va_end, flags; |
| 45 | 71 | ||
| 46 | /* | 72 | /* |
| 47 | * Make sure 'start' and 'end' reference the same page, as | 73 | * Make sure 'start' and 'end' reference the same page, as |
| @@ -51,17 +77,14 @@ static inline void l2_clean_mva_range(unsigned long start, unsigned long end) | |||
| 51 | BUG_ON((start ^ end) >> PAGE_SHIFT); | 77 | BUG_ON((start ^ end) >> PAGE_SHIFT); |
| 52 | 78 | ||
| 53 | raw_local_irq_save(flags); | 79 | raw_local_irq_save(flags); |
| 80 | va_start = l2_start_va(start); | ||
| 81 | va_end = va_start + (end - start); | ||
| 54 | __asm__("mcr p15, 1, %0, c15, c9, 4\n\t" | 82 | __asm__("mcr p15, 1, %0, c15, c9, 4\n\t" |
| 55 | "mcr p15, 1, %1, c15, c9, 5" | 83 | "mcr p15, 1, %1, c15, c9, 5" |
| 56 | : : "r" (start), "r" (end)); | 84 | : : "r" (va_start), "r" (va_end)); |
| 57 | raw_local_irq_restore(flags); | 85 | raw_local_irq_restore(flags); |
| 58 | } | 86 | } |
| 59 | 87 | ||
| 60 | static inline void l2_clean_pa_range(unsigned long start, unsigned long end) | ||
| 61 | { | ||
| 62 | l2_clean_mva_range(__phys_to_virt(start), __phys_to_virt(end)); | ||
| 63 | } | ||
| 64 | |||
| 65 | static inline void l2_clean_inv_pa(unsigned long addr) | 88 | static inline void l2_clean_inv_pa(unsigned long addr) |
| 66 | { | 89 | { |
| 67 | __asm__("mcr p15, 1, %0, c15, c10, 3" : : "r" (addr)); | 90 | __asm__("mcr p15, 1, %0, c15, c10, 3" : : "r" (addr)); |
| @@ -72,9 +95,9 @@ static inline void l2_inv_pa(unsigned long addr) | |||
| 72 | __asm__("mcr p15, 1, %0, c15, c11, 3" : : "r" (addr)); | 95 | __asm__("mcr p15, 1, %0, c15, c11, 3" : : "r" (addr)); |
| 73 | } | 96 | } |
| 74 | 97 | ||
| 75 | static inline void l2_inv_mva_range(unsigned long start, unsigned long end) | 98 | static inline void l2_inv_pa_range(unsigned long start, unsigned long end) |
| 76 | { | 99 | { |
| 77 | unsigned long flags; | 100 | unsigned long va_start, va_end, flags; |
| 78 | 101 | ||
| 79 | /* | 102 | /* |
| 80 | * Make sure 'start' and 'end' reference the same page, as | 103 | * Make sure 'start' and 'end' reference the same page, as |
| @@ -84,17 +107,14 @@ static inline void l2_inv_mva_range(unsigned long start, unsigned long end) | |||
| 84 | BUG_ON((start ^ end) >> PAGE_SHIFT); | 107 | BUG_ON((start ^ end) >> PAGE_SHIFT); |
| 85 | 108 | ||
| 86 | raw_local_irq_save(flags); | 109 | raw_local_irq_save(flags); |
| 110 | va_start = l2_start_va(start); | ||
| 111 | va_end = va_start + (end - start); | ||
| 87 | __asm__("mcr p15, 1, %0, c15, c11, 4\n\t" | 112 | __asm__("mcr p15, 1, %0, c15, c11, 4\n\t" |
| 88 | "mcr p15, 1, %1, c15, c11, 5" | 113 | "mcr p15, 1, %1, c15, c11, 5" |
| 89 | : : "r" (start), "r" (end)); | 114 | : : "r" (va_start), "r" (va_end)); |
| 90 | raw_local_irq_restore(flags); | 115 | raw_local_irq_restore(flags); |
| 91 | } | 116 | } |
| 92 | 117 | ||
| 93 | static inline void l2_inv_pa_range(unsigned long start, unsigned long end) | ||
| 94 | { | ||
| 95 | l2_inv_mva_range(__phys_to_virt(start), __phys_to_virt(end)); | ||
| 96 | } | ||
| 97 | |||
| 98 | 118 | ||
| 99 | /* | 119 | /* |
| 100 | * Linux primitives. | 120 | * Linux primitives. |
diff --git a/arch/arm/mm/cache-xsc3l2.c b/arch/arm/mm/cache-xsc3l2.c index 464de893a988..5d180cb0bd94 100644 --- a/arch/arm/mm/cache-xsc3l2.c +++ b/arch/arm/mm/cache-xsc3l2.c | |||
| @@ -17,12 +17,14 @@ | |||
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 18 | */ | 18 | */ |
| 19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
| 20 | #include <linux/spinlock.h> | ||
| 21 | #include <linux/io.h> | ||
| 22 | |||
| 23 | #include <asm/system.h> | 20 | #include <asm/system.h> |
| 24 | #include <asm/cputype.h> | 21 | #include <asm/cputype.h> |
| 25 | #include <asm/cacheflush.h> | 22 | #include <asm/cacheflush.h> |
| 23 | #include <asm/kmap_types.h> | ||
| 24 | #include <asm/fixmap.h> | ||
| 25 | #include <asm/pgtable.h> | ||
| 26 | #include <asm/tlbflush.h> | ||
| 27 | #include "mm.h" | ||
| 26 | 28 | ||
| 27 | #define CR_L2 (1 << 26) | 29 | #define CR_L2 (1 << 26) |
| 28 | 30 | ||
| @@ -47,21 +49,11 @@ static inline void xsc3_l2_clean_mva(unsigned long addr) | |||
| 47 | __asm__("mcr p15, 1, %0, c7, c11, 1" : : "r" (addr)); | 49 | __asm__("mcr p15, 1, %0, c7, c11, 1" : : "r" (addr)); |
| 48 | } | 50 | } |
| 49 | 51 | ||
| 50 | static inline void xsc3_l2_clean_pa(unsigned long addr) | ||
| 51 | { | ||
| 52 | xsc3_l2_clean_mva(__phys_to_virt(addr)); | ||
| 53 | } | ||
| 54 | |||
| 55 | static inline void xsc3_l2_inv_mva(unsigned long addr) | 52 | static inline void xsc3_l2_inv_mva(unsigned long addr) |
| 56 | { | 53 | { |
| 57 | __asm__("mcr p15, 1, %0, c7, c7, 1" : : "r" (addr)); | 54 | __asm__("mcr p15, 1, %0, c7, c7, 1" : : "r" (addr)); |
| 58 | } | 55 | } |
| 59 | 56 | ||
| 60 | static inline void xsc3_l2_inv_pa(unsigned long addr) | ||
| 61 | { | ||
| 62 | xsc3_l2_inv_mva(__phys_to_virt(addr)); | ||
| 63 | } | ||
| 64 | |||
| 65 | static inline void xsc3_l2_inv_all(void) | 57 | static inline void xsc3_l2_inv_all(void) |
| 66 | { | 58 | { |
| 67 | unsigned long l2ctype, set_way; | 59 | unsigned long l2ctype, set_way; |
| @@ -79,50 +71,103 @@ static inline void xsc3_l2_inv_all(void) | |||
| 79 | dsb(); | 71 | dsb(); |
| 80 | } | 72 | } |
| 81 | 73 | ||
| 74 | #ifdef CONFIG_HIGHMEM | ||
| 75 | #define l2_map_save_flags(x) raw_local_save_flags(x) | ||
| 76 | #define l2_map_restore_flags(x) raw_local_irq_restore(x) | ||
| 77 | #else | ||
| 78 | #define l2_map_save_flags(x) ((x) = 0) | ||
| 79 | #define l2_map_restore_flags(x) ((void)(x)) | ||
| 80 | #endif | ||
| 81 | |||
| 82 | static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va, | ||
| 83 | unsigned long flags) | ||
| 84 | { | ||
| 85 | #ifdef CONFIG_HIGHMEM | ||
| 86 | unsigned long va = prev_va & PAGE_MASK; | ||
| 87 | unsigned long pa_offset = pa << (32 - PAGE_SHIFT); | ||
| 88 | if (unlikely(pa_offset < (prev_va << (32 - PAGE_SHIFT)))) { | ||
| 89 | /* | ||
| 90 | * Switching to a new page. Because cache ops are | ||
| 91 | * using virtual addresses only, we must put a mapping | ||
| 92 | * in place for it. We also enable interrupts for a | ||
| 93 | * short while and disable them again to protect this | ||
| 94 | * mapping. | ||
| 95 | */ | ||
| 96 | unsigned long idx; | ||
| 97 | raw_local_irq_restore(flags); | ||
| 98 | idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id(); | ||
| 99 | va = __fix_to_virt(FIX_KMAP_BEGIN + idx); | ||
| 100 | raw_local_irq_restore(flags | PSR_I_BIT); | ||
| 101 | set_pte_ext(TOP_PTE(va), pfn_pte(pa >> PAGE_SHIFT, PAGE_KERNEL), 0); | ||
| 102 | local_flush_tlb_kernel_page(va); | ||
| 103 | } | ||
| 104 | return va + (pa_offset >> (32 - PAGE_SHIFT)); | ||
| 105 | #else | ||
| 106 | return __phys_to_virt(pa); | ||
| 107 | #endif | ||
| 108 | } | ||
| 109 | |||
| 82 | static void xsc3_l2_inv_range(unsigned long start, unsigned long end) | 110 | static void xsc3_l2_inv_range(unsigned long start, unsigned long end) |
| 83 | { | 111 | { |
| 112 | unsigned long vaddr, flags; | ||
| 113 | |||
| 84 | if (start == 0 && end == -1ul) { | 114 | if (start == 0 && end == -1ul) { |
| 85 | xsc3_l2_inv_all(); | 115 | xsc3_l2_inv_all(); |
| 86 | return; | 116 | return; |
| 87 | } | 117 | } |
| 88 | 118 | ||
| 119 | vaddr = -1; /* to force the first mapping */ | ||
| 120 | l2_map_save_flags(flags); | ||
| 121 | |||
| 89 | /* | 122 | /* |
| 90 | * Clean and invalidate partial first cache line. | 123 | * Clean and invalidate partial first cache line. |
| 91 | */ | 124 | */ |
| 92 | if (start & (CACHE_LINE_SIZE - 1)) { | 125 | if (start & (CACHE_LINE_SIZE - 1)) { |
| 93 | xsc3_l2_clean_pa(start & ~(CACHE_LINE_SIZE - 1)); | 126 | vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr, flags); |
| 94 | xsc3_l2_inv_pa(start & ~(CACHE_LINE_SIZE - 1)); | 127 | xsc3_l2_clean_mva(vaddr); |
| 128 | xsc3_l2_inv_mva(vaddr); | ||
| 95 | start = (start | (CACHE_LINE_SIZE - 1)) + 1; | 129 | start = (start | (CACHE_LINE_SIZE - 1)) + 1; |
| 96 | } | 130 | } |
| 97 | 131 | ||
| 98 | /* | 132 | /* |
| 99 | * Clean and invalidate partial last cache line. | 133 | * Invalidate all full cache lines between 'start' and 'end'. |
| 100 | */ | 134 | */ |
| 101 | if (start < end && (end & (CACHE_LINE_SIZE - 1))) { | 135 | while (start < (end & ~(CACHE_LINE_SIZE - 1))) { |
| 102 | xsc3_l2_clean_pa(end & ~(CACHE_LINE_SIZE - 1)); | 136 | vaddr = l2_map_va(start, vaddr, flags); |
| 103 | xsc3_l2_inv_pa(end & ~(CACHE_LINE_SIZE - 1)); | 137 | xsc3_l2_inv_mva(vaddr); |
| 104 | end &= ~(CACHE_LINE_SIZE - 1); | 138 | start += CACHE_LINE_SIZE; |
| 105 | } | 139 | } |
| 106 | 140 | ||
| 107 | /* | 141 | /* |
| 108 | * Invalidate all full cache lines between 'start' and 'end'. | 142 | * Clean and invalidate partial last cache line. |
| 109 | */ | 143 | */ |
| 110 | while (start < end) { | 144 | if (start < end) { |
| 111 | xsc3_l2_inv_pa(start); | 145 | vaddr = l2_map_va(start, vaddr, flags); |
| 112 | start += CACHE_LINE_SIZE; | 146 | xsc3_l2_clean_mva(vaddr); |
| 147 | xsc3_l2_inv_mva(vaddr); | ||
| 113 | } | 148 | } |
| 114 | 149 | ||
| 150 | l2_map_restore_flags(flags); | ||
| 151 | |||
| 115 | dsb(); | 152 | dsb(); |
| 116 | } | 153 | } |
| 117 | 154 | ||
| 118 | static void xsc3_l2_clean_range(unsigned long start, unsigned long end) | 155 | static void xsc3_l2_clean_range(unsigned long start, unsigned long end) |
| 119 | { | 156 | { |
| 157 | unsigned long vaddr, flags; | ||
| 158 | |||
| 159 | vaddr = -1; /* to force the first mapping */ | ||
| 160 | l2_map_save_flags(flags); | ||
| 161 | |||
| 120 | start &= ~(CACHE_LINE_SIZE - 1); | 162 | start &= ~(CACHE_LINE_SIZE - 1); |
| 121 | while (start < end) { | 163 | while (start < end) { |
| 122 | xsc3_l2_clean_pa(start); | 164 | vaddr = l2_map_va(start, vaddr, flags); |
| 165 | xsc3_l2_clean_mva(vaddr); | ||
| 123 | start += CACHE_LINE_SIZE; | 166 | start += CACHE_LINE_SIZE; |
| 124 | } | 167 | } |
| 125 | 168 | ||
| 169 | l2_map_restore_flags(flags); | ||
| 170 | |||
| 126 | dsb(); | 171 | dsb(); |
| 127 | } | 172 | } |
| 128 | 173 | ||
| @@ -148,18 +193,26 @@ static inline void xsc3_l2_flush_all(void) | |||
| 148 | 193 | ||
| 149 | static void xsc3_l2_flush_range(unsigned long start, unsigned long end) | 194 | static void xsc3_l2_flush_range(unsigned long start, unsigned long end) |
| 150 | { | 195 | { |
| 196 | unsigned long vaddr, flags; | ||
| 197 | |||
| 151 | if (start == 0 && end == -1ul) { | 198 | if (start == 0 && end == -1ul) { |
| 152 | xsc3_l2_flush_all(); | 199 | xsc3_l2_flush_all(); |
| 153 | return; | 200 | return; |
| 154 | } | 201 | } |
| 155 | 202 | ||
| 203 | vaddr = -1; /* to force the first mapping */ | ||
| 204 | l2_map_save_flags(flags); | ||
| 205 | |||
| 156 | start &= ~(CACHE_LINE_SIZE - 1); | 206 | start &= ~(CACHE_LINE_SIZE - 1); |
| 157 | while (start < end) { | 207 | while (start < end) { |
| 158 | xsc3_l2_clean_pa(start); | 208 | vaddr = l2_map_va(start, vaddr, flags); |
| 159 | xsc3_l2_inv_pa(start); | 209 | xsc3_l2_clean_mva(vaddr); |
| 210 | xsc3_l2_inv_mva(vaddr); | ||
| 160 | start += CACHE_LINE_SIZE; | 211 | start += CACHE_LINE_SIZE; |
| 161 | } | 212 | } |
| 162 | 213 | ||
| 214 | l2_map_restore_flags(flags); | ||
| 215 | |||
| 163 | dsb(); | 216 | dsb(); |
| 164 | } | 217 | } |
| 165 | 218 | ||
diff --git a/arch/arm/mm/copypage-fa.c b/arch/arm/mm/copypage-fa.c new file mode 100644 index 000000000000..b2a6008b0111 --- /dev/null +++ b/arch/arm/mm/copypage-fa.c | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/copypage-fa.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 2005 Faraday Corp. | ||
| 5 | * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> | ||
| 6 | * | ||
| 7 | * Based on copypage-v4wb.S: | ||
| 8 | * Copyright (C) 1995-1999 Russell King | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/highmem.h> | ||
| 16 | |||
| 17 | /* | ||
| 18 | * Faraday optimised copy_user_page | ||
| 19 | */ | ||
| 20 | static void __naked | ||
| 21 | fa_copy_user_page(void *kto, const void *kfrom) | ||
| 22 | { | ||
| 23 | asm("\ | ||
| 24 | stmfd sp!, {r4, lr} @ 2\n\ | ||
| 25 | mov r2, %0 @ 1\n\ | ||
| 26 | 1: ldmia r1!, {r3, r4, ip, lr} @ 4\n\ | ||
| 27 | stmia r0, {r3, r4, ip, lr} @ 4\n\ | ||
| 28 | mcr p15, 0, r0, c7, c14, 1 @ 1 clean and invalidate D line\n\ | ||
| 29 | add r0, r0, #16 @ 1\n\ | ||
| 30 | ldmia r1!, {r3, r4, ip, lr} @ 4\n\ | ||
| 31 | stmia r0, {r3, r4, ip, lr} @ 4\n\ | ||
| 32 | mcr p15, 0, r0, c7, c14, 1 @ 1 clean and invalidate D line\n\ | ||
| 33 | add r0, r0, #16 @ 1\n\ | ||
| 34 | subs r2, r2, #1 @ 1\n\ | ||
| 35 | bne 1b @ 1\n\ | ||
| 36 | mcr p15, 0, r2, c7, c10, 4 @ 1 drain WB\n\ | ||
| 37 | ldmfd sp!, {r4, pc} @ 3" | ||
| 38 | : | ||
| 39 | : "I" (PAGE_SIZE / 32)); | ||
| 40 | } | ||
| 41 | |||
| 42 | void fa_copy_user_highpage(struct page *to, struct page *from, | ||
| 43 | unsigned long vaddr) | ||
| 44 | { | ||
| 45 | void *kto, *kfrom; | ||
| 46 | |||
| 47 | kto = kmap_atomic(to, KM_USER0); | ||
| 48 | kfrom = kmap_atomic(from, KM_USER1); | ||
| 49 | fa_copy_user_page(kto, kfrom); | ||
| 50 | kunmap_atomic(kfrom, KM_USER1); | ||
| 51 | kunmap_atomic(kto, KM_USER0); | ||
| 52 | } | ||
| 53 | |||
| 54 | /* | ||
| 55 | * Faraday optimised clear_user_page | ||
| 56 | * | ||
| 57 | * Same story as above. | ||
| 58 | */ | ||
| 59 | void fa_clear_user_highpage(struct page *page, unsigned long vaddr) | ||
| 60 | { | ||
| 61 | void *ptr, *kaddr = kmap_atomic(page, KM_USER0); | ||
| 62 | asm volatile("\ | ||
| 63 | mov r1, %2 @ 1\n\ | ||
| 64 | mov r2, #0 @ 1\n\ | ||
| 65 | mov r3, #0 @ 1\n\ | ||
| 66 | mov ip, #0 @ 1\n\ | ||
| 67 | mov lr, #0 @ 1\n\ | ||
| 68 | 1: stmia %0, {r2, r3, ip, lr} @ 4\n\ | ||
| 69 | mcr p15, 0, %0, c7, c14, 1 @ 1 clean and invalidate D line\n\ | ||
| 70 | add %0, %0, #16 @ 1\n\ | ||
| 71 | stmia %0, {r2, r3, ip, lr} @ 4\n\ | ||
| 72 | mcr p15, 0, %0, c7, c14, 1 @ 1 clean and invalidate D line\n\ | ||
| 73 | add %0, %0, #16 @ 1\n\ | ||
| 74 | subs r1, r1, #1 @ 1\n\ | ||
| 75 | bne 1b @ 1\n\ | ||
| 76 | mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB" | ||
| 77 | : "=r" (ptr) | ||
| 78 | : "0" (kaddr), "I" (PAGE_SIZE / 32) | ||
| 79 | : "r1", "r2", "r3", "ip", "lr"); | ||
| 80 | kunmap_atomic(kaddr, KM_USER0); | ||
| 81 | } | ||
| 82 | |||
| 83 | struct cpu_user_fns fa_user_fns __initdata = { | ||
| 84 | .cpu_clear_user_highpage = fa_clear_user_highpage, | ||
| 85 | .cpu_copy_user_highpage = fa_copy_user_highpage, | ||
| 86 | }; | ||
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index f1ef5613ccd4..510c179b0ac8 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/dma-mapping.h> | 19 | #include <linux/dma-mapping.h> |
| 20 | 20 | ||
| 21 | #include <asm/memory.h> | 21 | #include <asm/memory.h> |
| 22 | #include <asm/highmem.h> | ||
| 22 | #include <asm/cacheflush.h> | 23 | #include <asm/cacheflush.h> |
| 23 | #include <asm/tlbflush.h> | 24 | #include <asm/tlbflush.h> |
| 24 | #include <asm/sizes.h> | 25 | #include <asm/sizes.h> |
| @@ -517,6 +518,74 @@ void dma_cache_maint(const void *start, size_t size, int direction) | |||
| 517 | } | 518 | } |
| 518 | EXPORT_SYMBOL(dma_cache_maint); | 519 | EXPORT_SYMBOL(dma_cache_maint); |
| 519 | 520 | ||
| 521 | static void dma_cache_maint_contiguous(struct page *page, unsigned long offset, | ||
| 522 | size_t size, int direction) | ||
| 523 | { | ||
| 524 | void *vaddr; | ||
| 525 | unsigned long paddr; | ||
| 526 | void (*inner_op)(const void *, const void *); | ||
| 527 | void (*outer_op)(unsigned long, unsigned long); | ||
| 528 | |||
| 529 | switch (direction) { | ||
| 530 | case DMA_FROM_DEVICE: /* invalidate only */ | ||
| 531 | inner_op = dmac_inv_range; | ||
| 532 | outer_op = outer_inv_range; | ||
| 533 | break; | ||
| 534 | case DMA_TO_DEVICE: /* writeback only */ | ||
| 535 | inner_op = dmac_clean_range; | ||
| 536 | outer_op = outer_clean_range; | ||
| 537 | break; | ||
| 538 | case DMA_BIDIRECTIONAL: /* writeback and invalidate */ | ||
| 539 | inner_op = dmac_flush_range; | ||
| 540 | outer_op = outer_flush_range; | ||
| 541 | break; | ||
| 542 | default: | ||
| 543 | BUG(); | ||
| 544 | } | ||
| 545 | |||
| 546 | if (!PageHighMem(page)) { | ||
| 547 | vaddr = page_address(page) + offset; | ||
| 548 | inner_op(vaddr, vaddr + size); | ||
| 549 | } else { | ||
| 550 | vaddr = kmap_high_get(page); | ||
| 551 | if (vaddr) { | ||
| 552 | vaddr += offset; | ||
| 553 | inner_op(vaddr, vaddr + size); | ||
| 554 | kunmap_high(page); | ||
| 555 | } | ||
| 556 | } | ||
| 557 | |||
| 558 | paddr = page_to_phys(page) + offset; | ||
| 559 | outer_op(paddr, paddr + size); | ||
| 560 | } | ||
| 561 | |||
| 562 | void dma_cache_maint_page(struct page *page, unsigned long offset, | ||
| 563 | size_t size, int dir) | ||
| 564 | { | ||
| 565 | /* | ||
| 566 | * A single sg entry may refer to multiple physically contiguous | ||
| 567 | * pages. But we still need to process highmem pages individually. | ||
| 568 | * If highmem is not configured then the bulk of this loop gets | ||
| 569 | * optimized out. | ||
| 570 | */ | ||
| 571 | size_t left = size; | ||
| 572 | do { | ||
| 573 | size_t len = left; | ||
| 574 | if (PageHighMem(page) && len + offset > PAGE_SIZE) { | ||
| 575 | if (offset >= PAGE_SIZE) { | ||
| 576 | page += offset / PAGE_SIZE; | ||
| 577 | offset %= PAGE_SIZE; | ||
| 578 | } | ||
| 579 | len = PAGE_SIZE - offset; | ||
| 580 | } | ||
| 581 | dma_cache_maint_contiguous(page, offset, len, dir); | ||
| 582 | offset = 0; | ||
| 583 | page++; | ||
| 584 | left -= len; | ||
| 585 | } while (left); | ||
| 586 | } | ||
| 587 | EXPORT_SYMBOL(dma_cache_maint_page); | ||
| 588 | |||
| 520 | /** | 589 | /** |
| 521 | * dma_map_sg - map a set of SG buffers for streaming mode DMA | 590 | * dma_map_sg - map a set of SG buffers for streaming mode DMA |
| 522 | * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices | 591 | * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices |
| @@ -614,7 +683,8 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, | |||
| 614 | continue; | 683 | continue; |
| 615 | 684 | ||
| 616 | if (!arch_is_coherent()) | 685 | if (!arch_is_coherent()) |
| 617 | dma_cache_maint(sg_virt(s), s->length, dir); | 686 | dma_cache_maint_page(sg_page(s), s->offset, |
| 687 | s->length, dir); | ||
| 618 | } | 688 | } |
| 619 | } | 689 | } |
| 620 | EXPORT_SYMBOL(dma_sync_sg_for_device); | 690 | EXPORT_SYMBOL(dma_sync_sg_for_device); |
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 0fa9bf388f0b..4e283481cee1 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c | |||
| @@ -192,7 +192,7 @@ void flush_dcache_page(struct page *page) | |||
| 192 | struct address_space *mapping = page_mapping(page); | 192 | struct address_space *mapping = page_mapping(page); |
| 193 | 193 | ||
| 194 | #ifndef CONFIG_SMP | 194 | #ifndef CONFIG_SMP |
| 195 | if (mapping && !mapping_mapped(mapping)) | 195 | if (!PageHighMem(page) && mapping && !mapping_mapped(mapping)) |
| 196 | set_bit(PG_dcache_dirty, &page->flags); | 196 | set_bit(PG_dcache_dirty, &page->flags); |
| 197 | else | 197 | else |
| 198 | #endif | 198 | #endif |
diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c new file mode 100644 index 000000000000..a34954d9df7d --- /dev/null +++ b/arch/arm/mm/highmem.c | |||
| @@ -0,0 +1,116 @@ | |||
| 1 | /* | ||
| 2 | * arch/arm/mm/highmem.c -- ARM highmem support | ||
| 3 | * | ||
| 4 | * Author: Nicolas Pitre | ||
| 5 | * Created: september 8, 2008 | ||
| 6 | * Copyright: Marvell Semiconductors Inc. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/highmem.h> | ||
| 15 | #include <linux/interrupt.h> | ||
| 16 | #include <asm/fixmap.h> | ||
| 17 | #include <asm/cacheflush.h> | ||
| 18 | #include <asm/tlbflush.h> | ||
| 19 | #include "mm.h" | ||
| 20 | |||
| 21 | void *kmap(struct page *page) | ||
| 22 | { | ||
| 23 | might_sleep(); | ||
| 24 | if (!PageHighMem(page)) | ||
| 25 | return page_address(page); | ||
| 26 | return kmap_high(page); | ||
| 27 | } | ||
| 28 | EXPORT_SYMBOL(kmap); | ||
| 29 | |||
| 30 | void kunmap(struct page *page) | ||
| 31 | { | ||
| 32 | BUG_ON(in_interrupt()); | ||
| 33 | if (!PageHighMem(page)) | ||
| 34 | return; | ||
| 35 | kunmap_high(page); | ||
| 36 | } | ||
| 37 | EXPORT_SYMBOL(kunmap); | ||
| 38 | |||
| 39 | void *kmap_atomic(struct page *page, enum km_type type) | ||
| 40 | { | ||
| 41 | unsigned int idx; | ||
| 42 | unsigned long vaddr; | ||
| 43 | |||
| 44 | pagefault_disable(); | ||
| 45 | if (!PageHighMem(page)) | ||
| 46 | return page_address(page); | ||
| 47 | |||
| 48 | idx = type + KM_TYPE_NR * smp_processor_id(); | ||
| 49 | vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); | ||
| 50 | #ifdef CONFIG_DEBUG_HIGHMEM | ||
| 51 | /* | ||
| 52 | * With debugging enabled, kunmap_atomic forces that entry to 0. | ||
| 53 | * Make sure it was indeed properly unmapped. | ||
| 54 | */ | ||
| 55 | BUG_ON(!pte_none(*(TOP_PTE(vaddr)))); | ||
| 56 | #endif | ||
| 57 | set_pte_ext(TOP_PTE(vaddr), mk_pte(page, kmap_prot), 0); | ||
| 58 | /* | ||
| 59 | * When debugging is off, kunmap_atomic leaves the previous mapping | ||
| 60 | * in place, so this TLB flush ensures the TLB is updated with the | ||
| 61 | * new mapping. | ||
| 62 | */ | ||
| 63 | local_flush_tlb_kernel_page(vaddr); | ||
| 64 | |||
| 65 | return (void *)vaddr; | ||
| 66 | } | ||
| 67 | EXPORT_SYMBOL(kmap_atomic); | ||
| 68 | |||
| 69 | void kunmap_atomic(void *kvaddr, enum km_type type) | ||
| 70 | { | ||
| 71 | unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; | ||
| 72 | unsigned int idx = type + KM_TYPE_NR * smp_processor_id(); | ||
| 73 | |||
| 74 | if (kvaddr >= (void *)FIXADDR_START) { | ||
| 75 | __cpuc_flush_dcache_page((void *)vaddr); | ||
| 76 | #ifdef CONFIG_DEBUG_HIGHMEM | ||
| 77 | BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx)); | ||
| 78 | set_pte_ext(TOP_PTE(vaddr), __pte(0), 0); | ||
| 79 | local_flush_tlb_kernel_page(vaddr); | ||
| 80 | #else | ||
| 81 | (void) idx; /* to kill a warning */ | ||
| 82 | #endif | ||
| 83 | } | ||
| 84 | pagefault_enable(); | ||
| 85 | } | ||
| 86 | EXPORT_SYMBOL(kunmap_atomic); | ||
| 87 | |||
| 88 | void *kmap_atomic_pfn(unsigned long pfn, enum km_type type) | ||
| 89 | { | ||
| 90 | unsigned int idx; | ||
| 91 | unsigned long vaddr; | ||
| 92 | |||
| 93 | pagefault_disable(); | ||
| 94 | |||
| 95 | idx = type + KM_TYPE_NR * smp_processor_id(); | ||
| 96 | vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); | ||
| 97 | #ifdef CONFIG_DEBUG_HIGHMEM | ||
| 98 | BUG_ON(!pte_none(*(TOP_PTE(vaddr)))); | ||
| 99 | #endif | ||
| 100 | set_pte_ext(TOP_PTE(vaddr), pfn_pte(pfn, kmap_prot), 0); | ||
| 101 | local_flush_tlb_kernel_page(vaddr); | ||
| 102 | |||
| 103 | return (void *)vaddr; | ||
| 104 | } | ||
| 105 | |||
| 106 | struct page *kmap_atomic_to_page(const void *ptr) | ||
| 107 | { | ||
| 108 | unsigned long vaddr = (unsigned long)ptr; | ||
| 109 | pte_t *pte; | ||
| 110 | |||
| 111 | if (vaddr < FIXADDR_START) | ||
| 112 | return virt_to_page(ptr); | ||
| 113 | |||
| 114 | pte = TOP_PTE(vaddr); | ||
| 115 | return pte_page(*pte); | ||
| 116 | } | ||
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 80fd3b69ae1f..8277802ec859 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/mman.h> | 15 | #include <linux/mman.h> |
| 16 | #include <linux/nodemask.h> | 16 | #include <linux/nodemask.h> |
| 17 | #include <linux/initrd.h> | 17 | #include <linux/initrd.h> |
| 18 | #include <linux/highmem.h> | ||
| 18 | 19 | ||
| 19 | #include <asm/mach-types.h> | 20 | #include <asm/mach-types.h> |
| 20 | #include <asm/sections.h> | 21 | #include <asm/sections.h> |
| @@ -485,7 +486,7 @@ void __init mem_init(void) | |||
| 485 | int i, node; | 486 | int i, node; |
| 486 | 487 | ||
| 487 | #ifndef CONFIG_DISCONTIGMEM | 488 | #ifndef CONFIG_DISCONTIGMEM |
| 488 | max_mapnr = virt_to_page(high_memory) - mem_map; | 489 | max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map; |
| 489 | #endif | 490 | #endif |
| 490 | 491 | ||
| 491 | /* this will put all unused low memory onto the freelists */ | 492 | /* this will put all unused low memory onto the freelists */ |
| @@ -504,6 +505,19 @@ void __init mem_init(void) | |||
| 504 | __phys_to_pfn(__pa(swapper_pg_dir)), NULL); | 505 | __phys_to_pfn(__pa(swapper_pg_dir)), NULL); |
| 505 | #endif | 506 | #endif |
| 506 | 507 | ||
| 508 | #ifdef CONFIG_HIGHMEM | ||
| 509 | /* set highmem page free */ | ||
| 510 | for_each_online_node(node) { | ||
| 511 | for_each_nodebank (i, &meminfo, node) { | ||
| 512 | unsigned long start = bank_pfn_start(&meminfo.bank[i]); | ||
| 513 | unsigned long end = bank_pfn_end(&meminfo.bank[i]); | ||
| 514 | if (start >= max_low_pfn + PHYS_PFN_OFFSET) | ||
| 515 | totalhigh_pages += free_area(start, end, NULL); | ||
| 516 | } | ||
| 517 | } | ||
| 518 | totalram_pages += totalhigh_pages; | ||
| 519 | #endif | ||
| 520 | |||
| 507 | /* | 521 | /* |
| 508 | * Since our memory may not be contiguous, calculate the | 522 | * Since our memory may not be contiguous, calculate the |
| 509 | * real number of pages we have in this system | 523 | * real number of pages we have in this system |
| @@ -521,9 +535,10 @@ void __init mem_init(void) | |||
| 521 | initsize = __init_end - __init_begin; | 535 | initsize = __init_end - __init_begin; |
| 522 | 536 | ||
| 523 | printk(KERN_NOTICE "Memory: %luKB available (%dK code, " | 537 | printk(KERN_NOTICE "Memory: %luKB available (%dK code, " |
| 524 | "%dK data, %dK init)\n", | 538 | "%dK data, %dK init, %luK highmem)\n", |
| 525 | (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), | 539 | (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), |
| 526 | codesize >> 10, datasize >> 10, initsize >> 10); | 540 | codesize >> 10, datasize >> 10, initsize >> 10, |
| 541 | (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))); | ||
| 527 | 542 | ||
| 528 | if (PAGE_SIZE >= 16384 && num_physpages <= 128) { | 543 | if (PAGE_SIZE >= 16384 && num_physpages <= 128) { |
| 529 | extern int sysctl_overcommit_memory; | 544 | extern int sysctl_overcommit_memory; |
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h index 95bbe112965e..c4f6f05198e0 100644 --- a/arch/arm/mm/mm.h +++ b/arch/arm/mm/mm.h | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | /* the upper-most page table pointer */ | ||
| 2 | |||
| 3 | #ifdef CONFIG_MMU | 1 | #ifdef CONFIG_MMU |
| 4 | 2 | ||
| 3 | /* the upper-most page table pointer */ | ||
| 5 | extern pmd_t *top_pmd; | 4 | extern pmd_t *top_pmd; |
| 6 | 5 | ||
| 7 | #define TOP_PTE(x) pte_offset_kernel(top_pmd, x) | 6 | #define TOP_PTE(x) pte_offset_kernel(top_pmd, x) |
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index d4d082c5c2d4..b438fc4fb77b 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c | |||
| @@ -18,9 +18,11 @@ | |||
| 18 | #include <asm/cputype.h> | 18 | #include <asm/cputype.h> |
| 19 | #include <asm/mach-types.h> | 19 | #include <asm/mach-types.h> |
| 20 | #include <asm/sections.h> | 20 | #include <asm/sections.h> |
| 21 | #include <asm/cachetype.h> | ||
| 21 | #include <asm/setup.h> | 22 | #include <asm/setup.h> |
| 22 | #include <asm/sizes.h> | 23 | #include <asm/sizes.h> |
| 23 | #include <asm/tlb.h> | 24 | #include <asm/tlb.h> |
| 25 | #include <asm/highmem.h> | ||
| 24 | 26 | ||
| 25 | #include <asm/mach/arch.h> | 27 | #include <asm/mach/arch.h> |
| 26 | #include <asm/mach/map.h> | 28 | #include <asm/mach/map.h> |
| @@ -243,6 +245,10 @@ static struct mem_type mem_types[] = { | |||
| 243 | .prot_sect = PMD_TYPE_SECT, | 245 | .prot_sect = PMD_TYPE_SECT, |
| 244 | .domain = DOMAIN_KERNEL, | 246 | .domain = DOMAIN_KERNEL, |
| 245 | }, | 247 | }, |
| 248 | [MT_MEMORY_NONCACHED] = { | ||
| 249 | .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, | ||
| 250 | .domain = DOMAIN_KERNEL, | ||
| 251 | }, | ||
| 246 | }; | 252 | }; |
| 247 | 253 | ||
| 248 | const struct mem_type *get_mem_type(unsigned int type) | 254 | const struct mem_type *get_mem_type(unsigned int type) |
| @@ -406,9 +412,28 @@ static void __init build_mem_type_table(void) | |||
| 406 | kern_pgprot |= L_PTE_SHARED; | 412 | kern_pgprot |= L_PTE_SHARED; |
| 407 | vecs_pgprot |= L_PTE_SHARED; | 413 | vecs_pgprot |= L_PTE_SHARED; |
| 408 | mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; | 414 | mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; |
| 415 | mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S; | ||
| 409 | #endif | 416 | #endif |
| 410 | } | 417 | } |
| 411 | 418 | ||
| 419 | /* | ||
| 420 | * Non-cacheable Normal - intended for memory areas that must | ||
| 421 | * not cause dirty cache line writebacks when used | ||
| 422 | */ | ||
| 423 | if (cpu_arch >= CPU_ARCH_ARMv6) { | ||
| 424 | if (cpu_arch >= CPU_ARCH_ARMv7 && (cr & CR_TRE)) { | ||
| 425 | /* Non-cacheable Normal is XCB = 001 */ | ||
| 426 | mem_types[MT_MEMORY_NONCACHED].prot_sect |= | ||
| 427 | PMD_SECT_BUFFERED; | ||
| 428 | } else { | ||
| 429 | /* For both ARMv6 and non-TEX-remapping ARMv7 */ | ||
| 430 | mem_types[MT_MEMORY_NONCACHED].prot_sect |= | ||
| 431 | PMD_SECT_TEX(1); | ||
| 432 | } | ||
| 433 | } else { | ||
| 434 | mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_BUFFERABLE; | ||
| 435 | } | ||
| 436 | |||
| 412 | for (i = 0; i < 16; i++) { | 437 | for (i = 0; i < 16; i++) { |
| 413 | unsigned long v = pgprot_val(protection_map[i]); | 438 | unsigned long v = pgprot_val(protection_map[i]); |
| 414 | protection_map[i] = __pgprot(v | user_pgprot); | 439 | protection_map[i] = __pgprot(v | user_pgprot); |
| @@ -677,6 +702,10 @@ static void __init sanity_check_meminfo(void) | |||
| 677 | if (meminfo.nr_banks >= NR_BANKS) { | 702 | if (meminfo.nr_banks >= NR_BANKS) { |
| 678 | printk(KERN_CRIT "NR_BANKS too low, " | 703 | printk(KERN_CRIT "NR_BANKS too low, " |
| 679 | "ignoring high memory\n"); | 704 | "ignoring high memory\n"); |
| 705 | } else if (cache_is_vipt_aliasing()) { | ||
| 706 | printk(KERN_CRIT "HIGHMEM is not yet supported " | ||
| 707 | "with VIPT aliasing cache, " | ||
| 708 | "ignoring high memory\n"); | ||
| 680 | } else { | 709 | } else { |
| 681 | memmove(bank + 1, bank, | 710 | memmove(bank + 1, bank, |
| 682 | (meminfo.nr_banks - i) * sizeof(*bank)); | 711 | (meminfo.nr_banks - i) * sizeof(*bank)); |
| @@ -694,7 +723,7 @@ static void __init sanity_check_meminfo(void) | |||
| 694 | * the vmalloc area. | 723 | * the vmalloc area. |
| 695 | */ | 724 | */ |
| 696 | if (__va(bank->start) >= VMALLOC_MIN || | 725 | if (__va(bank->start) >= VMALLOC_MIN || |
| 697 | __va(bank->start) < PAGE_OFFSET) { | 726 | __va(bank->start) < (void *)PAGE_OFFSET) { |
| 698 | printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx " | 727 | printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx " |
| 699 | "(vmalloc region overlap).\n", | 728 | "(vmalloc region overlap).\n", |
| 700 | bank->start, bank->start + bank->size - 1); | 729 | bank->start, bank->start + bank->size - 1); |
| @@ -895,6 +924,17 @@ static void __init devicemaps_init(struct machine_desc *mdesc) | |||
| 895 | flush_cache_all(); | 924 | flush_cache_all(); |
| 896 | } | 925 | } |
| 897 | 926 | ||
| 927 | static void __init kmap_init(void) | ||
| 928 | { | ||
| 929 | #ifdef CONFIG_HIGHMEM | ||
| 930 | pmd_t *pmd = pmd_off_k(PKMAP_BASE); | ||
| 931 | pte_t *pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t)); | ||
| 932 | BUG_ON(!pmd_none(*pmd) || !pte); | ||
| 933 | __pmd_populate(pmd, __pa(pte) | _PAGE_KERNEL_TABLE); | ||
| 934 | pkmap_page_table = pte + PTRS_PER_PTE; | ||
| 935 | #endif | ||
| 936 | } | ||
| 937 | |||
| 898 | /* | 938 | /* |
| 899 | * paging_init() sets up the page tables, initialises the zone memory | 939 | * paging_init() sets up the page tables, initialises the zone memory |
| 900 | * maps, and sets up the zero page, bad page and bad page tables. | 940 | * maps, and sets up the zero page, bad page and bad page tables. |
| @@ -908,6 +948,7 @@ void __init paging_init(struct machine_desc *mdesc) | |||
| 908 | prepare_page_table(); | 948 | prepare_page_table(); |
| 909 | bootmem_init(); | 949 | bootmem_init(); |
| 910 | devicemaps_init(mdesc); | 950 | devicemaps_init(mdesc); |
| 951 | kmap_init(); | ||
| 911 | 952 | ||
| 912 | top_pmd = pmd_off_k(0xffff0000); | 953 | top_pmd = pmd_off_k(0xffff0000); |
| 913 | 954 | ||
diff --git a/arch/arm/mm/proc-fa526.S b/arch/arm/mm/proc-fa526.S new file mode 100644 index 000000000000..08b8a955d5d7 --- /dev/null +++ b/arch/arm/mm/proc-fa526.S | |||
| @@ -0,0 +1,248 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mm/proc-fa526.S: MMU functions for FA526 | ||
| 3 | * | ||
| 4 | * Written by : Luke Lee | ||
| 5 | * Copyright (C) 2005 Faraday Corp. | ||
| 6 | * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * | ||
| 14 | * These are the low level assembler for performing cache and TLB | ||
| 15 | * functions on the fa526. | ||
| 16 | */ | ||
| 17 | #include <linux/linkage.h> | ||
| 18 | #include <linux/init.h> | ||
| 19 | #include <asm/assembler.h> | ||
| 20 | #include <asm/hwcap.h> | ||
| 21 | #include <asm/pgtable-hwdef.h> | ||
| 22 | #include <asm/pgtable.h> | ||
| 23 | #include <asm/page.h> | ||
| 24 | #include <asm/ptrace.h> | ||
| 25 | #include <asm/system.h> | ||
| 26 | |||
| 27 | #include "proc-macros.S" | ||
| 28 | |||
| 29 | #define CACHE_DLINESIZE 16 | ||
| 30 | |||
| 31 | .text | ||
| 32 | /* | ||
| 33 | * cpu_fa526_proc_init() | ||
| 34 | */ | ||
| 35 | ENTRY(cpu_fa526_proc_init) | ||
| 36 | mov pc, lr | ||
| 37 | |||
| 38 | /* | ||
| 39 | * cpu_fa526_proc_fin() | ||
| 40 | */ | ||
| 41 | ENTRY(cpu_fa526_proc_fin) | ||
| 42 | stmfd sp!, {lr} | ||
| 43 | mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE | ||
| 44 | msr cpsr_c, ip | ||
| 45 | bl fa_flush_kern_cache_all | ||
| 46 | mrc p15, 0, r0, c1, c0, 0 @ ctrl register | ||
| 47 | bic r0, r0, #0x1000 @ ...i............ | ||
| 48 | bic r0, r0, #0x000e @ ............wca. | ||
| 49 | mcr p15, 0, r0, c1, c0, 0 @ disable caches | ||
| 50 | nop | ||
| 51 | nop | ||
| 52 | ldmfd sp!, {pc} | ||
| 53 | |||
| 54 | /* | ||
| 55 | * cpu_fa526_reset(loc) | ||
| 56 | * | ||
| 57 | * Perform a soft reset of the system. Put the CPU into the | ||
| 58 | * same state as it would be if it had been reset, and branch | ||
| 59 | * to what would be the reset vector. | ||
| 60 | * | ||
| 61 | * loc: location to jump to for soft reset | ||
| 62 | */ | ||
| 63 | .align 4 | ||
| 64 | ENTRY(cpu_fa526_reset) | ||
| 65 | /* TODO: Use CP8 if possible... */ | ||
| 66 | mov ip, #0 | ||
| 67 | mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches | ||
| 68 | mcr p15, 0, ip, c7, c10, 4 @ drain WB | ||
| 69 | #ifdef CONFIG_MMU | ||
| 70 | mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs | ||
| 71 | #endif | ||
| 72 | mrc p15, 0, ip, c1, c0, 0 @ ctrl register | ||
| 73 | bic ip, ip, #0x000f @ ............wcam | ||
| 74 | bic ip, ip, #0x1100 @ ...i...s........ | ||
| 75 | bic ip, ip, #0x0800 @ BTB off | ||
| 76 | mcr p15, 0, ip, c1, c0, 0 @ ctrl register | ||
| 77 | nop | ||
| 78 | nop | ||
| 79 | mov pc, r0 | ||
| 80 | |||
| 81 | /* | ||
| 82 | * cpu_fa526_do_idle() | ||
| 83 | */ | ||
| 84 | .align 4 | ||
| 85 | ENTRY(cpu_fa526_do_idle) | ||
| 86 | mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt | ||
| 87 | mov pc, lr | ||
| 88 | |||
| 89 | |||
| 90 | ENTRY(cpu_fa526_dcache_clean_area) | ||
| 91 | 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry | ||
| 92 | add r0, r0, #CACHE_DLINESIZE | ||
| 93 | subs r1, r1, #CACHE_DLINESIZE | ||
| 94 | bhi 1b | ||
| 95 | mcr p15, 0, r0, c7, c10, 4 @ drain WB | ||
| 96 | mov pc, lr | ||
| 97 | |||
| 98 | /* =============================== PageTable ============================== */ | ||
| 99 | |||
| 100 | /* | ||
| 101 | * cpu_fa526_switch_mm(pgd) | ||
| 102 | * | ||
| 103 | * Set the translation base pointer to be as described by pgd. | ||
| 104 | * | ||
| 105 | * pgd: new page tables | ||
| 106 | */ | ||
| 107 | .align 4 | ||
| 108 | ENTRY(cpu_fa526_switch_mm) | ||
| 109 | #ifdef CONFIG_MMU | ||
| 110 | mov ip, #0 | ||
| 111 | #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH | ||
| 112 | mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache | ||
| 113 | #else | ||
| 114 | mcr p15, 0, ip, c7, c14, 0 @ clean and invalidate whole D cache | ||
| 115 | #endif | ||
| 116 | mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache | ||
| 117 | mcr p15, 0, ip, c7, c5, 6 @ invalidate BTB since mm changed | ||
| 118 | mcr p15, 0, ip, c7, c10, 4 @ data write barrier | ||
| 119 | mcr p15, 0, ip, c7, c5, 4 @ prefetch flush | ||
| 120 | mcr p15, 0, r0, c2, c0, 0 @ load page table pointer | ||
| 121 | mcr p15, 0, ip, c8, c7, 0 @ invalidate UTLB | ||
| 122 | #endif | ||
| 123 | mov pc, lr | ||
| 124 | |||
| 125 | /* | ||
| 126 | * cpu_fa526_set_pte_ext(ptep, pte, ext) | ||
| 127 | * | ||
| 128 | * Set a PTE and flush it out | ||
| 129 | */ | ||
| 130 | .align 4 | ||
| 131 | ENTRY(cpu_fa526_set_pte_ext) | ||
| 132 | #ifdef CONFIG_MMU | ||
| 133 | armv3_set_pte_ext | ||
| 134 | mov r0, r0 | ||
| 135 | mcr p15, 0, r0, c7, c10, 1 @ clean D entry | ||
| 136 | mov r0, #0 | ||
| 137 | mcr p15, 0, r0, c7, c10, 4 @ drain WB | ||
| 138 | #endif | ||
| 139 | mov pc, lr | ||
| 140 | |||
| 141 | __INIT | ||
| 142 | |||
| 143 | .type __fa526_setup, #function | ||
| 144 | __fa526_setup: | ||
| 145 | /* On return of this routine, r0 must carry correct flags for CFG register */ | ||
| 146 | mov r0, #0 | ||
| 147 | mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 | ||
| 148 | mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 | ||
| 149 | #ifdef CONFIG_MMU | ||
| 150 | mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 | ||
| 151 | #endif | ||
| 152 | mcr p15, 0, r0, c7, c5, 5 @ invalidate IScratchpad RAM | ||
| 153 | |||
| 154 | mov r0, #1 | ||
| 155 | mcr p15, 0, r0, c1, c1, 0 @ turn-on ECR | ||
| 156 | |||
| 157 | mov r0, #0 | ||
| 158 | mcr p15, 0, r0, c7, c5, 6 @ invalidate BTB All | ||
| 159 | mcr p15, 0, r0, c7, c10, 4 @ data write barrier | ||
| 160 | mcr p15, 0, r0, c7, c5, 4 @ prefetch flush | ||
| 161 | |||
| 162 | mov r0, #0x1f @ Domains 0, 1 = manager, 2 = client | ||
| 163 | mcr p15, 0, r0, c3, c0 @ load domain access register | ||
| 164 | |||
| 165 | mrc p15, 0, r0, c1, c0 @ get control register v4 | ||
| 166 | ldr r5, fa526_cr1_clear | ||
| 167 | bic r0, r0, r5 | ||
| 168 | ldr r5, fa526_cr1_set | ||
| 169 | orr r0, r0, r5 | ||
| 170 | mov pc, lr | ||
| 171 | .size __fa526_setup, . - __fa526_setup | ||
| 172 | |||
| 173 | /* | ||
| 174 | * .RVI ZFRS BLDP WCAM | ||
| 175 | * ..11 1001 .111 1101 | ||
| 176 | * | ||
| 177 | */ | ||
| 178 | .type fa526_cr1_clear, #object | ||
| 179 | .type fa526_cr1_set, #object | ||
| 180 | fa526_cr1_clear: | ||
| 181 | .word 0x3f3f | ||
| 182 | fa526_cr1_set: | ||
| 183 | .word 0x397D | ||
| 184 | |||
| 185 | __INITDATA | ||
| 186 | |||
| 187 | /* | ||
| 188 | * Purpose : Function pointers used to access above functions - all calls | ||
| 189 | * come through these | ||
| 190 | */ | ||
| 191 | .type fa526_processor_functions, #object | ||
| 192 | fa526_processor_functions: | ||
| 193 | .word v4_early_abort | ||
| 194 | .word pabort_noifar | ||
| 195 | .word cpu_fa526_proc_init | ||
| 196 | .word cpu_fa526_proc_fin | ||
| 197 | .word cpu_fa526_reset | ||
| 198 | .word cpu_fa526_do_idle | ||
| 199 | .word cpu_fa526_dcache_clean_area | ||
| 200 | .word cpu_fa526_switch_mm | ||
| 201 | .word cpu_fa526_set_pte_ext | ||
| 202 | .size fa526_processor_functions, . - fa526_processor_functions | ||
| 203 | |||
| 204 | .section ".rodata" | ||
| 205 | |||
| 206 | .type cpu_arch_name, #object | ||
| 207 | cpu_arch_name: | ||
| 208 | .asciz "armv4" | ||
| 209 | .size cpu_arch_name, . - cpu_arch_name | ||
| 210 | |||
| 211 | .type cpu_elf_name, #object | ||
| 212 | cpu_elf_name: | ||
| 213 | .asciz "v4" | ||
| 214 | .size cpu_elf_name, . - cpu_elf_name | ||
| 215 | |||
| 216 | .type cpu_fa526_name, #object | ||
| 217 | cpu_fa526_name: | ||
| 218 | .asciz "FA526" | ||
| 219 | .size cpu_fa526_name, . - cpu_fa526_name | ||
| 220 | |||
| 221 | .align | ||
| 222 | |||
| 223 | .section ".proc.info.init", #alloc, #execinstr | ||
| 224 | |||
| 225 | .type __fa526_proc_info,#object | ||
| 226 | __fa526_proc_info: | ||
| 227 | .long 0x66015261 | ||
| 228 | .long 0xff01fff1 | ||
| 229 | .long PMD_TYPE_SECT | \ | ||
| 230 | PMD_SECT_BUFFERABLE | \ | ||
| 231 | PMD_SECT_CACHEABLE | \ | ||
| 232 | PMD_BIT4 | \ | ||
| 233 | PMD_SECT_AP_WRITE | \ | ||
| 234 | PMD_SECT_AP_READ | ||
| 235 | .long PMD_TYPE_SECT | \ | ||
| 236 | PMD_BIT4 | \ | ||
| 237 | PMD_SECT_AP_WRITE | \ | ||
| 238 | PMD_SECT_AP_READ | ||
| 239 | b __fa526_setup | ||
| 240 | .long cpu_arch_name | ||
| 241 | .long cpu_elf_name | ||
| 242 | .long HWCAP_SWP | HWCAP_HALF | ||
| 243 | .long cpu_fa526_name | ||
| 244 | .long fa526_processor_functions | ||
| 245 | .long fa_tlb_fns | ||
| 246 | .long fa_user_fns | ||
| 247 | .long fa_cache_fns | ||
| 248 | .size __fa526_proc_info, . - __fa526_proc_info | ||
diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S new file mode 100644 index 000000000000..540f5078496b --- /dev/null +++ b/arch/arm/mm/proc-mohawk.S | |||
| @@ -0,0 +1,416 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mm/proc-mohawk.S: MMU functions for Marvell PJ1 core | ||
| 3 | * | ||
| 4 | * PJ1 (codename Mohawk) is a hybrid of the xscale3 and Marvell's own core. | ||
| 5 | * | ||
| 6 | * Heavily based on proc-arm926.S and proc-xsc3.S | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/linkage.h> | ||
| 24 | #include <linux/init.h> | ||
| 25 | #include <asm/assembler.h> | ||
| 26 | #include <asm/hwcap.h> | ||
| 27 | #include <asm/pgtable-hwdef.h> | ||
| 28 | #include <asm/pgtable.h> | ||
| 29 | #include <asm/page.h> | ||
| 30 | #include <asm/ptrace.h> | ||
| 31 | #include "proc-macros.S" | ||
| 32 | |||
| 33 | /* | ||
| 34 | * This is the maximum size of an area which will be flushed. If the | ||
| 35 | * area is larger than this, then we flush the whole cache. | ||
| 36 | */ | ||
| 37 | #define CACHE_DLIMIT 32768 | ||
| 38 | |||
| 39 | /* | ||
| 40 | * The cache line size of the L1 D cache. | ||
| 41 | */ | ||
| 42 | #define CACHE_DLINESIZE 32 | ||
| 43 | |||
| 44 | /* | ||
| 45 | * cpu_mohawk_proc_init() | ||
| 46 | */ | ||
| 47 | ENTRY(cpu_mohawk_proc_init) | ||
| 48 | mov pc, lr | ||
| 49 | |||
| 50 | /* | ||
| 51 | * cpu_mohawk_proc_fin() | ||
| 52 | */ | ||
| 53 | ENTRY(cpu_mohawk_proc_fin) | ||
| 54 | stmfd sp!, {lr} | ||
| 55 | mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE | ||
| 56 | msr cpsr_c, ip | ||
| 57 | bl mohawk_flush_kern_cache_all | ||
| 58 | mrc p15, 0, r0, c1, c0, 0 @ ctrl register | ||
| 59 | bic r0, r0, #0x1800 @ ...iz........... | ||
| 60 | bic r0, r0, #0x0006 @ .............ca. | ||
| 61 | mcr p15, 0, r0, c1, c0, 0 @ disable caches | ||
| 62 | ldmfd sp!, {pc} | ||
| 63 | |||
| 64 | /* | ||
| 65 | * cpu_mohawk_reset(loc) | ||
| 66 | * | ||
| 67 | * Perform a soft reset of the system. Put the CPU into the | ||
| 68 | * same state as it would be if it had been reset, and branch | ||
| 69 | * to what would be the reset vector. | ||
| 70 | * | ||
| 71 | * loc: location to jump to for soft reset | ||
| 72 | * | ||
| 73 | * (same as arm926) | ||
| 74 | */ | ||
| 75 | .align 5 | ||
| 76 | ENTRY(cpu_mohawk_reset) | ||
| 77 | mov ip, #0 | ||
| 78 | mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches | ||
| 79 | mcr p15, 0, ip, c7, c10, 4 @ drain WB | ||
| 80 | mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs | ||
| 81 | mrc p15, 0, ip, c1, c0, 0 @ ctrl register | ||
| 82 | bic ip, ip, #0x0007 @ .............cam | ||
| 83 | bic ip, ip, #0x1100 @ ...i...s........ | ||
| 84 | mcr p15, 0, ip, c1, c0, 0 @ ctrl register | ||
| 85 | mov pc, r0 | ||
| 86 | |||
| 87 | /* | ||
| 88 | * cpu_mohawk_do_idle() | ||
| 89 | * | ||
| 90 | * Called with IRQs disabled | ||
| 91 | */ | ||
| 92 | .align 5 | ||
| 93 | ENTRY(cpu_mohawk_do_idle) | ||
| 94 | mov r0, #0 | ||
| 95 | mcr p15, 0, r0, c7, c10, 4 @ drain write buffer | ||
| 96 | mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt | ||
| 97 | mov pc, lr | ||
| 98 | |||
| 99 | /* | ||
| 100 | * flush_user_cache_all() | ||
| 101 | * | ||
| 102 | * Clean and invalidate all cache entries in a particular | ||
| 103 | * address space. | ||
| 104 | */ | ||
| 105 | ENTRY(mohawk_flush_user_cache_all) | ||
| 106 | /* FALLTHROUGH */ | ||
| 107 | |||
| 108 | /* | ||
| 109 | * flush_kern_cache_all() | ||
| 110 | * | ||
| 111 | * Clean and invalidate the entire cache. | ||
| 112 | */ | ||
| 113 | ENTRY(mohawk_flush_kern_cache_all) | ||
| 114 | mov r2, #VM_EXEC | ||
| 115 | mov ip, #0 | ||
| 116 | __flush_whole_cache: | ||
| 117 | mcr p15, 0, ip, c7, c14, 0 @ clean & invalidate all D cache | ||
| 118 | tst r2, #VM_EXEC | ||
| 119 | mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache | ||
| 120 | mcrne p15, 0, ip, c7, c10, 0 @ drain write buffer | ||
| 121 | mov pc, lr | ||
| 122 | |||
| 123 | /* | ||
| 124 | * flush_user_cache_range(start, end, flags) | ||
| 125 | * | ||
| 126 | * Clean and invalidate a range of cache entries in the | ||
| 127 | * specified address range. | ||
| 128 | * | ||
| 129 | * - start - start address (inclusive) | ||
| 130 | * - end - end address (exclusive) | ||
| 131 | * - flags - vm_flags describing address space | ||
| 132 | * | ||
| 133 | * (same as arm926) | ||
| 134 | */ | ||
| 135 | ENTRY(mohawk_flush_user_cache_range) | ||
| 136 | mov ip, #0 | ||
| 137 | sub r3, r1, r0 @ calculate total size | ||
| 138 | cmp r3, #CACHE_DLIMIT | ||
| 139 | bgt __flush_whole_cache | ||
| 140 | 1: tst r2, #VM_EXEC | ||
| 141 | mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry | ||
| 142 | mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry | ||
| 143 | add r0, r0, #CACHE_DLINESIZE | ||
| 144 | mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry | ||
| 145 | mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry | ||
| 146 | add r0, r0, #CACHE_DLINESIZE | ||
| 147 | cmp r0, r1 | ||
| 148 | blo 1b | ||
| 149 | tst r2, #VM_EXEC | ||
| 150 | mcrne p15, 0, ip, c7, c10, 4 @ drain WB | ||
| 151 | mov pc, lr | ||
| 152 | |||
| 153 | /* | ||
| 154 | * coherent_kern_range(start, end) | ||
| 155 | * | ||
| 156 | * Ensure coherency between the Icache and the Dcache in the | ||
| 157 | * region described by start, end. If you have non-snooping | ||
| 158 | * Harvard caches, you need to implement this function. | ||
| 159 | * | ||
| 160 | * - start - virtual start address | ||
| 161 | * - end - virtual end address | ||
| 162 | */ | ||
| 163 | ENTRY(mohawk_coherent_kern_range) | ||
| 164 | /* FALLTHROUGH */ | ||
| 165 | |||
| 166 | /* | ||
| 167 | * coherent_user_range(start, end) | ||
| 168 | * | ||
| 169 | * Ensure coherency between the Icache and the Dcache in the | ||
| 170 | * region described by start, end. If you have non-snooping | ||
| 171 | * Harvard caches, you need to implement this function. | ||
| 172 | * | ||
| 173 | * - start - virtual start address | ||
| 174 | * - end - virtual end address | ||
| 175 | * | ||
| 176 | * (same as arm926) | ||
| 177 | */ | ||
| 178 | ENTRY(mohawk_coherent_user_range) | ||
| 179 | bic r0, r0, #CACHE_DLINESIZE - 1 | ||
| 180 | 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry | ||
| 181 | mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry | ||
| 182 | add r0, r0, #CACHE_DLINESIZE | ||
| 183 | cmp r0, r1 | ||
| 184 | blo 1b | ||
| 185 | mcr p15, 0, r0, c7, c10, 4 @ drain WB | ||
| 186 | mov pc, lr | ||
| 187 | |||
| 188 | /* | ||
| 189 | * flush_kern_dcache_page(void *page) | ||
| 190 | * | ||
| 191 | * Ensure no D cache aliasing occurs, either with itself or | ||
| 192 | * the I cache | ||
| 193 | * | ||
| 194 | * - addr - page aligned address | ||
| 195 | */ | ||
| 196 | ENTRY(mohawk_flush_kern_dcache_page) | ||
| 197 | add r1, r0, #PAGE_SZ | ||
| 198 | 1: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry | ||
| 199 | add r0, r0, #CACHE_DLINESIZE | ||
| 200 | cmp r0, r1 | ||
| 201 | blo 1b | ||
| 202 | mov r0, #0 | ||
| 203 | mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache | ||
| 204 | mcr p15, 0, r0, c7, c10, 4 @ drain WB | ||
| 205 | mov pc, lr | ||
| 206 | |||
| 207 | /* | ||
| 208 | * dma_inv_range(start, end) | ||
| 209 | * | ||
| 210 | * Invalidate (discard) the specified virtual address range. | ||
| 211 | * May not write back any entries. If 'start' or 'end' | ||
| 212 | * are not cache line aligned, those lines must be written | ||
| 213 | * back. | ||
| 214 | * | ||
| 215 | * - start - virtual start address | ||
| 216 | * - end - virtual end address | ||
| 217 | * | ||
| 218 | * (same as v4wb) | ||
| 219 | */ | ||
| 220 | ENTRY(mohawk_dma_inv_range) | ||
| 221 | tst r0, #CACHE_DLINESIZE - 1 | ||
| 222 | mcrne p15, 0, r0, c7, c10, 1 @ clean D entry | ||
| 223 | tst r1, #CACHE_DLINESIZE - 1 | ||
| 224 | mcrne p15, 0, r1, c7, c10, 1 @ clean D entry | ||
| 225 | bic r0, r0, #CACHE_DLINESIZE - 1 | ||
| 226 | 1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry | ||
| 227 | add r0, r0, #CACHE_DLINESIZE | ||
| 228 | cmp r0, r1 | ||
| 229 | blo 1b | ||
| 230 | mcr p15, 0, r0, c7, c10, 4 @ drain WB | ||
| 231 | mov pc, lr | ||
| 232 | |||
| 233 | /* | ||
| 234 | * dma_clean_range(start, end) | ||
| 235 | * | ||
| 236 | * Clean the specified virtual address range. | ||
| 237 | * | ||
| 238 | * - start - virtual start address | ||
| 239 | * - end - virtual end address | ||
| 240 | * | ||
| 241 | * (same as v4wb) | ||
| 242 | */ | ||
| 243 | ENTRY(mohawk_dma_clean_range) | ||
| 244 | bic r0, r0, #CACHE_DLINESIZE - 1 | ||
| 245 | 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry | ||
| 246 | add r0, r0, #CACHE_DLINESIZE | ||
| 247 | cmp r0, r1 | ||
| 248 | blo 1b | ||
| 249 | mcr p15, 0, r0, c7, c10, 4 @ drain WB | ||
| 250 | mov pc, lr | ||
| 251 | |||
| 252 | /* | ||
| 253 | * dma_flush_range(start, end) | ||
| 254 | * | ||
| 255 | * Clean and invalidate the specified virtual address range. | ||
| 256 | * | ||
| 257 | * - start - virtual start address | ||
| 258 | * - end - virtual end address | ||
| 259 | */ | ||
| 260 | ENTRY(mohawk_dma_flush_range) | ||
| 261 | bic r0, r0, #CACHE_DLINESIZE - 1 | ||
| 262 | 1: | ||
| 263 | mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry | ||
| 264 | add r0, r0, #CACHE_DLINESIZE | ||
| 265 | cmp r0, r1 | ||
| 266 | blo 1b | ||
| 267 | mcr p15, 0, r0, c7, c10, 4 @ drain WB | ||
| 268 | mov pc, lr | ||
| 269 | |||
| 270 | ENTRY(mohawk_cache_fns) | ||
| 271 | .long mohawk_flush_kern_cache_all | ||
| 272 | .long mohawk_flush_user_cache_all | ||
| 273 | .long mohawk_flush_user_cache_range | ||
| 274 | .long mohawk_coherent_kern_range | ||
| 275 | .long mohawk_coherent_user_range | ||
| 276 | .long mohawk_flush_kern_dcache_page | ||
| 277 | .long mohawk_dma_inv_range | ||
| 278 | .long mohawk_dma_clean_range | ||
| 279 | .long mohawk_dma_flush_range | ||
| 280 | |||
| 281 | ENTRY(cpu_mohawk_dcache_clean_area) | ||
| 282 | 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry | ||
| 283 | add r0, r0, #CACHE_DLINESIZE | ||
| 284 | subs r1, r1, #CACHE_DLINESIZE | ||
| 285 | bhi 1b | ||
| 286 | mcr p15, 0, r0, c7, c10, 4 @ drain WB | ||
| 287 | mov pc, lr | ||
| 288 | |||
| 289 | /* | ||
| 290 | * cpu_mohawk_switch_mm(pgd) | ||
| 291 | * | ||
| 292 | * Set the translation base pointer to be as described by pgd. | ||
| 293 | * | ||
| 294 | * pgd: new page tables | ||
| 295 | */ | ||
| 296 | .align 5 | ||
| 297 | ENTRY(cpu_mohawk_switch_mm) | ||
| 298 | mov ip, #0 | ||
| 299 | mcr p15, 0, ip, c7, c14, 0 @ clean & invalidate all D cache | ||
| 300 | mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache | ||
| 301 | mcr p15, 0, ip, c7, c10, 4 @ drain WB | ||
| 302 | orr r0, r0, #0x18 @ cache the page table in L2 | ||
| 303 | mcr p15, 0, r0, c2, c0, 0 @ load page table pointer | ||
| 304 | mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs | ||
| 305 | mov pc, lr | ||
| 306 | |||
| 307 | /* | ||
| 308 | * cpu_mohawk_set_pte_ext(ptep, pte, ext) | ||
| 309 | * | ||
| 310 | * Set a PTE and flush it out | ||
| 311 | */ | ||
| 312 | .align 5 | ||
| 313 | ENTRY(cpu_mohawk_set_pte_ext) | ||
| 314 | armv3_set_pte_ext | ||
| 315 | mov r0, r0 | ||
| 316 | mcr p15, 0, r0, c7, c10, 1 @ clean D entry | ||
| 317 | mcr p15, 0, r0, c7, c10, 4 @ drain WB | ||
| 318 | mov pc, lr | ||
| 319 | |||
| 320 | __INIT | ||
| 321 | |||
| 322 | .type __mohawk_setup, #function | ||
| 323 | __mohawk_setup: | ||
| 324 | mov r0, #0 | ||
| 325 | mcr p15, 0, r0, c7, c7 @ invalidate I,D caches | ||
| 326 | mcr p15, 0, r0, c7, c10, 4 @ drain write buffer | ||
| 327 | mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs | ||
| 328 | orr r4, r4, #0x18 @ cache the page table in L2 | ||
| 329 | mcr p15, 0, r4, c2, c0, 0 @ load page table pointer | ||
| 330 | |||
| 331 | mov r0, #0 @ don't allow CP access | ||
| 332 | mcr p15, 0, r0, c15, c1, 0 @ write CP access register | ||
| 333 | |||
| 334 | adr r5, mohawk_crval | ||
| 335 | ldmia r5, {r5, r6} | ||
| 336 | mrc p15, 0, r0, c1, c0 @ get control register | ||
| 337 | bic r0, r0, r5 | ||
| 338 | orr r0, r0, r6 | ||
| 339 | mov pc, lr | ||
| 340 | |||
| 341 | .size __mohawk_setup, . - __mohawk_setup | ||
| 342 | |||
| 343 | /* | ||
| 344 | * R | ||
| 345 | * .RVI ZFRS BLDP WCAM | ||
| 346 | * .011 1001 ..00 0101 | ||
| 347 | * | ||
| 348 | */ | ||
| 349 | .type mohawk_crval, #object | ||
| 350 | mohawk_crval: | ||
| 351 | crval clear=0x00007f3f, mmuset=0x00003905, ucset=0x00001134 | ||
| 352 | |||
| 353 | __INITDATA | ||
| 354 | |||
| 355 | /* | ||
| 356 | * Purpose : Function pointers used to access above functions - all calls | ||
| 357 | * come through these | ||
| 358 | */ | ||
| 359 | .type mohawk_processor_functions, #object | ||
| 360 | mohawk_processor_functions: | ||
| 361 | .word v5t_early_abort | ||
| 362 | .word pabort_noifar | ||
| 363 | .word cpu_mohawk_proc_init | ||
| 364 | .word cpu_mohawk_proc_fin | ||
| 365 | .word cpu_mohawk_reset | ||
| 366 | .word cpu_mohawk_do_idle | ||
| 367 | .word cpu_mohawk_dcache_clean_area | ||
| 368 | .word cpu_mohawk_switch_mm | ||
| 369 | .word cpu_mohawk_set_pte_ext | ||
| 370 | .size mohawk_processor_functions, . - mohawk_processor_functions | ||
| 371 | |||
| 372 | .section ".rodata" | ||
| 373 | |||
| 374 | .type cpu_arch_name, #object | ||
| 375 | cpu_arch_name: | ||
| 376 | .asciz "armv5te" | ||
| 377 | .size cpu_arch_name, . - cpu_arch_name | ||
| 378 | |||
| 379 | .type cpu_elf_name, #object | ||
| 380 | cpu_elf_name: | ||
| 381 | .asciz "v5" | ||
| 382 | .size cpu_elf_name, . - cpu_elf_name | ||
| 383 | |||
| 384 | .type cpu_mohawk_name, #object | ||
| 385 | cpu_mohawk_name: | ||
| 386 | .asciz "Marvell 88SV331x" | ||
| 387 | .size cpu_mohawk_name, . - cpu_mohawk_name | ||
| 388 | |||
| 389 | .align | ||
| 390 | |||
| 391 | .section ".proc.info.init", #alloc, #execinstr | ||
| 392 | |||
| 393 | .type __88sv331x_proc_info,#object | ||
| 394 | __88sv331x_proc_info: | ||
| 395 | .long 0x56158000 @ Marvell 88SV331x (MOHAWK) | ||
| 396 | .long 0xfffff000 | ||
| 397 | .long PMD_TYPE_SECT | \ | ||
| 398 | PMD_SECT_BUFFERABLE | \ | ||
| 399 | PMD_SECT_CACHEABLE | \ | ||
| 400 | PMD_BIT4 | \ | ||
| 401 | PMD_SECT_AP_WRITE | \ | ||
| 402 | PMD_SECT_AP_READ | ||
| 403 | .long PMD_TYPE_SECT | \ | ||
| 404 | PMD_BIT4 | \ | ||
| 405 | PMD_SECT_AP_WRITE | \ | ||
| 406 | PMD_SECT_AP_READ | ||
| 407 | b __mohawk_setup | ||
| 408 | .long cpu_arch_name | ||
| 409 | .long cpu_elf_name | ||
| 410 | .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP | ||
| 411 | .long cpu_mohawk_name | ||
| 412 | .long mohawk_processor_functions | ||
| 413 | .long v4wbi_tlb_fns | ||
| 414 | .long v4wb_user_fns | ||
| 415 | .long mohawk_cache_fns | ||
| 416 | .size __88sv331x_proc_info, . - __88sv331x_proc_info | ||
diff --git a/arch/arm/mm/tlb-fa.S b/arch/arm/mm/tlb-fa.S new file mode 100644 index 000000000000..9694f1f6f485 --- /dev/null +++ b/arch/arm/mm/tlb-fa.S | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mm/tlb-fa.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 2005 Faraday Corp. | ||
| 5 | * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> | ||
| 6 | * | ||
| 7 | * Based on tlb-v4wbi.S: | ||
| 8 | * Copyright (C) 1997-2002 Russell King | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | * | ||
| 14 | * ARM architecture version 4, Faraday variation. | ||
| 15 | * This assume an unified TLBs, with a write buffer, and branch target buffer (BTB) | ||
| 16 | * | ||
| 17 | * Processors: FA520 FA526 FA626 | ||
| 18 | */ | ||
| 19 | #include <linux/linkage.h> | ||
| 20 | #include <linux/init.h> | ||
| 21 | #include <asm/asm-offsets.h> | ||
| 22 | #include <asm/tlbflush.h> | ||
| 23 | #include "proc-macros.S" | ||
| 24 | |||
| 25 | |||
| 26 | /* | ||
| 27 | * flush_user_tlb_range(start, end, mm) | ||
| 28 | * | ||
| 29 | * Invalidate a range of TLB entries in the specified address space. | ||
| 30 | * | ||
| 31 | * - start - range start address | ||
| 32 | * - end - range end address | ||
| 33 | * - mm - mm_struct describing address space | ||
| 34 | */ | ||
| 35 | .align 4 | ||
| 36 | ENTRY(fa_flush_user_tlb_range) | ||
| 37 | vma_vm_mm ip, r2 | ||
| 38 | act_mm r3 @ get current->active_mm | ||
| 39 | eors r3, ip, r3 @ == mm ? | ||
| 40 | movne pc, lr @ no, we dont do anything | ||
| 41 | mov r3, #0 | ||
| 42 | mcr p15, 0, r3, c7, c10, 4 @ drain WB | ||
| 43 | bic r0, r0, #0x0ff | ||
| 44 | bic r0, r0, #0xf00 | ||
| 45 | 1: mcr p15, 0, r0, c8, c7, 1 @ invalidate UTLB entry | ||
| 46 | add r0, r0, #PAGE_SZ | ||
| 47 | cmp r0, r1 | ||
| 48 | blo 1b | ||
| 49 | mcr p15, 0, r3, c7, c5, 6 @ invalidate BTB | ||
| 50 | mcr p15, 0, r3, c7, c10, 4 @ data write barrier | ||
| 51 | mov pc, lr | ||
| 52 | |||
| 53 | |||
| 54 | ENTRY(fa_flush_kern_tlb_range) | ||
| 55 | mov r3, #0 | ||
| 56 | mcr p15, 0, r3, c7, c10, 4 @ drain WB | ||
| 57 | bic r0, r0, #0x0ff | ||
| 58 | bic r0, r0, #0xf00 | ||
| 59 | 1: mcr p15, 0, r0, c8, c7, 1 @ invalidate UTLB entry | ||
| 60 | add r0, r0, #PAGE_SZ | ||
| 61 | cmp r0, r1 | ||
| 62 | blo 1b | ||
| 63 | mcr p15, 0, r3, c7, c5, 6 @ invalidate BTB | ||
| 64 | mcr p15, 0, r3, c7, c10, 4 @ data write barrier | ||
| 65 | mcr p15, 0, r3, c7, c5, 4 @ prefetch flush | ||
| 66 | mov pc, lr | ||
| 67 | |||
| 68 | __INITDATA | ||
| 69 | |||
| 70 | .type fa_tlb_fns, #object | ||
| 71 | ENTRY(fa_tlb_fns) | ||
| 72 | .long fa_flush_user_tlb_range | ||
| 73 | .long fa_flush_kern_tlb_range | ||
| 74 | .long fa_tlb_flags | ||
| 75 | .size fa_tlb_fns, . - fa_tlb_fns | ||
