1 /**
2 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
10 #include "gator.h"
11 #include <trace/events/irq.h>
13 #define HARDIRQ 0
14 #define SOFTIRQ 1
15 #define TOTALIRQ (SOFTIRQ+1)
17 static ulong hardirq_enabled;
18 static ulong softirq_enabled;
19 static ulong hardirq_key;
20 static ulong softirq_key;
21 static DEFINE_PER_CPU(int[TOTALIRQ], irqCnt);
22 static DEFINE_PER_CPU(int[TOTALIRQ], irqPrev);
23 static DEFINE_PER_CPU(int[TOTALIRQ * 2], irqGet);
25 GATOR_DEFINE_PROBE(irq_handler_exit, TP_PROTO(int irq,
26 struct irqaction *action, int ret))
27 {
28 unsigned long flags;
30 // disable interrupts to synchronize with gator_events_irq_read()
31 // spinlocks not needed since percpu buffers are used
32 local_irq_save(flags);
33 per_cpu(irqCnt, smp_processor_id())[HARDIRQ]++;
34 local_irq_restore(flags);
35 }
37 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
38 GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(struct softirq_action *h, struct softirq_action *vec))
39 #else
40 GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(unsigned int vec_nr))
41 #endif
42 {
43 unsigned long flags;
45 // disable interrupts to synchronize with gator_events_irq_read()
46 // spinlocks not needed since percpu buffers are used
47 local_irq_save(flags);
48 per_cpu(irqCnt, smp_processor_id())[SOFTIRQ]++;
49 local_irq_restore(flags);
50 }
52 static int gator_events_irq_create_files(struct super_block *sb, struct dentry *root)
53 {
54 struct dentry *dir;
56 /* irq */
57 dir = gatorfs_mkdir(sb, root, "Linux_irq_irq");
58 if (!dir) {
59 return -1;
60 }
61 gatorfs_create_ulong(sb, dir, "enabled", &hardirq_enabled);
62 gatorfs_create_ro_ulong(sb, dir, "key", &hardirq_key);
64 /* soft irq */
65 dir = gatorfs_mkdir(sb, root, "Linux_irq_softirq");
66 if (!dir) {
67 return -1;
68 }
69 gatorfs_create_ulong(sb, dir, "enabled", &softirq_enabled);
70 gatorfs_create_ro_ulong(sb, dir, "key", &softirq_key);
72 return 0;
73 }
75 static int gator_events_irq_start(void)
76 {
77 int cpu, i;
79 for_each_present_cpu(cpu) {
80 for (i = 0; i < TOTALIRQ; i++)
81 per_cpu(irqPrev, cpu)[i] = 0;
82 }
84 // register tracepoints
85 if (hardirq_enabled)
86 if (GATOR_REGISTER_TRACE(irq_handler_exit))
87 goto fail_hardirq_exit;
88 if (softirq_enabled)
89 if (GATOR_REGISTER_TRACE(softirq_exit))
90 goto fail_softirq_exit;
91 pr_debug("gator: registered irq tracepoints\n");
93 return 0;
95 // unregister tracepoints on error
96 fail_softirq_exit:
97 if (hardirq_enabled)
98 GATOR_UNREGISTER_TRACE(irq_handler_exit);
99 fail_hardirq_exit:
100 pr_err("gator: irq tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
102 return -1;
103 }
105 static void gator_events_irq_stop(void)
106 {
107 if (hardirq_enabled)
108 GATOR_UNREGISTER_TRACE(irq_handler_exit);
109 if (softirq_enabled)
110 GATOR_UNREGISTER_TRACE(softirq_exit);
111 pr_debug("gator: unregistered irq tracepoints\n");
113 hardirq_enabled = 0;
114 softirq_enabled = 0;
115 }
117 static int gator_events_irq_read(int **buffer)
118 {
119 unsigned long flags;
120 int len, value;
121 int cpu = smp_processor_id();
123 len = 0;
124 if (hardirq_enabled) {
125 local_irq_save(flags);
126 value = per_cpu(irqCnt, cpu)[HARDIRQ];
127 per_cpu(irqCnt, cpu)[HARDIRQ] = 0;
128 local_irq_restore(flags);
129 if (value != per_cpu(irqPrev, cpu)[HARDIRQ]) {
130 per_cpu(irqPrev, cpu)[HARDIRQ] = value;
131 per_cpu(irqGet, cpu)[len++] = hardirq_key;
132 per_cpu(irqGet, cpu)[len++] = value;
133 }
134 }
136 if (softirq_enabled) {
137 local_irq_save(flags);
138 value = per_cpu(irqCnt, cpu)[SOFTIRQ];
139 per_cpu(irqCnt, cpu)[SOFTIRQ] = 0;
140 local_irq_restore(flags);
141 if (value != per_cpu(irqPrev, cpu)[SOFTIRQ]) {
142 per_cpu(irqPrev, cpu)[SOFTIRQ] = value;
143 per_cpu(irqGet, cpu)[len++] = softirq_key;
144 per_cpu(irqGet, cpu)[len++] = value;
145 }
146 }
148 if (buffer)
149 *buffer = per_cpu(irqGet, cpu);
151 return len;
152 }
154 static struct gator_interface gator_events_irq_interface = {
155 .create_files = gator_events_irq_create_files,
156 .start = gator_events_irq_start,
157 .stop = gator_events_irq_stop,
158 .read = gator_events_irq_read,
159 };
161 int gator_events_irq_init(void)
162 {
163 hardirq_key = gator_events_get_key();
164 softirq_key = gator_events_get_key();
166 hardirq_enabled = 0;
167 softirq_enabled = 0;
169 return gator_events_install(&gator_events_irq_interface);
170 }
171 gator_events_init(gator_events_irq_init);