1 /**
2 * Copyright (C) ARM Limited 2010-2012. 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 * 2], irqGet);
24 GATOR_DEFINE_PROBE(irq_handler_exit, TP_PROTO(int irq,
25 struct irqaction *action, int ret))
26 {
27 unsigned long flags;
29 // disable interrupts to synchronize with gator_events_irq_read()
30 // spinlocks not needed since percpu buffers are used
31 local_irq_save(flags);
32 per_cpu(irqCnt, smp_processor_id())[HARDIRQ]++;
33 local_irq_restore(flags);
34 }
36 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
37 GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(struct softirq_action *h, struct softirq_action *vec))
38 #else
39 GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(unsigned int vec_nr))
40 #endif
41 {
42 unsigned long flags;
44 // disable interrupts to synchronize with gator_events_irq_read()
45 // spinlocks not needed since percpu buffers are used
46 local_irq_save(flags);
47 per_cpu(irqCnt, smp_processor_id())[SOFTIRQ]++;
48 local_irq_restore(flags);
49 }
51 static int gator_events_irq_create_files(struct super_block *sb, struct dentry *root)
52 {
53 struct dentry *dir;
55 /* irq */
56 dir = gatorfs_mkdir(sb, root, "Linux_irq_irq");
57 if (!dir) {
58 return -1;
59 }
60 gatorfs_create_ulong(sb, dir, "enabled", &hardirq_enabled);
61 gatorfs_create_ro_ulong(sb, dir, "key", &hardirq_key);
63 /* soft irq */
64 dir = gatorfs_mkdir(sb, root, "Linux_irq_softirq");
65 if (!dir) {
66 return -1;
67 }
68 gatorfs_create_ulong(sb, dir, "enabled", &softirq_enabled);
69 gatorfs_create_ro_ulong(sb, dir, "key", &softirq_key);
71 return 0;
72 }
74 static int gator_events_irq_online(int** buffer)
75 {
76 int len = 0, cpu = smp_processor_id();
77 unsigned long flags; // not necessary as we are in interrupt context anyway, but doesn't hurt
79 // synchronization with the irq_exit functions is not necessary as the values are being reset
80 if (hardirq_enabled) {
81 local_irq_save(flags);
82 per_cpu(irqCnt, cpu)[HARDIRQ] = 0;
83 local_irq_restore(flags);
84 per_cpu(irqGet, cpu)[len++] = hardirq_key;
85 per_cpu(irqGet, cpu)[len++] = 0;
86 }
88 if (softirq_enabled) {
89 local_irq_save(flags);
90 per_cpu(irqCnt, cpu)[SOFTIRQ] = 0;
91 local_irq_restore(flags);
92 per_cpu(irqGet, cpu)[len++] = softirq_key;
93 per_cpu(irqGet, cpu)[len++] = 0;
94 }
96 if (buffer)
97 *buffer = per_cpu(irqGet, cpu);
99 return len;
100 }
102 static int gator_events_irq_start(void)
103 {
104 // register tracepoints
105 if (hardirq_enabled)
106 if (GATOR_REGISTER_TRACE(irq_handler_exit))
107 goto fail_hardirq_exit;
108 if (softirq_enabled)
109 if (GATOR_REGISTER_TRACE(softirq_exit))
110 goto fail_softirq_exit;
111 pr_debug("gator: registered irq tracepoints\n");
113 return 0;
115 // unregister tracepoints on error
116 fail_softirq_exit:
117 if (hardirq_enabled)
118 GATOR_UNREGISTER_TRACE(irq_handler_exit);
119 fail_hardirq_exit:
120 pr_err("gator: irq tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
122 return -1;
123 }
125 static void gator_events_irq_stop(void)
126 {
127 if (hardirq_enabled)
128 GATOR_UNREGISTER_TRACE(irq_handler_exit);
129 if (softirq_enabled)
130 GATOR_UNREGISTER_TRACE(softirq_exit);
131 pr_debug("gator: unregistered irq tracepoints\n");
133 hardirq_enabled = 0;
134 softirq_enabled = 0;
135 }
137 static int gator_events_irq_read(int **buffer)
138 {
139 unsigned long flags; // not necessary as we are in interrupt context anyway, but doesn't hurt
140 int len, value;
141 int cpu = smp_processor_id();
143 len = 0;
144 if (hardirq_enabled) {
145 local_irq_save(flags);
146 value = per_cpu(irqCnt, cpu)[HARDIRQ];
147 per_cpu(irqCnt, cpu)[HARDIRQ] = 0;
148 local_irq_restore(flags);
150 per_cpu(irqGet, cpu)[len++] = hardirq_key;
151 per_cpu(irqGet, cpu)[len++] = value;
152 }
154 if (softirq_enabled) {
155 local_irq_save(flags);
156 value = per_cpu(irqCnt, cpu)[SOFTIRQ];
157 per_cpu(irqCnt, cpu)[SOFTIRQ] = 0;
158 local_irq_restore(flags);
160 per_cpu(irqGet, cpu)[len++] = softirq_key;
161 per_cpu(irqGet, cpu)[len++] = value;
162 }
164 if (buffer)
165 *buffer = per_cpu(irqGet, cpu);
167 return len;
168 }
170 static struct gator_interface gator_events_irq_interface = {
171 .create_files = gator_events_irq_create_files,
172 .online = gator_events_irq_online,
173 .start = gator_events_irq_start,
174 .stop = gator_events_irq_stop,
175 .read = gator_events_irq_read,
176 };
178 int gator_events_irq_init(void)
179 {
180 hardirq_key = gator_events_get_key();
181 softirq_key = gator_events_get_key();
183 hardirq_enabled = 0;
184 softirq_enabled = 0;
186 return gator_events_install(&gator_events_irq_interface);
187 }
188 gator_events_init(gator_events_irq_init);