diff options
author | Christopher Kenna <cjk@cs.unc.edu> | 2012-10-17 13:31:13 -0400 |
---|---|---|
committer | Christopher Kenna <cjk@cs.unc.edu> | 2012-10-17 13:51:07 -0400 |
commit | a1cf3bfebbf32ac9022db9482e7009ba447a85af (patch) | |
tree | 44ad56b56e3d3cb5c87f3a90fb745fa4d77f3534 | |
parent | 76ec41ad78e824c421c29e20cd145d95ec88b258 (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.h | 13 | ||||
-rw-r--r-- | include/litmus/clock.h | 44 | ||||
-rw-r--r-- | include/litmus/color.h | 16 | ||||
-rw-r--r-- | include/litmus/feather_trace.h | 4 | ||||
-rw-r--r-- | include/litmus/litmus_proc.h | 3 | ||||
-rw-r--r-- | litmus/Makefile | 1 | ||||
-rw-r--r-- | litmus/clock.c | 31 | ||||
-rw-r--r-- | litmus/color.c | 5 | ||||
-rw-r--r-- | litmus/color_proc.c | 59 | ||||
-rw-r--r-- | litmus/litmus.c | 26 | ||||
-rw-r--r-- | litmus/lockdown.c | 381 |
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 | ||
17 | typedef unsigned long cycles_t; | 17 | typedef u64 cycles_t; |
18 | |||
19 | #if defined(CONFIG_CPU_V7) && !defined(CONFIG_HW_PERF_EVENTS) | ||
20 | static 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 |
31 | static inline cycles_t get_cycles (void) | 20 | static 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> | ||
10 | extern struct clocksource mct_frc; | ||
11 | |||
12 | static inline cycles_t mct_frc_read(void) | ||
13 | { | ||
14 | cycle_t cycles = mct_frc.read(&mct_frc); | ||
15 | return cycles; | ||
16 | } | ||
17 | |||
18 | static 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 | |||
27 | static 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 | ||
23 | int litmus_test_prefetch(struct ctl_table *, int, void __user *, | 23 | #ifdef CONFIG_CPU_V7 |
24 | size_t *, loff_t *); | 24 | int litmus_test_prefetch_proc_handler(struct ctl_table *, int, |
25 | void __user *, size_t *, loff_t *); | ||
26 | int litmus_l1_prefetch_proc_handler(struct ctl_table *, int, | ||
27 | void __user *, size_t *, loff_t *); | ||
28 | int litmus_l2_prefetch_hint_proc_handler(struct ctl_table *, int, | ||
29 | void __user *, size_t *, loff_t *); | ||
30 | int litmus_l2_double_linefill_proc_handler(struct ctl_table *, int, | ||
31 | void __user *, size_t *, loff_t *); | ||
32 | int litmus_l2_data_prefetch_proc_handler(struct ctl_table *, int, | ||
33 | void __user *, size_t *, loff_t *); | ||
34 | int 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 */ |
27 | extern struct color_cache_info color_cache_info; | 39 | extern 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 | ||
37 | static inline unsigned long long ft_timestamp(void) | 37 | static 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. */ |
24 | int copy_and_chomp(char *kbuf, unsigned long ksize, | 24 | int 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 | |||
27 | int 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 | ||
35 | obj-$(CONFIG_EXYNOS_MCT) += clock.o | ||
35 | obj-$(CONFIG_CPU_V7) += lockdown.o | 36 | obj-$(CONFIG_CPU_V7) += lockdown.o |
36 | obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o | 37 | obj-$(CONFIG_PLUGIN_CEDF) += sched_cedf.o |
37 | obj-$(CONFIG_PLUGIN_PFAIR) += sched_pfair.o | 38 | obj-$(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 | |||
12 | extern struct clocksource mct_frc; | ||
13 | |||
14 | static 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 | |||
26 | static void exit_litmus_clock(void) | ||
27 | { | ||
28 | } | ||
29 | |||
30 | module_init(init_litmus_clock); | ||
31 | module_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 | ||
343 | static void __init print_cycle_count(void *_unused) | 344 | static 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 | ||
349 | static int __init init_color(void) | 350 | static 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; | |||
32 | int cache_preempt; | 33 | int cache_preempt; |
33 | int lock_cache; | 34 | int lock_cache; |
34 | 35 | ||
36 | #ifdef CONFIG_CPU_V7 | ||
37 | static int l1_prefetch_proc; | ||
38 | static int l2_prefetch_hint_proc; | ||
39 | static int l2_double_linefill_proc; | ||
40 | static int l2_data_prefetch_proc; | ||
41 | static int lockdown_proc; | ||
42 | #endif | ||
43 | |||
35 | #define INFO_BUFFER_SIZE 100 | 44 | #define INFO_BUFFER_SIZE 100 |
36 | static char info_buffer[100]; | 45 | static 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) |
660 | static void __init litmus_enable_perfcounters_v7(void *_ignore) | 660 | static 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 | ||
679 | static void __init litmus_enable_perfcounters(void) | 693 | static 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 | ||
16 | static void __iomem *cache_base; | 21 | static void __iomem *cache_base; |
17 | static void __iomem *lockreg_d; | 22 | static void __iomem *lockreg_d; |
@@ -21,6 +26,10 @@ static raw_spinlock_t prefetch_lock; | |||
21 | static u32 cache_id; | 26 | static u32 cache_id; |
22 | static int nr_lockregs; | 27 | static int nr_lockregs; |
23 | 28 | ||
29 | struct mutex actlr_mutex; | ||
30 | struct mutex l2x0_prefetch_mutex; | ||
31 | struct 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 | ||
108 | static void dump_lockdown_registers(void) | 117 | static 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 | */ | ||
138 | static 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 | |||
163 | int 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 | |||
180 | int 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) | ||
200 | static 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 | |||
224 | int 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 | |||
240 | int 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 | |||
256 | int 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 | |||
280 | static 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 | |||
307 | static 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 | |||
329 | static 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 | |||
344 | static 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 | |||
450 | out_free_colors: | ||
451 | for (i = 0; i < TOTAL_PAGES; i++) { | ||
452 | put_page(pages[i]); | ||
453 | add_page_to_color_list(pages[i]); | ||
454 | } | ||
455 | out_free: | ||
456 | kfree(pages); | ||
457 | out: | ||
458 | return 0; | ||
459 | } | ||
460 | |||
120 | static void test_lockdown(void *ignore) | 461 | static 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 | ||
171 | static 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 | ||
183 | static int perf_test(void) { | 512 | static 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 |
240 | int litmus_test_prefetch(struct ctl_table *table, int write, void __user *buffer, | 569 | int 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 | } |