]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4sys/include/icu.h
update
[l4.git] / l4 / pkg / l4sys / include / icu.h
1 /**
2  * \file
3  * \brief Interrupt controller.
4  * \ingroup l4_api
5  */
6 /*
7  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
8  *               Alexander Warg <warg@os.inf.tu-dresden.de>,
9  *               Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
10  *     economic rights: Technische Universität Dresden (Germany)
11  *
12  * This file is part of TUD:OS and distributed under the terms of the
13  * GNU General Public License 2.
14  * Please see the COPYING-GPL-2 file for details.
15  *
16  * As a special exception, you may use this file as part of a free software
17  * library without restriction.  Specifically, if other files instantiate
18  * templates or use macros or inline functions from this file, or you compile
19  * this file and link it with other files to produce an executable, this
20  * file does not by itself cause the resulting executable to be covered by
21  * the GNU General Public License.  This exception does not however
22  * invalidate any other reasons why the executable file might be covered by
23  * the GNU General Public License.
24  */
25 #pragma once
26
27 #include <l4/sys/kernel_object.h>
28 #include <l4/sys/ipc.h>
29
30 /**
31  * \defgroup l4_icu_api Interrupt controller
32  * \ingroup  l4_kernel_object_api
33  *
34  * \brief The ICU class.
35  *
36  * <c>\#include <l4/sys/icu.h></c>
37  */
38
39
40 /**
41  * \brief Flags for IRQ numbers used for the ICU.
42  * \ingroup l4_icu_api
43  */
44 enum L4_icu_flags
45 {
46   /**
47    * \brief Flag to denote that the IRQ is actually an MSI.
48    * \hideinitializer
49    *
50    * This flag may be used for l4_icu_bind() and l4_icu_unbind() functions to
51    * denote that the IRQ number is meant to be an MSI.
52    */
53   L4_ICU_FLAG_MSI = 0x80000000,
54 };
55
56
57 /**
58  * \brief Interrupt flow types.
59  * \ingroup l4_irq_api
60  */
61 enum L4_irq_flow_type
62 {
63   L4_IRQ_F_NONE       = 0,     /**< None */
64   L4_IRQ_F_LEVEL      = 0x2,   /**< Level triggered */
65   L4_IRQ_F_EDGE       = 0x0,   /**< Edge triggered */
66   L4_IRQ_F_POS        = 0x0,   /**< Positive trigger */
67   L4_IRQ_F_NEG        = 0x4,   /**< Negative trigger */
68   L4_IRQ_F_BOTH       = 0x8,   /**< Both edges trigger */
69   L4_IRQ_F_LEVEL_HIGH = 0x3,   /**< Level high trigger */
70   L4_IRQ_F_LEVEL_LOW  = 0x7,   /**< Level low trigger */
71   L4_IRQ_F_POS_EDGE   = 0x1,   /**< Positive edge trigger */
72   L4_IRQ_F_NEG_EDGE   = 0x5,   /**< Negative edge trigger */
73   L4_IRQ_F_BOTH_EDGE  = 0x9,   /**< Both edges trigger */
74   L4_IRQ_F_MASK       = 0xf,   /**< Mask */
75 };
76
77
78 /**
79  * \brief Opcodes to the ICU interface.
80  * \ingroup l4_api_icu
81  */
82 enum L4_icu_opcode
83 {
84   /**
85    * \brief Bind opcode.
86    * \hideinitializer
87    * \see l4_icu_bind()
88    */
89   L4_ICU_OP_BIND = 0,
90
91   /**
92    * \brief Unbind opcode.
93    * \hideinitializer
94    * \see l4_icu_unbind()
95    */
96   L4_ICU_OP_UNBIND = 1,
97
98   /**
99    * \brief Info opcode.
100    * \hideinitializer
101    * \see l4_icu_info()
102    */
103   L4_ICU_OP_INFO = 2,
104
105   /**
106    * \brief Msi-info opcode.
107    * \hideinitializer
108    * \see l4_icu_msi_info()
109    */
110   L4_ICU_OP_MSI_INFO = 3,
111
112   /**
113    * \brief Unmask opcode.
114    * \hideinitializer
115    * \see l4_icu_unmask()
116    */
117   L4_ICU_OP_UNMASK   = 4,
118
119   /**
120    * \brief Mask opcode.
121    * \hideinitializer
122    * \see l4_icu_mask()
123    */
124   L4_ICU_OP_MASK     = 5,
125
126   /**
127    * \brief Set-mode opcode.
128    * \hideinitializer
129    * \see l4_icu_set_mode()
130    */
131   L4_ICU_OP_SET_MODE = 6,
132 };
133
134 enum L4_icu_ctl_op
135 {
136   L4_ICU_CTL_UNMASK = 0,
137   L4_ICU_CTL_MASK   = 1
138 };
139
140
141 /**
142  * \brief Info structure for an ICU.
143  * \ingroup l4_icu_api
144  *
145  * This structure contains information about the features of an ICU.
146  * \see l4_icu_info().
147  */
148 typedef struct l4_icu_info_t
149 {
150   /**
151    * \brief Feature flags.
152    *
153    * If #L4_ICU_FLAG_MSI is set the ICU supports MSIs.
154    */
155   unsigned features;
156
157   /**
158    * \brief The number of IRQ lines supported by the ICU,
159    */
160   unsigned nr_irqs;
161
162   /**
163    * \brief The number of MSI vectors supported by the ICU,
164    */
165   unsigned nr_msis;
166 } l4_icu_info_t;
167
168 /**
169  * \brief Bind an interrupt vector of an interrupt controller to an interrupt object.
170  * \ingroup l4_icu_api
171  *
172  * \param icu    ICU to use.
173  * \param irqnum IRQ vector at the ICU.
174  * \param irq    IRQ capability to bind the IRQ to.
175  * \return Syscall return tag
176  */
177 L4_INLINE l4_msgtag_t
178 l4_icu_bind(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq) L4_NOTHROW;
179
180 /**
181  * \internal
182  */
183 L4_INLINE l4_msgtag_t
184 l4_icu_bind_u(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq,
185               l4_utcb_t *utcb) L4_NOTHROW;
186
187 /**
188  * \brief Remove binding of an interrupt vector from the interrupt controller object.
189  * \ingroup l4_icu_api
190  *
191  * \param icu    ICU to use.
192  * \param irqnum IRQ vector at the ICU.
193  * \param irq    IRQ object to remove from the ICU.
194  * \return Syscall return tag
195  */
196 L4_INLINE l4_msgtag_t
197 l4_icu_unbind(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq) L4_NOTHROW;
198
199 /**
200  * \internal
201  */
202 L4_INLINE l4_msgtag_t
203 l4_icu_unbind_u(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq,
204                 l4_utcb_t *utcb) L4_NOTHROW;
205
206 /**
207  * \brief Set mode of interrupt.
208  * \ingroup l4_icu_api
209  *
210  * \param  icu     ICU to use.
211  * \param  irqnum  IRQ vector at the ICU.
212  * \param  mode    Mode, see L4_irq_flow_type.
213  * \return Syscall return tag
214  *
215  * \ingroup l4_icu_api
216  */
217 L4_INLINE l4_msgtag_t
218 l4_icu_set_mode(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t mode) L4_NOTHROW;
219
220 /**
221  * \internal
222  */
223 L4_INLINE l4_msgtag_t
224 l4_icu_set_mode_u(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t mode,
225                   l4_utcb_t *utcb) L4_NOTHROW;
226
227 /**
228  * \brief Get info about capabilites of ICU.
229  * \ingroup l4_icu_api
230  *
231  * \param icu    ICU to use.
232  * \param info   Pointer to an info structure to be filled with information.
233  * \return Syscall return tag
234  */
235 L4_INLINE l4_msgtag_t
236 l4_icu_info(l4_cap_idx_t icu, l4_icu_info_t *info) L4_NOTHROW;
237
238 /**
239  * \internal
240  */
241 L4_INLINE l4_msgtag_t
242 l4_icu_info_u(l4_cap_idx_t icu, l4_icu_info_t *info,
243               l4_utcb_t *utcb) L4_NOTHROW;
244
245 /**
246  * \brief Get MSI info about IRQ.
247  * \ingroup l4_icu_api
248  *
249  * \param icu    ICU to use.
250  * \param irqnum IRQ vector at the ICU.
251  * \param msg    Pointer to a word to receive the message that must be used
252  *               for the PCI devices MSI message.
253  * \return Syscall return tag
254  */
255 L4_INLINE l4_msgtag_t
256 l4_icu_msi_info(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *msg) L4_NOTHROW;
257
258 /**
259  * \internal
260  */
261 L4_INLINE l4_msgtag_t
262 l4_icu_msi_info_u(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *msg,
263                   l4_utcb_t *utcb) L4_NOTHROW;
264
265
266 /**
267  * \brief Unmask an IRQ vector.
268  * \ingroup l4_icu_api
269  *
270  * \param icu    ICU to use.
271  * \param irqnum IRQ vector at the ICU.
272  * \param label  If non-NULL the function also waits for the next message.
273  * \param to     Timeout for message to ICU, if unsure use L4_IPC_NEVER.
274  * \return Syscall return tag
275  */
276 L4_INLINE l4_msgtag_t
277 l4_icu_unmask(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *label,
278               l4_timeout_t to) L4_NOTHROW;
279
280 /**
281  * \internal
282  */
283 L4_INLINE l4_msgtag_t
284 l4_icu_unmask_u(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *label,
285                 l4_timeout_t to, l4_utcb_t *utcb) L4_NOTHROW;
286
287 /**
288  * \brief Mask an IRQ vector.
289  * \ingroup l4_icu_api
290  *
291  * \param icu    ICU to use.
292  * \param irqnum IRQ vector at the ICU.
293  * \param label  If non-NULL the function also waits for the next message.
294  * \param to     Timeout for message to ICU, if unsure use L4_IPC_NEVER.
295  * \return Syscall return tag
296  */
297 L4_INLINE l4_msgtag_t
298 l4_icu_mask(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *label,
299             l4_timeout_t to) L4_NOTHROW;
300
301 /**
302  * \internal
303  */
304 L4_INLINE l4_msgtag_t
305 l4_icu_mask_u(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *label,
306               l4_timeout_t to, l4_utcb_t *utcb) L4_NOTHROW;
307
308 /**
309  * \internal
310  */
311 L4_INLINE l4_msgtag_t
312 l4_icu_control_u(l4_cap_idx_t icu, unsigned irqnum, unsigned op,
313                  l4_umword_t *label,l4_timeout_t to,
314                  l4_utcb_t *utcb) L4_NOTHROW;
315
316
317 /**************************************************************************
318  * Implementations
319  */
320
321 L4_INLINE l4_msgtag_t
322 l4_icu_bind_u(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq,
323               l4_utcb_t *utcb) L4_NOTHROW
324 {
325   l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
326   m->mr[0] = L4_ICU_OP_BIND;
327   m->mr[1] = irqnum;
328   m->mr[2] = l4_map_obj_control(0, 0);
329   m->mr[3] = l4_obj_fpage(irq, 0, L4_FPAGE_RWX).raw;
330   return l4_ipc_call(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 2, 1, 0), L4_IPC_NEVER);
331 }
332
333 L4_INLINE l4_msgtag_t
334 l4_icu_unbind_u(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq,
335                 l4_utcb_t *utcb) L4_NOTHROW
336 {
337   l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
338   m->mr[0] = L4_ICU_OP_UNBIND;
339   m->mr[1] = irqnum;
340   m->mr[2] = l4_map_obj_control(0, 0);
341   m->mr[3] = l4_obj_fpage(irq, 0, L4_FPAGE_RWX).raw;
342   return l4_ipc_call(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 2, 1, 0), L4_IPC_NEVER);
343 }
344
345 L4_INLINE l4_msgtag_t
346 l4_icu_info_u(l4_cap_idx_t icu, l4_icu_info_t *info,
347               l4_utcb_t *utcb) L4_NOTHROW
348 {
349   l4_msgtag_t res;
350   l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
351   m->mr[0] = L4_ICU_OP_INFO;
352   res = l4_ipc_call(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 1, 0, 0), L4_IPC_NEVER);
353   if (!l4_msgtag_has_error(res) && l4_msgtag_label(res) >= 0
354       && l4_msgtag_words(res) >= 3)
355     {
356       info->features = m->mr[0];
357       info->nr_irqs  = m->mr[1];
358       info->nr_msis  = m->mr[2];
359     }
360   return res;
361 }
362
363 L4_INLINE l4_msgtag_t
364 l4_icu_msi_info_u(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *msg,
365                   l4_utcb_t *utcb) L4_NOTHROW
366 {
367   l4_msgtag_t res;
368   l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
369   m->mr[0] = L4_ICU_OP_MSI_INFO;
370   m->mr[1] = irqnum;
371   res = l4_ipc_call(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 2, 0, 0), L4_IPC_NEVER);
372   if (!l4_msgtag_has_error(res) && l4_msgtag_label(res) >= 0
373       && l4_msgtag_words(res) >= 1)
374     *msg = m->mr[0];
375   return res;
376 }
377
378 L4_INLINE l4_msgtag_t
379 l4_icu_set_mode_u(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t mode,
380                   l4_utcb_t *utcb) L4_NOTHROW
381 {
382   l4_msg_regs_t *mr = l4_utcb_mr_u(utcb);
383   mr->mr[0] = L4_ICU_OP_SET_MODE;
384   mr->mr[1] = irqnum;
385   mr->mr[2] = mode;
386   return l4_ipc_call(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 3, 0, 0), L4_IPC_NEVER);
387 }
388
389 L4_INLINE l4_msgtag_t
390 l4_icu_control_u(l4_cap_idx_t icu, unsigned irqnum, unsigned op,
391                  l4_umword_t *label, l4_timeout_t to,
392                  l4_utcb_t *utcb) L4_NOTHROW
393 {
394   l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
395   m->mr[0] = L4_ICU_OP_UNMASK + op;
396   m->mr[1] = irqnum;
397   if (label)
398     return l4_ipc_send_and_wait(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 2, 0, 0),
399                                 label, to);
400   else
401     return l4_ipc_send(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 2, 0, 0), to);
402 }
403
404 L4_INLINE l4_msgtag_t
405 l4_icu_mask_u(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *label,
406               l4_timeout_t to, l4_utcb_t *utcb) L4_NOTHROW
407 { return l4_icu_control_u(icu, irqnum, L4_ICU_CTL_MASK, label, to, utcb); }
408
409 L4_INLINE l4_msgtag_t
410 l4_icu_unmask_u(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *label,
411                 l4_timeout_t to, l4_utcb_t *utcb) L4_NOTHROW
412 { return l4_icu_control_u(icu, irqnum, L4_ICU_CTL_UNMASK, label, to, utcb); }
413
414
415
416
417 L4_INLINE l4_msgtag_t
418 l4_icu_bind(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq) L4_NOTHROW
419 { return l4_icu_bind_u(icu, irqnum, irq, l4_utcb()); }
420
421 L4_INLINE l4_msgtag_t
422 l4_icu_unbind(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq) L4_NOTHROW
423 { return l4_icu_unbind_u(icu, irqnum, irq, l4_utcb()); }
424
425 L4_INLINE l4_msgtag_t
426 l4_icu_info(l4_cap_idx_t icu, l4_icu_info_t *info) L4_NOTHROW
427 { return l4_icu_info_u(icu, info, l4_utcb()); }
428
429 L4_INLINE l4_msgtag_t
430 l4_icu_msi_info(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *msg) L4_NOTHROW
431 { return l4_icu_msi_info_u(icu, irqnum, msg, l4_utcb()); }
432
433 L4_INLINE l4_msgtag_t
434 l4_icu_unmask(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *label,
435               l4_timeout_t to) L4_NOTHROW
436 { return l4_icu_control_u(icu, irqnum, L4_ICU_CTL_UNMASK, label, to, l4_utcb()); }
437
438 L4_INLINE l4_msgtag_t
439 l4_icu_mask(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *label,
440             l4_timeout_t to) L4_NOTHROW
441 { return l4_icu_control_u(icu, irqnum, L4_ICU_CTL_MASK, label, to, l4_utcb()); }
442
443 L4_INLINE l4_msgtag_t
444 l4_icu_set_mode(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t mode) L4_NOTHROW
445 {
446   return l4_icu_set_mode_u(icu, irqnum, mode, l4_utcb());
447 }