aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Kenna <cjk@cs.unc.edu>2012-10-17 13:31:13 -0400
committerChristopher Kenna <cjk@cs.unc.edu>2012-10-17 13:51:07 -0400
commita1cf3bfebbf32ac9022db9482e7009ba447a85af (patch)
tree44ad56b56e3d3cb5c87f3a90fb745fa4d77f3534
parent76ec41ad78e824c421c29e20cd145d95ec88b258 (diff)
Changes to ARM lockdown and LITMUS cycle counting code.
Try and fix the cycle counter on ARMv7 CPUs (unsuccessful). Use the multi-core timer on the ODROID-X to count cycles. Add lockdown register access to proc. Add proc options to disable prefetching for L1/L2 cache. Add test to lockdown.c to print the time to read in various WSSs. Signed-off-by: Christopher Kenna <cjk@cs.unc.edu>
-rw-r--r--arch/arm/include/asm/timex.h13
-rw-r--r--include/litmus/clock.h44
-rw-r--r--include/litmus/color.h16
-rw-r--r--include/litmus/feather_trace.h4
-rw-r--r--include/litmus/litmus_proc.h3
-rw-r--r--litmus/Makefile1
-rw-r--r--litmus/clock.c31
-rw-r--r--litmus/color.c5
-rw-r--r--litmus/color_proc.c59
-rw-r--r--litmus/litmus.c26
-rw-r--r--litmus/lockdown.c381
11 files changed, 528 insertions, 55 deletions
diff --git a/arch/arm/include/asm/timex.h b/arch/arm/include/asm/timex.h
index 12a53699cd20..7f75e9a0cd32 100644
--- a/arch/arm/include/asm/timex.h
+++ b/arch/arm/include/asm/timex.h
@@ -14,18 +14,7 @@
14 14
15#include <mach/timex.h> 15#include <mach/timex.h>
16 16
17typedef unsigned long cycles_t; 17typedef u64 cycles_t;
18
19#if defined(CONFIG_CPU_V7) && !defined(CONFIG_HW_PERF_EVENTS)
20static inline cycles_t v7_get_cycles (void)
21{
22 u32 value;
23 /* read CCNT register */
24 asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(value));
25 return value;
26}
27#define get_cycles v7_get_cycles
28#endif
29 18
30#ifndef get_cycles 19#ifndef get_cycles
31static inline cycles_t get_cycles (void) 20static inline cycles_t get_cycles (void)
diff --git a/include/litmus/clock.h b/include/litmus/clock.h
new file mode 100644
index 000000000000..d6f1cfd2ca60
--- /dev/null
+++ b/include/litmus/clock.h
@@ -0,0 +1,44 @@
1#ifndef _LITMUS_CLOCK_H_
2#define _LITMUS_CLOCK_H_
3
4#if defined(CONFIG_EXYNOS_MCT)
5/*
6 * Only used if we are using the EXYNOS MCT clock.
7 */
8
9#include <linux/clocksource.h>
10extern struct clocksource mct_frc;
11
12static inline cycles_t mct_frc_read(void)
13{
14 cycle_t cycles = mct_frc.read(&mct_frc);
15 return cycles;
16}
17
18static inline s64 litmus_cycles_to_ns(cycles_t cycles)
19{
20 return clocksource_cyc2ns(cycles, mct_frc.mult, mct_frc.shift);
21}
22
23#define litmus_get_cycles mct_frc_read
24
25#elif defined(CONFIG_CPU_V7) && !defined(CONFIG_HW_PERF_EVENTS)
26
27static inline cycles_t v7_get_cycles (void)
28{
29 u32 value;
30 /* read CCNT register */
31 asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(value));
32 return value;
33}
34
35#define litmus_get_cycles v7_get_cycles
36
37#else
38#include <asm/timex.h>
39
40#define litmus_get_cycles get_cycles
41
42#endif
43
44#endif
diff --git a/include/litmus/color.h b/include/litmus/color.h
index b8e8a8d5fce7..465d768b2d6b 100644
--- a/include/litmus/color.h
+++ b/include/litmus/color.h
@@ -20,8 +20,20 @@ struct color_cache_info {
20 unsigned long nr_colors; 20 unsigned long nr_colors;
21}; 21};
22 22
23int litmus_test_prefetch(struct ctl_table *, int, void __user *, 23#ifdef CONFIG_CPU_V7
24 size_t *, loff_t *); 24int litmus_test_prefetch_proc_handler(struct ctl_table *, int,
25 void __user *, size_t *, loff_t *);
26int litmus_l1_prefetch_proc_handler(struct ctl_table *, int,
27 void __user *, size_t *, loff_t *);
28int litmus_l2_prefetch_hint_proc_handler(struct ctl_table *, int,
29 void __user *, size_t *, loff_t *);
30int litmus_l2_double_linefill_proc_handler(struct ctl_table *, int,
31 void __user *, size_t *, loff_t *);
32int litmus_l2_data_prefetch_proc_handler(struct ctl_table *, int,
33 void __user *, size_t *, loff_t *);
34int litmus_lockdown_proc_handler(struct ctl_table *, int,
35 void __user *, size_t *, loff_t *);
36#endif
25 37
26/* defined in litmus/color.c */ 38/* defined in litmus/color.c */
27extern struct color_cache_info color_cache_info; 39extern struct color_cache_info color_cache_info;
diff --git a/include/litmus/feather_trace.h b/include/litmus/feather_trace.h
index 028dfb206fb0..a816dc4e6809 100644
--- a/include/litmus/feather_trace.h
+++ b/include/litmus/feather_trace.h
@@ -32,11 +32,11 @@ static inline int fetch_and_dec(int *val)
32 32
33/* provide default implementation */ 33/* provide default implementation */
34 34
35#include <asm/timex.h> /* for get_cycles() */ 35#include <litmus/clock.h>
36 36
37static inline unsigned long long ft_timestamp(void) 37static inline unsigned long long ft_timestamp(void)
38{ 38{
39 return get_cycles(); 39 return litmus_get_cycles();
40} 40}
41 41
42#define feather_callback 42#define feather_callback
diff --git a/include/litmus/litmus_proc.h b/include/litmus/litmus_proc.h
index 6800e725d48c..06b73b746f87 100644
--- a/include/litmus/litmus_proc.h
+++ b/include/litmus/litmus_proc.h
@@ -23,3 +23,6 @@ void remove_plugin_proc_dir(struct sched_plugin* plugin);
23 * -EFAULT. */ 23 * -EFAULT. */
24int copy_and_chomp(char *kbuf, unsigned long ksize, 24int copy_and_chomp(char *kbuf, unsigned long ksize,
25 __user const char* ubuf, unsigned long ulength); 25 __user const char* ubuf, unsigned long ulength);
26
27int litmus_preempt_and_irq_proc_handler(struct ctl_table *, int,
28 void __user *, size_t *, loff_t *);
diff --git a/litmus/Makefile b/litmus/Makefile
index 61f7c9576d35..62878336f560 100644
--- a/litmus/Makefile
+++ b/litmus/Makefile
@@ -32,6 +32,7 @@ obj-y = sched_plugin.o litmus.o \
32 sync.o 32 sync.o
33 33
34 34
35obj-$(CONFIG_EXYNOS_MCT) += clock.o
35obj-$(CONFIG_CPU_V7) += lockdown.o 36obj-$(CONFIG_CPU_V7) += lockdown.o
36obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o 37obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o
37obj-$(CONFIG_PLUGIN_PFAIR) += sched_pfair.o 38obj-$(CONFIG_PLUGIN_PFAIR) += sched_pfair.o
diff --git a/litmus/clock.c b/litmus/clock.c
new file mode 100644
index 000000000000..d0ec082cd496
--- /dev/null
+++ b/litmus/clock.c
@@ -0,0 +1,31 @@
1#include <linux/module.h>
2#include <linux/clocksource.h>
3
4#include <asm/timex.h>
5
6/*
7 * Note that:
8 * - cycle_t => linux/clocksource.h
9 * - cycles_t => asm/timex.h (LITMUS^RT)
10 */
11
12extern struct clocksource mct_frc;
13
14static int __init init_litmus_clock(void)
15{
16 BUILD_BUG_ON(sizeof(cycles_t) != sizeof(cycle_t));
17
18 printk("LITMUS^RT: Set up %s as clock source. "
19 "mult=%u shift=%u mask=0x%016llx\n",
20 mct_frc.name, mct_frc.mult, mct_frc.shift,
21 mct_frc.mask);
22
23 return 0;
24}
25
26static void exit_litmus_clock(void)
27{
28}
29
30module_init(init_litmus_clock);
31module_exit(exit_litmus_clock);
diff --git a/litmus/color.c b/litmus/color.c
index 278f541e07c1..96ccf3efd228 100644
--- a/litmus/color.c
+++ b/litmus/color.c
@@ -14,6 +14,7 @@
14 14
15#include <litmus/color.h> 15#include <litmus/color.h>
16#include <litmus/litmus.h> /* for in_list(...) */ 16#include <litmus/litmus.h> /* for in_list(...) */
17#include <litmus/clock.h>
17 18
18#define PAGES_PER_COLOR 1024 19#define PAGES_PER_COLOR 1024
19 20
@@ -342,8 +343,8 @@ out:
342 343
343static void __init print_cycle_count(void *_unused) 344static void __init print_cycle_count(void *_unused)
344{ 345{
345 cycles_t cycles = get_cycles(); 346 cycles_t cycles = litmus_get_cycles();
346 printk("CPU %2d: %10lu cycles\n", smp_processor_id(), cycles); 347 printk("CPU %2d: %10llu cycles\n", smp_processor_id(), cycles);
347} 348}
348 349
349static int __init init_color(void) 350static int __init init_color(void)
diff --git a/litmus/color_proc.c b/litmus/color_proc.c
index abfa4c8a3c3b..3c301f059b9f 100644
--- a/litmus/color_proc.c
+++ b/litmus/color_proc.c
@@ -2,6 +2,7 @@
2#include <linux/sysctl.h> 2#include <linux/sysctl.h>
3#include <linux/slab.h> 3#include <linux/slab.h>
4 4
5#include <litmus/litmus_proc.h>
5#include <litmus/sched_trace.h> 6#include <litmus/sched_trace.h>
6#include <litmus/color.h> 7#include <litmus/color.h>
7 8
@@ -32,6 +33,14 @@ unsigned long color_chunk;
32int cache_preempt; 33int cache_preempt;
33int lock_cache; 34int lock_cache;
34 35
36#ifdef CONFIG_CPU_V7
37static int l1_prefetch_proc;
38static int l2_prefetch_hint_proc;
39static int l2_double_linefill_proc;
40static int l2_data_prefetch_proc;
41static int lockdown_proc;
42#endif
43
35#define INFO_BUFFER_SIZE 100 44#define INFO_BUFFER_SIZE 100
36static char info_buffer[100]; 45static char info_buffer[100];
37 46
@@ -59,6 +68,49 @@ static struct ctl_table cache_table[] =
59 .data = &color_cache_info.nr_colors, 68 .data = &color_cache_info.nr_colors,
60 .maxlen = sizeof(color_cache_info.nr_colors), 69 .maxlen = sizeof(color_cache_info.nr_colors),
61 }, 70 },
71#ifdef CONFIG_CPU_V7
72 {
73 .procname = "prefetch_test",
74 .mode = 0644,
75 .proc_handler = litmus_test_prefetch_proc_handler,
76 },
77 {
78 .procname = "l1_prefetch",
79 .mode = 0644,
80 .proc_handler = litmus_l1_prefetch_proc_handler,
81 .data = &l1_prefetch_proc,
82 .maxlen = sizeof(l1_prefetch_proc),
83 },
84 {
85 .procname = "l2_prefetch_hint",
86 .mode = 0644,
87 .proc_handler = litmus_l2_prefetch_hint_proc_handler,
88 .data = &l2_prefetch_hint_proc,
89 .maxlen = sizeof(l2_prefetch_hint_proc),
90 },
91 {
92 .procname = "l2_double_linefill",
93 .mode = 0644,
94 .proc_handler = litmus_l2_double_linefill_proc_handler,
95 .data = &l2_double_linefill_proc,
96 .maxlen = sizeof(l2_double_linefill_proc),
97 },
98 {
99 .procname = "l2_data_prefetch",
100 .mode = 0644,
101 .proc_handler = litmus_l2_data_prefetch_proc_handler,
102 .data = &l2_data_prefetch_proc,
103 .maxlen = sizeof(l2_data_prefetch_proc),
104 },
105 {
106 .procname = "lockdown",
107 .mode = 0644,
108 .proc_handler = litmus_lockdown_proc_handler,
109 .data = &lockdown_proc,
110 .maxlen = sizeof(lockdown_proc),
111
112 },
113#endif
62 { } 114 { }
63}; 115};
64 116
@@ -120,13 +172,6 @@ static struct ctl_table color_table[] =
120 .mode = 0555, 172 .mode = 0555,
121 .child = cache_table, 173 .child = cache_table,
122 }, 174 },
123#ifdef CONFIG_CPU_V7
124 {
125 .procname = "prefetch_test",
126 .mode = 0644,
127 .proc_handler = litmus_test_prefetch,
128 },
129#endif
130 { } 175 { }
131}; 176};
132 177
diff --git a/litmus/litmus.c b/litmus/litmus.c
index 531a2245133d..4cb6b5c47fd6 100644
--- a/litmus/litmus.c
+++ b/litmus/litmus.c
@@ -304,7 +304,7 @@ asmlinkage long sys_null_call(cycles_t __user *ts)
304 cycles_t now; 304 cycles_t now;
305 305
306 if (ts) { 306 if (ts) {
307 now = get_cycles(); 307 now = litmus_get_cycles();
308 ret = put_user(now, ts); 308 ret = put_user(now, ts);
309 } 309 }
310 310
@@ -659,7 +659,13 @@ extern struct sched_plugin linux_sched_plugin;
659#if defined(CONFIG_CPU_V7) && !defined(CONFIG_HW_PERF_EVENTS) 659#if defined(CONFIG_CPU_V7) && !defined(CONFIG_HW_PERF_EVENTS)
660static void __init litmus_enable_perfcounters_v7(void *_ignore) 660static void __init litmus_enable_perfcounters_v7(void *_ignore)
661{ 661{
662 u32 enable_val; 662 u32 enable_val = 0;
663
664 /* disable performance monitoring */
665 asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (0x00000006));
666
667 /* disable all events */
668 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (0xffffffff));
663 669
664 /* write 1 to enable user-mode access to the performance counter */ 670 /* write 1 to enable user-mode access to the performance counter */
665 asm volatile("mcr p15, 0, %0, c9, c14, 0" : : "r" (1)); 671 asm volatile("mcr p15, 0, %0, c9, c14, 0" : : "r" (1));
@@ -667,13 +673,21 @@ static void __init litmus_enable_perfcounters_v7(void *_ignore)
667 /* disable counter overflow interrupts (just in case) */ 673 /* disable counter overflow interrupts (just in case) */
668 asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (0x8000000f)); 674 asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (0x8000000f));
669 675
670 enable_val = 1; /* bit 1 enables the counters */ 676 /* select event zero */
671 enable_val |= 2; /* resets cycle counter to zero */ 677 asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (0));
678
679 /* count cycles in the selected event zero */
680 asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (0x00000011));
681
682 enable_val |= 1; /* bit 1 enables the counters */
683 enable_val |= 2; /* resets event counters to zero */
684 enable_val |= 4; /* resets cycle counter to zero */
685
672 /* performance monitor control register: enable all counters */ 686 /* performance monitor control register: enable all counters */
673 asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(enable_val)); 687 asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(enable_val));
674 688
675 /* enables counters (currently just cycle counter) */ 689 /* enables counters (cycle counter and event 1) */
676 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(0x80000000)); 690 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(0x80000001));
677} 691}
678 692
679static void __init litmus_enable_perfcounters(void) 693static void __init litmus_enable_perfcounters(void)
diff --git a/litmus/lockdown.c b/litmus/lockdown.c
index 7cfa24859c0d..ac7b9a24a512 100644
--- a/litmus/lockdown.c
+++ b/litmus/lockdown.c
@@ -4,14 +4,19 @@
4#include <linux/io.h> 4#include <linux/io.h>
5#include <linux/spinlock.h> 5#include <linux/spinlock.h>
6#include <linux/time.h> 6#include <linux/time.h>
7#include <linux/sysctl.h>
8#include <linux/mutex.h>
9#include <linux/math64.h>
10#include <linux/vmalloc.h>
11#include <linux/slab.h>
7 12
8#include <linux/smp.h> /* smp_call_func */ 13#include <litmus/clock.h>
9#include <asm/processor.h> /* cpu relax */
10 14
11#include <asm/hardware/cache-l2x0.h> 15#include <asm/hardware/cache-l2x0.h>
12#include <asm/cacheflush.h> 16#include <asm/cacheflush.h>
13 17
14#include <litmus/color.h> 18#include <litmus/color.h>
19#include <litmus/debug_trace.h>
15 20
16static void __iomem *cache_base; 21static void __iomem *cache_base;
17static void __iomem *lockreg_d; 22static void __iomem *lockreg_d;
@@ -21,6 +26,10 @@ static raw_spinlock_t prefetch_lock;
21static u32 cache_id; 26static u32 cache_id;
22static int nr_lockregs; 27static int nr_lockregs;
23 28
29struct mutex actlr_mutex;
30struct mutex l2x0_prefetch_mutex;
31struct mutex lockdown_proc;
32
24#define ld_d_reg(cpu) ({ int __cpu = cpu; \ 33#define ld_d_reg(cpu) ({ int __cpu = cpu; \
25 void __iomem *__v = cache_base + L2X0_LOCKDOWN_WAY_D_BASE + \ 34 void __iomem *__v = cache_base + L2X0_LOCKDOWN_WAY_D_BASE + \
26 __cpu * L2X0_LOCKDOWN_STRIDE; __v; }) 35 __cpu * L2X0_LOCKDOWN_STRIDE; __v; })
@@ -55,8 +64,8 @@ static u32 read_in_page(u32 lock_val,
55" .align 5\n" 64" .align 5\n"
56" str %[lockval], [%[cachereg]]\n" 65" str %[lockval], [%[cachereg]]\n"
57"1: ldr %[val], [%[addr]], #32 @ 32 bytes = 1 cache line\n" 66"1: ldr %[val], [%[addr]], #32 @ 32 bytes = 1 cache line\n"
58" cmp %[addr], %[end]\n" 67" cmp %[end], %[addr] @ subtracts addr from end\n"
59" bne 1b\n" 68" bgt 1b\n @ read more, if necessary\n"
60" str %[unlockval], [%[cachereg]]\n" 69" str %[unlockval], [%[cachereg]]\n"
61 : [addr] "+r" (start), 70 : [addr] "+r" (start),
62 [val] "+r" (v) 71 [val] "+r" (v)
@@ -105,7 +114,7 @@ static u32 unlocked[MAX_NR_WAYS] = {
105 0xFFFF7FFF, 114 0xFFFF7FFF,
106}; 115};
107 116
108static void dump_lockdown_registers(void) 117static void print_lockdown_registers(void)
109{ 118{
110 int i; 119 int i;
111 120
@@ -117,6 +126,338 @@ static void dump_lockdown_registers(void)
117 } 126 }
118} 127}
119 128
129/* Operate on the Cortex-A9's ACTLR register */
130#define ACTLR_L2_PREFETCH_HINT (1 << 1)
131#define ACTLR_L1_PREFETCH (1 << 2)
132
133/*
134 * Change the ACTLR.
135 * @mode - If 1 (0), set (clear) the bit given in @mask in the ACTLR.
136 * @mask - A mask in which one bit is set to operate on the ACTLR.
137 */
138static void actlr_change(int mode, int mask)
139{
140 u32 orig_value, new_value, reread_value;
141
142 if (0 != mode && 1 != mode) {
143 printk(KERN_WARNING "Called %s with mode != 0 and mode != 1.\n",
144 __FUNCTION__);
145 return;
146 }
147
148 /* get the original value */
149 asm volatile("mrc p15, 0, %0, c1, c0, 1" : "=r" (orig_value));
150
151 if (0 == mode)
152 new_value = orig_value & ~(mask);
153 else
154 new_value = orig_value | mask;
155
156 asm volatile("mcr p15, 0, %0, c1, c0, 1" : : "r" (new_value));
157 asm volatile("mrc p15, 0, %0, c1, c0, 1" : "=r" (reread_value));
158
159 printk("ACTLR: orig: 0x%8x wanted: 0x%8x new: 0x%8x\n",
160 orig_value, new_value, reread_value);
161}
162
163int litmus_l1_prefetch_proc_handler(struct ctl_table *table, int write,
164 void __user *buffer, size_t *lenp, loff_t *ppos)
165{
166 int ret, mode;
167
168 mutex_lock(&actlr_mutex);
169 ret = proc_dointvec(table, write, buffer, lenp, ppos);
170
171 if (!ret && write) {
172 mode = *((int*)table->data);
173 actlr_change(mode, ACTLR_L1_PREFETCH);
174 }
175 mutex_unlock(&actlr_mutex);
176
177 return ret;
178}
179
180int litmus_l2_prefetch_hint_proc_handler(struct ctl_table *table, int write,
181 void __user *buffer, size_t *lenp, loff_t *ppos)
182{
183 int ret, mode;
184
185 mutex_lock(&actlr_mutex);
186 ret = proc_dointvec(table, write, buffer, lenp, ppos);
187 if (!ret && write) {
188 mode = *((int*)table->data);
189 actlr_change(mode, ACTLR_L2_PREFETCH_HINT);
190 }
191 mutex_unlock(&actlr_mutex);
192
193 return ret;
194}
195
196
197/* Operate on the PL-310's Prefetch Control Register, L2X0_PREFETCH_CTRL */
198#define L2X0_PREFETCH_DOUBLE_LINEFILL (1 << 30)
199#define L2X0_PREFETCH_DATA_PREFETCH (1 << 28)
200static void l2x0_prefetch_change(int mode, int mask)
201{
202 u32 orig_value, new_value, reread_value;
203
204 if (0 != mode && 1 != mode) {
205 printk(KERN_WARNING "Called %s with mode != 0 and mode != 1.\n",
206 __FUNCTION__);
207 return;
208 }
209
210 orig_value = readl_relaxed(cache_base + L2X0_PREFETCH_CTRL);
211
212 if (0 == mode)
213 new_value = orig_value & ~(mask);
214 else
215 new_value = orig_value | mask;
216
217 writel_relaxed(new_value, cache_base + L2X0_PREFETCH_CTRL);
218 reread_value = readl_relaxed(cache_base + L2X0_PREFETCH_CTRL);
219
220 printk("l2x0 prefetch: orig: 0x%8x wanted: 0x%8x new: 0x%8x\n",
221 orig_value, new_value, reread_value);
222}
223
224int litmus_l2_double_linefill_proc_handler(struct ctl_table *table, int write,
225 void __user *buffer, size_t *lenp, loff_t *ppos)
226{
227 int ret, mode;
228
229 mutex_lock(&l2x0_prefetch_mutex);
230 ret = proc_dointvec(table, write, buffer, lenp, ppos);
231 if (!ret && write) {
232 mode = *((int*)table->data);
233 l2x0_prefetch_change(mode, L2X0_PREFETCH_DOUBLE_LINEFILL);
234 }
235 mutex_unlock(&l2x0_prefetch_mutex);
236
237 return ret;
238}
239
240int litmus_l2_data_prefetch_proc_handler(struct ctl_table *table, int write,
241 void __user *buffer, size_t *lenp, loff_t *ppos)
242{
243 int ret, mode;
244
245 mutex_lock(&l2x0_prefetch_mutex);
246 ret = proc_dointvec(table, write, buffer, lenp, ppos);
247 if (!ret && write) {
248 mode = *((int*)table->data);
249 l2x0_prefetch_change(mode, L2X0_PREFETCH_DATA_PREFETCH);
250 }
251 mutex_unlock(&l2x0_prefetch_mutex);
252
253 return ret;
254}
255
256int litmus_lockdown_proc_handler(struct ctl_table *table, int write,
257 void __user *buffer, size_t *lenp, loff_t *ppos)
258{
259 int ret, lockdown, *data_ptr;
260 data_ptr = (int*) table->data;
261
262 mutex_lock(&lockdown_proc);
263 if (!write) {
264 lockdown = readl_relaxed(lockreg_d);
265 *data_ptr = lockdown;
266 }
267
268 ret = proc_dointvec(table, write, buffer, lenp, ppos);
269 if (!ret && write) {
270 lockdown = *((int*)table->data);
271 writel_relaxed(lockdown, lockreg_d);
272 }
273 mutex_unlock(&lockdown_proc);
274
275 return ret;
276}
277
278#define TRIALS 1000
279
280static int test_get_cycles_overhead(void)
281{
282 u64 sum = 0, min = (u64)-1, max = 0;
283 unsigned long flags;
284 cycles_t a, b;
285 int i;
286
287 for (i = 0; i < TRIALS; i++) {
288 u64 diff;
289 local_irq_save(flags);
290 preempt_disable();
291 a = litmus_get_cycles();
292 b = litmus_get_cycles();
293 preempt_enable();
294 local_irq_restore(flags);
295 diff = b - a;
296 if (diff > max)
297 max = diff;
298 if (diff < min)
299 min = diff;
300 sum += diff;
301 }
302 printk("cycle test: avg: %llu min: %llu max: %llu\n",
303 div64_u64(sum, TRIALS), min, max);
304 return 0;
305}
306
307static long update_timeval(struct timespec lhs, struct timespec rhs)
308{
309 long val;
310 struct timespec ts;
311
312 ts = timespec_sub(rhs, lhs);
313 val = ts.tv_sec*NSEC_PER_SEC + ts.tv_nsec;
314
315 return val;
316}
317
318/*
319 * 16 * 4 pages to use as colors 0->15 in 4 ways, and
320 * 16 * 32 pages to use as colors 0->15 in 32 ways
321 * Don't change these, because it will break things.
322 */
323#define NR_COLORS 16
324#define CTRL_PAGES (NR_COLORS * 4)
325#define THRASH_PAGES (NR_COLORS * 32)
326#define TOTAL_PAGES (CTRL_PAGES + THRASH_PAGES)
327#define WAY_OFFSET 4
328
329static void thrash(void *vaddr)
330{
331 void *thrash_pages = vaddr + CTRL_PAGES * PAGE_SIZE;
332
333 /* try and flush it */
334 v7_flush_kern_dcache_area(vaddr, CTRL_PAGES * PAGE_SIZE);
335
336 /* thrash. don't lock down, we want to fill the dcache with these */
337 read_in_page(UNLOCK_ALL, UNLOCK_ALL, thrash_pages,
338 thrash_pages + THRASH_PAGES * PAGE_SIZE);
339}
340
341//#define READ_TRACE(fmt, args...) TRACE("read_trace: " fmt, ##args)
342#define READ_TRACE(fmt, args...) do { } while (0)
343
344static int test_read_in(void)
345{
346 struct page **pages;
347 cycles_t start, stop;
348 unsigned long flags;
349 void *remapped;
350 u32 sum = 0;
351 int ret = 0, i, j;
352
353 pages = (struct page**) kmalloc(TOTAL_PAGES * sizeof(*pages), GFP_KERNEL);
354 if (!pages) {
355 printk("could not allocate pages array.\n");
356 ret = -ENOMEM;
357 goto out;
358 }
359
360 /* Allocate a bunch of pages. */
361 for (i = 0; i < TOTAL_PAGES; i++) {
362 const unsigned long color = i % NR_COLORS;
363
364 pages[i] = get_colored_page(color);
365 if (!pages[i]) {
366 printk(KERN_WARNING "%s: no pages available.\n", __FUNCTION__);
367 ret = -ENOMEM;
368 goto out_free;
369 }
370 }
371
372 /* Put the pages in a contiguous virtual address space. */
373 remapped = vmap(pages, TOTAL_PAGES, VM_MAP, PAGE_KERNEL);
374 if (!remapped) {
375 printk(KERN_WARNING "%s: bad vmap\n", __FUNCTION__);
376 ret = -EINVAL;
377 goto out_free_colors;
378 }
379
380 /* smaller readings, in bytes */
381 for (i = 8; i <= 4096; i += 8) {
382 thrash(remapped);
383
384 READ_TRACE("small test, i:%d\n", i);
385
386 preempt_disable();
387 local_irq_save(flags);
388 start = litmus_get_cycles();
389 read_in_page(unlocked[WAY_OFFSET], UNLOCK_ALL,
390 remapped, remapped + i);
391 stop = litmus_get_cycles();
392 local_irq_restore(flags);
393 preempt_enable();
394
395 TRACE("wss, nanoseconds: %4d, %lld\n",
396 i, litmus_cycles_to_ns(stop - start));
397 }
398
399 for (i = 1; i <= CTRL_PAGES; i += 1) {
400 /* i is the number of pages to read in */
401 /* we will read in from page zero to page i (exclusive) */
402
403 READ_TRACE("start on i:%d\n", i);
404
405 thrash(remapped);
406
407 preempt_disable();
408 local_irq_save(flags);
409 start = litmus_get_cycles();
410 for (j = 0; j < i; j += NR_COLORS) {
411 /* need to chunk the reads into groups of NR_COLORS
412 * so we can switch ways
413 */
414 void *vaddr_start, *vaddr_end;
415 int read_start = j, read_end = j + NR_COLORS;
416 int way = WAY_OFFSET + j / NR_COLORS;
417
418 if (read_end > i)
419 read_end = i;
420
421 vaddr_start = remapped + PAGE_SIZE * read_start;
422 vaddr_end = remapped + PAGE_SIZE * read_end;
423
424 read_in_page(unlocked[way], UNLOCK_ALL,
425 vaddr_start, vaddr_end);
426
427 READ_TRACE("i:%d j:%d read_start:%d read_end:%d way:%d\n",
428 i, j, read_start, read_end, way);
429 }
430 stop = litmus_get_cycles();
431 local_irq_restore(flags);
432 preempt_enable();
433
434 TRACE("wss, nanoseconds: %4lu, %lld\n",
435 PAGE_SIZE * i,
436 litmus_cycles_to_ns(stop - start));
437 }
438
439#if 0
440 printk("read in %d pages (avg): %llu cycles %ld (getnstimeofday) sum: %u\n",
441 NR_PAGES,
442 div64_u64(stop - start, TRIALS),
443 update_timeval(before, after) / TRIALS,
444 sum);
445#endif
446
447 /* Done with these pages */
448 vunmap(remapped);
449
450out_free_colors:
451 for (i = 0; i < TOTAL_PAGES; i++) {
452 put_page(pages[i]);
453 add_page_to_color_list(pages[i]);
454 }
455out_free:
456 kfree(pages);
457out:
458 return 0;
459}
460
120static void test_lockdown(void *ignore) 461static void test_lockdown(void *ignore)
121{ 462{
122 int i; 463 int i;
@@ -129,7 +470,7 @@ static void test_lockdown(void *ignore)
129 } 470 }
130 471
131 printk("Lockdown initial state:\n"); 472 printk("Lockdown initial state:\n");
132 dump_lockdown_registers(); 473 print_lockdown_registers();
133 printk("---\n"); 474 printk("---\n");
134 475
135 for (i = 0; i < nr_lockregs; i++) { 476 for (i = 0; i < nr_lockregs; i++) {
@@ -137,7 +478,7 @@ static void test_lockdown(void *ignore)
137 writel_relaxed(2, ld_i_reg(i)); 478 writel_relaxed(2, ld_i_reg(i));
138 } 479 }
139 printk("Lockdown all data=1 instr=2:\n"); 480 printk("Lockdown all data=1 instr=2:\n");
140 dump_lockdown_registers(); 481 print_lockdown_registers();
141 printk("---\n"); 482 printk("---\n");
142 483
143 for (i = 0; i < nr_lockregs; i++) { 484 for (i = 0; i < nr_lockregs; i++) {
@@ -145,7 +486,7 @@ static void test_lockdown(void *ignore)
145 writel_relaxed(((1 << 8) >> i), ld_i_reg(i)); 486 writel_relaxed(((1 << 8) >> i), ld_i_reg(i));
146 } 487 }
147 printk("Lockdown varies:\n"); 488 printk("Lockdown varies:\n");
148 dump_lockdown_registers(); 489 print_lockdown_registers();
149 printk("---\n"); 490 printk("---\n");
150 491
151 for (i = 0; i < nr_lockregs; i++) { 492 for (i = 0; i < nr_lockregs; i++) {
@@ -153,7 +494,7 @@ static void test_lockdown(void *ignore)
153 writel_relaxed(UNLOCK_ALL, ld_i_reg(i)); 494 writel_relaxed(UNLOCK_ALL, ld_i_reg(i));
154 } 495 }
155 printk("Lockdown all zero:\n"); 496 printk("Lockdown all zero:\n");
156 dump_lockdown_registers(); 497 print_lockdown_registers();
157 498
158 /* Checks that the unlocked array is set up correctly. */ 499 /* Checks that the unlocked array is set up correctly. */
159 for (i = 0; i < MAX_NR_WAYS; i++) { 500 for (i = 0; i < MAX_NR_WAYS; i++) {
@@ -168,18 +509,6 @@ static void test_lockdown(void *ignore)
168 printk("End lockdown test.\n"); 509 printk("End lockdown test.\n");
169} 510}
170 511
171static long update_timeval(struct timespec lhs, struct timespec rhs)
172{
173 long val;
174 struct timespec ts;
175
176 ts = timespec_sub(rhs, lhs);
177 val = ts.tv_sec*NSEC_PER_SEC + ts.tv_nsec;
178
179 return val;
180}
181
182#define TRIALS 1000
183static int perf_test(void) { 512static int perf_test(void) {
184 struct timespec before, after; 513 struct timespec before, after;
185 struct page *page; 514 struct page *page;
@@ -237,8 +566,8 @@ static int perf_test(void) {
237} 566}
238 567
239#define LOCKREG_TEST_VAL 0x00000002 568#define LOCKREG_TEST_VAL 0x00000002
240int litmus_test_prefetch(struct ctl_table *table, int write, void __user *buffer, 569int litmus_test_prefetch_proc_handler(struct ctl_table *table, int write,
241 size_t *lenp, loff_t *ppos) 570 void __user *buffer, size_t *lenp, loff_t *ppos)
242{ 571{
243 struct page *page; 572 struct page *page;
244 void *vaddr; 573 void *vaddr;
@@ -277,7 +606,8 @@ int litmus_test_prefetch(struct ctl_table *table, int write, void __user *buffer
277 606
278 free_page((unsigned long)vaddr); 607 free_page((unsigned long)vaddr);
279 608
280 perf_test(); 609 //test_get_cycles_overhead();
610 test_read_in();
281 611
282 return 0; 612 return 0;
283} 613}
@@ -298,6 +628,9 @@ void litmus_setup_lockdown(void __iomem *base, u32 id)
298 } 628 }
299 629
300 raw_spin_lock_init(&prefetch_lock); 630 raw_spin_lock_init(&prefetch_lock);
631 mutex_init(&actlr_mutex);
632 mutex_init(&l2x0_prefetch_mutex);
633 mutex_init(&lockdown_proc);
301 634
302 test_lockdown(NULL); 635 test_lockdown(NULL);
303} 636}