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, raw_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, raw_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_init(int *key)
76 {
77 hardirq_key = *key;
78 *key = *key + 1;
79 softirq_key = *key;
80 *key = *key + 1;
82 hardirq_enabled = 0;
83 softirq_enabled = 0;
85 return 0;
86 }
88 static int gator_events_irq_start(void)
89 {
90 int cpu, i;
92 for_each_present_cpu(cpu) {
93 for (i = 0; i < TOTALIRQ; i++)
94 per_cpu(irqPrev, cpu)[i] = 0;
95 }
97 // register tracepoints
98 if (hardirq_enabled)
99 if (GATOR_REGISTER_TRACE(irq_handler_exit))
100 goto fail_hardirq_exit;
101 if (softirq_enabled)
102 if (GATOR_REGISTER_TRACE(softirq_exit))
103 goto fail_softirq_exit;
104 pr_debug("gator: registered irq tracepoints\n");
106 return 0;
108 // unregister tracepoints on error
109 fail_softirq_exit:
110 if (hardirq_enabled)
111 GATOR_UNREGISTER_TRACE(irq_handler_exit);
112 fail_hardirq_exit:
113 pr_err("gator: irq tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
115 return -1;
116 }
118 static void gator_events_irq_stop(void)
119 {
120 if (hardirq_enabled)
121 GATOR_UNREGISTER_TRACE(irq_handler_exit);
122 if (softirq_enabled)
123 GATOR_UNREGISTER_TRACE(softirq_exit);
124 pr_debug("gator: unregistered irq tracepoints\n");
126 hardirq_enabled = 0;
127 softirq_enabled = 0;
128 }
130 static int gator_events_irq_read(int **buffer)
131 {
132 unsigned long flags;
133 int len, value;
134 int cpu = raw_smp_processor_id();
136 len = 0;
137 if (hardirq_enabled) {
138 local_irq_save(flags);
139 value = per_cpu(irqCnt, cpu)[HARDIRQ];
140 per_cpu(irqCnt, cpu)[HARDIRQ] = 0;
141 local_irq_restore(flags);
142 if (value != per_cpu(irqPrev, cpu)[HARDIRQ]) {
143 per_cpu(irqPrev, cpu)[HARDIRQ] = value;
144 per_cpu(irqGet, cpu)[len++] = hardirq_key;
145 per_cpu(irqGet, cpu)[len++] = value;
146 }
147 }
149 if (softirq_enabled) {
150 local_irq_save(flags);
151 value = per_cpu(irqCnt, cpu)[SOFTIRQ];
152 per_cpu(irqCnt, cpu)[SOFTIRQ] = 0;
153 local_irq_restore(flags);
154 if (value != per_cpu(irqPrev, cpu)[SOFTIRQ]) {
155 per_cpu(irqPrev, cpu)[SOFTIRQ] = value;
156 per_cpu(irqGet, cpu)[len++] = softirq_key;
157 per_cpu(irqGet, cpu)[len++] = value;
158 }
159 }
161 if (buffer)
162 *buffer = per_cpu(irqGet, cpu);
164 return len;
165 }
167 int gator_events_irq_install(gator_interface *gi) {
168 gi->create_files = gator_events_irq_create_files;
169 gi->init = gator_events_irq_init;
170 gi->start = gator_events_irq_start;
171 gi->stop = gator_events_irq_stop;
172 gi->read = gator_events_irq_read;
173 return 0;
174 }