gator: ARM DS-5.6 Streamline gator driver
[android-sdk/arm-ds5-gator.git] / gator_events_irq.c
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;
105 static void gator_events_irq_stop(void)
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;
117 static int gator_events_irq_read(int **buffer)
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;
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)
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);
171 gator_events_init(gator_events_irq_init);