1 /**
2 * \file
3 * C Irq interface
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 * Björn Döbel <doebel@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 #include <l4/sys/rcv_endpoint.h>
30
31 /**
32 * \defgroup l4_irq_api IRQs
33 * \ingroup l4_kernel_object_api
34 *
35 * C IRQ interface.
36 *
37 * The IRQ interface provides access to abstract interrupts provided by the
38 * microkernel. Interrupts may be
39 * - hardware interrupts provided by the platform interrupt controller,
40 * - virtual device interrupts provided by the microkernel's virtual devices
41 * (virtual serial or trace buffer) or
42 * - virtual interrupts that can be triggered by user programs (IRQs) via
43 * l4_irq_trigger().
44 *
45 * IRQ objects can be created using a factory, see the \ref l4_factory_api API
46 * (use l4_factory_create_irq()).
47 *
48 * \includefile{l4/sys/irq.h}
49 *
50 * For the C++ interface refer to the L4::Irq API for an overview.
51 */
52
53 /**
54 * Chain an IRQ to another master IRQ source.
55 * \ingroup l4_irq_api
56 *
57 * \param irq The master IRQ object.
58 * \param slave The slave that shall be attached to the master.
59 *
60 * \return Syscall return tag
61 *
62 * The chaining feature of IRQ objects allows to deal with shared IRQs. For
63 * chaining IRQs there must be a master IRQ object, bound to the real IRQ
64 * source. Note, the master IRQ must not have a thread bound to it.
65 *
66 * This function allows to add a limited number of slave IRQs to this master
67 * IRQ, with the semantics that each of the slave IRQs is triggered whenever
68 * the master IRQ is triggered. The master IRQ will be masked automatically
69 * when an IRQ is delivered and shall be unmasked when all attached slave IRQs
70 * are unmasked.
71 */
72 L4_INLINE l4_msgtag_t
73 l4_irq_mux_chain(l4_cap_idx_t irq, l4_cap_idx_t slave) L4_NOTHROW;
74
75 /**
76 * \ingroup l4_irq_api
77 * \copybrief L4::Irq_mux::chain
78 * \param irq The master IRQ object.
79 * \copydetails L4::Irq_mux::chain
80 */
81 L4_INLINE l4_msgtag_t
82 l4_irq_mux_chain_u(l4_cap_idx_t irq, l4_cap_idx_t slave,
83 l4_utcb_t *utcb) L4_NOTHROW;
84
85 /**
86 * Detach from an interrupt source.
87 * \ingroup l4_irq_api
88 *
89 * \param irq The IRQ object that shall be detached.
90 *
91 * \return Syscall return tag
92 */
93 L4_INLINE l4_msgtag_t
94 l4_irq_detach(l4_cap_idx_t irq) L4_NOTHROW;
95
96 /**
97 * \ingroup l4_irq_api
98 * \copybrief L4::Irq::detach
99 * \param irq The IRQ object that shall be detached.
100 * \copydetails L4::Irq::detach
101 */
102 L4_INLINE l4_msgtag_t
103 l4_irq_detach_u(l4_cap_idx_t irq, l4_utcb_t *utcb) L4_NOTHROW;
104
105
106 /**
107 * Trigger an IRQ.
108 * \ingroup l4_irq_api
109 *
110 * \param irq The IRQ object that shall be triggered.
111 *
112 * \return Syscall return tag.
113 *
114 * Note that this function is a send only operation, i.e. there is no return
115 * value except for a failed send operation. Especially l4_error() will
116 * return an error value from the message tag which still contains the IRQ
117 * protocol used for the send operation.
118 *
119 * Use l4_ipc_error() to check for (send) errors.
120 */
121 L4_INLINE l4_msgtag_t
122 l4_irq_trigger(l4_cap_idx_t irq) L4_NOTHROW;
123
124 /**
125 * \ingroup l4_irq_api
126 * \copybrief L4::Irq::trigger
127 * \param irq The IRQ object that shall be triggered.
128 * \copydetails L4::Irq::trigger
129 */
130 L4_INLINE l4_msgtag_t
131 l4_irq_trigger_u(l4_cap_idx_t irq, l4_utcb_t *utcb) L4_NOTHROW;
132
133 /**
134 * Unmask and wait for specified IRQ.
135 * \ingroup l4_irq_api
136 *
137 * \param irq The IRQ object that shall be unmasked.
138 * \param to Timeout.
139 *
140 * \return Syscall return tag
141 */
142 L4_INLINE l4_msgtag_t
143 l4_irq_receive(l4_cap_idx_t irq, l4_timeout_t to) L4_NOTHROW;
144
145 /**
146 * \ingroup l4_irq_api
147 * \copybrief L4::Irq::receive
148 * \param irq The IRQ object that shall be unmasked.
149 * \copydetails L4::Irq::receive
150 */
151 L4_INLINE l4_msgtag_t
152 l4_irq_receive_u(l4_cap_idx_t irq, l4_timeout_t timeout, l4_utcb_t *utcb) L4_NOTHROW;
153
154 /**
155 * Unmask IRQ and wait for any message.
156 * \ingroup l4_irq_api
157 *
158 * \param irq The IRQ object that shall be unmasked.
159 * \param label Receive label.
160 * \param to Timeout.
161 *
162 * \return Syscall return tag
163 */
164 L4_INLINE l4_msgtag_t
165 l4_irq_wait(l4_cap_idx_t irq, l4_umword_t *label,
166 l4_timeout_t to) L4_NOTHROW;
167
168 /**
169 * \ingroup l4_irq_api
170 * \copybrief L4::Irq::wait
171 * \param irq The IRQ object that shall be unmasked.
172 * \copydetails L4::Irq::wait
173 */
174 L4_INLINE l4_msgtag_t
175 l4_irq_wait_u(l4_cap_idx_t irq, l4_umword_t *label,
176 l4_timeout_t timeout, l4_utcb_t *utcb) L4_NOTHROW;
177
178 /**
179 * Unmask IRQ.
180 * \ingroup l4_irq_api
181 *
182 * \param irq The IRQ object that shall be unmasked.
183 *
184 * \return Syscall return tag
185 *
186 * \note l4_irq_wait() and l4_irq_receive() are doing the unmask themselves.
187 */
188 L4_INLINE l4_msgtag_t
189 l4_irq_unmask(l4_cap_idx_t irq) L4_NOTHROW;
190
191 /**
192 * \ingroup l4_irq_api
193 * \copybrief L4::Irq::unmask
194 * \param irq The IRQ object that shall be unmasked.
195 * \copydetails L4::Irq::unmask
196 */
197 L4_INLINE l4_msgtag_t
198 l4_irq_unmask_u(l4_cap_idx_t irq, l4_utcb_t *utcb) L4_NOTHROW;
199
200 /**
201 * \internal
202 */
203 enum L4_irq_sender_op
204 {
205 L4_IRQ_SENDER_OP_RESERVED1 = 0, // Ex ATTACH
206 L4_IRQ_SENDER_OP_DETACH = 1
207 };
208
209 /**
210 * \internal
211 */
212 enum L4_irq_mux_op
213 {
214 L4_IRQ_MUX_OP_CHAIN = 0
215 };
216
217 /**
218 * \internal
219 */
220 enum L4_irq_op
221 {
222 L4_IRQ_OP_TRIGGER = 2,
223 L4_IRQ_OP_EOI = 4
224 };
225
226 /**************************************************************************
227 * Implementations
228 */
229
230 L4_INLINE l4_msgtag_t
l4_irq_mux_chain_u(l4_cap_idx_t irq,l4_cap_idx_t slave,l4_utcb_t * utcb)231 l4_irq_mux_chain_u(l4_cap_idx_t irq, l4_cap_idx_t slave,
232 l4_utcb_t *utcb) L4_NOTHROW
233 {
234 l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
235 m->mr[0] = L4_IRQ_MUX_OP_CHAIN;
236 m->mr[1] = l4_map_obj_control(0, 0);
237 m->mr[2] = l4_obj_fpage(slave, 0, L4_CAP_FPAGE_RWS).raw;
238 return l4_ipc_call(irq, utcb, l4_msgtag(L4_PROTO_IRQ_MUX, 1, 1, 0),
239 L4_IPC_NEVER);
240 }
241
242 L4_INLINE l4_msgtag_t
l4_irq_detach_u(l4_cap_idx_t irq,l4_utcb_t * utcb)243 l4_irq_detach_u(l4_cap_idx_t irq, l4_utcb_t *utcb) L4_NOTHROW
244 {
245 l4_utcb_mr_u(utcb)->mr[0] = L4_IRQ_SENDER_OP_DETACH;
246 return l4_ipc_call(irq, utcb, l4_msgtag(L4_PROTO_IRQ_SENDER, 1, 0, 0),
247 L4_IPC_NEVER);
248 }
249
250 L4_INLINE l4_msgtag_t
l4_irq_trigger_u(l4_cap_idx_t irq,l4_utcb_t * utcb)251 l4_irq_trigger_u(l4_cap_idx_t irq, l4_utcb_t *utcb) L4_NOTHROW
252 {
253 return l4_ipc_send(irq, utcb, l4_msgtag(L4_PROTO_IRQ, 0, 0, 0),
254 L4_IPC_BOTH_TIMEOUT_0);
255 }
256
257 L4_INLINE l4_msgtag_t
l4_irq_receive_u(l4_cap_idx_t irq,l4_timeout_t to,l4_utcb_t * utcb)258 l4_irq_receive_u(l4_cap_idx_t irq, l4_timeout_t to, l4_utcb_t *utcb) L4_NOTHROW
259 {
260 l4_utcb_mr_u(utcb)->mr[0] = L4_IRQ_OP_EOI;
261 return l4_ipc_call(irq, utcb, l4_msgtag(L4_PROTO_IRQ, 1, 0, 0), to);
262 }
263
264 L4_INLINE l4_msgtag_t
l4_irq_wait_u(l4_cap_idx_t irq,l4_umword_t * label,l4_timeout_t to,l4_utcb_t * utcb)265 l4_irq_wait_u(l4_cap_idx_t irq, l4_umword_t *label,
266 l4_timeout_t to, l4_utcb_t *utcb) L4_NOTHROW
267 {
268 l4_utcb_mr_u(utcb)->mr[0] = L4_IRQ_OP_EOI;
269 return l4_ipc_send_and_wait(irq, utcb, l4_msgtag(L4_PROTO_IRQ, 1, 0, 0),
270 label, to);
271 }
272
273 L4_INLINE l4_msgtag_t
l4_irq_unmask_u(l4_cap_idx_t irq,l4_utcb_t * utcb)274 l4_irq_unmask_u(l4_cap_idx_t irq, l4_utcb_t *utcb) L4_NOTHROW
275 {
276 l4_utcb_mr_u(utcb)->mr[0] = L4_IRQ_OP_EOI;
277 return l4_ipc_send(irq, utcb, l4_msgtag(L4_PROTO_IRQ, 1, 0, 0), L4_IPC_NEVER);
278 }
279
280
281 L4_INLINE l4_msgtag_t
l4_irq_mux_chain(l4_cap_idx_t irq,l4_cap_idx_t slave)282 l4_irq_mux_chain(l4_cap_idx_t irq, l4_cap_idx_t slave) L4_NOTHROW
283 {
284 return l4_irq_mux_chain_u(irq, slave, l4_utcb());
285 }
286
287 L4_INLINE l4_msgtag_t
l4_irq_detach(l4_cap_idx_t irq)288 l4_irq_detach(l4_cap_idx_t irq) L4_NOTHROW
289 {
290 return l4_irq_detach_u(irq, l4_utcb());
291 }
292
293 L4_INLINE l4_msgtag_t
l4_irq_trigger(l4_cap_idx_t irq)294 l4_irq_trigger(l4_cap_idx_t irq) L4_NOTHROW
295 {
296 return l4_irq_trigger_u(irq, l4_utcb());
297 }
298
299 L4_INLINE l4_msgtag_t
l4_irq_receive(l4_cap_idx_t irq,l4_timeout_t to)300 l4_irq_receive(l4_cap_idx_t irq, l4_timeout_t to) L4_NOTHROW
301 {
302 return l4_irq_receive_u(irq, to, l4_utcb());
303 }
304
305 L4_INLINE l4_msgtag_t
l4_irq_wait(l4_cap_idx_t irq,l4_umword_t * label,l4_timeout_t to)306 l4_irq_wait(l4_cap_idx_t irq, l4_umword_t *label,
307 l4_timeout_t to) L4_NOTHROW
308 {
309 return l4_irq_wait_u(irq, label, to, l4_utcb());
310 }
311
312 L4_INLINE l4_msgtag_t
l4_irq_unmask(l4_cap_idx_t irq)313 l4_irq_unmask(l4_cap_idx_t irq) L4_NOTHROW
314 {
315 return l4_irq_unmask_u(irq, l4_utcb());
316 }
317
318