]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/dde/linux26/lib/src/arch/l4/irq.c
update
[l4.git] / l4 / pkg / dde / linux26 / lib / src / arch / l4 / irq.c
1 /*
2  * This file is part of DDE/Linux2.6.
3  *
4  * (c) 2006-2010 Bjoern Doebel <doebel@os.inf.tu-dresden.de>
5  *               Christian Helmuth <ch12@os.inf.tu-dresden.de>
6  *     economic rights: Technische Universitaet Dresden (Germany)
7  *
8  * This file is part of TUD:OS and distributed under the terms of the
9  * GNU General Public License 2.
10  * Please see the COPYING-GPL-2 file for details.
11  */
12
13 /*
14  * \brief   Hardware-interrupt support
15  *
16  * XXX Consider support for IRQ_HANDLED and friends (linux/irqreturn.h)
17  */
18
19 /* Linux */
20 #include <linux/interrupt.h>
21 #include <linux/string.h>     /* memset() */
22
23 /* DDEKit */
24 #include <l4/dde/ddekit/interrupt.h>
25 #include <l4/dde/ddekit/memory.h>
26
27 /* local */
28 #include "dde26.h"
29 #include "local.h"
30
31 /* dummy */
32 irq_cpustat_t irq_stat[CONFIG_NR_CPUS];
33
34 /**
35  * IRQ handling data
36  */
37 static struct dde_irq
38 {
39         unsigned              irq;     /* IRQ number */
40         unsigned              count;   /* usage count */
41         int                   shared;  /* shared IRQ */
42         struct ddekit_thread *thread;  /* DDEKit interrupt thread */
43         struct irqaction     *action;  /* Linux IRQ action */
44
45         struct dde_irq       *next;    /* next DDE IRQ */
46 } *used_irqs;
47
48
49 static void irq_thread_init(void *p) {
50         l4dde26_process_add_worker(); }
51
52
53 extern ddekit_sem_t *dde_softirq_sem;
54 static void irq_handler(void *arg)
55 {
56         struct dde_irq *irq = arg;
57         struct irqaction *action;
58
59 #if 0
60         DEBUG_MSG("irq 0x%x", irq->irq);
61 #endif
62         /* interrupt occurred - call all handlers */
63         for (action = irq->action; action; action = action->next) {
64                 irqreturn_t r = action->handler(action->irq, action->dev_id);
65 #if 0
66                 DEBUG_MSG("return: %s", r == IRQ_HANDLED ? "IRQ_HANDLED" : r == IRQ_NONE ? "IRQ_NONE" : "??");
67 #endif
68         }
69
70         /* upon return we check for pending soft irqs */
71         if (local_softirq_pending())
72                 ddekit_sem_up(dde_softirq_sem);
73 }
74
75
76 /*****************************
77  ** IRQ handler bookkeeping **
78  *****************************/
79
80 /**
81  * Claim IRQ
82  *
83  * \return usage counter or negative error code
84  *
85  * FIXME are there more races?
86  */
87 static int claim_irq(struct irqaction *action)
88 {
89         int shared = action->flags & IRQF_SHARED ? 1 : 0;
90         struct dde_irq *irq;
91
92         /* check if IRQ already used */
93         for (irq = used_irqs; irq; irq = irq->next)
94                 if (irq->irq == action->irq) break;
95
96         /* we have to setup IRQ handling */
97         if (!irq) {
98                 /* allocate and initalize new descriptor */
99                 irq = ddekit_simple_malloc(sizeof(*irq));
100                 if (!irq) return -ENOMEM;
101                 memset(irq, 0, sizeof(*irq));
102
103                 irq->irq    = action->irq;
104                 irq->shared = shared;
105
106                 /* attach to interrupt */
107                 irq->thread = ddekit_interrupt_attach(irq->irq,
108                                                       irq->shared,
109                                                       irq_thread_init,
110                                                       irq_handler,
111                                                       (void *)irq);
112                 if (!irq->thread) {
113                         DEBUG_MSG("failed to attach IRQ");
114                         ddekit_simple_free(irq);
115                         return -EBUSY;
116                 }
117
118                 /* FIXME list locking */
119                 irq->next   = used_irqs;
120                 used_irqs   = irq;
121         }
122
123         /* does desciptor allow our new handler? */
124         if ((!irq->shared || !shared) && irq->action) return -EBUSY;
125
126         /* add handler */
127         irq->count++;
128         action->next = irq->action;
129         irq->action = action;
130
131         return irq->count;
132 }
133
134
135 /**
136  * Free previously claimed IRQ
137  *
138  * \return usage counter or negative error code
139  */
140 static struct irqaction *release_irq(unsigned irq_num, void *dev_id)
141 {
142         struct dde_irq *prev_irq, *irq;
143
144         /* check if IRQ already used */
145         for (prev_irq = 0, irq = used_irqs; irq;
146              prev_irq = irq, irq = irq->next)
147                 if (irq->irq == irq_num) break;
148
149         if (!irq) return 0;
150
151         struct irqaction *prev_action, *action;
152
153         for (prev_action = 0, action = irq->action; action;
154              prev_action = action, action = action->next)
155                 if (action->dev_id == dev_id) break;
156
157         if (!action) return 0;
158
159         /* dequeue action from irq */
160         if (prev_action)
161                 prev_action->next = action->next;
162         else
163                 irq->action = action->next;
164
165         /* dequeue irq from used_irqs list and free structure,
166            if no more actions available */
167         if (!irq->action) {
168                 if (prev_irq)
169                         prev_irq->next = irq->next;
170                 else
171                         used_irqs = irq->next;
172
173                 /* detach from interrupt */
174                 ddekit_interrupt_detach(irq->irq);
175
176                 ddekit_simple_free(irq);
177         }
178
179   return action;
180 }
181
182
183 /***************
184  ** Linux API **
185  ***************/
186
187 /**
188  * Request interrupt
189  *
190  * \param  irq       interrupt number
191  * \param  handler   interrupt handler -> top half
192  * \param  flags     interrupt handling flags (SA_SHIRQ, ...)
193  * \param  dev_name  device name
194  * \param  dev_id    cookie passed back to handler
195  *
196  * \return 0 on success; error code otherwise
197  *
198  * \todo FIXME consider locking!
199  */
200 int request_irq(unsigned int irq, irq_handler_t handler,
201                 unsigned long flags, const char *dev_name, void *dev_id)
202 {
203   if (!handler) return -EINVAL;
204
205   /* facilitate Linux irqaction for this handler */
206   struct irqaction *irq_action = ddekit_simple_malloc(sizeof(*irq_action));
207   if (!irq_action) return -ENOMEM;
208   memset(irq_action, 0, sizeof(*irq_action));
209
210   irq_action->handler = handler;
211   irq_action->flags   = flags;
212   irq_action->name    = dev_name;
213   irq_action->dev_id  = dev_id;
214   irq_action->irq     = irq;
215
216   /* attach to IRQ */
217   int err = claim_irq(irq_action);
218   if (err < 0) return err;
219
220   return 0;
221 }
222
223 /** Release Interrupt
224  * \ingroup mod_irq
225  *
226  * \param  irq     interrupt number
227  * \param  dev_id  cookie passed back to handler
228  *
229  */
230 void free_irq(unsigned int irq, void *dev_id)
231 {
232         struct irqaction *irq_action = release_irq(irq, dev_id);
233
234         if (irq_action)
235                 ddekit_simple_free(irq_action);
236 }
237
238 void disable_irq(unsigned int irq)
239 {
240         ddekit_interrupt_disable(irq);
241 }
242
243 void disable_irq_nosync(unsigned int irq)
244 {
245         /*
246          * Note:
247          * In contrast to the _nosync semantics, DDEKit's
248          * disable definitely waits until a currently executed
249          * IRQ handler terminates.
250          */
251         ddekit_interrupt_disable(irq);
252 }
253
254 void enable_irq(unsigned int irq)
255 {
256         ddekit_interrupt_enable(irq);
257 }