3 * \brief Interrupt controller.
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)
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.
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.
27 #include <l4/sys/kernel_object.h>
28 #include <l4/sys/ipc.h>
31 * \defgroup l4_icu_api Interrupt controller
32 * \ingroup l4_kernel_object_api
34 * \brief The ICU class.
36 * <c>\#include <l4/sys/icu.h></c>
41 * \brief Flags for IRQ numbers used for the ICU.
47 * \brief Flag to denote that the IRQ is actually an MSI.
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.
53 L4_ICU_FLAG_MSI = 0x80000000,
58 * \brief Interrupt flow types.
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 */
79 * \brief Opcodes to the ICU interface.
92 * \brief Unbind opcode.
94 * \see l4_icu_unbind()
106 * \brief Msi-info opcode.
108 * \see l4_icu_msi_info()
110 L4_ICU_OP_MSI_INFO = 3,
113 * \brief Unmask opcode.
115 * \see l4_icu_unmask()
117 L4_ICU_OP_UNMASK = 4,
120 * \brief Mask opcode.
127 * \brief Set-mode opcode.
129 * \see l4_icu_set_mode()
131 L4_ICU_OP_SET_MODE = 6,
136 L4_ICU_CTL_UNMASK = 0,
142 * \brief Info structure for an ICU.
143 * \ingroup l4_icu_api
145 * This structure contains information about the features of an ICU.
146 * \see l4_icu_info().
148 typedef struct l4_icu_info_t
151 * \brief Feature flags.
153 * If #L4_ICU_FLAG_MSI is set the ICU supports MSIs.
158 * \brief The number of IRQ lines supported by the ICU,
163 * \brief The number of MSI vectors supported by the ICU,
169 * \brief Bind an interrupt vector of an interrupt controller to an interrupt object.
170 * \ingroup l4_icu_api
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
177 L4_INLINE l4_msgtag_t
178 l4_icu_bind(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq) L4_NOTHROW;
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;
188 * \brief Remove binding of an interrupt vector from the interrupt controller object.
189 * \ingroup l4_icu_api
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
196 L4_INLINE l4_msgtag_t
197 l4_icu_unbind(l4_cap_idx_t icu, unsigned irqnum, l4_cap_idx_t irq) L4_NOTHROW;
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;
207 * \brief Set mode of interrupt.
208 * \ingroup l4_icu_api
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
215 * \ingroup l4_icu_api
217 L4_INLINE l4_msgtag_t
218 l4_icu_set_mode(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t mode) L4_NOTHROW;
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;
228 * \brief Get info about capabilites of ICU.
229 * \ingroup l4_icu_api
231 * \param icu ICU to use.
232 * \param info Pointer to an info structure to be filled with information.
233 * \return Syscall return tag
235 L4_INLINE l4_msgtag_t
236 l4_icu_info(l4_cap_idx_t icu, l4_icu_info_t *info) L4_NOTHROW;
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;
246 * \brief Get MSI info about IRQ.
247 * \ingroup l4_icu_api
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
255 L4_INLINE l4_msgtag_t
256 l4_icu_msi_info(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t *msg) L4_NOTHROW;
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;
267 * \brief Unmask an IRQ vector.
268 * \ingroup l4_icu_api
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
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;
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;
288 * \brief Mask an IRQ vector.
289 * \ingroup l4_icu_api
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
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;
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;
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;
317 /**************************************************************************
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
325 l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
326 m->mr[0] = L4_ICU_OP_BIND;
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);
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
337 l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
338 m->mr[0] = L4_ICU_OP_UNBIND;
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);
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
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)
356 info->features = m->mr[0];
357 info->nr_irqs = m->mr[1];
358 info->nr_msis = m->mr[2];
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
368 l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
369 m->mr[0] = L4_ICU_OP_MSI_INFO;
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)
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
382 l4_msg_regs_t *mr = l4_utcb_mr_u(utcb);
383 mr->mr[0] = L4_ICU_OP_SET_MODE;
386 return l4_ipc_call(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 3, 0, 0), L4_IPC_NEVER);
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
394 l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
395 m->mr[0] = L4_ICU_OP_UNMASK + op;
398 return l4_ipc_send_and_wait(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 2, 0, 0),
401 return l4_ipc_send(icu, utcb, l4_msgtag(L4_PROTO_IRQ, 2, 0, 0), to);
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); }
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); }
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()); }
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()); }
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()); }
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()); }
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()); }
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()); }
443 L4_INLINE l4_msgtag_t
444 l4_icu_set_mode(l4_cap_idx_t icu, unsigned irqnum, l4_umword_t mode) L4_NOTHROW
446 return l4_icu_set_mode_u(icu, irqnum, mode, l4_utcb());