xref: /freebsd/share/man/man9/intr_event.9 (revision 6fe0a6c80a1aff14236924eb33e4013aa8c14f91)
1.\" Copyright (c) 2001 John H. Baldwin <jhb@FreeBSD.org>
2.\" Copyright (c) 2006 Tom Rhodes <trhodes@FreeBSD.org>
3.\" Copyright (c) 2021 Mitchell Horne <mhorne@FreeBSD.org>
4.\" Copyright (c) 2022 The FreeBSD Foundation
5.\"
6.\" Portions of this documentation were written by Mitchell Horne
7.\" under sponsorship from the FreeBSD Foundation.
8.\"
9.\" Redistribution and use in source and binary forms, with or without
10.\" modification, are permitted provided that the following conditions
11.\" are met:
12.\" 1. Redistributions of source code must retain the above copyright
13.\"    notice, this list of conditions and the following disclaimer.
14.\" 2. Redistributions in binary form must reproduce the above copyright
15.\"    notice, this list of conditions and the following disclaimer in the
16.\"    documentation and/or other materials provided with the distribution.
17.\"
18.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28.\" SUCH DAMAGE.
29.\"
30.\" $FreeBSD$
31.\"
32.Dd October 15, 2022
33.Dt INTR_EVENT 9
34.Os
35.Sh NAME
36.Nm intr_event_add_handler ,
37.Nm intr_event_create ,
38.Nm intr_event_destroy ,
39.Nm intr_event_remove_handler ,
40.Nm intr_priority
41.Nd "kernel interrupt handler and thread API"
42.Sh SYNOPSIS
43.In sys/param.h
44.In sys/bus.h
45.In sys/interrupt.h
46.Ft int
47.Fo intr_event_add_handler
48.Fa "struct intr_event *ie"
49.Fa "const char *name"
50.Fa "driver_filter_t filter"
51.Fa "driver_intr_t handler"
52.Fa "void *arg"
53.Fa "u_char pri"
54.Fa "enum intr_type flags"
55.Fa "void **cookiep"
56.Fc
57.Ft int
58.Fo intr_event_create
59.Fa "struct intr_event **event"
60.Fa "void *source"
61.Fa "int flags"
62.Fa "int irq"
63.Fa "void (*pre_ithread)(void *)"
64.Fa "void (*post_ithread)(void *)"
65.Fa "void (*post_filter)(void *)"
66.Fa "int (*assign_cpu)(void *, int)"
67.Fa "const char *fmt"
68.Fa "..."
69.Fc
70.Ft int
71.Fn intr_event_destroy "struct intr_event *ie"
72.Ft int
73.Fn intr_event_remove_handler "void *cookie"
74.Ft u_char
75.Fn intr_priority "enum intr_type flags"
76.Sh DESCRIPTION
77The interrupt event API provides methods to manage the registration and
78execution of interrupt handlers and their associated thread contexts.
79.Pp
80Each interrupt event in the system corresponds to a single hardware or software
81interrupt source.
82Each interrupt event maintains a list of interrupt handlers, sorted by
83priority, which will be invoked when handling the event.
84An interrupt event will typically, but not always, have an associated
85.Xr kthread 9 ,
86known as the interrupt thread.
87Finally, each event contains optional callback functions which will be
88invoked before and after the handler functions themselves.
89.Pp
90An interrupt handler contains two distinct handler functions:
91the
92.Em filter
93and the thread
94.Em handler .
95The
96.Em filter
97function is run from interrupt context and is intended to perform quick
98handling such as acknowledging or masking a hardware interrupt,
99and queueing work for the ensuing thread
100.Em handler .
101Both functions are optional; each interrupt handler may choose to register a
102filter, a thread handler, or both.
103Each interrupt handler also consists of a name,
104a set of flags,
105and an opaque argument which will be passed to both the
106.Em filter
107and
108.Em handler
109functions.
110.Ss Handler Constraints
111The
112.Em filter
113function is executed inside a
114.Xr critical 9
115section.
116Therefore, filters may not yield the CPU for any reason, and may only use spin
117locks to access shared data.
118Allocating memory within a filter is not permitted.
119.Pp
120The
121.Em handler
122function executes from the context of the associated interrupt kernel thread.
123Sleeping is not permitted, but the interrupt thread may be preempted by higher
124priority threads.
125Thus, threaded handler functions may obtain non-sleepable locks, as described
126in
127.Xr locking 9 .
128Any memory or zone allocations in an interrupt thread must specify the
129.Dv M_NOWAIT
130flag, and any allocation errors must be handled.
131.Pp
132The exception to these constraints is software interrupt threads, which are
133allowed to sleep but should be allocated and scheduled using the
134.Xr swi 9
135interface.
136.Ss Function Descriptions
137The
138.Fn intr_event_create
139function creates a new interrupt event.
140The
141.Fa event
142argument points to a
143.Vt struct intr_event
144pointer that will reference the newly created event upon success.
145The
146.Fa source
147argument is an opaque pointer which will be passed to the
148.Fa pre_ithread ,
149.Fa post_ithread ,
150and
151.Fa post_filter
152callbacks.
153The
154.Fa flags
155argument is a mask of properties of this thread.
156The only valid flag currently for
157.Fn intr_event_create
158is
159.Dv IE_SOFT
160to specify that this interrupt thread is a software interrupt.
161The
162.Fa enable
163and
164.Fa disable
165arguments specify optional functions used to enable and disable this
166interrupt thread's interrupt source.
167The
168.Fa irq
169argument is the unique interrupt vector number corresponding to the event.
170The
171.Fa pre_ithread ,
172.Fa post_ithread ,
173and
174.Fa post_filter
175arguments are callback functions that are invoked at different
176points while handling an interrupt.
177This is described in more detail in the
178.Sx Handler Callbacks
179section, below.
180They may be
181.Va NULL
182to specify no callback.
183The
184.Fa assign_cpu
185argument points to a callback function that will be invoked when binding
186an interrupt to a particular CPU.
187It may be
188.Va NULL
189if binding is unsupported.
190The
191remaining arguments form a
192.Xr printf 9
193argument list that is used to build the base name of the new interrupt thread.
194The full name of an interrupt thread is formed by concatenating the base
195name of the interrupt thread with the names of all of its interrupt handlers.
196.Pp
197The
198.Fn intr_event_destroy
199function destroys a previously created interrupt event by releasing its
200resources.
201.\" The following is not true (yet):
202.\"and arranging for the backing kernel thread to terminate.
203An interrupt event can only be destroyed if it has no handlers remaining.
204.Pp
205The
206.Fn intr_event_add_handler
207function adds a new handler to an existing interrupt event specified by
208.Fa ie .
209The
210.Fa name
211argument specifies a name for this handler.
212The
213.Fa filter
214argument provide the filter function to execute.
215The
216.Fa handler
217argument provides the handler function to be executed from the
218event's interrupt thread.
219The
220.Fa arg
221argument will be passed to the
222.Fa filter
223and
224.Fa handler
225functions when they are invoked.
226The
227.Fa pri
228argument specifies the priority of this handler,
229corresponding to the values defined in
230.In sys/priority.h .
231It determines the order this handler is called relative to the other handlers
232for this event, as well as the scheduling priority of of the backing kernel
233thread.
234.Fa flags
235argument can be used to specify properties of this handler as defined in
236.In sys/bus.h .
237If
238.Fa cookiep
239is not
240.Dv NULL ,
241then it will be assigned a cookie that can be used later to remove this
242handler.
243.Pp
244The
245.Fn intr_event_remove_handler
246function removes an interrupt handler from the interrupt event specified by
247.Fa ie .
248The
249.Fa cookie
250argument, obtained from
251.Fn intr_event_add_handler ,
252identifies the handler to remove.
253.Pp
254The
255.Fn intr_priority
256function translates the
257.Dv INTR_TYPE_*
258interrupt flags into interrupt thread scheduling priorities.
259.Pp
260The interrupt flags not related to the type of a particular interrupt
261.Pq Dv INTR_TYPE_*
262can be used to specify additional properties of both hardware and software
263interrupt handlers.
264The
265.Dv INTR_EXCL
266flag specifies that this handler cannot share an interrupt thread with
267another handler.
268The
269.Dv INTR_MPSAFE
270flag specifies that this handler is MP safe in that it does not need the
271Giant mutex to be held while it is executed.
272The
273.Dv INTR_ENTROPY
274flag specifies that the interrupt source this handler is tied to is a good
275source of entropy, and thus that entropy should be gathered when an interrupt
276from the handler's source triggers.
277Presently, the
278.Dv INTR_ENTROPY
279flag is not valid for software interrupt handlers.
280.Ss Handler Callbacks
281Each
282.Vt struct intr_event
283is assigned three optional callback functions when it is created:
284.Fa pre_ithread ,
285.Fa post_ithread ,
286and
287.Fa post_filter .
288These callbacks are intended to be defined by the interrupt controller driver,
289to allow for actions such as masking and unmasking hardware interrupt signals.
290.Pp
291When an interrupt is triggered, all filters are run to determine if any
292threaded interrupt handlers should be scheduled for execution by the associated
293interrupt thread. If no threaded handlers are scheduled, the
294.Fa post_filter
295callback is invoked which should acknowledge the interrupt and permit it to
296trigger in the future.
297If any threaded handlers are scheduled, the
298.Fa pre_ithread
299callback is invoked instead.
300This handler should acknowledge the interrupt, but it should also ensure that
301the interrupt will not fire continuously until after the threaded handlers have
302executed.
303Typically this callback masks level-triggered interrupts in an interrupt
304controller while leaving edge-triggered interrupts alone.
305Once all threaded handlers have executed,
306the
307.Fa post_ithread
308callback is invoked from the interrupt thread to enable future interrupts.
309Typically this callback unmasks level-triggered interrupts in an interrupt
310controller.
311.Sh RETURN VALUES
312The
313.Fn intr_event_add_handler ,
314.Fn intr_event_create ,
315.Fn intr_event_destroy ,
316and
317.Fn intr_event_remove_handler
318functions return zero on success and non-zero on failure.
319The
320.Fn intr_priority
321function returns a process priority corresponding to the passed in interrupt
322flags.
323.Sh EXAMPLES
324The
325.Xr swi_add 9
326function demonstrates the use of
327.Fn intr_event_create
328and
329.Fn intr_event_add_handler .
330.Bd -literal -offset indent
331int
332swi_add(struct intr_event **eventp, const char *name, driver_intr_t handler,
333    void *arg, int pri, enum intr_type flags, void **cookiep)
334{
335	struct intr_event *ie;
336	int error = 0;
337
338	if (flags & INTR_ENTROPY)
339		return (EINVAL);
340
341	ie = (eventp != NULL) ? *eventp : NULL;
342
343	if (ie != NULL) {
344		if (!(ie->ie_flags & IE_SOFT))
345			return (EINVAL);
346	} else {
347		error = intr_event_create(&ie, NULL, IE_SOFT, 0,
348		    NULL, NULL, NULL, swi_assign_cpu, "swi%d:", pri);
349		if (error)
350			return (error);
351		if (eventp != NULL)
352			*eventp = ie;
353	}
354	if (handler != NULL) {
355		error = intr_event_add_handler(ie, name, NULL, handler, arg,
356		    PI_SWI(pri), flags, cookiep);
357	}
358	return (error);
359}
360.Ed
361.Sh ERRORS
362The
363.Fn intr_event_add_handler
364function will fail if:
365.Bl -tag -width Er
366.It Bq Er EINVAL
367The
368.Fa ie
369or
370.Fa name
371arguments are
372.Dv NULL .
373.It Bq Er EINVAL
374The
375.Fa handler
376and
377.Fa filter
378arguments are both
379.Dv NULL .
380.It Bq Er EINVAL
381The
382.Dv IH_EXCLUSIVE
383flag is specified and the interrupt thread
384.Fa ie
385already has at least one handler, or the interrupt thread
386.Fa ie
387already has an exclusive handler.
388.El
389.Pp
390The
391.Fn intr_event_create
392function will fail if:
393.Bl -tag -width Er
394.It Bq Er EINVAL
395A flag other than
396.Dv IE_SOFT
397was specified in the
398.Fa flags
399parameter.
400.El
401.Pp
402The
403.Fn intr_event_destroy
404function will fail if:
405.Bl -tag -width Er
406.It Bq Er EINVAL
407The
408.Fa ie
409argument is
410.Dv NULL .
411.It Bq Er EBUSY
412The interrupt event pointed to by
413.Fa ie
414has at least one handler which has not been removed with
415.Fn intr_event_remove_handler .
416.El
417.Pp
418The
419.Fn intr_event_remove_handler
420function will fail if:
421.Bl -tag -width Er
422.It Bq Er EINVAL
423The
424.Fa cookie
425argument is
426.Dv NULL .
427.El
428.Sh SEE ALSO
429.Xr kthread 9 ,
430.Xr locking 9 ,
431.Xr malloc 9 ,
432.Xr swi 9 ,
433.Xr uma 9
434.Sh HISTORY
435Interrupt threads and their corresponding API first appeared in
436.Fx 5.0 .
437