diff options
-rw-r--r-- | arch/metag/mm/cache.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/arch/metag/mm/cache.c b/arch/metag/mm/cache.c index 89da74a80ea7..4dd96e457fa2 100644 --- a/arch/metag/mm/cache.c +++ b/arch/metag/mm/cache.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <asm/cacheflush.h> | 15 | #include <asm/cacheflush.h> |
16 | #include <asm/core_reg.h> | 16 | #include <asm/core_reg.h> |
17 | #include <asm/global_lock.h> | ||
17 | #include <asm/metag_isa.h> | 18 | #include <asm/metag_isa.h> |
18 | #include <asm/metag_mem.h> | 19 | #include <asm/metag_mem.h> |
19 | #include <asm/metag_regs.h> | 20 | #include <asm/metag_regs.h> |
@@ -36,6 +37,82 @@ static int icache_set_shift = METAG_TBI_CACHE_SIZE_BASE_LOG2 | |||
36 | static unsigned char dcache_sets_log2 = DEFAULT_CACHE_WAYS_LOG2; | 37 | static unsigned char dcache_sets_log2 = DEFAULT_CACHE_WAYS_LOG2; |
37 | static unsigned char icache_sets_log2 = DEFAULT_CACHE_WAYS_LOG2; | 38 | static unsigned char icache_sets_log2 = DEFAULT_CACHE_WAYS_LOG2; |
38 | 39 | ||
40 | #ifndef CONFIG_METAG_META12 | ||
41 | /** | ||
42 | * metag_lnkget_probe() - Probe whether lnkget/lnkset go around the cache | ||
43 | */ | ||
44 | static volatile u32 lnkget_testdata[16] __initdata __aligned(64); | ||
45 | |||
46 | #define LNKGET_CONSTANT 0xdeadbeef | ||
47 | |||
48 | void __init metag_lnkget_probe(void) | ||
49 | { | ||
50 | int temp; | ||
51 | long flags; | ||
52 | |||
53 | /* | ||
54 | * It's conceivable the user has configured a globally coherent cache | ||
55 | * shared with non-Linux hardware threads, so use LOCK2 to prevent them | ||
56 | * from executing and causing cache eviction during the test. | ||
57 | */ | ||
58 | __global_lock2(flags); | ||
59 | |||
60 | /* read a value to bring it into the cache */ | ||
61 | (void)lnkget_testdata[0]; | ||
62 | lnkget_testdata[0] = 0; | ||
63 | |||
64 | /* lnkget/lnkset it to modify it */ | ||
65 | asm volatile( | ||
66 | "1: LNKGETD %0, [%1]\n" | ||
67 | " LNKSETD [%1], %2\n" | ||
68 | " DEFR %0, TXSTAT\n" | ||
69 | " ANDT %0, %0, #HI(0x3f000000)\n" | ||
70 | " CMPT %0, #HI(0x02000000)\n" | ||
71 | " BNZ 1b\n" | ||
72 | : "=&d" (temp) | ||
73 | : "da" (&lnkget_testdata[0]), "bd" (LNKGET_CONSTANT) | ||
74 | : "cc"); | ||
75 | |||
76 | /* re-read it to see if the cached value changed */ | ||
77 | temp = lnkget_testdata[0]; | ||
78 | |||
79 | __global_unlock2(flags); | ||
80 | |||
81 | /* flush the cache line to fix any incoherency */ | ||
82 | __builtin_dcache_flush((void *)&lnkget_testdata[0]); | ||
83 | |||
84 | #if defined(CONFIG_METAG_LNKGET_AROUND_CACHE) | ||
85 | /* if the cache is right, LNKGET_AROUND_CACHE is unnecessary */ | ||
86 | if (temp == LNKGET_CONSTANT) | ||
87 | pr_info("LNKGET/SET go through cache but CONFIG_METAG_LNKGET_AROUND_CACHE=y\n"); | ||
88 | #elif defined(CONFIG_METAG_ATOMICITY_LNKGET) | ||
89 | /* | ||
90 | * if the cache is wrong, LNKGET_AROUND_CACHE is really necessary | ||
91 | * because the kernel is configured to use LNKGET/SET for atomicity | ||
92 | */ | ||
93 | WARN(temp != LNKGET_CONSTANT, | ||
94 | "LNKGET/SET go around cache but CONFIG_METAG_LNKGET_AROUND_CACHE=n\n" | ||
95 | "Expect kernel failure as it's used for atomicity primitives\n"); | ||
96 | #elif defined(CONFIG_SMP) | ||
97 | /* | ||
98 | * if the cache is wrong, LNKGET_AROUND_CACHE should be used or the | ||
99 | * gateway page won't flush and userland could break. | ||
100 | */ | ||
101 | WARN(temp != LNKGET_CONSTANT, | ||
102 | "LNKGET/SET go around cache but CONFIG_METAG_LNKGET_AROUND_CACHE=n\n" | ||
103 | "Expect userland failure as it's used for user gateway page\n"); | ||
104 | #else | ||
105 | /* | ||
106 | * if the cache is wrong, LNKGET_AROUND_CACHE is set wrong, but it | ||
107 | * doesn't actually matter as it doesn't have any effect on !SMP && | ||
108 | * !ATOMICITY_LNKGET. | ||
109 | */ | ||
110 | if (temp != LNKGET_CONSTANT) | ||
111 | pr_warn("LNKGET/SET go around cache but CONFIG_METAG_LNKGET_AROUND_CACHE=n\n"); | ||
112 | #endif | ||
113 | } | ||
114 | #endif /* !CONFIG_METAG_META12 */ | ||
115 | |||
39 | /** | 116 | /** |
40 | * metag_cache_probe() - Probe L1 cache configuration. | 117 | * metag_cache_probe() - Probe L1 cache configuration. |
41 | * | 118 | * |
@@ -68,6 +145,8 @@ void __init metag_cache_probe(void) | |||
68 | dcache_set_shift += (config & METAC_CORECFG2_DCSZ_BITS) | 145 | dcache_set_shift += (config & METAC_CORECFG2_DCSZ_BITS) |
69 | >> METAC_CORECFG2_DCSZ_S; | 146 | >> METAC_CORECFG2_DCSZ_S; |
70 | dcache_set_shift -= dcache_sets_log2; | 147 | dcache_set_shift -= dcache_sets_log2; |
148 | |||
149 | metag_lnkget_probe(); | ||
71 | #else | 150 | #else |
72 | /* Extract cache sizes from global heap segment */ | 151 | /* Extract cache sizes from global heap segment */ |
73 | unsigned long val, u; | 152 | unsigned long val, u; |