aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2013-01-31 06:06:03 -0500
committerJames Hogan <james.hogan@imgtec.com>2013-03-02 15:09:56 -0500
commit883a635591ef25bc6a325f8a43af17ec8ecfe011 (patch)
tree2bc087451e14343e35cc6159cb91bfe0b5dd48f5 /arch
parent0a38a8adc5d479c1e59a82d1fcee3bdf59b85ef3 (diff)
metag: add boot time LNKGET/LNKSET check
Add boot time check for whether LNKGET/LNKSET go through or around the cache. Depending on the configuration an info message (no harm), warning (technically wrong but no harm), or big WARN (expect failure in either kernel or userland) may be emitted if the behaviour is not as expected: Configuration Hardware Response ------------------------------------------ -------- -------- AROUND_CACHE through pr_info !AROUND_CACHE && ATOMICITY_LNKGET around WARN (kernel) " && !ATOMICITY_LNKGET && SMP around WARN (user) " " && !SMP around pr_warn Signed-off-by: James Hogan <james.hogan@imgtec.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/metag/mm/cache.c79
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
36static unsigned char dcache_sets_log2 = DEFAULT_CACHE_WAYS_LOG2; 37static unsigned char dcache_sets_log2 = DEFAULT_CACHE_WAYS_LOG2;
37static unsigned char icache_sets_log2 = DEFAULT_CACHE_WAYS_LOG2; 38static 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 */
44static volatile u32 lnkget_testdata[16] __initdata __aligned(64);
45
46#define LNKGET_CONSTANT 0xdeadbeef
47
48void __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;