gator: ARM DS-5.4 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, 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;
118 static void gator_events_irq_stop(void)
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;
130 static int gator_events_irq_read(int **buffer)
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;
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;