diff options
Diffstat (limited to 'litmus/cache_proc.c')
-rw-r--r-- | litmus/cache_proc.c | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/litmus/cache_proc.c b/litmus/cache_proc.c new file mode 100644 index 000000000000..4425bfb8bbd4 --- /dev/null +++ b/litmus/cache_proc.c | |||
@@ -0,0 +1,245 @@ | |||
1 | #include <linux/init.h> | ||
2 | #include <linux/types.h> | ||
3 | #include <linux/kernel.h> | ||
4 | #include <linux/module.h> | ||
5 | #include <linux/sysctl.h> | ||
6 | #include <linux/slab.h> | ||
7 | #include <linux/io.h> | ||
8 | #include <linux/mutex.h> | ||
9 | |||
10 | #include <litmus/litmus_proc.h> | ||
11 | #include <litmus/sched_trace.h> | ||
12 | |||
13 | #include <asm/hardware/cache-l2x0.h> | ||
14 | #include <asm/cacheflush.h> | ||
15 | |||
16 | #define UNLOCK_ALL 0x00000000 /* allocation in any way */ | ||
17 | #define LOCK_ALL (~UNLOCK_ALL) | ||
18 | #define MAX_NR_WAYS 16 | ||
19 | |||
20 | u32 nr_unlocked_way[MAX_NR_WAYS+1] = { | ||
21 | 0xFFFFFFFF, /* all ways are locked. usable = 0*/ | ||
22 | 0xFFFFFFFE, /* way ~0 unlocked. usable = 1 */ | ||
23 | 0xFFFFFFFC, | ||
24 | 0xFFFFFFF8, | ||
25 | 0xFFFFFFF0, | ||
26 | 0xFFFFFFE0, | ||
27 | 0xFFFFFFC0, | ||
28 | 0xFFFFFF80, | ||
29 | 0xFFFFFF00, | ||
30 | 0xFFFFFE00, | ||
31 | 0xFFFFFC00, | ||
32 | 0xFFFFF800, | ||
33 | 0xFFFFF000, | ||
34 | 0xFFFFE000, | ||
35 | 0xFFFFC000, | ||
36 | 0xFFFF8000, | ||
37 | 0xFFFF0000, /* way ~15 unlocked. usable = 16 */ | ||
38 | }; | ||
39 | |||
40 | static void __iomem *cache_base; | ||
41 | static void __iomem *lockreg_d; | ||
42 | static void __iomem *lockreg_i; | ||
43 | |||
44 | static u32 cache_id; | ||
45 | |||
46 | struct mutex actlr_mutex; | ||
47 | struct mutex l2x0_prefetch_mutex; | ||
48 | struct mutex lockdown_proc; | ||
49 | |||
50 | static int min_usable_ways = 0; | ||
51 | static int max_usable_ways = 16; | ||
52 | static int zero = 0; | ||
53 | static int one = 1; | ||
54 | |||
55 | #define ld_d_reg(cpu) ({ int __cpu = cpu; \ | ||
56 | void __iomem *__v = cache_base + L2X0_LOCKDOWN_WAY_D_BASE + \ | ||
57 | __cpu * L2X0_LOCKDOWN_STRIDE; __v; }) | ||
58 | #define ld_i_reg(cpu) ({ int __cpu = cpu; \ | ||
59 | void __iomem *__v = cache_base + L2X0_LOCKDOWN_WAY_I_BASE + \ | ||
60 | __cpu * L2X0_LOCKDOWN_STRIDE; __v; }) | ||
61 | |||
62 | int l2_usable_ways; | ||
63 | int lock_all; | ||
64 | int nr_lockregs; | ||
65 | |||
66 | static void print_lockdown_registers(void) | ||
67 | { | ||
68 | int i; | ||
69 | |||
70 | for (i = 0; i < nr_lockregs; i++) { | ||
71 | printk("Lockdown Data CPU %2d: 0x%8x\n", | ||
72 | i, readl_relaxed(ld_d_reg(i))); | ||
73 | printk("Lockdown Inst CPU %2d: 0x%8x\n", | ||
74 | i, readl_relaxed(ld_i_reg(i))); | ||
75 | } | ||
76 | } | ||
77 | |||
78 | static void test_lockdown(void *ignore) | ||
79 | { | ||
80 | int i; | ||
81 | |||
82 | printk("Start lockdown test on CPU %d.\n", smp_processor_id()); | ||
83 | |||
84 | for (i = 0; i < nr_lockregs; i++) { | ||
85 | printk("CPU %2d data reg: 0x%8p\n", i, ld_d_reg(i)); | ||
86 | printk("CPU %2d inst reg: 0x%8p\n", i, ld_i_reg(i)); | ||
87 | } | ||
88 | |||
89 | printk("Lockdown initial state:\n"); | ||
90 | print_lockdown_registers(); | ||
91 | printk("---\n"); | ||
92 | |||
93 | for (i = 0; i < nr_lockregs; i++) { | ||
94 | writel_relaxed(1, ld_d_reg(i)); | ||
95 | writel_relaxed(2, ld_i_reg(i)); | ||
96 | } | ||
97 | printk("Lockdown all data=1 instr=2:\n"); | ||
98 | print_lockdown_registers(); | ||
99 | printk("---\n"); | ||
100 | |||
101 | for (i = 0; i < nr_lockregs; i++) { | ||
102 | writel_relaxed((1 << i), ld_d_reg(i)); | ||
103 | writel_relaxed(((1 << 8) >> i), ld_i_reg(i)); | ||
104 | } | ||
105 | printk("Lockdown varies:\n"); | ||
106 | print_lockdown_registers(); | ||
107 | printk("---\n"); | ||
108 | |||
109 | for (i = 0; i < nr_lockregs; i++) { | ||
110 | writel_relaxed(UNLOCK_ALL, ld_d_reg(i)); | ||
111 | writel_relaxed(UNLOCK_ALL, ld_i_reg(i)); | ||
112 | } | ||
113 | printk("Lockdown all zero:\n"); | ||
114 | print_lockdown_registers(); | ||
115 | |||
116 | printk("End lockdown test.\n"); | ||
117 | } | ||
118 | |||
119 | void litmus_setup_lockdown(void __iomem *base, u32 id) | ||
120 | { | ||
121 | cache_base = base; | ||
122 | cache_id = id; | ||
123 | lockreg_d = cache_base + L2X0_LOCKDOWN_WAY_D_BASE; | ||
124 | lockreg_i = cache_base + L2X0_LOCKDOWN_WAY_I_BASE; | ||
125 | |||
126 | if (L2X0_CACHE_ID_PART_L310 == (cache_id & L2X0_CACHE_ID_PART_MASK)) { | ||
127 | nr_lockregs = 8; | ||
128 | } else { | ||
129 | printk("Unknown cache ID!\n"); | ||
130 | nr_lockregs = 1; | ||
131 | } | ||
132 | |||
133 | mutex_init(&actlr_mutex); | ||
134 | mutex_init(&l2x0_prefetch_mutex); | ||
135 | mutex_init(&lockdown_proc); | ||
136 | |||
137 | test_lockdown(NULL); | ||
138 | } | ||
139 | int lock_all_handler(struct ctl_table *table, int write, void __user *buffer, | ||
140 | size_t *lenp, loff_t *ppos) | ||
141 | { | ||
142 | int ret = 0, i; | ||
143 | |||
144 | mutex_lock(&lockdown_proc); | ||
145 | |||
146 | flush_cache_all(); | ||
147 | |||
148 | ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); | ||
149 | if (ret) | ||
150 | goto out; | ||
151 | |||
152 | if (write && lock_all == 1) { | ||
153 | for (i = 0; i < nr_lockregs; i++) { | ||
154 | writel_relaxed(nr_unlocked_way[0], ld_d_reg(i)); | ||
155 | writel_relaxed(nr_unlocked_way[0], ld_i_reg(i)); | ||
156 | } | ||
157 | print_lockdown_registers(); | ||
158 | } | ||
159 | |||
160 | out: | ||
161 | mutex_unlock(&lockdown_proc); | ||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | int l2_usable_ways_handler(struct ctl_table *table, int write, void __user *buffer, | ||
166 | size_t *lenp, loff_t *ppos) | ||
167 | { | ||
168 | int ret = 0, i = 0; | ||
169 | |||
170 | mutex_lock(&lockdown_proc); | ||
171 | |||
172 | flush_cache_all(); | ||
173 | |||
174 | ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); | ||
175 | if (ret) | ||
176 | goto out; | ||
177 | |||
178 | TRACE_CUR("l2_usable_ways : %d\n", l2_usable_ways); | ||
179 | |||
180 | if (write) { | ||
181 | //for (i = 0; i < nr_lockregs; i++) { | ||
182 | writel_relaxed(nr_unlocked_way[l2_usable_ways], ld_d_reg(i)); | ||
183 | writel_relaxed(nr_unlocked_way[l2_usable_ways], ld_i_reg(i)); | ||
184 | //} | ||
185 | print_lockdown_registers(); | ||
186 | } | ||
187 | |||
188 | out: | ||
189 | mutex_unlock(&lockdown_proc); | ||
190 | return ret; | ||
191 | } | ||
192 | |||
193 | static struct ctl_table cache_table[] = | ||
194 | { | ||
195 | { | ||
196 | .procname = "l2_usable_ways", | ||
197 | .mode = 0666, | ||
198 | .proc_handler = l2_usable_ways_handler, | ||
199 | .data = &l2_usable_ways, | ||
200 | .maxlen = sizeof(l2_usable_ways), | ||
201 | .extra1 = &min_usable_ways, | ||
202 | .extra2 = &max_usable_ways, | ||
203 | }, | ||
204 | { | ||
205 | .procname = "lock_all", | ||
206 | .mode = 0666, | ||
207 | .proc_handler = lock_all_handler, | ||
208 | .data = &lock_all, | ||
209 | .maxlen = sizeof(lock_all), | ||
210 | .extra1 = &zero, | ||
211 | .extra2 = &one, | ||
212 | }, | ||
213 | { } | ||
214 | }; | ||
215 | |||
216 | static struct ctl_table litmus_dir_table[] = { | ||
217 | { | ||
218 | .procname = "litmus", | ||
219 | .mode = 0555, | ||
220 | .child = cache_table, | ||
221 | }, | ||
222 | { } | ||
223 | }; | ||
224 | |||
225 | static struct ctl_table_header *litmus_sysctls; | ||
226 | |||
227 | static int __init litmus_sysctl_init(void) | ||
228 | { | ||
229 | int ret = 0; | ||
230 | |||
231 | printk(KERN_INFO "Registering LITMUS^RT proc sysctl.\n"); | ||
232 | litmus_sysctls = register_sysctl_table(litmus_dir_table); | ||
233 | if (!litmus_sysctls) { | ||
234 | printk(KERN_WARNING "Could not register LITMUS^RT sysctl.\n"); | ||
235 | ret = -EFAULT; | ||
236 | goto out; | ||
237 | } | ||
238 | |||
239 | l2_usable_ways = 16; | ||
240 | |||
241 | out: | ||
242 | return ret; | ||
243 | } | ||
244 | |||
245 | module_init(litmus_sysctl_init); \ No newline at end of file | ||