]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/dde/ddekit/src/interrupt.c
Inital import
[l4.git] / l4 / pkg / dde / ddekit / src / interrupt.c
1 /*
2  * \brief   Hardware-interrupt subsystem
3  * \author  Thomas Friebel <tf13@os.inf.tu-dresden.de>
4  * \author  Christian Helmuth <ch12@os.inf.tu-dresden.de>
5  * \date    2007-01-22
6  *
7  * FIXME could intloop_param freed after startup?
8  * FIXME use consume flag to indicate IRQ was handled
9  */
10
11 #include <l4/dde/ddekit/interrupt.h>
12 #include <l4/dde/ddekit/semaphore.h>
13 #include <l4/dde/ddekit/thread.h>
14 #include <l4/dde/ddekit/memory.h>
15 #include <l4/dde/ddekit/panic.h>
16 #include <l4/dde/ddekit/printf.h>
17
18 #include <l4/re/c/util/cap_alloc.h>
19 #include <l4/sys/irq.h>
20 #include <l4/sys/icu.h>
21 #include <l4/util/util.h>
22 #include <l4/io/io.h>
23 #include <l4/irq/irq.h>
24
25 #include <stdio.h>
26
27 #include <l4/sys/debugger.h>
28 #include <l4/sys/kdebug.h>
29 #include <pthread-l4.h>
30
31 #define MAX_INTERRUPTS   128
32
33 #define DEBUG_INTERRUPTS  0
34 /*
35  * Internal type for interrupt loop parameters
36  */
37 struct intloop_params
38 {
39         unsigned          irq;       /* irq number */
40         int               shared;    /* irq sharing supported? */
41         void(*thread_init)(void *);  /* thread initialization */
42         void(*handler)(void *);      /* IRQ handler function */
43         void             *priv;      /* private token */ 
44         ddekit_sem_t     *started1;
45         ddekit_sem_t     *started;
46
47         int               start_err;
48 };
49
50 static struct
51 {
52         int               handle_irq; /* nested irq disable count */
53         ddekit_sem_t     *irqsem;     /* synch semaphore */
54         ddekit_sem_t     *stopsem;    /* stop semaphore */
55         ddekit_thread_t  *irq_thread; /* thread ID for detaching from IRQ later on */
56         l4_cap_idx_t      irq_cap;   /* capability of IRQ object */
57         unsigned         trigger;       /* trigger mode control */
58         struct intloop_params   *params;
59 } ddekit_irq_ctrl[MAX_INTERRUPTS];
60
61
62 static void ddekit_irq_exit_fn(l4_cap_idx_t thread __attribute__((unused)),
63                                void *data)
64 {
65         int idx = (int)data;
66
67         // * detach from IRQ
68         l4_irq_detach(ddekit_irq_ctrl[idx].irq_cap);
69 }
70
71 //L4THREAD_EXIT_FN_STATIC(exit_fn, ddekit_irq_exit_fn);
72
73 static int do_irq_attach(int irq)
74 {
75   ddekit_irq_ctrl[irq].irq_cap = l4re_util_cap_alloc();
76  
77   if (l4_is_invalid_cap(ddekit_irq_ctrl[irq].irq_cap))
78     return -1;
79
80   if (l4io_request_irq(irq, ddekit_irq_ctrl[irq].irq_cap))
81     return -2;
82
83   pthread_t pthread = (pthread_t)ddekit_thread_get_id(ddekit_irq_ctrl[irq].irq_thread);
84   l4_cap_idx_t thread_cap = pthread_getl4cap(pthread);
85   if (l4_msgtag_has_error(l4_irq_attach(ddekit_irq_ctrl[irq].irq_cap,
86                               irq, /*ddekit_irq_ctrl[irq].trigger, */ thread_cap)))
87     return -3;
88
89   return 0;
90 }
91
92 static int do_irq_detach(int irq)
93 {
94   if (l4_msgtag_has_error(l4_irq_detach(ddekit_irq_ctrl[irq].irq_cap)))
95     return -3;
96
97   if (l4io_release_irq(irq, ddekit_irq_ctrl[irq].irq_cap))
98     return -2;
99
100   l4re_util_cap_free(ddekit_irq_ctrl[irq].irq_cap);
101
102   ddekit_irq_ctrl[irq].irq_cap = L4_INVALID_CAP;
103
104   return 0;
105 }
106
107 static l4_umword_t do_irq_wait(int irq)
108 {
109   l4_msgtag_t res;
110   l4_umword_t label;
111   
112   do
113     {
114       res = l4_irq_wait(ddekit_irq_ctrl[irq].irq_cap, &label, L4_IPC_NEVER);
115 #if DEBUG_INTERRUPTS
116       if (l4_ipc_error(res, l4_utcb()))
117         ddekit_printf("do_irq_wait returned %d\n", l4_ipc_error(res, l4_utcb()));
118 #endif
119     } while (l4_ipc_error(res, l4_utcb()));
120
121   return label;
122 }
123
124 /**
125  * Interrupt service loop
126  *
127  */
128 static void intloop(void *arg)
129 {
130         struct intloop_params *params = arg;
131
132         printf("Thread 0x%lx for IRQ %d\n", l4_debugger_global_id(pthread_getl4cap(pthread_self())), params->irq);
133
134         /* wait for main thread thread to fill irqctrl structure */
135         ddekit_sem_down(params->started1);
136         
137         int my_index = params->irq;
138
139         /* allocate irq */
140         int ret = do_irq_attach(my_index);
141         if (ret < 0) {
142                 /* inform thread creator of error */
143                 /* XXX does error code have any meaning to DDEKit users? */
144                 params->start_err = ret;
145                 ddekit_sem_up(params->started);
146                 return;
147         }
148
149         // XXX IMPLEMENT EXIT FN?
150 #if 0
151         /* 
152          * Setup an exit fn. This will make sure that we clean up everything,
153          * before shutting down an IRQ thread.
154          */
155         if (l4thread_on_exit(&exit_fn, (void *)my_index) < 0)
156                 ddekit_panic("Could not set exit handler for IRQ fn.");
157 #endif
158
159         /* after successful initialization call thread_init() before doing anything
160          * else here */
161         if (params->thread_init) params->thread_init(params->priv);
162
163         /* save handle + inform thread creator of success */
164         params->start_err = 0;
165         ddekit_sem_up(params->started);
166
167 #if 0
168         /* prepare request structure */
169         req.s.param   = params->irq + 1;
170         req.s.wait    = 1;
171         req.s.consume = 0;
172         req.s.unmask  = 1;
173 #endif
174
175         while (1) {
176                 l4_umword_t label;
177
178                 /* wait for int */
179                 label = do_irq_wait(my_index);
180
181                 /* if label == 0, than the interrupt should be disabled */
182                 if (!label) {
183                     break;
184                   }
185 #if DEBUG_INTERRUPTS
186                 ddekit_printf("received irq 0x%X\n", params->irq);
187 #endif
188
189                 /* unmask only the first time */
190                 //req.s.unmask = 0;
191
192                 /* only call registered handler function, if IRQ is not disabled */
193                 ddekit_sem_down(ddekit_irq_ctrl[my_index].irqsem);
194                 if (ddekit_irq_ctrl[my_index].handle_irq > 0) {
195 #if DEBUG_INTERRUPTS
196                     ddekit_printf("handling IRQ 0x%X\n", params->irq);
197 #endif
198                     params->handler(params->priv);
199                 }
200                 else {
201 #if DEBUG_INTERRUPTS
202                         ddekit_printf("not handling IRQ %x, because it is disabled (%d).\n",
203                                       my_index, ddekit_irq_ctrl[my_index].handle_irq);
204 #endif
205                   }
206                 ddekit_sem_up(ddekit_irq_ctrl[my_index].irqsem);
207         }
208         
209         int res = do_irq_detach(my_index);
210         if (res)
211           {
212             printf("do_irq_detach failed with:%d\n", res);
213             ddekit_panic("detach from irq failed\n");
214           }
215         
216         /* signal successful detach from irq */
217         ddekit_sem_up(ddekit_irq_ctrl[my_index].stopsem);
218
219         l4_sleep_forever();
220 }
221
222
223 /**
224  * Attach to hardware interrupt
225  *
226  * \param irq          IRQ number to attach to
227  * \param shared       set to 1 if interrupt sharing is supported; set to 0
228  *                     otherwise
229  * \param thread_init  called just after DDEKit internal init and before any
230  *                     other function
231  * \param handler      IRQ handler for interrupt irq
232  * \param priv         private token (argument for thread_init and handler)
233  *
234  * \return pointer to interrupt thread created
235  */
236 ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared,
237                                          void(*thread_init)(void *),
238                                          void(*handler)(void *), void *priv)
239 {
240         struct intloop_params *params;
241         ddekit_thread_t *thread;
242         char thread_name[10];
243
244         if (irq >= MAX_INTERRUPTS)
245           {
246 #if DEBUG_INTERRUPTS
247             ddekit_printf("IRQ: Interrupt number out of range\n");
248 #endif
249             return NULL;
250           }
251
252         /* initialize info structure for interrupt loop */
253         params = ddekit_simple_malloc(sizeof(*params));
254         if (!params) return NULL;
255
256         params->irq         = irq;
257         params->thread_init = thread_init;
258         params->handler     = handler;
259         params->priv        = priv;
260         params->started1    = ddekit_sem_init(0);
261         params->started     = ddekit_sem_init(0);
262         params->start_err   = 0;
263         params->shared      = shared;
264
265         /* construct name */
266         snprintf(thread_name, 10, "irq%02X", irq);
267
268         /* create interrupt loop thread */
269         thread = ddekit_thread_create(intloop, params, thread_name, DDEKIT_IRQ_PRIO);
270         if (!thread) {
271                 ddekit_simple_free(params);
272                 return NULL;
273         }
274         
275         ddekit_irq_ctrl[irq].handle_irq = 1; /* IRQ nesting level is initially 1 */
276         ddekit_irq_ctrl[irq].irq_thread = thread;
277         ddekit_irq_ctrl[irq].irqsem     = ddekit_sem_init(1);
278         ddekit_irq_ctrl[irq].stopsem    = ddekit_sem_init(0);
279         ddekit_irq_ctrl[irq].params     = params;
280
281         /* tigger intloop initialization */
282         ddekit_sem_up(params->started1);
283
284         /* wait for intloop initialization result */
285         ddekit_sem_down(params->started);
286         ddekit_sem_deinit(params->started);
287         ddekit_sem_deinit(params->started1);
288         if (params->start_err) {
289                 ddekit_simple_free(params);
290                 return NULL;
291         }
292
293         return thread;
294 }
295
296 /**
297  * Detach from interrupt by disabling it and then shutting down the IRQ
298  * thread.
299  */
300 void ddekit_interrupt_detach(int irq)
301 {
302         //ddekit_interrupt_disable(irq);
303         //ddekit_thread_terminate(ddekit_irq_ctrl[irq].irq_thread);
304         pthread_t _thread = (pthread_t)ddekit_thread_get_id(ddekit_irq_ctrl[irq].irq_thread);
305         l4_cap_idx_t thread_cap = pthread_getl4cap(_thread);
306         l4_msgtag_t res = l4_ipc_send(thread_cap, l4_utcb(),
307                                       l4_msgtag(0, 0, 0, 0), L4_IPC_NEVER);
308         if (l4_ipc_error(res, l4_utcb()))
309                 ddekit_panic("cannot stop irq thread\n");
310         
311         // wait for thread to detach from irq
312         ddekit_sem_down(ddekit_irq_ctrl[irq].stopsem);
313         
314         if (ddekit_thread_terminate(ddekit_irq_ctrl[irq].irq_thread))
315             ddekit_panic("cannot shutdown irq thread\n");
316
317         ddekit_simple_free(ddekit_irq_ctrl[irq].params);
318         
319         ddekit_irq_ctrl[irq].handle_irq = 0;
320         ddekit_irq_ctrl[irq].irq_thread = 0;
321         ddekit_sem_deinit(ddekit_irq_ctrl[irq].irqsem);
322         ddekit_sem_deinit(ddekit_irq_ctrl[irq].stopsem);
323 }
324
325
326 void ddekit_interrupt_disable(int irq)
327 {
328         if (!l4_is_invalid_cap(ddekit_irq_ctrl[irq].irq_cap)) {
329                 ddekit_sem_down(ddekit_irq_ctrl[irq].irqsem);
330                 --ddekit_irq_ctrl[irq].handle_irq;
331                 ddekit_sem_up(ddekit_irq_ctrl[irq].irqsem);
332         }
333 }
334
335
336 void ddekit_interrupt_enable(int irq)
337 {
338         if (!l4_is_invalid_cap(ddekit_irq_ctrl[irq].irq_cap)) {
339                 ddekit_sem_down(ddekit_irq_ctrl[irq].irqsem);
340                 ++ddekit_irq_ctrl[irq].handle_irq;
341                 ddekit_sem_up(ddekit_irq_ctrl[irq].irqsem);
342         }
343 }
344
345 int ddekit_irq_set_type(int irq, unsigned type)
346 {
347         if (irq < MAX_INTERRUPTS) {
348                 ddekit_printf("IRQ: set irq type of %u to %x\n", irq, type);
349                 switch (type & IRQF_TRIGGER_MASK) {
350                         case IRQF_TRIGGER_RISING:
351                           ddekit_irq_ctrl[irq].trigger = L4_IRQ_F_POS_EDGE;
352                           break;
353                         case IRQF_TRIGGER_FALLING:
354                           ddekit_irq_ctrl[irq].trigger = L4_IRQ_F_NEG_EDGE;
355                           break;
356                         case IRQF_TRIGGER_HIGH:
357                           ddekit_irq_ctrl[irq].trigger = L4_IRQ_F_LEVEL_HIGH;
358                           break;
359                         case IRQF_TRIGGER_LOW:
360                           ddekit_irq_ctrl[irq].trigger = L4_IRQ_F_LEVEL_LOW;
361                           break;
362                         default: ddekit_irq_ctrl[irq].trigger = 0; break;
363                 }
364
365                 return 0;
366         }
367
368         return -1;
369 }
370
371 void ddekit_init_irqs(void)
372 {
373         int i;
374         for (i = 0; i < MAX_INTERRUPTS; i++) {
375                 ddekit_irq_ctrl[i].irq_cap = L4_INVALID_CAP;
376                 ddekit_irq_ctrl[i].trigger = 0;
377         }
378 }
379