2 #include <linux/module.h>
4 #include <linux/init.h>
5 #include <linux/interrupt.h>
6 #include <linux/irqnr.h>
7 #include <linux/proc_fs.h>
8 #include <linux/seq_file.h>
9 #include <linux/timex.h>
10 #include <linux/delay.h>
11 #include <linux/sched.h>
12 #include <asm/uaccess.h>
14 int do_watch_preempt_disable
= 0;
15 EXPORT_SYMBOL(do_watch_preempt_disable
);
17 DEFINE_PER_CPU(u64
, max_prmtdsbled
);
18 DEFINE_PER_CPU(u64
, tm_prmtdsbled
);
19 DEFINE_PER_CPU(u32
, nowatch_set
);
21 static u32 nowatch_mask
= NOPWATCH_DEAD
| NOPWATCH_LOCTIM
| NEVER_PWATCH
;
24 #ifdef CONFIG_LATENCY_TRACE
25 static int do_stop_tracing
;
26 static u64 tm_stop_tracing
;
29 #define peempt_value() (preempt_count() & ~PREEMPT_ACTIVE)
33 extern u64
get_usec_from_start(void);
37 void save_tm_prmtdsbl(int val
)
39 if (val
== peempt_value()) {
41 __get_cpu_var(tm_prmtdsbled
) = get_usec_from_start() << 1;
43 __get_cpu_var(tm_prmtdsbled
) = get_cycles();
47 EXPORT_SYMBOL(save_tm_prmtdsbl
);
49 void chck_tm_prmtdsbl(int val
)
51 u64 stm
= __get_cpu_var(tm_prmtdsbled
);
53 if (peempt_value() == val
) {
54 current
->my_last_ipi_prmt_enable
=
55 (unsigned long)__builtin_return_address(0);
61 if (peempt_value() == val
) {
62 if (__get_cpu_var(nowatch_set
) & nowatch_mask
) {
63 /* Not intersting case for us */
64 __get_cpu_var(nowatch_set
) = 0;
65 __get_cpu_var(tm_prmtdsbled
) = 0;
69 u64 delta
= (get_usec_from_start() << 1) - stm
;
70 if (delta
> 2000000) {
71 /* we can get wrong value . skip */
72 __get_cpu_var(tm_prmtdsbled
) = 0;
76 u64 delta
= get_cycles() - stm
;
78 __get_cpu_var(tm_prmtdsbled
) = 0;
79 if (delta
> __get_cpu_var(max_prmtdsbled
)) {
80 __get_cpu_var(max_prmtdsbled
) = delta
;
82 #ifdef CONFIG_LATENCY_TRACE
83 if (tm_stop_tracing
&& delta
> tm_stop_tracing
) {
86 pr_info("Tracing stopped. delta = 0x%lld\n", delta
);
91 trace_printk("PREEMPT delta=%lld\n", delta
);
93 if (max_tm
&& delta
> max_tm
&& num_dumps
> 0) {
98 WARN(1, "Preempt disable time too long on CPU%d: %llu\n",
99 smp_processor_id(), delta
);
103 EXPORT_SYMBOL(chck_tm_prmtdsbl
);
105 /* show max prrempt disable time for each CPU */
107 static void *wp_seq_start(struct seq_file
*f
, loff_t
*pos
)
109 return (*pos
<= num_possible_cpus()) ? pos
: NULL
;
112 static void *wp_seq_next(struct seq_file
*f
, void *v
, loff_t
*pos
)
120 static void wp_seq_stop(struct seq_file
*f
, void *v
)
125 static ssize_t
wp_write(struct file
*file
, const char __user
*buf
,
126 size_t count
, loff_t
*ppos
)
136 if (get_user(c
, buf
)) {
140 do_watch_preempt_disable
= 0;
144 if (do_watch_preempt_disable
) {
145 do_watch_preempt_disable
= 0;
148 for_each_possible_cpu(cpu
) {
149 per_cpu(max_prmtdsbled
, cpu
) = 0;
150 per_cpu(tm_prmtdsbled
, cpu
) = 0;
152 do_watch_preempt_disable
= 1;
156 l
= (count
> 32) ? 32 : (count
- 1);
157 if (copy_from_user(mb
, buf
+ 1, l
)) {
160 max_tm
= usecs_2cycles(simple_strtoul(mb
, &me
, 10));
162 num_dumps
= simple_strtoul(me
+ 1, NULL
, 10);
164 if (num_dumps
== 0) {
170 l
= (count
> 32) ? 32 : (count
- 1);
171 if (copy_from_user(mb
, buf
+ 1, l
)) {
174 num_dumps
= simple_strtoul(mb
, NULL
, 10);
178 l
= (count
> 32) ? 32 : (count
- 1);
179 if (copy_from_user(mb
, buf
+ 1, l
)) {
182 if (!strncmp(mb
, "loctim", 6)) {
183 nowatch_mask
|= NOPWATCH_LOCTIM
;
184 } else if (!strncmp(mb
, "tsbgrow", 7)) {
185 nowatch_mask
|= NOPWATCH_TSBGROW
;
186 } else if (!strncmp(mb
, "sched", 5)) {
187 nowatch_mask
|= NOPWATCH_SCHED
;
188 } else if (!strncmp(mb
, "exitmm", 6)) {
189 nowatch_mask
|= NOPWATCH_EXITMM
;
196 l
= (count
> 32) ? 32 : (count
- 1);
197 if (copy_from_user(mb
, buf
+ 1, l
)) {
200 if (!strncmp(mb
, "loctim", 6)) {
201 nowatch_mask
&= ~NOPWATCH_LOCTIM
;
202 } else if (!strncmp(mb
, "tsbgrow", 7)) {
203 nowatch_mask
&= ~NOPWATCH_TSBGROW
;
204 } else if (!strncmp(mb
, "sched", 5)) {
205 nowatch_mask
&= ~NOPWATCH_SCHED
;
206 } else if (!strncmp(mb
, "exitmm", 6)) {
207 nowatch_mask
&= ~NOPWATCH_EXITMM
;
214 #ifdef CONFIG_LATENCY_TRACE
216 l
= (count
> 32) ? 32 : (count
- 1);
217 if (copy_from_user(mb
, buf
+ 1, l
)) {
220 if (tm_stop_tracing
) {
223 tm_stop_tracing
= usecs_2cycles(simple_strtoul(mb
, NULL
, 10));
229 #if defined(CONFIG_E90S) || defined(__e2k__)
230 extern void print_IO_LOCAL_APICS(void);
232 print_IO_LOCAL_APICS();
242 int show_wp(struct seq_file
*p
, void *v
)
244 int i
= *(loff_t
*) v
;
246 if (!cpu_online(i
)) {
249 seq_printf(p
, "CPU%d\t%llu usecs\n", i
,
250 cycles_2usec(per_cpu(max_prmtdsbled
, i
)));
254 static const struct seq_operations wp_seq_ops
= {
255 .start
= wp_seq_start
,
261 static int wp_open(struct inode
*inode
, struct file
*filp
)
263 return seq_open(filp
, &wp_seq_ops
);
266 static const struct file_operations proc_wp_operations
= {
271 .release
= seq_release
,
274 static int __init
proc_wp_init(void)
276 proc_create("watch-preempt", 0, NULL
, &proc_wp_operations
);
279 module_init(proc_wp_init
);