]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4sys/include/icu.h
2b3f4e1176026b7d85ab4ce396616a608553607b
[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_LEVEL_HIGH = 0x3,   /**< Level high trigger */
69   L4_IRQ_F_LEVEL_LOW  = 0x7,   /**< Level low trigger */
70   L4_IRQ_F_POS_EDGE   = 0x1,   /**< Positive edge trigger */
71   L4_IRQ_F_NEG_EDGE   = 0x5,   /**< Negative edge trigger */
72   L4_IRQ_F_MASK       = 0x7,   /**< Mask */
73 };
74
75
76 /**
77  * \brief Opcodes to the ICU interface.
78  * \ingroup l4_api_icu
79  */
80 enum L4_icu_opcode
81 {
82   /**
83    * \brief Bind opcode.
84    * \hideinitializer
85    * \see l4_icu_bind()
86    */
87   L4_ICU_OP_BIND = 0,
88
89   /**
90    * \brief Unbind opcode.
91    * \hideinitializer
92    * \see l4_icu_unbind()
93    */
94   L4_ICU_OP_UNBIND = 1,
95
96   /**
97    * \brief Info opcode.
98    * \hideinitializer
99    * \see l4_icu_info()
100    */
101   L4_ICU_OP_INFO = 2,
102
103   /**
104    * \brief Msi-info opcode.
105    * \hideinitializer
106    * \see l4_icu_msi_info()
107    */
108   L4_ICU_OP_MSI_INFO = 3,
109   L4_ICU_OP_UNMASK   = 4,
110   L4_ICU_OP_MASK     = 5,
111   L4_ICU_OP_SET_MODE = 6
112 };
113
114 enum L4_icu_ctl_op
115 {
116   L4_ICU_CTL_UNMASK = 0,
117   L4_ICU_CTL_MASK   = 1
118 };
119
120
121 /**
122  * \brief Info structure for an ICU.
123  * \ingroup l4_icu_api
124  *
125  * This structure contains information about the features of an ICU.
126  * \see l4_icu_info().
127  */
128 typedef struct l4_icu_info_t
129 {
130   /**
131    * \brief Feature flags.
132    *
133    * If #L4_ICU_FLAG_MSI is set the ICU supports MSIs.
134    */
135   unsigned features;
136
137   /**
138    * \brief The number of IRQ lines supported by the ICU,
139    */
140   unsigned nr_irqs;
141
142   /**
143    * \brief The number of MSI vectors supported by the ICU,
144    */
145   unsigned nr_msis;
146 } l4_icu_info_t;
147
148 /**
149  * \brief Bind an interrupt vector of an interrupt controller to an interrupt object.
150  * \ingroup l4_icu_api
151  *
152  * \param icu    ICU to use.
153  * \param irqnum IRQ vector at the ICU.
154  * \param irq    IRQ capability to bind the IRQ to.
155  * \return Syscall return tag
156  */
157 L4_INLINE l4_msgtag_t
158 l4_icu_bind(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq) L4_NOTHROW;
159
160 /**
161  * \internal
162  */
163 L4_INLINE l4_msgtag_t
164 l4_icu_bind_u(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq,
165               l4_utcb_t *utcb) L4_NOTHROW;
166
167 /**
168  * \brief Remove binding of an interrupt vector from the interrupt controller object.
169  * \ingroup l4_icu_api
170  *
171  * \param icu    ICU to use.
172  * \param irqnum IRQ vector at the ICU.
173  * \param irq    IRQ object to remove from the ICU.
174  * \return Syscall return tag
175  */
176 L4_INLINE l4_msgtag_t
177 l4_icu_unbind(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq) L4_NOTHROW;
178
179 /**
180  * \internal
181  */
182 L4_INLINE l4_msgtag_t
183 l4_icu_unbind_u(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq,
184                 l4_utcb_t *utcb) L4_NOTHROW;
185
186 L4_INLINE l4_msgtag_t
187 l4_icu_set_mode(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t mode) L4_NOTHROW;
188
189 /**
190  * \internal
191  */
192 L4_INLINE l4_msgtag_t
193 l4_icu_set_mode_u(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t mode,
194                   l4_utcb_t *utcb) L4_NOTHROW;
195
196 /**
197  * \brief Get info about capabilites of ICU.
198  * \ingroup l4_icu_api
199  *
200  * \param icu    ICU to use.
201  * \param info   Pointer to an info structure to be filled with information.
202  * \return Syscall return tag
203  */
204 L4_INLINE l4_msgtag_t
205 l4_icu_info(l4_cap_idx_t icu, l4_icu_info_t *info) L4_NOTHROW;
206
207 /**
208  * \internal
209  */
210 L4_INLINE l4_msgtag_t
211 l4_icu_info_u(l4_cap_idx_t icu, l4_icu_info_t *info,
212               l4_utcb_t *utcb) L4_NOTHROW;
213
214 /**
215  * \brief Get MSI info about IRQ.
216  * \ingroup l4_icu_api
217  *
218  * \param icu    ICU to use.
219  * \param irqnum IRQ vector at the ICU.
220  * \param msg    Pointer to a word to receive the message that must be used
221  *               for the PCI devices MSI message.
222  * \return Syscall return tag
223  */
224 L4_INLINE l4_msgtag_t
225 l4_icu_msi_info(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *msg) L4_NOTHROW;
226
227 /**
228  * \internal
229  */
230 L4_INLINE l4_msgtag_t
231 l4_icu_msi_info_u(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *msg,
232                   l4_utcb_t *utcb) L4_NOTHROW;
233
234
235 L4_INLINE l4_msgtag_t
236 l4_icu_unmask(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *label,
237               l4_timeout_t to) L4_NOTHROW;
238
239 L4_INLINE l4_msgtag_t
240 l4_icu_mask(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *label,
241             l4_timeout_t to) L4_NOTHROW;
242
243 /**
244  * \internal
245  */
246 L4_INLINE l4_msgtag_t
247 l4_icu_control_u(l4_cap_idx_t icu, unsigned irqnum, unsigned op,
248                  l4_umword_t *label,l4_timeout_t to,
249                  l4_utcb_t *utcb) L4_NOTHROW;
250
251
252 /**************************************************************************
253  * Implementations
254  */
255
256 L4_INLINE l4_msgtag_t
257 l4_icu_bind_u(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq,
258               l4_utcb_t *utcb) L4_NOTHROW
259 {
260   l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
261   m->mr[0] = L4_ICU_OP_BIND;
262   m->mr[1] = irqnum;
263   m->mr[2] = l4_map_obj_control(0, 0);
264   m->mr[3] = l4_obj_fpage(irq, 0, L4_FPAGE_RWX).raw;
265   return l4_ipc_call(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 2, 1, 0), L4_IPC_NEVER);
266 }
267
268 L4_INLINE l4_msgtag_t
269 l4_icu_unbind_u(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq,
270                 l4_utcb_t *utcb) L4_NOTHROW
271 {
272   l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
273   m->mr[0] = L4_ICU_OP_UNBIND;
274   m->mr[1] = irqnum;
275   m->mr[2] = l4_map_obj_control(0, 0);
276   m->mr[3] = l4_obj_fpage(irq, 0, L4_FPAGE_RWX).raw;
277   return l4_ipc_call(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 2, 1, 0), L4_IPC_NEVER);
278 }
279
280 L4_INLINE l4_msgtag_t
281 l4_icu_info_u(l4_cap_idx_t icu, l4_icu_info_t *info,
282               l4_utcb_t *utcb) L4_NOTHROW
283 {
284   l4_msgtag_t res;
285   l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
286   m->mr[0] = L4_ICU_OP_INFO;
287   res = l4_ipc_call(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 1, 0, 0), L4_IPC_NEVER);
288   if (!l4_msgtag_has_error(res) && l4_msgtag_label(res) >= 0
289       && l4_msgtag_words(res) >= 3)
290     {
291       info->features = m->mr[0];
292       info->nr_irqs  = m->mr[1];
293       info->nr_msis  = m->mr[2];
294     }
295   return res;
296 }
297
298 L4_INLINE l4_msgtag_t
299 l4_icu_msi_info_u(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *msg,
300                   l4_utcb_t *utcb) L4_NOTHROW
301 {
302   l4_msgtag_t res;
303   l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
304   m->mr[0] = L4_ICU_OP_MSI_INFO;
305   m->mr[1] = irqnum;
306   res = l4_ipc_call(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 2, 0, 0), L4_IPC_NEVER);
307   if (!l4_msgtag_has_error(res) && l4_msgtag_label(res) >= 0
308       && l4_msgtag_words(res) >= 1)
309     *msg = m->mr[0];
310   return res;
311 }
312
313
314
315 L4_INLINE l4_msgtag_t
316 l4_icu_bind(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq) L4_NOTHROW
317 { return l4_icu_bind_u(icu, irqnum, irq, l4_utcb()); }
318
319 L4_INLINE l4_msgtag_t
320 l4_icu_unbind(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq) L4_NOTHROW
321 { return l4_icu_unbind_u(icu, irqnum, irq, l4_utcb()); }
322
323 L4_INLINE l4_msgtag_t
324 l4_icu_info(l4_cap_idx_t icu, l4_icu_info_t *info) L4_NOTHROW
325 { return l4_icu_info_u(icu, info, l4_utcb()); }
326
327 L4_INLINE l4_msgtag_t
328 l4_icu_msi_info(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *msg) L4_NOTHROW
329 { return l4_icu_msi_info_u(icu, irqnum, msg, l4_utcb()); }
330
331 /**
332  * \internal
333  */
334 L4_INLINE l4_msgtag_t
335 l4_icu_control_u(l4_cap_idx_t icu, unsigned irqnum, unsigned op,
336                  l4_umword_t *label, l4_timeout_t to,
337                  l4_utcb_t *utcb) L4_NOTHROW
338 {
339   l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
340   m->mr[0] = L4_ICU_OP_UNMASK + op;
341   m->mr[1] = irqnum;
342   if (label)
343     return l4_ipc_send_and_wait(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 2, 0, 0),
344                                 label, to);
345   else
346     return l4_ipc_send(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 2, 0, 0), to);
347 }
348
349 L4_INLINE l4_msgtag_t
350 l4_icu_unmask(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *label,
351               l4_timeout_t to) L4_NOTHROW
352 { return l4_icu_control_u(icu, irqnum, L4_ICU_CTL_UNMASK, label, to, l4_utcb()); }
353
354 L4_INLINE l4_msgtag_t
355 l4_icu_mask(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *label,
356             l4_timeout_t to) L4_NOTHROW
357 { return l4_icu_control_u(icu, irqnum, L4_ICU_CTL_MASK, label, to, l4_utcb()); }
358
359 L4_INLINE l4_msgtag_t
360 l4_icu_set_mode_u(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t mode,
361                   l4_utcb_t *utcb) L4_NOTHROW
362 {
363   l4_msg_regs_t *mr = l4_utcb_mr_u(utcb);
364   mr->mr[0] = L4_ICU_OP_SET_MODE;
365   mr->mr[1] = irqnum;
366   mr->mr[2] = mode;
367   return l4_ipc_call(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 3, 0, 0), L4_IPC_NEVER);
368 }
369
370 L4_INLINE l4_msgtag_t
371 l4_icu_set_mode(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t mode) L4_NOTHROW
372 {
373   return l4_icu_set_mode_u(icu, irqnum, mode, l4_utcb());
374 }
375