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>
7 * FIXME could intloop_param freed after startup?
8 * FIXME use consume flag to indicate IRQ was handled
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>
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>
23 #include <l4/irq/irq.h>
27 #include <l4/sys/debugger.h>
28 #include <l4/sys/kdebug.h>
29 #include <pthread-l4.h>
31 #define MAX_INTERRUPTS 128
33 #define DEBUG_INTERRUPTS 0
35 * Internal type for interrupt loop parameters
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;
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];
62 static void ddekit_irq_exit_fn(l4_cap_idx_t thread __attribute__((unused)),
68 l4_irq_detach(ddekit_irq_ctrl[idx].irq_cap);
71 //L4THREAD_EXIT_FN_STATIC(exit_fn, ddekit_irq_exit_fn);
73 static int do_irq_attach(int irq)
75 ddekit_irq_ctrl[irq].irq_cap = l4re_util_cap_alloc();
77 if (l4_is_invalid_cap(ddekit_irq_ctrl[irq].irq_cap))
80 if (l4io_request_irq(irq, ddekit_irq_ctrl[irq].irq_cap))
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)))
92 static int do_irq_detach(int irq)
94 if (l4_msgtag_has_error(l4_irq_detach(ddekit_irq_ctrl[irq].irq_cap)))
97 if (l4io_release_irq(irq, ddekit_irq_ctrl[irq].irq_cap))
100 l4re_util_cap_free(ddekit_irq_ctrl[irq].irq_cap);
102 ddekit_irq_ctrl[irq].irq_cap = L4_INVALID_CAP;
107 static l4_umword_t do_irq_wait(int irq)
114 res = l4_irq_wait(ddekit_irq_ctrl[irq].irq_cap, &label, L4_IPC_NEVER);
116 if (l4_ipc_error(res, l4_utcb()))
117 ddekit_printf("do_irq_wait returned %d\n", l4_ipc_error(res, l4_utcb()));
119 } while (l4_ipc_error(res, l4_utcb()));
125 * Interrupt service loop
128 static void intloop(void *arg)
130 struct intloop_params *params = arg;
132 printf("Thread 0x%lx for IRQ %d\n", l4_debugger_global_id(pthread_getl4cap(pthread_self())), params->irq);
134 /* wait for main thread thread to fill irqctrl structure */
135 ddekit_sem_down(params->started1);
137 int my_index = params->irq;
140 int ret = do_irq_attach(my_index);
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);
149 // XXX IMPLEMENT EXIT FN?
152 * Setup an exit fn. This will make sure that we clean up everything,
153 * before shutting down an IRQ thread.
155 if (l4thread_on_exit(&exit_fn, (void *)my_index) < 0)
156 ddekit_panic("Could not set exit handler for IRQ fn.");
159 /* after successful initialization call thread_init() before doing anything
161 if (params->thread_init) params->thread_init(params->priv);
163 /* save handle + inform thread creator of success */
164 params->start_err = 0;
165 ddekit_sem_up(params->started);
168 /* prepare request structure */
169 req.s.param = params->irq + 1;
179 label = do_irq_wait(my_index);
181 /* if label == 0, than the interrupt should be disabled */
186 ddekit_printf("received irq 0x%X\n", params->irq);
189 /* unmask only the first time */
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) {
196 ddekit_printf("handling IRQ 0x%X\n", params->irq);
198 params->handler(params->priv);
202 ddekit_printf("not handling IRQ %x, because it is disabled (%d).\n",
203 my_index, ddekit_irq_ctrl[my_index].handle_irq);
206 ddekit_sem_up(ddekit_irq_ctrl[my_index].irqsem);
209 int res = do_irq_detach(my_index);
212 printf("do_irq_detach failed with:%d\n", res);
213 ddekit_panic("detach from irq failed\n");
216 /* signal successful detach from irq */
217 ddekit_sem_up(ddekit_irq_ctrl[my_index].stopsem);
224 * Attach to hardware interrupt
226 * \param irq IRQ number to attach to
227 * \param shared set to 1 if interrupt sharing is supported; set to 0
229 * \param thread_init called just after DDEKit internal init and before any
231 * \param handler IRQ handler for interrupt irq
232 * \param priv private token (argument for thread_init and handler)
234 * \return pointer to interrupt thread created
236 ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared,
237 void(*thread_init)(void *),
238 void(*handler)(void *), void *priv)
240 struct intloop_params *params;
241 ddekit_thread_t *thread;
242 char thread_name[10];
244 if (irq >= MAX_INTERRUPTS)
247 ddekit_printf("IRQ: Interrupt number out of range\n");
252 /* initialize info structure for interrupt loop */
253 params = ddekit_simple_malloc(sizeof(*params));
254 if (!params) return NULL;
257 params->thread_init = thread_init;
258 params->handler = handler;
260 params->started1 = ddekit_sem_init(0);
261 params->started = ddekit_sem_init(0);
262 params->start_err = 0;
263 params->shared = shared;
266 snprintf(thread_name, 10, "irq%02X", irq);
268 /* create interrupt loop thread */
269 thread = ddekit_thread_create(intloop, params, thread_name, DDEKIT_IRQ_PRIO);
271 ddekit_simple_free(params);
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;
281 /* tigger intloop initialization */
282 ddekit_sem_up(params->started1);
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);
297 * Detach from interrupt by disabling it and then shutting down the IRQ
300 void ddekit_interrupt_detach(int irq)
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");
311 // wait for thread to detach from irq
312 ddekit_sem_down(ddekit_irq_ctrl[irq].stopsem);
314 if (ddekit_thread_terminate(ddekit_irq_ctrl[irq].irq_thread))
315 ddekit_panic("cannot shutdown irq thread\n");
317 ddekit_simple_free(ddekit_irq_ctrl[irq].params);
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);
326 void ddekit_interrupt_disable(int irq)
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);
336 void ddekit_interrupt_enable(int irq)
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);
345 int ddekit_irq_set_type(int irq, unsigned type)
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;
353 case IRQF_TRIGGER_FALLING:
354 ddekit_irq_ctrl[irq].trigger = L4_IRQ_F_NEG_EDGE;
356 case IRQF_TRIGGER_HIGH:
357 ddekit_irq_ctrl[irq].trigger = L4_IRQ_F_LEVEL_HIGH;
359 case IRQF_TRIGGER_LOW:
360 ddekit_irq_ctrl[irq].trigger = L4_IRQ_F_LEVEL_LOW;
362 default: ddekit_irq_ctrl[irq].trigger = 0; break;
371 void ddekit_init_irqs(void)
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;