gator: ARM DS-5.3 Streamline gator driver
[android-sdk/arm-ds5-gator.git] / gator_events_irq.c
1 /**
2  * Copyright (C) ARM Limited 2010. 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 <linux/slab.h>
11 #include <linux/fs.h>
12 #include <linux/mm.h>
13 #include <linux/dcookies.h>
14 #include <linux/version.h>
15 #include <trace/events/irq.h>
17 #include "gator.h"
18 #include "gator_trace.h"
20 #define HARDIRQ         0
21 #define SOFTIRQ         1
22 #define TOTALIRQ        (SOFTIRQ+1)
24 static ulong hardirq_enabled;
25 static ulong softirq_enabled;
26 static ulong hardirq_key;
27 static ulong softirq_key;
28 static DEFINE_PER_CPU(int[TOTALIRQ], irqCnt);
29 static DEFINE_PER_CPU(int[TOTALIRQ], irqPrev);
30 static DEFINE_PER_CPU(int[TOTALIRQ * 2], irqGet);
32 GATOR_DEFINE_PROBE(irq_handler_exit, TP_PROTO(int irq,
33                 struct irqaction *action, int ret))
34 {
35         unsigned long flags;
37         // disable interrupts to synchronize with gator_events_irq_read()
38         // spinlocks not needed since percpu buffers are used
39         local_irq_save(flags);
40         per_cpu(irqCnt, raw_smp_processor_id())[HARDIRQ]++;
41         local_irq_restore(flags);
42 }
44 GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(struct softirq_action *h,
45                 struct softirq_action *vec))
46 {
47         unsigned long flags;
49         // disable interrupts to synchronize with gator_events_irq_read()
50         // spinlocks not needed since percpu buffers are used
51         local_irq_save(flags);
52         per_cpu(irqCnt, raw_smp_processor_id())[SOFTIRQ]++;
53         local_irq_restore(flags);
54 }
56 static int gator_events_irq_create_files(struct super_block *sb, struct dentry *root)
57 {
58         struct dentry *dir;
60         /* irq */
61         dir = gatorfs_mkdir(sb, root, "Linux_irq_irq");
62         if (!dir) {
63                 return -1;
64         }
65         gatorfs_create_ulong(sb, dir, "enabled", &hardirq_enabled);
66         gatorfs_create_ro_ulong(sb, dir, "key", &hardirq_key);
68         /* soft irq */
69         dir = gatorfs_mkdir(sb, root, "Linux_irq_softirq");
70         if (!dir) {
71                 return -1;
72         }
73         gatorfs_create_ulong(sb, dir, "enabled", &softirq_enabled);
74         gatorfs_create_ro_ulong(sb, dir, "key", &softirq_key);
76         return 0;
77 }
79 static int gator_events_irq_init(int *key)
80 {
81         hardirq_key = *key;
82         *key = *key + 1;
83         softirq_key = *key;
84         *key = *key + 1;
86         hardirq_enabled = 0;
87         softirq_enabled = 0;
89         return 0;
90 }
92 static int gator_events_irq_start(void)
93 {
94         int cpu, i;
96         for_each_possible_cpu(cpu) {
97                 for (i = 0; i < TOTALIRQ; i++)
98                         per_cpu(irqPrev, cpu)[i] = 0;
99         }
101         // register tracepoints
102         if (hardirq_enabled)
103                 if (GATOR_REGISTER_TRACE(irq_handler_exit))
104                         goto fail_hardirq_exit;
105         if (softirq_enabled)
106                 if (GATOR_REGISTER_TRACE(softirq_exit))
107                         goto fail_softirq_exit;
108         pr_debug("gator: registered irq tracepoints\n");
110         return 0;
112         // unregister tracepoints on error
113 fail_softirq_exit:
114         if (hardirq_enabled)
115                 GATOR_UNREGISTER_TRACE(irq_handler_exit);
116 fail_hardirq_exit:
117         pr_err("gator: irq tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
119         return -1;
122 static void gator_events_irq_stop(void)
124         if (hardirq_enabled)
125                 GATOR_UNREGISTER_TRACE(irq_handler_exit);
126         if (softirq_enabled)
127                 GATOR_UNREGISTER_TRACE(softirq_exit);
128         pr_debug("gator: unregistered irq tracepoints\n");
130         hardirq_enabled = 0;
131         softirq_enabled = 0;
134 static int gator_events_irq_read(int **buffer)
136         unsigned long flags;
137         int len, value;
138         int cpu = raw_smp_processor_id();
140         len = 0;
141         if (hardirq_enabled) {
142                 local_irq_save(flags);
143                 value = per_cpu(irqCnt, cpu)[HARDIRQ];
144                 per_cpu(irqCnt, cpu)[HARDIRQ] = 0;
145                 local_irq_restore(flags);
146                 if (value != per_cpu(irqPrev, cpu)[HARDIRQ]) {
147                         per_cpu(irqPrev, cpu)[HARDIRQ] = value;
148                         per_cpu(irqGet, cpu)[len++] = hardirq_key;
149                         per_cpu(irqGet, cpu)[len++] = value;
150                 }
151         }
153         if (softirq_enabled) {
154                 local_irq_save(flags);
155                 value = per_cpu(irqCnt, cpu)[SOFTIRQ];
156                 per_cpu(irqCnt, cpu)[SOFTIRQ] = 0;
157                 local_irq_restore(flags);
158                 if (value != per_cpu(irqPrev, cpu)[SOFTIRQ]) {
159                         per_cpu(irqPrev, cpu)[SOFTIRQ] = value;
160                         per_cpu(irqGet, cpu)[len++] = softirq_key;
161                         per_cpu(irqGet, cpu)[len++] = value;
162                 }
163         }
165         if (buffer)
166                 *buffer = per_cpu(irqGet, cpu);
168         return len;
171 int gator_events_irq_install(gator_interface *gi) {
172         gi->create_files = gator_events_irq_create_files;
173         gi->init = gator_events_irq_init;
174         gi->start = gator_events_irq_start;
175         gi->stop = gator_events_irq_stop;
176         gi->read = gator_events_irq_read;
177         return 0;